summaryrefslogtreecommitdiff
path: root/tools.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2007-06-10 13:02:43 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2007-06-10 13:02:43 +0200
commitc6f8a149574f4e5196f802439e7439406ca82e71 (patch)
tree0b04b012f87d7033abb37aeb986385672b85da18 /tools.c
parent32dd727d057a1ba22d403f48306adae10285ac77 (diff)
downloadvdr-c6f8a149574f4e5196f802439e7439406ca82e71.tar.gz
vdr-c6f8a149574f4e5196f802439e7439406ca82e71.tar.bz2
Freetype font support; full UTF-8 support; dropped pixel fonts
Diffstat (limited to 'tools.c')
-rw-r--r--tools.c264
1 files changed, 260 insertions, 4 deletions
diff --git a/tools.c b/tools.c
index f14de924..a6af97a6 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.122 2007/01/07 14:44:57 kls Exp $
+ * $Id: tools.c 1.123 2007/06/09 14:21:21 kls Exp $
*/
#include "tools.h"
@@ -570,6 +570,221 @@ uint64_t cTimeMs::Elapsed(void)
return Now() - begin;
}
+// --- UTF-8 support ---------------------------------------------------------
+
+static uint SystemToUtf8[128] = { 0 };
+
+int Utf8CharLen(const char *s)
+{
+ if (cCharSetConv::SystemCharacterTable())
+ return 1;
+#define MT(s, m, v) ((*(s) & (m)) == (v)) // Mask Test
+ if (MT(s, 0xE0, 0xC0) && MT(s + 1, 0xC0, 0x80))
+ return 2;
+ if (MT(s, 0xF0, 0xE0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80))
+ return 3;
+ if (MT(s, 0xF8, 0xF0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80) && MT(s + 3, 0xC0, 0x80))
+ return 4;
+ return 1;
+}
+
+uint Utf8CharGet(const char *s, int Length)
+{
+ if (cCharSetConv::SystemCharacterTable())
+ return (uchar)*s < 128 ? *s : SystemToUtf8[(uchar)*s - 128];
+ if (!Length)
+ Length = Utf8CharLen(s);
+ switch (Length) {
+ case 2: return ((*s & 0x1F) << 6) | (*(s + 1) & 0x3F);
+ case 3: return ((*s & 0x0F) << 4) | ((*(s + 1) & 0x3F) << 6) | (*(s + 2) & 0x3F);
+ case 4: return ((*s & 0x07) << 2) | ((*(s + 1) & 0x3F) << 4) | ((*(s + 2) & 0x3F) << 6) | (*(s + 3) & 0x3F);
+ }
+ return *s;
+}
+
+int Utf8CharSet(uint c, char *s)
+{
+ if (c < 0x80 || cCharSetConv::SystemCharacterTable()) {
+ if (s)
+ *s = c;
+ return 1;
+ }
+ if (c < 0x800) {
+ if (s) {
+ *s++ = ((c >> 6) & 0x1F) | 0xC0;
+ *s = (c & 0x3F) | 0x80;
+ }
+ return 2;
+ }
+ if (c < 0x10000) {
+ if (s) {
+ *s++ = ((c >> 12) & 0x0F) | 0xE0;
+ *s++ = ((c >> 6) & 0x3F) | 0x80;
+ *s = (c & 0x3F) | 0x80;
+ }
+ return 3;
+ }
+ if (c < 0x110000) {
+ if (s) {
+ *s++ = ((c >> 18) & 0x07) | 0xF0;
+ *s++ = ((c >> 12) & 0x3F) | 0x80;
+ *s++ = ((c >> 6) & 0x3F) | 0x80;
+ *s = (c & 0x3F) | 0x80;
+ }
+ return 4;
+ }
+ return 0; // can't convert to UTF-8
+}
+
+int Utf8SymChars(const char *s, int Symbols)
+{
+ if (cCharSetConv::SystemCharacterTable())
+ return Symbols;
+ int n = 0;
+ while (*s && Symbols--) {
+ int sl = Utf8CharLen(s);
+ s += sl;
+ n += sl;
+ }
+ return n;
+}
+
+int Utf8ToArray(const char *s, uint *a, int Size)
+{
+ int n = 0;
+ while (*s && --Size > 0) {
+ if (cCharSetConv::SystemCharacterTable())
+ *a++ = *s++;
+ else {
+ int sl = Utf8CharLen(s);
+ *a++ = Utf8CharGet(s, sl);
+ s += sl;
+ }
+ n++;
+ }
+ if (Size > 0)
+ *a = 0;
+ return n;
+}
+
+int Utf8FromArray(const uint *a, char *s, int Size, int Max)
+{
+ int NumChars = 0;
+ int NumSyms = 0;
+ while (*a && NumChars < Size) {
+ if (Max >= 0 && NumSyms++ >= Max)
+ break;
+ if (cCharSetConv::SystemCharacterTable()) {
+ *s++ = *a++;
+ NumChars++;
+ }
+ else {
+ int sl = Utf8CharSet(*a);
+ if (NumChars + sl <= Size) {
+ Utf8CharSet(*a, s);
+ a++;
+ s += sl;
+ NumChars += sl;
+ }
+ else
+ break;
+ }
+ }
+ if (NumChars < Size)
+ *s = 0;
+ return NumChars;
+}
+
+// --- cCharSetConv ----------------------------------------------------------
+
+char *cCharSetConv::systemCharacterTable = NULL;
+
+cCharSetConv::cCharSetConv(const char *FromCode, const char *ToCode)
+{
+ if (!FromCode)
+ FromCode = systemCharacterTable;
+ if (!ToCode)
+ ToCode = "UTF-8";
+ cd = (FromCode && ToCode) ? iconv_open(ToCode, FromCode) : (iconv_t)-1;
+ result = NULL;
+ length = 0;
+}
+
+cCharSetConv::~cCharSetConv()
+{
+ free(result);
+ iconv_close(cd);
+}
+
+void cCharSetConv::SetSystemCharacterTable(const char *CharacterTable)
+{
+ free(systemCharacterTable);
+ systemCharacterTable = NULL;
+ if (!strcasestr(CharacterTable, "UTF")) {
+ // Set up a map for the character values 128...255:
+ char buf[129];
+ for (int i = 0; i < 128; i++)
+ buf[i] = i + 128;
+ buf[129] = 0;
+ cCharSetConv csc(CharacterTable);
+ const char *s = csc.Convert(buf);
+ int i = 0;
+ while (*s) {
+ int sl = Utf8CharLen(s);
+ SystemToUtf8[i] = Utf8CharGet(s, sl);
+ s += sl;
+ i++;
+ }
+ systemCharacterTable = strdup(CharacterTable);
+ }
+}
+
+const char *cCharSetConv::Convert(const char *From, char *To, size_t ToLength)
+{
+ if (cd != (iconv_t)-1) {
+ char *FromPtr = (char *)From;
+ size_t FromLength = strlen(From);
+ char *ToPtr = To;
+ if (!ToPtr) {
+ length = max(length, FromLength * 2); // some reserve to avoid later reallocations
+ result = (char *)realloc(result, length);
+ ToPtr = result;
+ ToLength = length;
+ }
+ else if (!ToLength)
+ return From; // can't convert into a zero sized buffer
+ ToLength--; // save space for terminating 0
+ char *Converted = ToPtr;
+ while (FromLength > 0) {
+ if (iconv(cd, &FromPtr, &FromLength, &ToPtr, &ToLength) == size_t(-1)) {
+ if (errno == E2BIG || errno == EILSEQ && ToLength < 1) {
+ if (To)
+ break; // caller provided a fixed size buffer, but it was too small
+ // The result buffer is too small, so increase it:
+ size_t d = ToPtr - result;
+ size_t r = length / 2;
+ length += r;
+ result = (char *)realloc(result, length);
+ ToLength += r;
+ ToPtr = result + d;
+ }
+ if (errno == EILSEQ) {
+ // A character can't be converted, so mark it with '?' and proceed:
+ FromPtr++;
+ FromLength--;
+ *ToPtr++ = '?';
+ ToLength--;
+ }
+ else if (errno != E2BIG)
+ return From; // unknown error, return original string
+ }
+ }
+ *ToPtr = 0;
+ return Converted;
+ }
+ return From;
+}
+
// --- cString ---------------------------------------------------------------
cString::cString(const char *S, bool TakePointer)
@@ -607,12 +822,12 @@ cString cString::sprintf(const char *fmt, ...)
cString WeekDayName(int WeekDay)
{
- char buffer[4];
+ char buffer[16];
WeekDay = WeekDay == 0 ? 6 : WeekDay - 1; // we start with Monday==0!
if (0 <= WeekDay && WeekDay <= 6) {
const char *day = tr("MonTueWedThuFriSatSun");
- day += WeekDay * 3;
- strn0cpy(buffer, day, sizeof(buffer));
+ day += Utf8SymChars(day, WeekDay * 3);
+ strn0cpy(buffer, day, min(Utf8SymChars(day, 3) + 1, int(sizeof(buffer))));
return buffer;
}
else
@@ -890,6 +1105,47 @@ struct dirent *cReadDir::Next(void)
return directory && readdir_r(directory, &u.d, &result) == 0 ? result : NULL;
}
+// --- cFileNameList ---------------------------------------------------------
+
+cFileNameList::cFileNameList(const char *Directory)
+{
+ Load(Directory);
+}
+
+cFileNameList::~cFileNameList()
+{
+ for (int i = 0; i < Size(); i++)
+ free(At(i));
+}
+
+bool cFileNameList::Load(const char *Directory)
+{
+ if (Directory) {
+ cReadDir d(Directory);
+ struct dirent *e;
+ if (d.Ok()) {
+ while ((e = d.Next()) != NULL) {
+ if (strcmp(e->d_name, ".") && strcmp(e->d_name, ".."))
+ Append(strdup(e->d_name));
+ }
+ Sort(CompareStrings);
+ return true;
+ }
+ else
+ LOG_ERROR_STR(Directory);
+ }
+ return false;
+}
+
+int cFileNameList::Find(const char *FileName)
+{
+ for (int i = 0; i < Size(); i++) {
+ if (!strcmp(FileName, At(i)))
+ return i;
+ }
+ return -1;
+}
+
// --- cFile -----------------------------------------------------------------
bool cFile::files[FD_SETSIZE] = { false };