Simplify decoding.
[gammu.git] / libgammu / misc / coding / coding.c
blobba7c7bd4fbf5bdaf9fd967f5accb333c7ade5055
1 /* (c) 2002-2004 by Marcin Wiacek, Michal Cihar and others */
2 /* based on some work from MyGnokii (www.mwiacek.com) */
3 /* based on some work from Gnokii (www.gnokii.org)
4 * (C) 1999-2000 Hugh Blemings & Pavel Janik ml. (C) 2001-2004 Pawel Kot
5 * GNU GPL version 2 or later
6 */
7 /* Due to a problem in the source code management, the names of some of
8 * the authors have unfortunately been lost. We do not mean to belittle
9 * their efforts and hope they will contact us to see their names
10 * properly added to the Copyright notice above.
11 * Having published their contributions under the terms of the GNU
12 * General Public License (GPL) [version 2], the Copyright of these
13 * authors will remain respected by adhering to the license they chose
14 * to publish their code under.
17 #include <gammu-config.h>
19 #ifdef HAVE_WCHAR_H
20 # include <wchar.h>
21 #endif
22 #ifdef HAVE_WCTYPE_H
23 # include <wctype.h>
24 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <locale.h>
31 #include <limits.h>
32 #ifdef WIN32
33 # define WIN32_LEAN_AND_MEAN
34 # include <windows.h>
35 #endif
37 #include "../../debug.h"
38 #include "coding.h"
40 /* function changes #10 #13 chars to \n \r */
41 unsigned char *EncodeUnicodeSpecialChars(unsigned char *dest, const unsigned char *buffer)
43 int Pos=0, Pos2=0;
45 while (buffer[Pos*2]!=0x00 || buffer[Pos*2+1]!=0x00) {
46 if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 10) {
47 dest[Pos2*2] = 0x00;
48 dest[Pos2*2+1] = '\\';
49 Pos2++;
50 dest[Pos2*2] = 0x00;
51 dest[Pos2*2+1] = 'n';
52 Pos2++;
53 } else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 13) {
54 dest[Pos2*2] = 0x00;
55 dest[Pos2*2+1] = '\\';
56 Pos2++;
57 dest[Pos2*2] = 0x00;
58 dest[Pos2*2+1] = 'r';
59 Pos2++;
60 } else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == '\\') {
61 dest[Pos2*2] = 0x00;
62 dest[Pos2*2+1] = '\\';
63 Pos2++;
64 dest[Pos2*2] = 0x00;
65 dest[Pos2*2+1] = '\\';
66 Pos2++;
67 } else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == ';') {
68 dest[Pos2*2] = 0x00;
69 dest[Pos2*2+1] = '\\';
70 Pos2++;
71 dest[Pos2*2] = 0x00;
72 dest[Pos2*2+1] = ';';
73 Pos2++;
74 } else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == ',') {
75 dest[Pos2*2] = 0x00;
76 dest[Pos2*2+1] = '\\';
77 Pos2++;
78 dest[Pos2*2] = 0x00;
79 dest[Pos2*2+1] = ',';
80 Pos2++;
81 } else {
82 dest[Pos2*2] = buffer[Pos*2];
83 dest[Pos2*2+1] = buffer[Pos*2+1];
84 Pos2++;
86 Pos++;
88 dest[Pos2*2] = 0;
89 dest[Pos2*2+1] = 0;
90 return dest;
93 /* function changes #10 #13 chars to \n \r */
94 char *EncodeSpecialChars(char *dest, const char *buffer)
96 int Pos=0, Pos2=0;
98 while (buffer[Pos]!=0x00) {
99 switch (buffer[Pos]) {
100 case 10:
101 dest[Pos2++] = '\\';
102 dest[Pos2++] = 'n';
103 break;
104 case 13:
105 dest[Pos2++] = '\\';
106 dest[Pos2++] = 'r';
107 break;
108 case '\\':
109 dest[Pos2++] = '\\';
110 dest[Pos2++] = '\\';
111 break;
112 default:
113 dest[Pos2++] = buffer[Pos];
115 Pos++;
117 dest[Pos2] = 0;
118 return dest;
121 unsigned char *DecodeUnicodeSpecialChars(unsigned char *dest, const unsigned char *buffer)
123 int Pos=0, Pos2=0, level=0;
125 while (buffer[Pos*2]!=0x00 || buffer[Pos*2+1]!=0x00) {
126 dest[Pos2*2] = buffer[Pos*2];
127 dest[Pos2*2+1] = buffer[Pos*2+1];
128 switch (level) {
129 case 0:
130 if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == '\\') {
131 level = 1;
132 } else {
133 Pos2++;
135 break;
136 case 1:
137 if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 'n') {
138 dest[Pos2*2] = 0;
139 dest[Pos2*2+1] = 10;
140 } else
141 if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 'r') {
142 dest[Pos2*2] = 0;
143 dest[Pos2*2+1] = 13;
144 } else
145 if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == '\\') {
146 dest[Pos2*2] = 0;
147 dest[Pos2*2+1] = '\\';
149 Pos2++;
150 level = 0;
152 Pos++;
154 dest[Pos2*2] = 0;
155 dest[Pos2*2+1] = 0;
156 return dest;
159 char *DecodeSpecialChars(char *dest, const char *buffer)
161 int Pos=0, Pos2=0, level=0;
163 while (buffer[Pos]!=0x00) {
164 dest[Pos2] = buffer[Pos];
165 switch (level) {
166 case 0:
167 if (buffer[Pos] == '\\') {
168 level = 1;
169 } else {
170 Pos2++;
172 break;
173 case 1:
174 if (buffer[Pos] == 'n') dest[Pos2] = 10;
175 if (buffer[Pos] == 'r') dest[Pos2] = 13;
176 if (buffer[Pos] == '\\') dest[Pos2] = '\\';
177 Pos2++;
178 level = 0;
180 Pos++;
182 dest[Pos2] = 0;
183 return dest;
186 size_t UnicodeLength(const unsigned char *str)
188 size_t len = 0;
190 if (str == NULL) return 0;
192 while(str[len*2] != 0 || str[len*2+1] != 0) len++;
194 return len;
197 /* Convert Unicode char saved in src to dest */
198 int EncodeWithUnicodeAlphabet(const unsigned char *src, wchar_t *dest)
200 int retval;
202 switch (retval = mbtowc(dest, src, MB_CUR_MAX)) {
203 case -1 :
204 case 0 : return 1;
205 default : return retval;
209 /* Convert Unicode char saved in src to dest */
210 int DecodeWithUnicodeAlphabet(wchar_t src, unsigned char *dest)
212 int retval;
214 switch (retval = wctomb(dest, src)) {
215 case -1:
216 *dest = '?';
217 return 1;
218 default:
219 return retval;
223 void DecodeUnicode (const unsigned char *src, char *dest)
225 int i=0,o=0;
226 wchar_t wc;
228 while (src[(2*i)+1]!=0x00 || src[2*i]!=0x00) {
229 wc = src[(2*i)+1] | (src[2*i] << 8);
230 o += DecodeWithUnicodeAlphabet(wc, dest + o);
231 i++;
233 dest[o]=0;
236 /* Decode Unicode string and return as function result */
237 char *DecodeUnicodeString (const unsigned char *src)
239 static char dest[500];
241 DecodeUnicode(src,dest);
242 return dest;
245 /* Decode Unicode string to UTF8 or other console charset
246 * and return as function result
248 char *DecodeUnicodeConsole(const unsigned char *src)
250 static char dest[500];
252 if (GSM_global_debug.coding[0] != 0) {
253 if (!strcmp(GSM_global_debug.coding,"utf8")) {
254 EncodeUTF8(dest, src);
255 } else {
256 #ifdef WIN32
257 setlocale(LC_ALL, GSM_global_debug.coding);
258 #endif
259 DecodeUnicode(src,dest);
261 } else {
262 #ifdef WIN32
263 setlocale(LC_ALL, ".OCP");
264 #endif
265 DecodeUnicode(src,dest);
266 #ifdef WIN32
267 setlocale(LC_ALL, ".ACP");
268 #endif
270 return dest;
273 /* Encode string to Unicode. Len is number of input chars */
274 void DecodeISO88591 (unsigned char *dest, const char *src, int len)
276 int i;
278 for (i = 0; i < len; i++) {
279 /* Hack for Euro sign */
280 if ((unsigned char)src[i] == 0x80) {
281 dest[2 * i] = 0x20;
282 dest[(2 * i) + 1] = 0xac;
283 } else {
284 dest[2 * i] = 0;
285 dest[(2 * i) + 1] = src[i];
288 dest[2 * i] = 0;
289 dest[(2 * i) + 1] = 0;
292 /* Encode string to Unicode. Len is number of input chars */
293 void EncodeUnicode (unsigned char *dest, const char *src, int len)
295 int i_len = 0, o_len;
296 wchar_t wc;
298 for (o_len = 0; i_len < len; o_len++) {
299 i_len += EncodeWithUnicodeAlphabet(&src[i_len], &wc);
300 dest[o_len*2] = (wc >> 8) & 0xff;
301 dest[(o_len*2)+1] = wc & 0xff;
303 dest[o_len*2] = 0;
304 dest[(o_len*2)+1] = 0;
307 unsigned char EncodeWithBCDAlphabet(int value)
309 div_t division;
311 division=div(value,10);
312 return ( ( (value-division.quot*10) & 0x0f) << 4) | (division.quot & 0xf);
315 int DecodeWithBCDAlphabet(unsigned char value)
317 return 10*(value & 0x0f)+(value >> 4);
320 void DecodeBCD (unsigned char *dest, const unsigned char *src, int len)
322 int i,current=0,digit;
324 for (i = 0; i < len; i++) {
325 digit=src[i] & 0x0f;
326 if (digit<10) dest[current++]=digit + '0';
327 digit=src[i] >> 4;
328 if (digit<10) dest[current++]=digit + '0';
330 dest[current++]=0;
333 void EncodeBCD (unsigned char *dest, const unsigned char *src, int len, gboolean fill)
335 int i,current=0;
337 for (i = 0; i < len; i++) {
338 if (i & 0x01) {
339 dest[current]=dest[current] | ((src[i]-'0') << 4);
340 current++;
341 } else {
342 dest[current]=src[i]-'0';
346 /* When fill is set: if number consist of odd number of digits,
347 we fill last bits in last byte with 0x0f
349 if (fill && (len & 0x01)) dest[current]=dest[current] | 0xf0;
352 int DecodeWithHexBinAlphabet (unsigned char mychar)
354 if (mychar >= 'A' && mychar <= 'F')
355 return mychar - 'A' + 10;
357 if (mychar >= 'a' && mychar <= 'f')
358 return mychar - 'a' + 10;
360 if (mychar >= '0' && mychar <= '9')
361 return mychar - '0';
363 return -1;
366 char EncodeWithHexBinAlphabet (int digit)
368 if (digit >= 0 && digit <= 9) return '0'+(digit);
369 if (digit >=10 && digit <=15) return 'A'+(digit-10);
370 return 0;
373 void DecodeHexUnicode (unsigned char *dest, const char *src, size_t len)
375 size_t i, current = 0;
377 for (i = 0; i < len ; i += 4) {
378 dest[current++] =
379 (DecodeWithHexBinAlphabet(src[i + 0]) << 4) +
380 DecodeWithHexBinAlphabet(src[i + 1]);
381 dest[current++] =
382 (DecodeWithHexBinAlphabet(src[i + 2]) << 4) +
383 DecodeWithHexBinAlphabet(src[i + 3]);
385 dest[current++] = 0;
386 dest[current++] = 0;
389 void EncodeHexUnicode (char *dest, const unsigned char *src, size_t len)
391 EncodeHexBin(dest, src, len * 2);
394 gboolean DecodeHexBin (unsigned char *dest, const unsigned char *src, int len)
396 int i,current=0, low, high;
398 for (i = 0; i < len/2 ; i++) {
399 low = DecodeWithHexBinAlphabet(src[i*2+1]);
400 high = DecodeWithHexBinAlphabet(src[i*2]);
401 if (low < 0 || high < 0) return FALSE;
402 dest[current++] = (high << 4) | low;
404 dest[current++] = 0;
405 return TRUE;
408 void EncodeHexBin (char *dest, const unsigned char *src, size_t len)
410 size_t i, outpos = 0;
412 for (i = 0; i < len; i++) {
413 dest[outpos++] = EncodeWithHexBinAlphabet(src[i] >> 4);
414 dest[outpos++] = EncodeWithHexBinAlphabet(src[i] & 0xF);
416 dest[outpos++] = 0;
419 /* ETSI GSM 03.38, section 6.2.1: Default alphabet for SMS messages */
420 static unsigned char GSM_DefaultAlphabetUnicode[128+1][2] =
422 {0x00,0x40},{0x00,0xa3},{0x00,0x24},{0x00,0xA5},
423 {0x00,0xE8},{0x00,0xE9},{0x00,0xF9},{0x00,0xEC},/*0x08*/
424 {0x00,0xF2},{0x00,0xE7},{0x00,'\n'},{0x00,0xD8},
425 {0x00,0xF8},{0x00,'\r'},{0x00,0xC5},{0x00,0xE5},
426 {0x03,0x94},{0x00,0x5f},{0x03,0xA6},{0x03,0x93},
427 {0x03,0x9B},{0x03,0xA9},{0x03,0xA0},{0x03,0xA8},
428 {0x03,0xA3},{0x03,0x98},{0x03,0x9E},{0x00,0xb9},
429 {0x00,0xC6},{0x00,0xE6},{0x00,0xDF},{0x00,0xC9},/*0x20*/
430 {0x00,' ' },{0x00,'!' },{0x00,'\"'},{0x00,'#' },
431 {0x00,0xA4},{0x00,'%' },{0x00,'&' },{0x00,'\''},
432 {0x00,'(' },{0x00,')' },{0x00,'*' },{0x00,'+' },
433 {0x00,',' },{0x00,'-' },{0x00,'.' },{0x00,'/' },/*0x30*/
434 {0x00,'0' },{0x00,'1' },{0x00,'2' },{0x00,'3' },
435 {0x00,'4' },{0x00,'5' },{0x00,'6' },{0x00,'7' },
436 {0x00,'8' },{0x00,'9' },{0x00,':' },{0x00,';' },
437 {0x00,'<' },{0x00,'=' },{0x00,'>' },{0x00,'?' },/*0x40*/
438 {0x00,0xA1},{0x00,'A' },{0x00,'B' },{0x00,'C' },
439 {0x00,'D' },{0x00,'E' },{0x00,'F' },{0x00,'G' },
440 {0x00,'H' },{0x00,'I' },{0x00,'J' },{0x00,'K' },
441 {0x00,'L' },{0x00,'M' },{0x00,'N' },{0x00,'O' },
442 {0x00,'P' },{0x00,'Q' },{0x00,'R' },{0x00,'S' },
443 {0x00,'T' },{0x00,'U' },{0x00,'V' },{0x00,'W' },
444 {0x00,'X' },{0x00,'Y' },{0x00,'Z' },{0x00,0xC4},
445 {0x00,0xD6},{0x00,0xD1},{0x00,0xDC},{0x00,0xA7},
446 {0x00,0xBF},{0x00,'a' },{0x00,'b' },{0x00,'c' },
447 {0x00,'d' },{0x00,'e' },{0x00,'f' },{0x00,'g' },
448 {0x00,'h' },{0x00,'i' },{0x00,'j' },{0x00,'k' },
449 {0x00,'l' },{0x00,'m' },{0x00,'n' },{0x00,'o' },
450 {0x00,'p' },{0x00,'q' },{0x00,'r' },{0x00,'s' },
451 {0x00,'t' },{0x00,'u' },{0x00,'v' },{0x00,'w' },
452 {0x00,'x' },{0x00,'y' },{0x00,'z' },{0x00,0xE4},
453 {0x00,0xF6},{0x00,0xF1},{0x00,0xFC},{0x00,0xE0},
454 {0x00,0x00}
457 /* ETSI GSM 3.38
458 * Some sequences of 2 default alphabet chars (for example,
459 * 0x1b, 0x65) are visible as one single additional char (for example,
460 * 0x1b, 0x65 gives Euro char saved in Unicode as 0x20, 0xAC)
461 * This table contains:
462 * 1. two first char means second char from the sequence of chars from GSM default alphabet (first being 0x1b)
463 * 2. two second is target (encoded) char saved in Unicode
465 static unsigned char GSM_DefaultAlphabetCharsExtension[][3] =
467 {0x0a,0x00,0x0c}, /* \r */
468 {0x14,0x00,0x5e}, /* ^ */
469 {0x28,0x00,0x7b}, /* { */
470 {0x29,0x00,0x7d}, /* } */
471 {0x2f,0x00,0x5c}, /* \ */
472 {0x3c,0x00,0x5b}, /* [ */
473 {0x3d,0x00,0x7E}, /* ~ */
474 {0x3e,0x00,0x5d}, /* ] */
475 {0x40,0x00,0x7C}, /* | */
476 {0x65,0x20,0xAC}, /* Euro */
477 {0x00,0x00,0x00}
480 void DecodeDefault (unsigned char *dest, const unsigned char *src, size_t len, gboolean UseExtensions, unsigned char *ExtraAlphabet)
482 size_t pos, current = 0, i;
484 #ifdef DEBUG
485 DumpMessageText(&GSM_global_debug, src, len);
486 #endif
488 for (pos = 0; pos < len; pos++) {
489 if ((pos < (len - 1)) && UseExtensions && src[pos] == 0x1b) {
490 for (i = 0; GSM_DefaultAlphabetCharsExtension[i][0] != 0x00; i++) {
491 if (GSM_DefaultAlphabetCharsExtension[i][0] == src[pos + 1]) {
492 dest[current++] = GSM_DefaultAlphabetCharsExtension[i][1];
493 dest[current++] = GSM_DefaultAlphabetCharsExtension[i][2];
494 pos++;
495 break;
498 /* Skip rest if we've found something */
499 if (GSM_DefaultAlphabetCharsExtension[i][0] != 0x00) {
500 continue;
503 if (ExtraAlphabet != NULL) {
504 for (i = 0; ExtraAlphabet[i] != 0x00; i += 3) {
505 if (ExtraAlphabet[i] == src[pos]) {
506 dest[current++] = ExtraAlphabet[i + 1];
507 dest[current++] = ExtraAlphabet[i + 2];
508 break;
511 /* Skip rest if we've found something */
512 if (ExtraAlphabet[i] != 0x00) {
513 continue;
516 dest[current++] = GSM_DefaultAlphabetUnicode[src[pos]][0];
517 dest[current++] = GSM_DefaultAlphabetUnicode[src[pos]][1];
519 dest[current++]=0;
520 dest[current++]=0;
521 #ifdef DEBUG
522 DumpMessageText(&GSM_global_debug, dest, UnicodeLength(dest)*2);
523 #endif
526 /* There are many national chars with "adds". In phone they're normally
527 * changed to "plain" Latin chars. We have such functionality too.
528 * This table is automatically created from convert.txt file (see
529 * /docs/developers) using --makeconverttable. It contains such chars
530 * to replace in order:
531 * 1. original char (Unicode) 2. destination char (Unicode)
533 static unsigned char ConvertTable[] =
534 "\x00\xc0\x00\x41\x00\xe0\x00\x61\x00\xc1\x00\x41\x00\xe1\x00\x61\x00\xc2\x00\x41\x00\xe2\x00\x61\x00\xc3\x00\x41\x00\xe3\x00\x61\x1e\xa0\x00\x41\x1e\xa1\x00\x61\x1e\xa2\x00\x41\x1e\xa3\x00\x61\x1e\xa4\x00\x41\x1e\xa5\x00\x61\x1e\xa6\x00\x41\x1e\xa7\x00\x61\x1e\xa8\x00\x41\x1e\xa9\x00\x61\x1e\xaa\x00\x41\x1e\xab\x00\x61\x1e\xac\x00\x41\x1e\xad\x00\x61\x1e\xae\x00\x41\x1e\xaf\x00\x61\x1e\xb0\x00\x41\x1e\xb1\x00\x61\x1e\xb2\x00\x41\x1e\xb3\x00\x61\x1e\xb4\x00\x41\x1e\xb5\x00\x61\x1e\xb6\x00\x41\x1e\xb7\x00\x61\x01\xcd\x00\x41\x01\xce\x00\x61\x01\x00\x00\x41\x01\x01\x00\x61\x01\x02\x00\x41\x01\x03\x00\x61\x01\x04\x00\x41\x01\x05\x00\x61\x01\xfb\x00\x61\x01\x06\x00\x43\x01\x07\x00\x63\x01\x08\x00\x43\x01\x09\x00\x63\x01\x0a\x00\x43\x01\x0b\x00\x63\x01\x0c\x00\x43\x01\x0d\x00\x63\x00\xe7"\
535 "\x00\x63\x01\x0e\x00\x44\x01\x0f\x00\x64\x01\x10\x00\x44\x01\x11\x00\x64\x00\xc8\x00\x45\x00\xca\x00\x45\x00\xea\x00\x65\x00\xcb\x00\x45\x00\xeb\x00\x65\x1e\xb8\x00\x45\x1e\xb9\x00\x65\x1e\xba\x00\x45\x1e\xbb\x00\x65\x1e\xbc\x00\x45\x1e\xbd\x00\x65\x1e\xbe\x00\x45\x1e\xbf\x00\x65\x1e\xc0\x00\x45\x1e\xc1\x00\x65\x1e\xc2\x00\x45\x1e\xc3\x00\x65\x1e\xc4\x00\x45\x1e\xc5\x00\x65\x1e\xc6\x00\x45\x1e\xc7\x00\x65\x01\x12\x00\x45\x01\x13\x00\x65\x01\x14\x00\x45\x01\x15\x00\x65\x01\x16\x00\x45\x01\x17\x00\x65\x01\x18\x00\x45\x01\x19\x00\x65\x01\x1a\x00\x45\x01\x1b\x00\x65\x01\x1c\x00\x47\x01\x1d\x00\x67\x01\x1e\x00\x47\x01\x1f\x00\x67\x01\x20\x00\x47\x01\x21\x00\x67\x01\x22\x00\x47\x01\x23\x00\x67\x01\x24\x00\x48\x01\x25\x00\x68\x01\x26\x00\x48\x01\x27\x00\x68\x00\xcc\x00\x49\x00\xcd\x00\x49\x00\xed"\
536 "\x00\x69\x00\xce\x00\x49\x00\xee\x00\x69\x00\xcf\x00\x49\x00\xef\x00\x69\x01\x28\x00\x49\x01\x29\x00\x69\x01\x2a\x00\x49\x01\x2b\x00\x69\x01\x2c\x00\x49\x01\x2d\x00\x69\x01\x2e\x00\x49\x01\x2f\x00\x69\x01\x30\x00\x49\x01\x31\x00\x69\x01\xcf\x00\x49\x01\xd0\x00\x69\x1e\xc8\x00\x49\x1e\xc9\x00\x69\x1e\xca\x00\x49\x1e\xcb\x00\x69\x01\x34\x00\x4a\x01\x35\x00\x6a\x01\x36\x00\x4b\x01\x37\x00\x6b\x01\x39\x00\x4c\x01\x3a\x00\x6c\x01\x3b\x00\x4c\x01\x3c\x00\x6c\x01\x3d\x00\x4c\x01\x3e\x00\x6c\x01\x3f\x00\x4c\x01\x40\x00\x6c\x01\x41\x00\x4c\x01\x42\x00\x6c\x01\x43\x00\x4e\x01\x44\x00\x6e\x01\x45\x00\x4e\x01\x46\x00\x6e\x01\x47\x00\x4e\x01\x48\x00\x6e\x01\x49\x00\x6e\x00\xd2\x00\x4f\x00\xd3\x00\x4f\x00\xf3\x00\x6f\x00\xd4\x00\x4f\x00\xf4\x00\x6f\x00\xd5\x00\x4f\x00\xf5\x00\x6f\x01\x4c\x00\x4f\x01\x4d"\
537 "\x00\x6f\x01\x4e\x00\x4f\x01\x4f\x00\x6f\x01\x50\x00\x4f\x01\x51\x00\x6f\x01\xa0\x00\x4f\x01\xa1\x00\x6f\x01\xd1\x00\x4f\x01\xd2\x00\x6f\x1e\xcc\x00\x4f\x1e\xcd\x00\x6f\x1e\xce\x00\x4f\x1e\xcf\x00\x6f\x1e\xd0\x00\x4f\x1e\xd1\x00\x6f\x1e\xd2\x00\x4f\x1e\xd3\x00\x6f\x1e\xd4\x00\x4f\x1e\xd5\x00\x6f\x1e\xd6\x00\x4f\x1e\xd7\x00\x6f\x1e\xd8\x00\x4f\x1e\xd9\x00\x6f\x1e\xda\x00\x4f\x1e\xdb\x00\x6f\x1e\xdc\x00\x4f\x1e\xdd\x00\x6f\x1e\xde\x00\x4f\x1e\xdf\x00\x6f\x1e\xe0\x00\x4f\x1e\xe1\x00\x6f\x1e\xe2\x00\x4f\x1e\xe3\x00\x6f\x01\x54\x00\x52\x01\x55\x00\x72\x01\x56\x00\x52\x01\x57\x00\x72\x01\x58\x00\x52\x01\x59\x00\x72\x01\x5a\x00\x53\x01\x5b\x00\x73\x01\x5c\x00\x53\x01\x5d\x00\x73\x01\x5e\x00\x53\x01\x5f\x00\x73\x01\x60\x00\x53\x01\x61\x00\x73\x01\x62\x00\x54\x01\x63\x00\x74\x01\x64\x00\x54\x01\x65"\
538 "\x00\x74\x01\x66\x00\x54\x01\x67\x00\x74\x00\xd9\x00\x55\x00\xda\x00\x55\x00\xfa\x00\x75\x00\xdb\x00\x55\x00\xfb\x00\x75\x01\x68\x00\x55\x01\x69\x00\x75\x01\x6a\x00\x55\x01\x6b\x00\x75\x01\x6c\x00\x55\x01\x6d\x00\x75\x01\x6e\x00\x55\x01\x6f\x00\x75\x01\x70\x00\x55\x01\x71\x00\x75\x01\x72\x00\x55\x01\x73\x00\x75\x01\xaf\x00\x55\x01\xb0\x00\x75\x01\xd3\x00\x55\x01\xd4\x00\x75\x01\xd5\x00\x55\x01\xd6\x00\x75\x01\xd7\x00\x55\x01\xd8\x00\x75\x01\xd9\x00\x55\x01\xda\x00\x75\x01\xdb\x00\x55\x01\xdc\x00\x75\x1e\xe4\x00\x55\x1e\xe5\x00\x75\x1e\xe6\x00\x55\x1e\xe7\x00\x75\x1e\xe8\x00\x55\x1e\xe9\x00\x75\x1e\xea\x00\x55\x1e\xeb\x00\x75\x1e\xec\x00\x55\x1e\xed\x00\x75\x1e\xee\x00\x55\x1e\xef\x00\x75\x1e\xf0\x00\x55\x1e\xf1\x00\x75\x01\x74\x00\x57\x01\x75\x00\x77\x1e\x80\x00\x57\x1e\x81\x00\x77\x1e\x82"\
539 "\x00\x57\x1e\x83\x00\x77\x1e\x84\x00\x57\x1e\x85\x00\x77\x00\xdd\x00\x59\x00\xfd\x00\x79\x00\xff\x00\x79\x01\x76\x00\x59\x01\x77\x00\x79\x01\x78\x00\x59\x1e\xf2\x00\x59\x1e\xf3\x00\x75\x1e\xf4\x00\x59\x1e\xf5\x00\x79\x1e\xf6\x00\x59\x1e\xf7\x00\x79\x1e\xf8\x00\x59\x1e\xf9\x00\x79\x01\x79\x00\x5a\x01\x7a\x00\x7a\x01\x7b\x00\x5a\x01\x7c\x00\x7a\x01\x7d\x00\x5a\x01\x7e\x00\x7a\x01\xfc\x00\xc6\x01\xfd\x00\xe6\x01\xfe\x00\xd8\x01\xff\x00\xf8\x00\x00";
541 void EncodeDefault(unsigned char *dest, const unsigned char *src, size_t *len, gboolean UseExtensions, unsigned char *ExtraAlphabet)
543 size_t i,current=0,j,z;
544 char ret;
545 gboolean FoundSpecial,FoundNormal;
547 #ifdef DEBUG
548 DumpMessageText(&GSM_global_debug, src, (*len)*2);
549 #endif
551 for (i = 0; i < *len; i++) {
552 FoundSpecial = FALSE;
553 j = 0;
554 while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00 && UseExtensions) {
555 if (src[i*2] == GSM_DefaultAlphabetCharsExtension[j][1] &&
556 src[i*2+1] == GSM_DefaultAlphabetCharsExtension[j][2]) {
557 dest[current++] = 0x1b;
558 dest[current++] = GSM_DefaultAlphabetCharsExtension[j][0];
559 FoundSpecial = TRUE;
560 break;
562 j++;
564 if (!FoundSpecial) {
565 ret = '?';
566 FoundNormal = FALSE;
567 j = 0;
568 while (GSM_DefaultAlphabetUnicode[j][1]!=0x00) {
569 if (src[i*2] == GSM_DefaultAlphabetUnicode[j][0] &&
570 src[i*2+1] == GSM_DefaultAlphabetUnicode[j][1]) {
571 ret = j;
572 FoundNormal = TRUE;
573 break;
575 j++;
577 if (ExtraAlphabet!=NULL && !FoundNormal) {
578 j = 0;
579 while (ExtraAlphabet[j] != 0x00 || ExtraAlphabet[j+1] != 0x00 || ExtraAlphabet[j+2] != 0x00) {
580 if (ExtraAlphabet[j+1] == src[i*2] &&
581 ExtraAlphabet[j+2] == src[i*2 + 1]) {
582 ret = ExtraAlphabet[j];
583 FoundSpecial = TRUE;
584 break;
586 j=j+3;
589 if (!FoundNormal && !FoundSpecial) {
590 j = 0;
591 FoundNormal = FALSE;
592 while (ConvertTable[j*4] != 0x00 ||
593 ConvertTable[j*4+1] != 0x00) {
594 if (src[i*2] == ConvertTable[j*4] &&
595 src[i*2+1] == ConvertTable[j*4+1]) {
596 z = 0;
597 while (GSM_DefaultAlphabetUnicode[z][1]!=0x00) {
598 if (ConvertTable[j*4+2] == GSM_DefaultAlphabetUnicode[z][0] &&
599 ConvertTable[j*4+3] == GSM_DefaultAlphabetUnicode[z][1]) {
600 ret = z;
601 FoundNormal = TRUE;
602 break;
604 z++;
606 if (FoundNormal) break;
608 j++;
611 dest[current++]=ret;
614 dest[current]=0;
615 #ifdef DEBUG
616 DumpMessageText(&GSM_global_debug, dest, current);
617 #endif
619 *len = current;
622 /* You don't have to use ConvertTable here - 1 char is replaced there by 1 char */
623 void FindDefaultAlphabetLen(const unsigned char *src, size_t *srclen, size_t *smslen, size_t maxlen)
625 size_t current=0,j,i;
626 gboolean FoundSpecial;
628 i = 0;
629 while (src[i*2] != 0x00 || src[i*2+1] != 0x00) {
630 FoundSpecial = FALSE;
631 j = 0;
632 while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00) {
633 if (src[i*2] == GSM_DefaultAlphabetCharsExtension[j][1] &&
634 src[i*2+1] == GSM_DefaultAlphabetCharsExtension[j][2]) {
635 FoundSpecial = TRUE;
636 if (current+2 > maxlen) {
637 *srclen = i;
638 *smslen = current;
639 return;
641 current+=2;
642 break;
644 j++;
646 if (!FoundSpecial) {
647 if (current+1 > maxlen) {
648 *srclen = i;
649 *smslen = current;
650 return;
652 current++;
654 i++;
656 *srclen = i;
657 *smslen = current;
660 #define ByteMask ((1 << Bits) - 1)
662 int GSM_UnpackEightBitsToSeven(int offset, int in_length, int out_length,
663 const unsigned char *input, unsigned char *output)
665 /* (c) by Pavel Janik and Pawel Kot */
667 unsigned char *output_pos = output; /* Current pointer to the output buffer */
668 const unsigned char *input_pos = input; /* Current pointer to the input buffer */
669 unsigned char Rest = 0x00;
670 int Bits;
672 Bits = offset ? offset : 7;
674 while ((input_pos - input) < in_length) {
676 *output_pos = ((*input_pos & ByteMask) << (7 - Bits)) | Rest;
677 Rest = *input_pos >> Bits;
679 /* If we don't start from 0th bit, we shouldn't go to the
680 next char. Under *output_pos we have now 0 and under Rest -
681 _first_ part of the char. */
682 if ((input_pos != input) || (Bits == 7)) output_pos++;
683 input_pos++;
685 if ((output_pos - output) >= out_length) break;
687 /* After reading 7 octets we have read 7 full characters but
688 we have 7 bits as well. This is the next character */
689 if (Bits == 1) {
690 *output_pos = Rest;
691 output_pos++;
692 Bits = 7;
693 Rest = 0x00;
694 } else {
695 Bits--;
699 return output_pos - output;
702 int GSM_PackSevenBitsToEight(int offset, const unsigned char *input, unsigned char *output, int length)
704 /* (c) by Pavel Janik and Pawel Kot */
706 unsigned char *output_pos = output; /* Current pointer to the output buffer */
707 const unsigned char *input_pos = input; /* Current pointer to the input buffer */
708 int Bits; /* Number of bits directly copied to
709 * the output buffer */
710 Bits = (7 + offset) % 8;
712 /* If we don't begin with 0th bit, we will write only a part of the
713 first octet */
714 if (offset) {
715 *output_pos = 0x00;
716 output_pos++;
719 while ((input_pos - input) < length) {
720 unsigned char Byte = *input_pos;
722 *output_pos = Byte >> (7 - Bits);
723 /* If we don't write at 0th bit of the octet, we should write
724 a second part of the previous octet */
725 if (Bits != 7)
726 *(output_pos-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1);
728 Bits--;
730 if (Bits == -1) Bits = 7; else output_pos++;
732 input_pos++;
734 return (output_pos - output);
737 int GSM_UnpackSemiOctetNumber(GSM_Debug_Info *di, unsigned char *retval, const unsigned char *Number, gboolean semioctet)
739 unsigned char Buffer[GSM_MAX_NUMBER_LENGTH + 1];
740 int length = Number[0];
742 smfprintf(di, "L=%d\n", length);
744 /* Default ouput on error */
745 strcpy(Buffer, "<NOT DECODED>");
747 if (semioctet) {
748 /* Convert number of semioctets to number of chars */
749 if (length % 2) length++;
750 length=length / 2 + 1;
753 /* Check length */
754 if (length > GSM_MAX_NUMBER_LENGTH) {
755 smfprintf(di, "Number too big, not decoding! (Length=%d, MAX=%d)\n", length, GSM_MAX_NUMBER_LENGTH);
756 goto out;
759 /*without leading byte with format of number*/
760 length--;
762 switch ((Number[1] & 0x70)) {
763 case (NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN & 0x70):
764 if (length > 6) length++;
765 smfprintf(di, "Alphanumeric number, length %i\n",length);
766 GSM_UnpackEightBitsToSeven(0, length, length, Number+2, Buffer);
767 Buffer[length]=0;
768 break;
769 case (NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN & 0x70):
770 smfprintf(di, "International number\n");
771 Buffer[0]='+';
772 DecodeBCD(Buffer+1,Number+2, length);
773 break;
774 default:
775 smfprintf(di, "Default number %02x (%d %d %d %d|%d %d %d %d)\n",Number[1],
776 Number[1] & 0x80 ? 1 : 0,
777 Number[1] & 0x40 ? 1 : 0,
778 Number[1] & 0x20 ? 1 : 0,
779 Number[1] & 0x10 ? 1 : 0,
780 Number[1] & 0x08 ? 1 : 0,
781 Number[1] & 0x04 ? 1 : 0,
782 Number[1] & 0x02 ? 1 : 0,
783 Number[1] & 0x01 ? 1 : 0
785 DecodeBCD (Buffer, Number+2, length);
786 break;
789 smfprintf(di, "Len %i\n",length);
790 out:
791 EncodeUnicode(retval,Buffer,strlen(Buffer));
792 if (semioctet) {
793 return 2 + ((Number[0] + 1) / 2);
794 } else {
795 return 1 + Number[0];
800 * Packing some phone numbers (SMSC, SMS destination and others)
802 * See GSM 03.40 9.1.1:
803 * 1 byte - length of number given in semioctets or bytes (when given in
804 * bytes, includes one byte for byte with number format).
805 * Returned by function (set semioctet to TRUE, if want result
806 * in semioctets).
807 * 1 byte - format of number (see GSM_NumberType in coding.h). Returned
808 * in unsigned char *Output.
809 * n bytes - 2n or 2n-1 semioctets with number. Returned in unsigned char
810 * *Output.
812 * 1 semioctet = 4 bits = half of byte
814 int GSM_PackSemiOctetNumber(const unsigned char *Number, unsigned char *Output, gboolean semioctet)
816 unsigned char format;
817 int length, i;
818 unsigned char *buffer;
820 length = UnicodeLength(Number);
821 buffer = (unsigned char*)malloc(length + 2);
823 if (buffer == NULL) {
824 return 0;
827 DecodeUnicode(Number, buffer);
829 /* Checking for format number */
830 if (buffer[0] == '+' || (buffer[0] == '0' && buffer[1] == '0')) {
831 format = NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN;
832 } else {
833 format = NUMBER_UNKNOWN_NUMBERING_PLAN_ISDN;
835 for (i = 0; i < length; i++) {
836 /* If there is something which can not be in normal
837 * number, mark it as alphanumberic */
838 if (strchr("+0123456789*#pP", buffer[i]) == NULL) {
839 format = NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN;
844 * First byte is used for saving type of number. See GSM 03.40
845 * section 9.1.2.5
847 Output[0]=format;
849 /* After number type we will have number. GSM 03.40 section 9.1.2 */
850 switch (format) {
851 case NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN:
852 length=GSM_PackSevenBitsToEight(0, buffer, Output+1, strlen(buffer))*2;
853 if (strlen(buffer)==7) length--;
854 break;
855 case NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN:
856 length--;
857 EncodeBCD (Output+1, buffer+1, length, TRUE);
858 break;
859 default:
860 EncodeBCD (Output+1, buffer, length, TRUE);
861 break;
864 free(buffer);
866 if (semioctet) return length;
868 /* Convert number of semioctets to number of chars */
869 if (length % 2) length++;
870 return length / 2 + 1;
873 void CopyUnicodeString(unsigned char *Dest, const unsigned char *Source)
875 int j = 0;
877 /* No need to copy if both are on same address */
878 if (Dest == Source) return;
880 while (Source[j]!=0x00 || Source[j+1]!=0x00) {
881 Dest[j] = Source[j];
882 Dest[j+1] = Source[j+1];
883 j=j+2;
885 Dest[j] = 0;
886 Dest[j+1] = 0;
889 /* Changes minor/major order in Unicode string */
890 void ReverseUnicodeString(unsigned char *String)
892 int j = 0;
893 unsigned char byte1, byte2;
895 while (String[j]!=0x00 || String[j+1]!=0x00) {
896 byte1 = String[j];
897 byte2 = String[j+1];
898 String[j+1] = byte1;
899 String[j] = byte2;
900 j=j+2;
902 String[j] = 0;
903 String[j+1] = 0;
906 /* All input is in Unicode. First char can show Unicode minor/major order.
907 Output is Unicode string in Gammu minor/major order */
908 void ReadUnicodeFile(unsigned char *Dest, const unsigned char *Source)
910 int j = 0, current = 0;
912 if (Source[0] == 0xFF && Source[1] == 0xFE) j = 2;
913 if (Source[0] == 0xFE && Source[1] == 0xFF) j = 2;
915 while (Source[j]!=0x00 || Source[j+1]!=0x00) {
916 if (Source[0] == 0xFF) {
917 Dest[current++] = Source[j+1];
918 Dest[current++] = Source[j];
919 } else {
920 Dest[current++] = Source[j];
921 Dest[current++] = Source[j+1];
923 j=j+2;
925 Dest[current++] = 0;
926 Dest[current++] = 0;
929 INLINE int GetBit(unsigned char *Buffer, size_t BitNum)
931 return Buffer[BitNum / 8] & (1 << (7 - (BitNum % 8)));
934 INLINE int SetBit(unsigned char *Buffer, size_t BitNum)
936 return Buffer[BitNum / 8] |= 1 << (7 - (BitNum % 8));
939 int ClearBit(unsigned char *Buffer, size_t BitNum)
941 return Buffer[BitNum / 8] &= 255 - (1 << (7 - (BitNum % 8)));
944 void BufferAlign(unsigned char *Destination, size_t *CurrentBit)
946 int i=0;
948 while(((*CurrentBit) + i) % 8 != 0) {
949 ClearBit(Destination, (*CurrentBit)+i);
950 i++;
953 (*CurrentBit) = (*CurrentBit) + i;
956 void BufferAlignNumber(size_t *CurrentBit)
958 int i=0;
960 while(((*CurrentBit) + i) % 8 != 0) {
961 i++;
964 (*CurrentBit) = (*CurrentBit) + i;
967 void AddBuffer(unsigned char *Destination,
968 size_t *CurrentBit,
969 unsigned char *Source,
970 size_t BitsToProcess)
972 size_t i=0;
974 while (i!=BitsToProcess) {
975 if (GetBit(Source, i)) {
976 SetBit(Destination, (*CurrentBit)+i);
977 } else {
978 ClearBit(Destination, (*CurrentBit)+i);
980 i++;
982 (*CurrentBit) = (*CurrentBit) + BitsToProcess;
985 void AddBufferByte(unsigned char *Destination,
986 size_t *CurrentBit,
987 unsigned char Source,
988 size_t BitsToProcess)
990 unsigned char Byte;
992 Byte = Source;
994 AddBuffer(Destination, CurrentBit, &Byte, BitsToProcess);
997 void GetBuffer(unsigned char *Source,
998 size_t *CurrentBit,
999 unsigned char *Destination,
1000 size_t BitsToProcess)
1002 size_t i=0;
1004 while (i!=BitsToProcess) {
1005 if (GetBit(Source, (*CurrentBit)+i)) {
1006 SetBit(Destination, i);
1007 } else {
1008 ClearBit(Destination, i);
1010 i++;
1012 (*CurrentBit) = (*CurrentBit) + BitsToProcess;
1015 void GetBufferInt(unsigned char *Source,
1016 size_t *CurrentBit,
1017 int *integer,
1018 size_t BitsToProcess)
1020 size_t l=0,z=128,i=0;
1022 while (i!=BitsToProcess) {
1023 if (GetBit(Source, (*CurrentBit)+i)) l=l+z;
1024 z=z/2;
1025 i++;
1027 *integer=l;
1028 (*CurrentBit) = (*CurrentBit) + i;
1031 void GetBufferI(unsigned char *Source,
1032 size_t *CurrentBit,
1033 int *result,
1034 size_t BitsToProcess)
1036 size_t l=0,z,i=0;
1038 z = 1<<(BitsToProcess-1);
1040 while (i!=BitsToProcess) {
1041 if (GetBit(Source, (*CurrentBit)+i)) l=l+z;
1042 z=z>>1;
1043 i++;
1045 *result=l;
1046 (*CurrentBit) = (*CurrentBit) + i;
1049 /* Unicode char 0x00 0x01 makes blinking in some Nokia phones.
1050 * We replace single ~ chars into it. When user give double ~, it's replaced
1051 * to single ~
1053 void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, int len)
1055 int i,current = 0;
1056 gboolean special=FALSE;
1058 for (i = 0; i < len; i++) {
1059 if (special) {
1060 if (src[i*2] == 0x00 && src[i*2+1] == '~') {
1061 dest[current++] = 0x00;
1062 dest[current++] = '~';
1063 } else {
1064 dest[current++] = 0x00;
1065 dest[current++] = 0x01;
1066 dest[current++] = src[i*2];
1067 dest[current++] = src[i*2+1];
1069 special = FALSE;
1070 } else {
1071 if (src[i*2] == 0x00 && src[i*2+1] == '~') {
1072 special = TRUE;
1073 } else {
1074 dest[current++] = src[i*2];
1075 dest[current++] = src[i*2+1];
1079 if (special) {
1080 dest[current++] = 0x00;
1081 dest[current++] = 0x01;
1083 dest[current++] = 0x00;
1084 dest[current++] = 0x00;
1087 void DecodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, int len)
1089 int i=0,current=0;
1091 for (i=0;i<len;i++) {
1092 switch (src[2*i]) {
1093 case 0x00:
1094 switch (src[2*i+1]) {
1095 case 0x01:
1096 dest[current++] = 0x00;
1097 dest[current++] = '~';
1098 break;
1099 case '~':
1100 dest[current++] = 0x00;
1101 dest[current++] = '~';
1102 dest[current++] = 0x00;
1103 dest[current++] = '~';
1104 break;
1105 default:
1106 dest[current++] = src[i*2];
1107 dest[current++] = src[i*2+1];
1109 break;
1110 default:
1111 dest[current++] = src[i*2];
1112 dest[current++] = src[i*2+1];
1115 dest[current++] = 0x00;
1116 dest[current++] = 0x00;
1120 /* Compares two Unicode strings without regarding to case.
1121 * Return TRUE, when they're equal
1123 gboolean mywstrncasecmp(unsigned const char *a, unsigned const char *b, int num)
1125 int i;
1126 wchar_t wc,wc2;
1128 if (a == NULL || b == NULL) return FALSE;
1130 if (num == 0) num = -1;
1132 for (i = 0; i != num; i++) {
1133 if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) && (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return TRUE;
1134 if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) || (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return FALSE;
1135 wc = a[i*2+1] | (a[i*2] << 8);
1136 wc2 = b[i*2+1] | (b[i*2] << 8);
1137 if (towlower(wc) != towlower(wc2)) return FALSE;
1139 return TRUE;
1142 /* wcscmp in Mandrake 9.0 is wrong */
1143 gboolean mywstrncmp(unsigned const char *a, unsigned const char *b, int num)
1145 int i=0;
1147 while (1) {
1148 if (a[i*2] != b[i*2] || a[i*2+1] != b[i*2+1]) return FALSE;
1149 if (a[i*2] == 0x00 && a[i*2+1] == 0x00) return TRUE;
1150 i++;
1151 if (num == i) return TRUE;
1155 /* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */
1156 gboolean myiswspace(unsigned const char *src)
1158 #ifndef HAVE_ISWSPACE
1159 int o;
1160 unsigned char dest[10];
1161 #endif
1162 wchar_t wc;
1164 wc = src[1] | (src[0] << 8);
1166 #ifndef HAVE_ISWSPACE
1167 o = DecodeWithUnicodeAlphabet(wc, dest);
1168 if (o == 1) {
1169 if (isspace(((int)dest[0]))!=0) return TRUE;
1170 return FALSE;
1172 return FALSE;
1173 #else
1174 if (iswspace(wc)) return TRUE;
1175 return FALSE;
1176 #endif
1180 * Following code is based on wcsstr from the GNU C Library, original
1181 * comment follows:
1184 * The original strstr() file contains the following comment:
1186 * My personal strstr() implementation that beats most other algorithms.
1187 * Until someone tells me otherwise, I assume that this is the
1188 * fastest implementation of strstr() in C.
1189 * I deliberately chose not to comment it. You should have at least
1190 * as much fun trying to understand it, as I had to write it :-).
1192 * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
1194 unsigned char *mywstrstr (const unsigned char *haystack, const unsigned char *needle)
1196 /* One crazy define to convert unicode used in Gammu to standard wchar_t */
1197 #define tolowerwchar(x) (towlower((wchar_t)( (((&(x))[0] & 0xff) << 8) | (((&(x))[1] & 0xff)) )))
1198 register wint_t a, b, c;
1199 register const unsigned char *rhaystack, *rneedle;
1202 if ((b = tolowerwchar(*needle)) != L'\0') {
1203 haystack -= 2; /* possible ANSI violation */
1204 do {
1205 haystack += 2;
1206 if ((c = tolowerwchar(*haystack)) == L'\0')
1207 goto ret0;
1208 } while (c != b);
1210 needle += 2;
1211 if ((c = tolowerwchar(*needle)) == L'\0')
1212 goto foundneedle;
1213 needle += 2;
1214 goto jin;
1216 for (;;) {
1217 do {
1218 haystack += 2;
1219 if ((a = tolowerwchar(*haystack)) == L'\0')
1220 goto ret0;
1221 if (a == b)
1222 break;
1223 haystack += 2;
1224 if ((a = tolowerwchar(*haystack)) == L'\0')
1225 goto ret0;
1226 shloop: ;
1227 } while (a != b);
1229 jin: haystack += 2;
1230 if ((a = tolowerwchar(*haystack)) == L'\0')
1231 goto ret0;
1233 if (a != c)
1234 goto shloop;
1236 rhaystack = haystack + 2;
1237 haystack -= 2;
1238 rneedle = needle;
1239 if (tolowerwchar(*rhaystack) == (a = tolowerwchar(*rneedle)))
1240 do {
1241 if (a == L'\0')
1242 goto foundneedle;
1243 rhaystack += 2;
1244 needle += 2;
1245 if (tolowerwchar(*rhaystack) != (a = tolowerwchar(*needle)))
1246 break ;
1247 if (a == L'\0')
1248 goto foundneedle;
1249 rhaystack += 2;
1250 needle += 2;
1251 } while (tolowerwchar(*rhaystack) == (a = tolowerwchar(*needle)));
1253 needle = rneedle; /* took the register-poor approach */
1255 if (a == L'\0')
1256 break;
1259 foundneedle:
1260 return (unsigned char *)haystack;
1261 ret0:
1262 return NULL;
1263 #undef tolowerwchar
1266 GSM_Error MyGetLine(char *Buffer, size_t *Pos, char *OutBuffer, size_t MaxLen, size_t MaxOutLen, gboolean MergeLines)
1268 gboolean skip = FALSE;
1269 gboolean quoted_printable = FALSE;
1270 gboolean was_cr = FALSE, was_lf = FALSE;
1271 size_t pos;
1272 int tmp;
1274 OutBuffer[0] = 0;
1275 pos = 0;
1276 if (Buffer == NULL) return ERR_NONE;
1277 while ((*Pos) < MaxLen) {
1278 switch (Buffer[*Pos]) {
1279 case 0x00:
1280 return ERR_NONE;
1281 case 0x0A:
1282 case 0x0D:
1283 if (skip) {
1284 if (Buffer[*Pos] == 0x0d) {
1285 if (was_cr && skip) return ERR_NONE;
1286 was_cr = TRUE;
1287 } else {
1288 if (was_lf && skip) return ERR_NONE;
1289 was_lf = TRUE;
1292 if (pos != 0 && !skip) {
1293 if (MergeLines) {
1294 /* (Quote printable new line) Does string end with = ? */
1295 if (OutBuffer[pos - 1] == '=' && quoted_printable) {
1296 pos--;
1297 OutBuffer[pos] = 0;
1298 skip = TRUE;
1299 was_cr = (Buffer[*Pos] == 0x0d);
1300 was_lf = (Buffer[*Pos] == 0x0a);
1301 break;
1303 /* (vCard continuation) Next line start with space? */
1304 tmp = *Pos + 1;
1305 if (Buffer[*Pos + 1] == 0x0a || Buffer[*Pos + 1] == 0x0d) {
1306 tmp += 1;
1308 if (Buffer[tmp] == ' ') {
1309 *Pos = tmp;
1310 break;
1313 return ERR_NONE;
1315 break;
1316 default:
1317 /* Detect quoted printable for possible escaping */
1318 if (Buffer[*Pos] == ':' &&
1319 strstr(OutBuffer, ";ENCODING=QUOTED-PRINTABLE") != NULL) {
1320 quoted_printable = TRUE;
1322 skip = FALSE;
1323 OutBuffer[pos] = Buffer[*Pos];
1324 pos++;
1325 OutBuffer[pos] = 0;
1326 if (pos + 1 >= MaxOutLen) return ERR_MOREMEMORY;
1328 (*Pos)++;
1330 return ERR_NONE;
1333 GSM_Error GSM_GetVCSLine(char **OutBuffer, char *Buffer, size_t *Pos, size_t MaxLen, gboolean MergeLines)
1335 gboolean skip = FALSE;
1336 gboolean quoted_printable = FALSE;
1337 gboolean was_cr = FALSE, was_lf = FALSE;
1338 size_t pos=0;
1339 int tmp=0;
1340 size_t OutLen = 200;
1342 *OutBuffer = (char *)malloc(OutLen);
1343 if (*OutBuffer == NULL) return ERR_MOREMEMORY;
1344 (*OutBuffer)[0] = 0;
1345 pos = 0;
1346 if (Buffer == NULL) return ERR_NONE;
1347 while ((*Pos) < MaxLen) {
1348 switch (Buffer[*Pos]) {
1349 case 0x00:
1350 return ERR_NONE;
1351 case 0x0A:
1352 case 0x0D:
1353 if (skip) {
1354 if (Buffer[*Pos] == 0x0d) {
1355 if (was_cr && skip) return ERR_NONE;
1356 was_cr = TRUE;
1357 } else {
1358 if (was_lf && skip) return ERR_NONE;
1359 was_lf = TRUE;
1362 if (pos != 0 && !skip) {
1363 if (MergeLines) {
1364 /* (Quote printable new line) Does string end with = ? */
1365 if ((*OutBuffer)[pos - 1] == '=' && quoted_printable) {
1366 pos--;
1367 (*OutBuffer)[pos] = 0;
1368 skip = TRUE;
1369 was_cr = (Buffer[*Pos] == 0x0d);
1370 was_lf = (Buffer[*Pos] == 0x0a);
1371 break;
1373 /* (vCard continuation) Next line start with space? */
1374 tmp = *Pos + 1;
1375 if (Buffer[*Pos + 1] == 0x0a || Buffer[*Pos + 1] == 0x0d) {
1376 tmp += 1;
1378 if (Buffer[tmp] == ' ') {
1379 *Pos = tmp;
1380 break;
1383 return ERR_NONE;
1385 break;
1386 default:
1387 /* Detect quoted printable for possible escaping */
1388 if (Buffer[*Pos] == ':' &&
1389 strstr(*OutBuffer, ";ENCODING=QUOTED-PRINTABLE") != NULL) {
1390 quoted_printable = TRUE;
1392 skip = FALSE;
1393 (*OutBuffer)[pos] = Buffer[*Pos];
1394 pos++;
1395 (*OutBuffer)[pos] = 0;
1396 if (pos + 2 >= OutLen) {
1397 OutLen += 100;
1398 *OutBuffer = (char *)realloc(*OutBuffer, OutLen);
1399 if (*OutBuffer == NULL) return ERR_MOREMEMORY;
1402 (*Pos)++;
1404 return ERR_NONE;
1408 void StringToDouble(char *text, double *d)
1410 gboolean before=TRUE;
1411 double multiply = 1;
1412 unsigned int i;
1414 *d = 0;
1415 for (i=0;i<strlen(text);i++) {
1416 if (isdigit((int)text[i])) {
1417 if (before) {
1418 (*d)=(*d)*10+(text[i]-'0');
1419 } else {
1420 multiply=multiply*0.1;
1421 (*d)=(*d)+(text[i]-'0')*multiply;
1424 if (text[i]=='.' || text[i]==',') before=FALSE;
1428 /* When char can be converted, convert it from Unicode to UTF8 */
1429 int EncodeWithUTF8Alphabet(unsigned char mychar1, unsigned char mychar2, char *ret)
1431 int src = mychar1*256+mychar2;
1433 /* Unicode 0080-07FF -> UTF8 110xxxxx 10xxxxxx */
1434 if (src >=128 && src <=2047) {
1435 ret[0] = 192 + (src / 64);
1436 ret[1] = 128 + (src % 64);
1437 return 2;
1439 /* Unicode 0800-FFFF -> UTF8 1110xxxx 10xxxxxx 10xxxxxx */
1440 if (src >2047) {
1441 ret[0] = 224 + (src / 4096);
1442 ret[1] = 128 + ((src / 64) % 64);
1443 ret[2] = 128 + (src % 64);
1444 return 3;
1447 /* Unicode 0000-007F -> UTF8 0xxxxxxx */
1448 ret[0] = mychar2;
1449 return 1;
1452 /* Make UTF8 string from Unicode input string */
1453 gboolean EncodeUTF8QuotedPrintable(char *dest, const unsigned char *src)
1455 int i,j=0,z,w;
1456 unsigned char mychar[3];
1457 gboolean retval = FALSE;
1458 int len;
1459 len = UnicodeLength(src);
1461 for (i = 0; i < len; i++) {
1462 z = EncodeWithUTF8Alphabet(src[i*2],src[i*2+1],mychar);
1463 if (z>1) {
1464 for (w=0;w<z;w++) {
1465 sprintf(dest+j, "=%02X",mychar[w]);
1466 j = j+3;
1468 retval = TRUE;
1469 } else {
1470 /* Encode low ASCII chars */
1471 if (src[i*2]*256 + src[i*2+1] < 32) {
1472 sprintf(dest+j, "=%02X", src[i*2]*256+src[i*2+1]);
1473 j = j+3;
1474 } else {
1475 j += DecodeWithUnicodeAlphabet(((wchar_t)(src[i*2]*256+src[i*2+1])), dest + j);
1479 dest[j++]=0;
1480 return retval;
1483 gboolean EncodeUTF8(char *dest, const unsigned char *src)
1485 int i,j=0,z;
1486 unsigned char mychar[3];
1487 gboolean retval = FALSE;
1489 for (i = 0; i < (int)(UnicodeLength(src)); i++) {
1490 z = EncodeWithUTF8Alphabet(src[i*2],src[i*2+1],mychar);
1491 if (z>1) {
1492 memcpy(dest+j,mychar,z);
1493 j+=z;
1494 retval = TRUE;
1495 } else {
1496 j+= DecodeWithUnicodeAlphabet(((wchar_t)(src[i*2]*256+src[i*2+1])), dest + j);
1499 dest[j++]=0;
1500 return retval;
1503 /* Decode UTF8 char to Unicode char */
1504 int DecodeWithUTF8Alphabet(const unsigned char *src, wchar_t *dest, int len)
1506 if (len < 1) return 0;
1507 if (src[0] < 128) {
1508 (*dest) = src[0];
1509 return 1;
1511 if (src[0] < 194) return 0;
1512 if (src[0] < 224) {
1513 if (len < 2) return 0;
1514 (*dest) = (src[0]-192)*64 + (src[1]-128);
1515 return 2;
1517 if (src[0] < 240) {
1518 if (len < 3) return 0;
1519 (*dest) = (src[0]-224)*4096 + (src[1]-128)*64 + (src[2]-128);
1520 return 3;
1522 return 0;
1526 /* Make Unicode string from ISO-8859-1 string */
1527 void DecodeISO88591QuotedPrintable(unsigned char *dest, const unsigned char *src, int len)
1529 int i = 0, j = 0;
1531 while (i < len) {
1532 if (src[i] == '=' && i + 2 < len
1533 && DecodeWithHexBinAlphabet(src[i + 1]) != -1
1534 && DecodeWithHexBinAlphabet(src[i + 2]) != -1) {
1535 dest[j++] = 0;
1536 dest[j++] = 16 * DecodeWithHexBinAlphabet(src[i + 1]) + DecodeWithHexBinAlphabet(src[i + 2]);
1537 i += 2;
1538 } else {
1539 dest[j++] = 0;
1540 dest[j++] = src[i];
1542 i++;
1544 dest[j++] = 0;
1545 dest[j++] = 0;
1548 /* Make Unicode string from UTF8 string */
1549 void DecodeUTF8QuotedPrintable(unsigned char *dest, const char *src, int len)
1551 int i=0,j=0,z;
1552 unsigned char mychar[10];
1553 wchar_t ret;
1555 while (i<=len) {
1556 z=0;
1557 while (TRUE) {
1558 if (src[z*3+i] != '=' || z*3+i+3>len ||
1559 DecodeWithHexBinAlphabet(src[z*3+i+1])==-1 ||
1560 DecodeWithHexBinAlphabet(src[z*3+i+2])==-1) {
1561 break;
1563 mychar[z] = 16*DecodeWithHexBinAlphabet(src[z*3+i+1])+DecodeWithHexBinAlphabet(src[z*3+i+2]);
1564 z++;
1565 /* Is it plain ASCII? */
1566 if (z == 1 && mychar[0] < 194) break;
1567 /* Do we already have valid UTF-8 char? */
1568 if (DecodeWithUTF8Alphabet(mychar, &ret, z) == z) break;
1570 if (z>0) {
1571 i += z * 3;
1572 /* we ignore wrong sequence */
1573 if (DecodeWithUTF8Alphabet(mychar,&ret,z)==0) continue;
1574 } else {
1575 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1577 dest[j++] = (ret >> 8) & 0xff;
1578 dest[j++] = ret & 0xff;
1580 dest[j++] = 0;
1581 dest[j++] = 0;
1584 void DecodeUTF8(unsigned char *dest, const char *src, int len)
1586 int i=0,j=0,z;
1587 wchar_t ret;
1589 while (i < len) {
1590 z = DecodeWithUTF8Alphabet(src+i,&ret,len-i);
1591 if (z<2) {
1592 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1593 } else {
1594 i+=z;
1596 dest[j++] = (ret >> 8) & 0xff;
1597 dest[j++] = ret & 0xff;
1599 dest[j++] = 0;
1600 dest[j++] = 0;
1603 void DecodeXMLUTF8(unsigned char *dest, const char *src, int len)
1605 char *tmp;
1606 char *pos, *pos_end;
1607 const char *lastpos;
1608 char *entity;
1609 unsigned long int c;
1610 int tmplen;
1612 /* Allocate buffer */
1613 tmp = (char *)calloc(len + 1, sizeof(char));
1614 if (tmp == NULL) {
1615 /* We have no memory for XML decoding */
1616 DecodeUTF8(dest, src, len);
1617 return;
1620 /* Find ampersand and decode the */
1621 lastpos = src;
1622 while ((lastpos != 0) && ((pos = strchr(lastpos, '&')) != NULL)) {
1623 /* Store current string */
1624 strncat(tmp, lastpos, pos - lastpos);
1625 lastpos = pos;
1626 /* Skip ampersand */
1627 pos++;
1628 /* Detect end of string */
1629 if (pos == 0) break;
1630 /* Find entity length */
1631 pos_end = strchr(pos, ';');
1632 if (pos_end - pos > 6 || pos_end == NULL) {
1633 if (pos_end == NULL) {
1634 dbgprintf(NULL, "No entity end found, ignoring!\n");
1635 } else {
1636 dbgprintf(NULL, "Too long html entity, ignoring!\n");
1638 strncat(tmp, lastpos, 1);
1639 lastpos++;
1640 continue;
1642 /* Create entity */
1643 /* strndup would be better, but not portable */
1644 entity = strdup(pos);
1645 entity[pos_end - pos] = 0;
1646 dbgprintf(NULL, "Found XML entity: %s\n", entity);
1647 if (entity == NULL) break;
1648 if (entity[0] == '#') {
1649 if (entity[1] == 'x' || entity[1] == 'X') {
1650 c = strtoull(entity + 2, NULL, 16);
1651 } else {
1652 c = strtoull(entity + 1, NULL, 10);
1654 dbgprintf(NULL, "Unicode char 0x%04lx\n", c);
1655 tmplen = strlen(tmp);
1656 tmplen += EncodeWithUTF8Alphabet((c >> 8) & 0xff, c & 0xff, tmp + tmplen);
1657 tmp[tmplen] = 0;
1658 } else if (strcmp(entity, "amp") == 0) {
1659 strcat(tmp, "&");
1660 } else if (strcmp(entity, "apos") == 0) {
1661 strcat(tmp, "'");
1662 } else if (strcmp(entity, "gt") == 0) {
1663 strcat(tmp, ">");
1664 } else if (strcmp(entity, "lt") == 0) {
1665 strcat(tmp, "<");
1666 } else if (strcmp(entity, "quot") == 0) {
1667 strcat(tmp, "\"");
1668 } else {
1669 dbgprintf(NULL, "Could not decode XML entity!\n");
1670 strncat(tmp, lastpos, pos_end - pos + 1);
1672 free(entity);
1673 entity=NULL;
1674 lastpos = pos_end + 1;
1676 /* Copy rest of string */
1677 strcat(tmp, lastpos);
1678 DecodeUTF8(dest, tmp, strlen(tmp));
1679 free(tmp);
1680 tmp=NULL;
1683 void DecodeUTF7(unsigned char *dest, const unsigned char *src, int len)
1685 int i=0,j=0,z,p;
1686 wchar_t ret;
1688 while (i<=len) {
1689 if (len-5>=i) {
1690 if (src[i] == '+') {
1691 z=0;
1692 while (src[z+i+1] != '-' && z+i+1<len) z++;
1693 p=DecodeBASE64(src+i+1, dest+j, z);
1694 if (p%2 != 0) p--;
1695 j+=p;
1696 i+=z+2;
1697 } else {
1698 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1699 dest[j++] = (ret >> 8) & 0xff;
1700 dest[j++] = ret & 0xff;
1702 } else {
1703 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1704 dest[j++] = (ret >> 8) & 0xff;
1705 dest[j++] = ret & 0xff;
1708 dest[j++] = 0;
1709 dest[j++] = 0;
1713 Bob Trower 08/04/01
1714 Copyright (c) Trantor Standard Systems Inc., 2001
1716 Permission is hereby granted, free of charge, to any person
1717 obtaining a copy of this software and associated
1718 documentation files (the "Software"), to deal in the
1719 Software without restriction, including without limitation
1720 the rights to use, copy, modify, merge, publish, distribute,
1721 sublicense, and/or sell copies of the Software, and to
1722 permit persons to whom the Software is furnished to do so,
1723 subject to the following conditions:
1725 The above copyright notice and this permission notice shall
1726 be included in all copies or substantial portions of the
1727 Software.
1729 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
1730 KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
1731 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
1732 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
1733 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1734 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1735 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1736 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1739 static void EncodeBASE64Block(const unsigned char in[3], char out[4], const size_t len)
1741 /* BASE64 translation Table as described in RFC1113 */
1742 unsigned char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1744 out[0] = cb64[ in[0] >> 2 ];
1745 out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
1746 out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
1747 out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
1750 void EncodeBASE64(const unsigned char *Input, char *Output, const size_t Length)
1752 unsigned char in[3], out[4];
1753 size_t i, pos = 0, len, outpos = 0;
1755 while (pos < Length) {
1756 len = 0;
1757 for (i = 0; i < 3; i++) {
1758 in[i] = 0;
1759 if (pos < Length) {
1760 in[i] = Input[pos];
1761 len++;
1762 pos++;
1765 if(len) {
1766 EncodeBASE64Block(in, out, len);
1767 for (i = 0; i < 4; i++) Output[outpos++] = out[i];
1771 Output[outpos++] = 0;
1774 static void DecodeBASE64Block(const char in[4], unsigned char out[3])
1776 out[0] = (unsigned char) ((in[0] << 2) | (in[1] >> 4));
1777 out[1] = (unsigned char) ((in[1] << 4) | (in[2] >> 2));
1778 out[2] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
1781 int DecodeBASE64(const char *Input, unsigned char *Output, const size_t Length)
1783 unsigned char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
1784 unsigned char in[4], out[3], v;
1785 size_t i, len, pos = 0, outpos = 0;
1787 while (pos < Length) {
1788 len = 0;
1789 for(i = 0; i < 4; i++) {
1790 v = 0;
1791 while(v == 0) {
1792 if (pos >= Length) break;
1793 v = (unsigned char) Input[pos++];
1794 v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
1795 if (v) v = (unsigned char) ((v == '$') ? 0 : v - 61);
1797 if(pos<=Length) {
1798 if (v) {
1799 len++;
1800 in[i] = (unsigned char) (v - 1);
1804 if (len) {
1805 DecodeBASE64Block(in, out);
1806 for(i = 0; i < len - 1; i++) Output[outpos++] = out[i];
1809 Output[outpos] = 0;
1810 return outpos;
1813 #ifdef ICONV_FOUND
1815 #include <iconv.h>
1817 #ifdef ICONV_SECOND_ARGUMENT_IS_CONST
1818 # define SECOND_ICONV_ARG const char *
1819 #else
1820 # define SECOND_ICONV_ARG char *
1821 #endif
1823 gboolean IconvDecode(const char *charset, const char *input, const size_t inlen, unsigned char *output, size_t outlen)
1825 iconv_t ic;
1826 /* Add one to convert also trailing zero, this is broken for
1827 * multibyte input, but we don't use iconv for this so far */
1828 size_t rest = inlen + 1;
1829 SECOND_ICONV_ARG in;
1830 char *out;
1832 ic = iconv_open("UCS-2BE", charset);
1833 if (ic == (iconv_t)(-1)) return FALSE;
1835 /* I know I loose const here, but it's iconv choice... */
1836 in = (SECOND_ICONV_ARG)input;
1837 out = output;
1838 iconv(ic, &in, &rest, &out, &outlen);
1840 iconv_close(ic);
1842 return (rest == 0);
1845 gboolean IconvEncode(const char *charset, const unsigned char *input, const size_t inlen, char *output, size_t outlen)
1847 iconv_t ic;
1848 size_t rest = inlen;
1849 SECOND_ICONV_ARG in;
1850 char *out;
1852 ic = iconv_open(charset, "UCS-2BE");
1853 if (ic == (iconv_t)(-1)) return FALSE;
1855 /* I know I loose const here, but it's iconv choice... */
1856 in = (SECOND_ICONV_ARG)input;
1857 out = output;
1858 iconv(ic, &in, &rest, &out, &outlen);
1860 iconv_close(ic);
1862 return (rest == 0);
1864 #endif
1867 /* How should editor hadle tabs in this file? Add editor commands here.
1868 * vim: noexpandtab sw=8 ts=8 sts=8: