/***************************************************************************** * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: str.c 543 2006-01-07 22:06:24Z picard $ * * The Core Pocket Media Player * Copyright (c) 2004-2005 Gabor Kovacs * ****************************************************************************/ #include "common.h" typedef struct stringdef { int Class; int Id; // tchar_t s[] } stringdef; #define TABLEINIT 3072 #define TABLEALIGN 1024 #ifdef TARGET_PALMOS #define BUFFERSIZE 512*sizeof(tchar_t) #else #define BUFFERSIZE 2048*sizeof(tchar_t) #endif void StringAlloc() { context* p = Context(); if (p->Lang != LANG_DEFAULT) ArrayAlloc(&p->StrTable[0],TABLEINIT,TABLEALIGN); ArrayAlloc(&p->StrTable[1],TABLEINIT,TABLEALIGN); p->StrLock = LockCreate(); } void StringFree() { context* p = Context(); array* i; for (i=ARRAYBEGIN(p->StrBuffer,array);i!=ARRAYEND(p->StrBuffer,array);++i) ArrayClear(i); ArrayClear(&p->StrTable[0]); ArrayClear(&p->StrTable[1]); ArrayClear(&p->StrBuffer); LockDelete(p->StrLock); p->StrLock = NULL; } static int CmpDef(const stringdef* const* pa, const stringdef* const* pb) { const stringdef* a = *pa; const stringdef* b = *pb; if (a->Class < b->Class || (a->Class == b->Class && a->Id < b->Id)) return -1; if (a->Class > b->Class || a->Id > b->Id) return 1; return 0; } static void AddDef(context* p, bool_t Default, const stringdef* Def) { array* Table = &p->StrTable[Default?1:0]; ArrayAdd(Table,ARRAYCOUNT(*Table,stringdef*),sizeof(stringdef*),&Def,(arraycmp)CmpDef,TABLEALIGN); } static void Filter(tchar_t* i) { tchar_t* j=i; for (;*i;++i,++j) { if (i[0]=='\\' && i[1]=='n') { *j=10; ++i; } else *j=*i; } *j=0; } void StringAddText(const char* p, int n) { uint32_t UserLang = Context()->Lang; tchar_t* s = (tchar_t*)malloc(MAXLINE*sizeof(tchar_t)); char* s8 = (char*)malloc(MAXLINE*sizeof(char)); int CodePage = -1; uint32_t Lang = 0; tchar_t* q; int i,No; if (s && s8) { while (n>0) { for (;n>0 && (*p==9 || *p==32);++p,--n); for (i=0;n>0 && *p!=13 && *p!=10;++p,--n) if (i0 && (*p==13 || *p==10);++p,--n) s8[i]=0; if (CodePage>=0 && s8[0]!='[' && s8[0]!=';') StrToTcsEx(s,MAXLINE,s8,CodePage); else AsciiToTcs(s,MAXLINE,s8); for (i=0;IsSpace(s[i]);++i); if (s[i]==0) continue; if (s[i]==';') { stscanf(s+i,T(";CODEPAGE = %d"),&CodePage); continue; } if (s[i]=='[') { ++i; q = tcschr(s+i,']'); if (!q || CodePage<0) break; // invalid language file *q = 0; Lang = StringToFourCC(s+i,1); if (Lang == FOURCC('D','E','F','A')) Lang = LANG_DEFAULT; if (Lang != LANG_DEFAULT) { if (Lang != UserLang) break; Context()->CodePage = CodePage; } } else { q = tcschr(s+i,'='); if (!q || !Lang) break; // invalid language file *q = 0; ++q; if (tcslen(s+i)>4) { if (tcslen(s+i)<8) No = StringToFourCC(s+i+4,1); else { No = StringToInt(s+i+4,1); if (No >= 32768) No -= 65536; } } else No = 0; Filter(q); StringAdd(Lang==LANG_DEFAULT,StringToFourCC(s+i,1),No,q); } } } free(s); free(s8); } bool_t StringIsBinary(int Class,int Id) { bool_t Result = 1; context* p = Context(); array* i; const tchar_t* Def = LangStrDef(Class,Id); if (Def[0]) { LockEnter(p->StrLock); for (i=ARRAYBEGIN(p->StrBuffer,array);i!=ARRAYEND(p->StrBuffer,array);++i) if (ARRAYBEGIN(*i,const tchar_t)<=Def && ARRAYEND(*i,const tchar_t)>Def) { Result = 0; break; } LockLeave(p->StrLock); } return Result; } bool_t StringAddBinary(const void* Data, size_t Length) { context* p = Context(); const uint8_t* Def = (const uint8_t*)Data + 2*sizeof(int); uint32_t Lang = *(const uint32_t*)Data; size_t Len; if (Lang != LANG_DEFAULT && Lang != p->Lang) return 0; LockEnter(p->StrLock); while (Length>sizeof(stringdef)) { AddDef(p,Lang==LANG_DEFAULT,(const stringdef*)Def); Len = (tcslen((const tchar_t*)(Def+sizeof(stringdef)))+1)*sizeof(tchar_t); Len = sizeof(stringdef)+((Len+sizeof(int)-1) & ~(sizeof(int)-1)); Def += Len; Length -= Len; } LockLeave(p->StrLock); return 1; } void StringAdd(bool_t Default, int Class, int Id, const tchar_t* s) { context* p = Context(); int Pos,Len,Total; bool_t Found; array* Last = &p->StrTable[Default?1:0]; stringdef Def; stringdef* Ptr = &Def; Def.Class = Class; Def.Id = Id; if (!s) s = T(""); LockEnter(p->StrLock); // already the same? Pos = ArrayFind(Last,ARRAYCOUNT(*Last,stringdef*),sizeof(stringdef*),&Ptr,(arraycmp)CmpDef,&Found); if (Found && tcscmp(s,(tchar_t*)(ARRAYBEGIN(*Last,stringdef*)[Pos]+1))==0) { LockLeave(p->StrLock); return; } // add to buffer Len = (tcslen(s)+1)*sizeof(tchar_t); Total = sizeof(stringdef)+((Len+sizeof(int)-1) & ~(sizeof(int)-1)); Last = ARRAYEND(p->StrBuffer,array)-1; if (ARRAYEMPTY(p->StrBuffer) || ARRAYCOUNT(*Last,uint8_t)+Total > ARRAYALLOCATED(*Last,uint8_t)) { // add new buffer if (!ArrayAppend(&p->StrBuffer,NULL,sizeof(array),128)) { LockLeave(p->StrLock); return; } Last = ARRAYEND(p->StrBuffer,array)-1; memset(Last,0,sizeof(array)); if (!ArrayAlloc(Last,BUFFERSIZE,1)) { LockLeave(p->StrLock); return; } } // no allocation needed here (can't fail) Ptr = (stringdef*)ARRAYEND(*Last,uint8_t); ArrayAppend(Last,&Def,sizeof(stringdef),1); ArrayAppend(Last,s,Len,1); ArrayAppend(Last,NULL,Total-Len-sizeof(stringdef),1); AddDef(p,Default,Ptr); LockLeave(p->StrLock); } void StringAddPrint(bool_t Default, int Class,int No,const tchar_t* Msg, ...) { tchar_t s[256]; va_list Arg; va_start(Arg, Msg); vstprintf_s(s,TSIZEOF(s), Msg, Arg); va_end(Arg); StringAdd(Default,Class,No,s); } int LangEnum(int Class, int No) { int Result = 0; context* p = Context(); stringdef **i; LockEnter(p->StrLock); for (i=ARRAYBEGIN(p->StrTable[1],stringdef*);i!=ARRAYEND(p->StrTable[1],stringdef*);++i) if ((*i)->Class==Class && No--==0) { Result = (*i)->Id; break; } LockLeave(p->StrLock); return Result; } const tchar_t* LangStr(int Class, int Id) { int n; context* p = Context(); bool_t Found; stringdef Def; stringdef* Ptr = &Def; Def.Class = Class; Def.Id = Id; LockEnter(p->StrLock); for (n=0;n<2;++n) { int Pos = ArrayFind(&p->StrTable[n],ARRAYCOUNT(p->StrTable[n],stringdef*), sizeof(stringdef*),&Ptr,(arraycmp)CmpDef,&Found); if (Found) { LockLeave(p->StrLock); return (tchar_t*)(ARRAYBEGIN(p->StrTable[n],stringdef*)[Pos]+1); } } LockLeave(p->StrLock); return T(""); } const tchar_t* LangStrDef(int Class, int Id) { int n; context* p = Context(); bool_t Found; stringdef Def; stringdef* Ptr = &Def; Def.Class = Class; Def.Id = Id; LockEnter(p->StrLock); for (n=1;n>=0;--n) { int Pos = ArrayFind(&p->StrTable[n],ARRAYCOUNT(p->StrTable[n],stringdef*), sizeof(stringdef*),&Ptr,(arraycmp)CmpDef,&Found); if (Found) { LockLeave(p->StrLock); return (tchar_t*)(ARRAYBEGIN(p->StrTable[n],stringdef*)[Pos]+1); } } LockLeave(p->StrLock); return T(""); }