cleaned all trailing white space from source files.
[sdk] / ecere / src / sys / i18n.ec
1 #ifndef ECERE_NOFILE
2 import "File"
3 #endif
4 import "Map"
5
6 #if defined(ECERE_BOOTSTRAP) || defined(ECERE_STATIC)
7 #define dllexport
8 #if !defined(ECERE_BOOTSTRAP)
9 #define stdcall
10 #endif
11 #endif
12
13 #ifndef ECERE_BOOTSTRAP
14 #define FileOpen FileOpenBuffered
15 #endif
16
17 static Map<String, Map<String, String>> moduleMaps { };
18
19 #define SWAP_DWORD(dword) ((((unsigned int)(dword) & 0x000000ff) << 24) \
20                          | (((unsigned int)(dword) & 0x0000ff00) <<  8) \
21                          | (((unsigned int)(dword) & 0x00ff0000) >>  8) \
22                          | (((unsigned int)(dword) & 0xff000000) >> 24))
23
24 public dllexport void LoadTranslatedStrings(Module module, char * name)
25 {
26 #ifndef ECERE_NOFILE
27    File f;
28    char fileName[MAX_LOCATION];
29
30    char lcAll[256];
31    char language[256];
32    char lang[256];
33    char lcMessages[256];
34    char * locale = null;
35
36    if(GetEnvironment("LANGUAGE", language, sizeof(language)))
37       locale = language;
38    else if(GetEnvironment("LC_ALL", lcAll, sizeof(lcAll)))
39       locale = lcAll;
40    else if(GetEnvironment("LC_MESSAGES", lcMessages, sizeof(lcMessages)))
41       locale = lcMessages;
42    else if(GetEnvironment("LANG", lang, sizeof(lang)))
43       locale = lang;
44
45    if(locale)
46    {
47       char * dot;
48       if(language != locale)
49          strcpy(language, locale);
50       dot = strstr(language, ".");
51       if(dot) *dot = 0;
52       locale = language;
53    }
54
55    if(module.name)
56       sprintf(fileName, "<:%s>locale/%s/LC_MESSAGES/%s.mo", module.name, locale, name);
57    else
58       sprintf(fileName, ":locale/%s/LC_MESSAGES/%s.mo", locale, name);
59    f = FileOpen(fileName, read);
60    if(!f)
61    {
62       sprintf(fileName, "locale/%s/LC_MESSAGES/%s.mo", locale, name);
63       f = FileOpen(fileName, read);
64    }
65    if(!f)
66    {
67       sprintf(fileName, "/usr/share/locale/%s/LC_MESSAGES/%s.mo", locale, name);
68       f = FileOpen(fileName, read);
69    }
70    if(f)
71    {
72       uint magic = 0;
73       f.Read(&magic, sizeof(uint), 1);
74       if(magic == 0x950412de || magic == 0xde120495)
75       {
76          Map<String, String> textMap;
77          bool swap = magic != 0x950412de;
78          uint revision = 0;
79          uint numStrings = 0;
80          uint origStrings = 0, transStrings = 0;
81          uint hashingSize = 0, hashingOffset = 0;
82          int c;
83          f.Read(&revision, sizeof(uint), 1);       if(swap) SWAP_DWORD(revision);
84          f.Read(&numStrings, sizeof(uint), 1);     if(swap) SWAP_DWORD(numStrings);
85          f.Read(&origStrings, sizeof(uint), 1);    if(swap) SWAP_DWORD(origStrings);
86          f.Read(&transStrings, sizeof(uint), 1);   if(swap) SWAP_DWORD(transStrings);
87          f.Read(&hashingSize, sizeof(uint), 1);    if(swap) SWAP_DWORD(hashingSize);
88          f.Read(&hashingOffset, sizeof(uint), 1);  if(swap) SWAP_DWORD(hashingOffset);
89
90          if(!moduleMaps)
91             moduleMaps = { };
92          {
93             MapIterator<String, Map<String, String>> it { map = moduleMaps };
94             if(it.Index(module.name, false))
95                delete it.data;
96             // TOFIX: delete moduleMaps[module];
97          }
98          moduleMaps[module.name] = textMap = { };
99          for(c = 0; c < numStrings; c++)
100          {
101             uint len = 0, offset = 0;
102             char * original = null, * translated = null;
103
104             f.Seek(origStrings + c*2*sizeof(uint), start);
105             f.Read(&len, sizeof(uint), 1);      if(swap)SWAP_DWORD(len);
106             f.Read(&offset, sizeof(uint), 1);   if(swap)SWAP_DWORD(offset);
107             f.Seek(offset, start);
108
109             original = new byte[len + 1];
110             f.Read(original, 1, len + 1);
111
112             f.Seek(transStrings + c*2*sizeof(uint), start);
113             f.Read(&len, sizeof(uint), 1);      if(swap)SWAP_DWORD(len);
114             f.Read(&offset, sizeof(uint), 1);   if(swap)SWAP_DWORD(offset);
115             f.Seek(offset, start);
116
117             translated = new byte[len + 1];
118             f.Read(translated, 1, len + 1);
119
120             if(len)
121             {
122                MapIterator<String, String> it { map = textMap };
123                // TOFIX: Memory leak if the add fails
124                if(it.Index(original, false))
125                   delete translated;
126                else
127                   textMap[original] = translated;
128             }
129             else
130                delete translated;
131             delete original;
132          }
133       }
134       else
135       {
136          // Failure
137          printf("Invalid format while loading %s\n", fileName);
138       }
139       delete f;
140    }
141 #endif
142 }
143
144 public dllexport void UnloadTranslatedStrings(Module module)
145 {
146    MapIterator<String, Map<String, String>> it { map = moduleMaps };
147    if(it.Index(module.name, false))
148    {
149       it.data.Free();
150       moduleMaps.Delete(it.pointer);
151    }
152 }
153
154 public dllexport char * GetTranslatedString(Module module, char * string, char * stringAndContext)
155 {
156    Map<String, String> textMap = moduleMaps ? moduleMaps[module.name] : null;
157    char * result = textMap ? textMap[stringAndContext ? stringAndContext : string] : string;
158    return (result && result[0]) ? result : string;
159 }