- fix character conversion for DVB
[enigma2.git] / lib / base / estring.cpp
1 #include <string>
2 #include <ctype.h>
3 #include <limits.h>
4 #include <lib/base/elock.h>
5 #include <lib/base/eerror.h>
6 #include <lib/base/estring.h>
7
8 static pthread_mutex_t lock=PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
9
10 std::string getNum(int val, int sys)
11 {
12 //      Returns a string that contain the value val as string
13 //      if sys == 16 than hexadezimal if sys == 10 than decimal
14         char buf[12];
15
16         if (sys == 10)
17                 std::snprintf(buf, 12, "%i", val);
18         else if (sys == 16)
19                 std::snprintf(buf, 12, "%X", val);              
20         
21         std::string res;
22         res.assign(buf);
23         return res;
24 }
25
26                 // 8859-x to dvb coding tables. taken from www.unicode.org/Public/MAPPINGS/ISO8859/
27 static unsigned long c88595[128]={
28 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 
29 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 
30 0x00a0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x00ad, 0x040e, 0x040f, 
31 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 
32 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 
33 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 
34 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 
35 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x00a7, 0x045e, 0x045f};
36
37 static unsigned long c88596[128]={
38 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 
39 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 
40 0x00a0, 0x0000, 0x0000, 0x0000, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x060c, 0x00ad, 0x0000, 0x0000, 
41 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f, 
42 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, 
43 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
44 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, 
45 0x0650, 0x0651, 0x0652, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
46
47 static unsigned long c88597[128]={
48 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 
49 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 
50 0x00a0, 0x2018, 0x2019, 0x00a3, 0x0000, 0x0000, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x0000, 0x00ab, 0x00ac, 0x00ad, 0x0000, 0x2015, 
51 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x0385, 0x0386, 0x00b7, 0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f, 
52 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 
53 0x03a0, 0x03a1, 0x0000, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af, 
54 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 
55 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x0000};
56
57 static unsigned long c88598[128]={
58 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 
59 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 
60 0x00a0, 0x0000, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 
61 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x0000, 
62 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
63 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2017, 
64 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, 
65 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x0000, 0x0000, 0x200e, 0x200f, 0x0000};
66
67 static unsigned long c88599[128]={
68 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 
69 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 
70 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 
71 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 
72 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 
73 0x011e, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0130, 0x015e, 0x00df, 
74 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 
75 0x011f, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0131, 0x015f, 0x00ff};
76
77                 // UPC Direct / HBO strange two-character encoding. 0xC2 means acute, 0xC8 doule 'dot', 0xCA small 'circle', 0xCD double 'acute', 0xCF acute.
78                 // many thanks to the czechs who helped me while solving this.
79 static inline unsigned int doCzech(int c1, int c2)
80 {
81         switch (c1)
82         {
83         case 0xC2: // acute
84                 switch (c2)
85                 {
86                 case 'A': return 0x00C1;
87                 case 'a': return 0x00E1;
88                 case 'E': return 0x00C9;
89                 case 'e': return 0x00E9;
90                 case 'I': return 0x00CD;
91                 case 'i': return 0x00ED;
92                 case 'O': return 0x00D3;
93                 case 'o': return 0x00F3; // corrected, was 0x00E3
94                 case 'U': return 0x00DA;
95                 case 'u': return 0x00FA;
96                 case 'Y': return 0x00DD;
97                 case 'y': return 0x00FD;
98                 default:
99                         return 0;
100                 }
101         case 0xC8: // double 'dot'
102                 switch (c2)
103                 {
104                 case 'A': return 0x00C4;
105                 case 'a': return 0x00E4;
106                 case 'E': return 0x00CB;
107                 case 'e': return 0x00EB;
108                 case 'O': return 0x00D6;
109                 case 'o': return 0x00F6;
110                 case 'U': return 0x00DC;
111                 case 'u': return 0x00FC;
112                 default:
113                         return 0;
114                 }
115         case 0xCA: // small 'circle'
116                 switch (c2)               
117                 {                         
118                 case 'U': return 0x016E;  
119                 case 'u': return 0x016F;  
120                 default:                  
121                         return 0;             
122                 }                         
123         case 0xCD: // double 'acute'
124                 switch (c2)               
125                 {                         
126                 case 'O': return 0x0150;  
127                 case 'o': return 0x0151;  
128                 case 'U': return 0x0170;  
129                 case 'u': return 0x0171;  
130                 default:                  
131                         return 0;             
132                 }                         
133         case 0xCF: // caron
134                 switch (c2)
135                 {
136                 case 'C': return 0x010C;
137                 case 'c': return 0x010D;
138                 case 'D': return 0x010E;
139                 case 'd': return 0x010F;
140                 case 'E': return 0x011A;
141                 case 'e': return 0x011B;
142                 case 'L': return 0x013D;        // not sure if they really exist.
143                 case 'l': return 0x013E;
144                 case 'N': return 0x0147;
145                 case 'n': return 0x0148;
146                 case 'R': return 0x0158;
147                 case 'r': return 0x0159;
148                 case 'S': return 0x0160;
149                 case 's': return 0x0161;
150                 case 'T': return 0x0164;
151                 case 't': return 0x0165;
152                 case 'Z': return 0x017D;
153                 case 'z': return 0x017E;
154                 default:
155                         return 0;
156                 }
157         default:
158                 return 0;
159         }
160 }
161
162 static inline unsigned int recode(unsigned char d, int cp)
163 {
164         if (d < 0x80)
165                 return d;
166         switch (cp)
167         {
168         case 0:         // 8859-1 Latin1 <-> unicode mapping
169                 return d;
170         case 1:         // 8859-5 -> unicode mapping
171                 return c88595[d-0x80];
172         case 2:         // 8859-6 -> unicode mapping
173                 return c88596[d-0x80];
174         case 3:         // 8859-7 -> unicode mapping
175                 return c88597[d-0x80];
176         case 4:         // 8859-8 -> unicode mapping
177                 return c88598[d-0x80];
178         case 5:         // 8859-9 -> unicode mapping
179                 return c88599[d-0x80];
180         default:
181                 return d;
182         }
183 }
184
185 std::string convertDVBUTF8(const std::string &s, int table)
186 {
187         return convertDVBUTF8((const unsigned char*)s.c_str(), s.size(), table);
188 }
189
190 std::string convertDVBUTF8(const unsigned char *data, int len, int table)
191 {
192         int i;
193         if (!len)
194                 return "";
195                 
196         i=0;
197         if (data[0] <= 5)
198                 table=data[i++];
199         if ((data[0] >= 0x10) && (data[0] <= 0x12))
200                 return "<unsupported encoding>";
201
202         int bytesneeded=0, t=0, s=i;
203         
204         for (; i<len; ++i)
205         {
206                 unsigned long code=0;
207                 if ((table == 5) && ((data[i] == 0xC2) || (data[i] == 0xC8) || (data[i] == 0xCA) || (data[i] == 0xCD) || (data[i] == 0xCF)) && (i+1 < len))
208                                 // braindead czech encoding...
209                         if ((code=doCzech(data[i], data[i+1])))
210                                 ++i;
211                 if (!code)
212                         code=recode(data[i], table);
213                 if (!code)
214                         continue;
215                 if (code >= 0x10000)
216                         bytesneeded++;
217                 if (code >= 0x800)
218                         bytesneeded++;
219                 if (code >= 0x80)
220                         bytesneeded++;
221                 bytesneeded++;
222         }
223         
224         i=s;
225         
226         unsigned char res[bytesneeded];
227         
228         while (i < len)
229         {
230                 unsigned long code=0;
231                 if ((table == 5) && ((data[i] == 0xC2) || (data[i] == 0xC8) || (data[i] == 0xCA) || (data[i] == 0xCD) || (data[i] == 0xCF)) && (i+1 < len))
232                                 // braindead czech encoding...
233                         if ((code=doCzech(data[i], data[i+1])))
234                                 i+=2;
235                 if (!code)
236                         code=recode(data[i++], table);
237                 if (!code)
238                         continue;
239                                 // Unicode->UTF8 encoding
240                 if (code < 0x80) // identity ascii <-> utf8 mapping
241                         res[t++]=char(code);
242                 else if (code < 0x800) // two byte mapping
243                 {
244                         res[t++]=(code>>6)|0xC0;
245                         res[t++]=(code&0x3F)|0x80;
246                 } else if (code < 0x10000) // three bytes mapping
247                 {
248                         res[t++]=(code>>12)|0xE0;
249                         res[t++]=((code>>6)&0x3F)|0x80;
250                         res[t++]=(code&0x3F)|0x80;
251                 } else
252                 {
253                         res[t++]=(code>>18)|0xF0;
254                         res[t++]=((code>>12)&0x3F)|0x80;
255                         res[t++]=((code>>6)&0x3F)|0x80;
256                         res[t++]=(code&0x3F)|0x80;
257                 }
258         }
259         if ( t != bytesneeded)
260                 eFatal("t: %d, bytesneeded: %d", t, bytesneeded);
261         return std::string().assign((char*)res, t);
262 }
263
264 std::string convertUTF8DVB(const std::string &string)
265 {
266         std::string ss=std::string();
267         
268         int len=string.length();
269         for(int i=0;i<len;i++){
270                 unsigned char c1=string[i];
271                 unsigned int c;
272                 if(c1<0x80)
273                         c=c1;
274                 else{
275                         i++;
276                         unsigned char c2=string[i];
277                         c=((c1&0x3F)<<6) + (c2&0x3F);
278                 }
279                 // c = UNICODE
280                 // now search it in table
281                 if(c>=0x80){
282                         for(unsigned int j=0;j<128;j++){
283                                 if(c88599[j]==c){            // now only 8859-9 ....
284                                         c=0x80+j;
285                                         break;
286                                 }
287                         }
288                 }
289                 ss+=c;
290         }
291
292         return ss;
293 }
294
295 std::string convertLatin1UTF8(const std::string &string)
296 {
297         unsigned int bytesneeded=0, t=0, i;
298         
299         unsigned int len=string.size();
300         
301         for (i=0; i<len; ++i)
302         {
303                 unsigned long code=string[i];
304                 if (!code)
305                         continue;
306                 if (code >= 0x10000)
307                         bytesneeded++;
308                 if (code >= 0x800)
309                         bytesneeded++;
310                 if (code >= 0x80)
311                         bytesneeded++;
312                 bytesneeded++;
313         }
314         
315         i=0;
316         
317         unsigned char res[bytesneeded];
318         
319         while (i < len)
320         {
321                 unsigned long code=string[i++];
322                                 // Unicode->UTF8 encoding
323                 if (code < 0x80) // identity latin <-> utf8 mapping
324                         res[t++]=char(code);
325                 else if (code < 0x800) // two byte mapping
326                 {
327                         res[t++]=(code>>6)|0xC0;
328                         res[t++]=(code&0x3F)|0x80;
329                 } else if (code < 0x10000) // three bytes mapping
330                 {
331                         res[t++]=(code>>12)|0xE0;
332                         res[t++]=((code>>6)&0x3F)|0x80;
333                         res[t++]=(code&0x3F)|0x80;
334                 } else
335                 {
336                         res[t++]=(code>>18)|0xF0;
337                         res[t++]=((code>>12)&0x3F)|0x80;
338                         res[t++]=((code>>6)&0x3F)|0x80;
339                         res[t++]=(code&0x3F)|0x80;
340                 }
341         }
342         if ( t != bytesneeded)
343                 eFatal("t: %d, bytesneeded: %d", t, bytesneeded);
344         return std::string().assign((char*)res, t);
345 }
346
347 int isUTF8(const std::string &string)
348 {
349         unsigned int len=string.size();
350         
351         for (unsigned int i=0; i < len; ++i)
352         {
353                 if (!(string[i]&0x80)) // normal ASCII
354                         continue;
355                 if ((string[i] & 0xE0) == 0xC0) // one char following.
356                 {
357                                 // first, length check:
358                         if (i+1 >= len)
359                                 return 0; // certainly NOT utf-8
360                         i++;
361                         if ((string[i]&0xC0) != 0x80)
362                                 return 0; // no, not UTF-8.
363                 } else if ((string[i] & 0xF0) == 0xE0)
364                 {
365                         if ((i+1) >= len)
366                                 return 0;
367                         i++;
368                         if ((string[i]&0xC0) != 0x80)
369                                 return 0;
370                         i++;
371                         if ((string[i]&0xC0) != 0x80)
372                                 return 0;
373                 }
374         }
375         return 1; // can be UTF8 (or pure ASCII, at least no non-UTF-8 8bit characters)
376 }
377