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
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>
33 # define WIN32_LEAN_AND_MEAN
37 #include "../../debug.h"
40 /* function changes #10 #13 chars to \n \r */
41 unsigned char *EncodeUnicodeSpecialChars(unsigned char *dest
, const unsigned char *buffer
)
45 while (buffer
[Pos
*2]!=0x00 || buffer
[Pos
*2+1]!=0x00) {
46 if (buffer
[Pos
*2] == 0x00 && buffer
[Pos
*2+1] == 10) {
48 dest
[Pos2
*2+1] = '\\';
53 } else if (buffer
[Pos
*2] == 0x00 && buffer
[Pos
*2+1] == 13) {
55 dest
[Pos2
*2+1] = '\\';
60 } else if (buffer
[Pos
*2] == 0x00 && buffer
[Pos
*2+1] == '\\') {
62 dest
[Pos2
*2+1] = '\\';
65 dest
[Pos2
*2+1] = '\\';
67 } else if (buffer
[Pos
*2] == 0x00 && buffer
[Pos
*2+1] == ';') {
69 dest
[Pos2
*2+1] = '\\';
74 } else if (buffer
[Pos
*2] == 0x00 && buffer
[Pos
*2+1] == ',') {
76 dest
[Pos2
*2+1] = '\\';
82 dest
[Pos2
*2] = buffer
[Pos
*2];
83 dest
[Pos2
*2+1] = buffer
[Pos
*2+1];
93 /* function changes #10 #13 chars to \n \r */
94 char *EncodeSpecialChars(char *dest
, const char *buffer
)
98 while (buffer
[Pos
]!=0x00) {
99 switch (buffer
[Pos
]) {
113 dest
[Pos2
++] = buffer
[Pos
];
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];
130 if (buffer
[Pos
*2] == 0x00 && buffer
[Pos
*2+1] == '\\') {
137 if (buffer
[Pos
*2] == 0x00 && buffer
[Pos
*2+1] == 'n') {
141 if (buffer
[Pos
*2] == 0x00 && buffer
[Pos
*2+1] == 'r') {
145 if (buffer
[Pos
*2] == 0x00 && buffer
[Pos
*2+1] == '\\') {
147 dest
[Pos2
*2+1] = '\\';
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
];
167 if (buffer
[Pos
] == '\\') {
174 if (buffer
[Pos
] == 'n') dest
[Pos2
] = 10;
175 if (buffer
[Pos
] == 'r') dest
[Pos2
] = 13;
176 if (buffer
[Pos
] == '\\') dest
[Pos2
] = '\\';
186 size_t UnicodeLength(const unsigned char *str
)
190 if (str
== NULL
) return 0;
192 while(str
[len
*2] != 0 || str
[len
*2+1] != 0) len
++;
197 /* Convert Unicode char saved in src to dest */
198 int EncodeWithUnicodeAlphabet(const unsigned char *src
, wchar_t *dest
)
202 switch (retval
= mbtowc(dest
, src
, MB_CUR_MAX
)) {
205 default : return retval
;
209 /* Convert Unicode char saved in src to dest */
210 int DecodeWithUnicodeAlphabet(wchar_t src
, unsigned char *dest
)
214 switch (retval
= wctomb(dest
, src
)) {
223 void DecodeUnicode (const unsigned char *src
, char *dest
)
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
);
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
);
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
);
257 setlocale(LC_ALL
, GSM_global_debug
.coding
);
259 DecodeUnicode(src
,dest
);
263 setlocale(LC_ALL
, ".OCP");
265 DecodeUnicode(src
,dest
);
267 setlocale(LC_ALL
, ".ACP");
273 /* Encode string to Unicode. Len is number of input chars */
274 void DecodeISO88591 (unsigned char *dest
, const char *src
, int len
)
278 for (i
= 0; i
< len
; i
++) {
279 /* Hack for Euro sign */
280 if ((unsigned char)src
[i
] == 0x80) {
282 dest
[(2 * i
) + 1] = 0xac;
285 dest
[(2 * i
) + 1] = src
[i
];
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
;
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;
304 dest
[(o_len
*2)+1] = 0;
307 unsigned char EncodeWithBCDAlphabet(int value
)
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
++) {
326 if (digit
<10) dest
[current
++]=digit
+ '0';
328 if (digit
<10) dest
[current
++]=digit
+ '0';
333 void EncodeBCD (unsigned char *dest
, const unsigned char *src
, int len
, gboolean fill
)
337 for (i
= 0; i
< len
; i
++) {
339 dest
[current
]=dest
[current
] | ((src
[i
]-'0') << 4);
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')
366 char EncodeWithHexBinAlphabet (int digit
)
368 if (digit
>= 0 && digit
<= 9) return '0'+(digit
);
369 if (digit
>=10 && digit
<=15) return 'A'+(digit
-10);
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) {
379 (DecodeWithHexBinAlphabet(src
[i
+ 0]) << 4) +
380 DecodeWithHexBinAlphabet(src
[i
+ 1]);
382 (DecodeWithHexBinAlphabet(src
[i
+ 2]) << 4) +
383 DecodeWithHexBinAlphabet(src
[i
+ 3]);
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
;
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);
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},
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 */
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
;
485 DumpMessageText(&GSM_global_debug
, src
, len
);
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];
498 /* Skip rest if we've found something */
499 if (GSM_DefaultAlphabetCharsExtension
[i
][0] != 0x00) {
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];
511 /* Skip rest if we've found something */
512 if (ExtraAlphabet
[i
] != 0x00) {
516 dest
[current
++] = GSM_DefaultAlphabetUnicode
[src
[pos
]][0];
517 dest
[current
++] = GSM_DefaultAlphabetUnicode
[src
[pos
]][1];
522 DumpMessageText(&GSM_global_debug
, dest
, UnicodeLength(dest
)*2);
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
;
545 gboolean FoundSpecial
,FoundNormal
;
548 DumpMessageText(&GSM_global_debug
, src
, (*len
)*2);
551 for (i
= 0; i
< *len
; i
++) {
552 FoundSpecial
= FALSE
;
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];
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]) {
577 if (ExtraAlphabet
!=NULL
&& !FoundNormal
) {
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
];
589 if (!FoundNormal
&& !FoundSpecial
) {
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]) {
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]) {
606 if (FoundNormal
) break;
616 DumpMessageText(&GSM_global_debug
, dest
, 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
;
629 while (src
[i
*2] != 0x00 || src
[i
*2+1] != 0x00) {
630 FoundSpecial
= FALSE
;
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]) {
636 if (current
+2 > maxlen
) {
647 if (current
+1 > maxlen
) {
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;
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
++;
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 */
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
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 */
726 *(output_pos
-1) |= (Byte
& ((1 << (7-Bits
)) - 1)) << (Bits
+1);
730 if (Bits
== -1) Bits
= 7; else output_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>");
748 /* Convert number of semioctets to number of chars */
749 if (length
% 2) length
++;
750 length
=length
/ 2 + 1;
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
);
759 /*without leading byte with format of number*/
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
);
769 case (NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN
& 0x70):
770 smfprintf(di
, "International number\n");
772 DecodeBCD(Buffer
+1,Number
+2, length
);
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
);
789 smfprintf(di
, "Len %i\n",length
);
791 EncodeUnicode(retval
,Buffer
,strlen(Buffer
));
793 return 2 + ((Number
[0] + 1) / 2);
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
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
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
;
818 unsigned char *buffer
;
820 length
= UnicodeLength(Number
);
821 buffer
= (unsigned char*)malloc(length
+ 2);
823 if (buffer
== NULL
) {
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
;
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
849 /* After number type we will have number. GSM 03.40 section 9.1.2 */
851 case NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN
:
852 length
=GSM_PackSevenBitsToEight(0, buffer
, Output
+1, strlen(buffer
))*2;
853 if (strlen(buffer
)==7) length
--;
855 case NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN
:
857 EncodeBCD (Output
+1, buffer
+1, length
, TRUE
);
860 EncodeBCD (Output
+1, buffer
, length
, TRUE
);
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
)
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) {
882 Dest
[j
+1] = Source
[j
+1];
889 /* Changes minor/major order in Unicode string */
890 void ReverseUnicodeString(unsigned char *String
)
893 unsigned char byte1
, byte2
;
895 while (String
[j
]!=0x00 || String
[j
+1]!=0x00) {
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
];
920 Dest
[current
++] = Source
[j
];
921 Dest
[current
++] = Source
[j
+1];
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
)
948 while(((*CurrentBit
) + i
) % 8 != 0) {
949 ClearBit(Destination
, (*CurrentBit
)+i
);
953 (*CurrentBit
) = (*CurrentBit
) + i
;
956 void BufferAlignNumber(size_t *CurrentBit
)
960 while(((*CurrentBit
) + i
) % 8 != 0) {
964 (*CurrentBit
) = (*CurrentBit
) + i
;
967 void AddBuffer(unsigned char *Destination
,
969 unsigned char *Source
,
970 size_t BitsToProcess
)
974 while (i
!=BitsToProcess
) {
975 if (GetBit(Source
, i
)) {
976 SetBit(Destination
, (*CurrentBit
)+i
);
978 ClearBit(Destination
, (*CurrentBit
)+i
);
982 (*CurrentBit
) = (*CurrentBit
) + BitsToProcess
;
985 void AddBufferByte(unsigned char *Destination
,
987 unsigned char Source
,
988 size_t BitsToProcess
)
994 AddBuffer(Destination
, CurrentBit
, &Byte
, BitsToProcess
);
997 void GetBuffer(unsigned char *Source
,
999 unsigned char *Destination
,
1000 size_t BitsToProcess
)
1004 while (i
!=BitsToProcess
) {
1005 if (GetBit(Source
, (*CurrentBit
)+i
)) {
1006 SetBit(Destination
, i
);
1008 ClearBit(Destination
, i
);
1012 (*CurrentBit
) = (*CurrentBit
) + BitsToProcess
;
1015 void GetBufferInt(unsigned char *Source
,
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
;
1028 (*CurrentBit
) = (*CurrentBit
) + i
;
1031 void GetBufferI(unsigned char *Source
,
1034 size_t BitsToProcess
)
1038 z
= 1<<(BitsToProcess
-1);
1040 while (i
!=BitsToProcess
) {
1041 if (GetBit(Source
, (*CurrentBit
)+i
)) l
=l
+z
;
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
1053 void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest
, const unsigned char *src
, int len
)
1056 gboolean special
=FALSE
;
1058 for (i
= 0; i
< len
; i
++) {
1060 if (src
[i
*2] == 0x00 && src
[i
*2+1] == '~') {
1061 dest
[current
++] = 0x00;
1062 dest
[current
++] = '~';
1064 dest
[current
++] = 0x00;
1065 dest
[current
++] = 0x01;
1066 dest
[current
++] = src
[i
*2];
1067 dest
[current
++] = src
[i
*2+1];
1071 if (src
[i
*2] == 0x00 && src
[i
*2+1] == '~') {
1074 dest
[current
++] = src
[i
*2];
1075 dest
[current
++] = src
[i
*2+1];
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
)
1091 for (i
=0;i
<len
;i
++) {
1094 switch (src
[2*i
+1]) {
1096 dest
[current
++] = 0x00;
1097 dest
[current
++] = '~';
1100 dest
[current
++] = 0x00;
1101 dest
[current
++] = '~';
1102 dest
[current
++] = 0x00;
1103 dest
[current
++] = '~';
1106 dest
[current
++] = src
[i
*2];
1107 dest
[current
++] = src
[i
*2+1];
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
)
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
;
1142 /* wcscmp in Mandrake 9.0 is wrong */
1143 gboolean
mywstrncmp(unsigned const char *a
, unsigned const char *b
, int num
)
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
;
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
1160 unsigned char dest
[10];
1164 wc
= src
[1] | (src
[0] << 8);
1166 #ifndef HAVE_ISWSPACE
1167 o
= DecodeWithUnicodeAlphabet(wc
, dest
);
1169 if (isspace(((int)dest
[0]))!=0) return TRUE
;
1174 if (iswspace(wc
)) return TRUE
;
1180 * Following code is based on wcsstr from the GNU C Library, original
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 */
1206 if ((c
= tolowerwchar(*haystack
)) == L
'\0')
1211 if ((c
= tolowerwchar(*needle
)) == L
'\0')
1219 if ((a
= tolowerwchar(*haystack
)) == L
'\0')
1224 if ((a
= tolowerwchar(*haystack
)) == L
'\0')
1230 if ((a
= tolowerwchar(*haystack
)) == L
'\0')
1236 rhaystack
= haystack
+ 2;
1239 if (tolowerwchar(*rhaystack
) == (a
= tolowerwchar(*rneedle
)))
1245 if (tolowerwchar(*rhaystack
) != (a
= tolowerwchar(*needle
)))
1251 } while (tolowerwchar(*rhaystack
) == (a
= tolowerwchar(*needle
)));
1253 needle
= rneedle
; /* took the register-poor approach */
1260 return (unsigned char *)haystack
;
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
;
1276 if (Buffer
== NULL
) return ERR_NONE
;
1277 while ((*Pos
) < MaxLen
) {
1278 switch (Buffer
[*Pos
]) {
1284 if (Buffer
[*Pos
] == 0x0d) {
1285 if (was_cr
&& skip
) return ERR_NONE
;
1288 if (was_lf
&& skip
) return ERR_NONE
;
1292 if (pos
!= 0 && !skip
) {
1294 /* (Quote printable new line) Does string end with = ? */
1295 if (OutBuffer
[pos
- 1] == '=' && quoted_printable
) {
1299 was_cr
= (Buffer
[*Pos
] == 0x0d);
1300 was_lf
= (Buffer
[*Pos
] == 0x0a);
1303 /* (vCard continuation) Next line start with space? */
1305 if (Buffer
[*Pos
+ 1] == 0x0a || Buffer
[*Pos
+ 1] == 0x0d) {
1308 if (Buffer
[tmp
] == ' ') {
1317 /* Detect quoted printable for possible escaping */
1318 if (Buffer
[*Pos
] == ':' &&
1319 strstr(OutBuffer
, ";ENCODING=QUOTED-PRINTABLE") != NULL
) {
1320 quoted_printable
= TRUE
;
1323 OutBuffer
[pos
] = Buffer
[*Pos
];
1326 if (pos
+ 1 >= MaxOutLen
) return ERR_MOREMEMORY
;
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
;
1340 size_t OutLen
= 200;
1342 *OutBuffer
= (char *)malloc(OutLen
);
1343 if (*OutBuffer
== NULL
) return ERR_MOREMEMORY
;
1344 (*OutBuffer
)[0] = 0;
1346 if (Buffer
== NULL
) return ERR_NONE
;
1347 while ((*Pos
) < MaxLen
) {
1348 switch (Buffer
[*Pos
]) {
1354 if (Buffer
[*Pos
] == 0x0d) {
1355 if (was_cr
&& skip
) return ERR_NONE
;
1358 if (was_lf
&& skip
) return ERR_NONE
;
1362 if (pos
!= 0 && !skip
) {
1364 /* (Quote printable new line) Does string end with = ? */
1365 if ((*OutBuffer
)[pos
- 1] == '=' && quoted_printable
) {
1367 (*OutBuffer
)[pos
] = 0;
1369 was_cr
= (Buffer
[*Pos
] == 0x0d);
1370 was_lf
= (Buffer
[*Pos
] == 0x0a);
1373 /* (vCard continuation) Next line start with space? */
1375 if (Buffer
[*Pos
+ 1] == 0x0a || Buffer
[*Pos
+ 1] == 0x0d) {
1378 if (Buffer
[tmp
] == ' ') {
1387 /* Detect quoted printable for possible escaping */
1388 if (Buffer
[*Pos
] == ':' &&
1389 strstr(*OutBuffer
, ";ENCODING=QUOTED-PRINTABLE") != NULL
) {
1390 quoted_printable
= TRUE
;
1393 (*OutBuffer
)[pos
] = Buffer
[*Pos
];
1395 (*OutBuffer
)[pos
] = 0;
1396 if (pos
+ 2 >= OutLen
) {
1398 *OutBuffer
= (char *)realloc(*OutBuffer
, OutLen
);
1399 if (*OutBuffer
== NULL
) return ERR_MOREMEMORY
;
1408 void StringToDouble(char *text
, double *d
)
1410 gboolean before
=TRUE
;
1411 double multiply
= 1;
1415 for (i
=0;i
<strlen(text
);i
++) {
1416 if (isdigit((int)text
[i
])) {
1418 (*d
)=(*d
)*10+(text
[i
]-'0');
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);
1439 /* Unicode 0800-FFFF -> UTF8 1110xxxx 10xxxxxx 10xxxxxx */
1441 ret
[0] = 224 + (src
/ 4096);
1442 ret
[1] = 128 + ((src
/ 64) % 64);
1443 ret
[2] = 128 + (src
% 64);
1447 /* Unicode 0000-007F -> UTF8 0xxxxxxx */
1452 /* Make UTF8 string from Unicode input string */
1453 gboolean
EncodeUTF8QuotedPrintable(char *dest
, const unsigned char *src
)
1456 unsigned char mychar
[3];
1457 gboolean retval
= FALSE
;
1459 len
= UnicodeLength(src
);
1461 for (i
= 0; i
< len
; i
++) {
1462 z
= EncodeWithUTF8Alphabet(src
[i
*2],src
[i
*2+1],mychar
);
1465 sprintf(dest
+j
, "=%02X",mychar
[w
]);
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]);
1475 j
+= DecodeWithUnicodeAlphabet(((wchar_t)(src
[i
*2]*256+src
[i
*2+1])), dest
+ j
);
1483 gboolean
EncodeUTF8(char *dest
, const unsigned char *src
)
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
);
1492 memcpy(dest
+j
,mychar
,z
);
1496 j
+= DecodeWithUnicodeAlphabet(((wchar_t)(src
[i
*2]*256+src
[i
*2+1])), dest
+ j
);
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;
1511 if (src
[0] < 194) return 0;
1513 if (len
< 2) return 0;
1514 (*dest
) = (src
[0]-192)*64 + (src
[1]-128);
1518 if (len
< 3) return 0;
1519 (*dest
) = (src
[0]-224)*4096 + (src
[1]-128)*64 + (src
[2]-128);
1526 /* Make Unicode string from ISO-8859-1 string */
1527 void DecodeISO88591QuotedPrintable(unsigned char *dest
, const unsigned char *src
, int len
)
1532 if (src
[i
] == '=' && i
+ 2 < len
1533 && DecodeWithHexBinAlphabet(src
[i
+ 1]) != -1
1534 && DecodeWithHexBinAlphabet(src
[i
+ 2]) != -1) {
1536 dest
[j
++] = 16 * DecodeWithHexBinAlphabet(src
[i
+ 1]) + DecodeWithHexBinAlphabet(src
[i
+ 2]);
1548 /* Make Unicode string from UTF8 string */
1549 void DecodeUTF8QuotedPrintable(unsigned char *dest
, const char *src
, int len
)
1552 unsigned char mychar
[10];
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) {
1563 mychar
[z
] = 16*DecodeWithHexBinAlphabet(src
[z
*3+i
+1])+DecodeWithHexBinAlphabet(src
[z
*3+i
+2]);
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;
1572 /* we ignore wrong sequence */
1573 if (DecodeWithUTF8Alphabet(mychar
,&ret
,z
)==0) continue;
1575 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1577 dest
[j
++] = (ret
>> 8) & 0xff;
1578 dest
[j
++] = ret
& 0xff;
1584 void DecodeUTF8(unsigned char *dest
, const char *src
, int len
)
1590 z
= DecodeWithUTF8Alphabet(src
+i
,&ret
,len
-i
);
1592 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1596 dest
[j
++] = (ret
>> 8) & 0xff;
1597 dest
[j
++] = ret
& 0xff;
1603 void DecodeXMLUTF8(unsigned char *dest
, const char *src
, int len
)
1606 char *pos
, *pos_end
;
1607 const char *lastpos
;
1609 unsigned long int c
;
1612 /* Allocate buffer */
1613 tmp
= (char *)calloc(len
+ 1, sizeof(char));
1615 /* We have no memory for XML decoding */
1616 DecodeUTF8(dest
, src
, len
);
1620 /* Find ampersand and decode the */
1622 while ((lastpos
!= 0) && ((pos
= strchr(lastpos
, '&')) != NULL
)) {
1623 /* Store current string */
1624 strncat(tmp
, lastpos
, pos
- lastpos
);
1626 /* Skip ampersand */
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");
1636 dbgprintf(NULL
, "Too long html entity, ignoring!\n");
1638 strncat(tmp
, lastpos
, 1);
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);
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
);
1658 } else if (strcmp(entity
, "amp") == 0) {
1660 } else if (strcmp(entity
, "apos") == 0) {
1662 } else if (strcmp(entity
, "gt") == 0) {
1664 } else if (strcmp(entity
, "lt") == 0) {
1666 } else if (strcmp(entity
, "quot") == 0) {
1669 dbgprintf(NULL
, "Could not decode XML entity!\n");
1670 strncat(tmp
, lastpos
, pos_end
- pos
+ 1);
1674 lastpos
= pos_end
+ 1;
1676 /* Copy rest of string */
1677 strcat(tmp
, lastpos
);
1678 DecodeUTF8(dest
, tmp
, strlen(tmp
));
1683 void DecodeUTF7(unsigned char *dest
, const unsigned char *src
, int len
)
1690 if (src
[i
] == '+') {
1692 while (src
[z
+i
+1] != '-' && z
+i
+1<len
) z
++;
1693 p
=DecodeBASE64(src
+i
+1, dest
+j
, z
);
1698 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1699 dest
[j
++] = (ret
>> 8) & 0xff;
1700 dest
[j
++] = ret
& 0xff;
1703 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1704 dest
[j
++] = (ret
>> 8) & 0xff;
1705 dest
[j
++] = ret
& 0xff;
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
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
) {
1757 for (i
= 0; i
< 3; i
++) {
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
) {
1789 for(i
= 0; i
< 4; i
++) {
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);
1800 in
[i
] = (unsigned char) (v
- 1);
1805 DecodeBASE64Block(in
, out
);
1806 for(i
= 0; i
< len
- 1; i
++) Output
[outpos
++] = out
[i
];
1817 #ifdef ICONV_SECOND_ARGUMENT_IS_CONST
1818 # define SECOND_ICONV_ARG const char *
1820 # define SECOND_ICONV_ARG char *
1823 gboolean
IconvDecode(const char *charset
, const char *input
, const size_t inlen
, unsigned char *output
, size_t outlen
)
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
;
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
;
1838 iconv(ic
, &in
, &rest
, &out
, &outlen
);
1845 gboolean
IconvEncode(const char *charset
, const unsigned char *input
, const size_t inlen
, char *output
, size_t outlen
)
1848 size_t rest
= inlen
;
1849 SECOND_ICONV_ARG in
;
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
;
1858 iconv(ic
, &in
, &rest
, &out
, &outlen
);
1867 /* How should editor hadle tabs in this file? Add editor commands here.
1868 * vim: noexpandtab sw=8 ts=8 sts=8: