mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
Freetype font support; full UTF-8 support; dropped pixel fonts
This commit is contained in:
264
tools.c
264
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 };
|
||||
|
Reference in New Issue
Block a user