diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2007-06-10 13:02:43 +0200 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2007-06-10 13:02:43 +0200 |
commit | c6f8a149574f4e5196f802439e7439406ca82e71 (patch) | |
tree | 0b04b012f87d7033abb37aeb986385672b85da18 /tools.c | |
parent | 32dd727d057a1ba22d403f48306adae10285ac77 (diff) | |
download | vdr-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.c | 264 |
1 files changed, 260 insertions, 4 deletions
@@ -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 }; |