17 unsigned int UnicodeLength(const unsigned char *str
)
22 if (str
[len
*2] == 0 && str
[len
*2+1] == 0) break;
28 /* Convert Unicode char saved in src to dest */
29 unsigned int EncodeWithUnicodeAlphabet(const unsigned char *src
, wchar_t *dest
)
33 switch (retval
= mbtowc(dest
, src
, MB_CUR_MAX
)) {
36 default : return retval
;
40 /* Convert Unicode char saved in src to dest */
41 unsigned int DecodeWithUnicodeAlphabet(wchar_t src
, unsigned char *dest
)
45 switch (retval
= wctomb(dest
, src
)) {
54 void DecodeUnicode (const unsigned char *src
, unsigned char *dest
)
59 while (src
[(2*i
)+1]!=0x00 || src
[2*i
]!=0x00) {
60 wc
= src
[(2*i
)+1] | (src
[2*i
] << 8);
61 o
+= DecodeWithUnicodeAlphabet(wc
, dest
+ o
);
67 /* Decode Unicode string and return as function result */
68 unsigned char *DecodeUnicodeString (const unsigned char *src
)
70 static char dest
[500];
72 DecodeUnicode(src
,dest
);
76 /* Decode Unicode string to UTF8 or other console charset
77 * and return as function result
79 unsigned char *DecodeUnicodeConsole(const unsigned char *src
)
81 static char dest
[500];
83 if (di
.coding
[0] != 0) {
84 if (!strcmp(di
.coding
,"utf8")) {
85 EncodeUTF8(dest
, src
);
88 setlocale(LC_ALL
, di
.coding
);
90 DecodeUnicode(src
,dest
);
94 setlocale(LC_ALL
, ".OCP");
96 DecodeUnicode(src
,dest
);
98 setlocale(LC_ALL
, ".ACP");
104 /* Encode string to Unicode. Len is number of input chars */
105 void EncodeUnicode (unsigned char *dest
, const unsigned char *src
, int len
)
107 int i_len
= 0, o_len
;
110 for (o_len
= 0; i_len
< len
; o_len
++) {
111 i_len
+= EncodeWithUnicodeAlphabet(&src
[i_len
], &wc
);
112 dest
[o_len
*2] = (wc
>> 8) & 0xff;
113 dest
[(o_len
*2)+1] = wc
& 0xff;
116 dest
[(o_len
*2)+1] = 0;
119 unsigned char EncodeWithBCDAlphabet(int value
)
123 division
=div(value
,10);
124 return ( ( (value
-division
.quot
*10) & 0x0f) << 4) | (division
.quot
& 0xf);
127 int DecodeWithBCDAlphabet(unsigned char value
)
129 return 10*(value
& 0x0f)+(value
>> 4);
132 void DecodeBCD (unsigned char *dest
, const unsigned char *src
, int len
)
134 int i
,current
=0,digit
;
136 for (i
= 0; i
< len
; i
++) {
138 if (digit
<10) dest
[current
++]=digit
+ '0';
140 if (digit
<10) dest
[current
++]=digit
+ '0';
145 void EncodeBCD (unsigned char *dest
, const unsigned char *src
, int len
, bool fill
)
149 for (i
= 0; i
< len
; i
++) {
151 dest
[current
]=dest
[current
] | ((src
[i
]-'0') << 4);
154 dest
[current
]=src
[i
]-'0';
158 /* When fill is set: we fill in the most significant bits of the
159 last byte with 0x0f (1111 binary) if the number is represented
160 with odd number of digits. */
161 if (fill
&& (len
& 0x01)) {
162 dest
[current
]=dest
[current
] | 0xf0;
166 int DecodeWithHexBinAlphabet (unsigned char mychar
)
168 if (mychar
>='A' && mychar
<='F') return mychar
-'A'+10;
169 if (mychar
>='a' && mychar
<='f') return mychar
-'a'+10;
170 if (mychar
>='0' && mychar
<='9') return mychar
-'0';
174 unsigned char EncodeWithHexBinAlphabet (int digit
)
176 if (digit
>= 0 && digit
<= 9) return '0'+(digit
);
177 if (digit
>=10 && digit
<=15) return 'A'+(digit
-10);
181 void DecodeHexUnicode (unsigned char *dest
, const unsigned char *src
, int len
)
186 if (len
!= 0 && src
[0] == '0' && src
[1] == '0') first
= true;
187 for (i
= 0; i
< len
/4 ; i
++) {
189 dest
[current
++] = DecodeWithHexBinAlphabet(src
[i
*4+0])*16+
190 DecodeWithHexBinAlphabet(src
[i
*4+1]);
191 dest
[current
++] = DecodeWithHexBinAlphabet(src
[i
*4+2])*16+
192 DecodeWithHexBinAlphabet(src
[i
*4+3]);
194 dest
[current
++] = DecodeWithHexBinAlphabet(src
[i
*4+2])*16+
195 DecodeWithHexBinAlphabet(src
[i
*4+3]);
196 dest
[current
++] = DecodeWithHexBinAlphabet(src
[i
*4+0])*16+
197 DecodeWithHexBinAlphabet(src
[i
*4+1]);
204 void EncodeHexUnicode (unsigned char *dest
, const unsigned char *src
, int len
)
208 for (i
= 0; i
< len
; i
++) {
209 dest
[current
++] = EncodeWithHexBinAlphabet(src
[2*i
] >> 0x04);
210 dest
[current
++] = EncodeWithHexBinAlphabet(src
[2*i
] & 0x0f);
211 dest
[current
++] = EncodeWithHexBinAlphabet(src
[2*i
+1] >> 0x04);
212 dest
[current
++] = EncodeWithHexBinAlphabet(src
[2*i
+1] & 0x0f);
217 void DecodeHexBin (unsigned char *dest
, const unsigned char *src
, int len
)
221 for (i
= 0; i
< len
/2 ; i
++) {
222 dest
[current
++] = DecodeWithHexBinAlphabet(src
[i
*2])*16+
223 DecodeWithHexBinAlphabet(src
[i
*2+1]);
228 void EncodeHexBin (unsigned char *dest
, const unsigned char *src
, int len
)
232 for (i
= 0; i
< len
; i
++) {
233 dest
[current
++] = EncodeWithHexBinAlphabet(src
[i
] >> 0x04);
234 dest
[current
++] = EncodeWithHexBinAlphabet(src
[i
] & 0x0f);
239 /* ETSI GSM 03.38, section 6.2.1: Default alphabet for SMS messages */
240 static unsigned char GSM_DefaultAlphabetUnicode
[128+1][2] =
242 {0x00,0x40},{0x00,0xa3},{0x00,0x24},{0x00,0xA5},
243 {0x00,0xE8},{0x00,0xE9},{0x00,0xF9},{0x00,0xEC},/*0x08*/
244 {0x00,0xF2},{0x00,0xC7},{0x00,'\n'},{0x00,0xD8},
245 {0x00,0xF8},{0x00,'\r'},{0x00,0xC5},{0x00,0xE5},
246 {0x03,0x94},{0x00,0x5f},{0x03,0xA6},{0x03,0x93},
247 {0x03,0x9B},{0x03,0xA9},{0x03,0xA0},{0x03,0xA8},
248 {0x03,0xA3},{0x03,0x98},{0x03,0x9E},{0x00,0xb9},
249 {0x00,0xC6},{0x00,0xE6},{0x00,0xDF},{0x00,0xC9},/*0x20*/
250 {0x00,' ' },{0x00,'!' },{0x00,'\"'},{0x00,'#' },
251 {0x00,0xA4},{0x00,'%' },{0x00,'&' },{0x00,'\''},
252 {0x00,'(' },{0x00,')' },{0x00,'*' },{0x00,'+' },
253 {0x00,',' },{0x00,'-' },{0x00,'.' },{0x00,'/' },/*0x30*/
254 {0x00,'0' },{0x00,'1' },{0x00,'2' },{0x00,'3' },
255 {0x00,'4' },{0x00,'5' },{0x00,'6' },{0x00,'7' },
256 {0x00,'8' },{0x00,'9' },{0x00,':' },{0x00,';' },
257 {0x00,'<' },{0x00,'=' },{0x00,'>' },{0x00,'?' },/*0x40*/
258 {0x00,0xA1},{0x00,'A' },{0x00,'B' },{0x00,'C' },
259 {0x00,'D' },{0x00,'E' },{0x00,'F' },{0x00,'G' },
260 {0x00,'H' },{0x00,'I' },{0x00,'J' },{0x00,'K' },
261 {0x00,'L' },{0x00,'M' },{0x00,'N' },{0x00,'O' },
262 {0x00,'P' },{0x00,'Q' },{0x00,'R' },{0x00,'S' },
263 {0x00,'T' },{0x00,'U' },{0x00,'V' },{0x00,'W' },
264 {0x00,'X' },{0x00,'Y' },{0x00,'Z' },{0x00,0xC4},
265 {0x00,0xD6},{0x00,0xD1},{0x00,0xDC},{0x00,0xA7},
266 {0x00,0xBF},{0x00,'a' },{0x00,'b' },{0x00,'c' },
267 {0x00,'d' },{0x00,'e' },{0x00,'f' },{0x00,'g' },
268 {0x00,'h' },{0x00,'i' },{0x00,'j' },{0x00,'k' },
269 {0x00,'l' },{0x00,'m' },{0x00,'n' },{0x00,'o' },
270 {0x00,'p' },{0x00,'q' },{0x00,'r' },{0x00,'s' },
271 {0x00,'t' },{0x00,'u' },{0x00,'v' },{0x00,'w' },
272 {0x00,'x' },{0x00,'y' },{0x00,'z' },{0x00,0xE4},
273 {0x00,0xF6},{0x00,0xF1},{0x00,0xFC},{0x00,0xE0},
278 * Some sequences of 2 default alphabet chars (for example,
279 * 0x1b, 0x65) are visible as one single additional char (for example,
280 * 0x1b, 0x65 gives Euro char saved in Unicode as 0x20, 0xAC)
281 * This table contains:
282 * 1. two first chars means sequence of chars from GSM default alphabet
283 * 2. two second is target (encoded) char saved in Unicode
285 static unsigned char GSM_DefaultAlphabetCharsExtension
[][4] =
287 {0x1b,0x14,0x00,0x5e}, /* ^ */
288 {0x1b,0x28,0x00,0x7b}, /* { */
289 {0x1b,0x29,0x00,0x7d}, /* } */
290 {0x1b,0x2f,0x00,0x5c}, /* \ */
291 {0x1b,0x3c,0x00,0x5b}, /* [ */
292 {0x1b,0x3d,0x00,0x7E}, /* ~ */
293 {0x1b,0x3e,0x00,0x5d}, /* ] */
294 {0x1b,0x40,0x00,0x7C}, /* | */
295 {0x1b,0x65,0x20,0xAC}, /* Euro */
296 {0x00,0x00,0x00,0x00}
299 void DecodeDefault (unsigned char *dest
, const unsigned char *src
, int len
, bool UseExtensions
, unsigned char *ExtraAlphabet
)
302 bool FoundSpecial
= false;
305 if (di
.dl
== DL_TEXTALL
|| di
.dl
== DL_TEXTALLDATE
) DumpMessage(di
.df
, src
, len
);
308 for (i
= 0; i
< len
; i
++) {
309 FoundSpecial
= false;
310 if ((i
< (len
-1)) && UseExtensions
) {
312 while (GSM_DefaultAlphabetCharsExtension
[j
][0]!=0x00) {
313 if (GSM_DefaultAlphabetCharsExtension
[j
][0]==src
[i
] &&
314 GSM_DefaultAlphabetCharsExtension
[j
][1]==src
[i
+1]) {
316 dest
[current
++] = GSM_DefaultAlphabetCharsExtension
[j
][2];
317 dest
[current
++] = GSM_DefaultAlphabetCharsExtension
[j
][3];
324 if (ExtraAlphabet
!=NULL
&& !FoundSpecial
) {
326 while (ExtraAlphabet
[j
] != 0x00 || ExtraAlphabet
[j
+1] != 0x00 || ExtraAlphabet
[j
+2] != 0x00) {
327 if (ExtraAlphabet
[j
] == src
[i
]) {
328 dest
[current
++] = ExtraAlphabet
[j
+1];
329 dest
[current
++] = ExtraAlphabet
[j
+2];
337 dest
[current
++] = GSM_DefaultAlphabetUnicode
[src
[i
]][0];
338 dest
[current
++] = GSM_DefaultAlphabetUnicode
[src
[i
]][1];
344 if (di
.dl
== DL_TEXTALL
|| di
.dl
== DL_TEXTALLDATE
) DumpMessage(di
.df
, dest
, UnicodeLength(dest
)*2);
348 /* There are many national chars with "adds". In phone they're normally
349 * changed to "plain" Latin chars. We have such functionality too.
350 * This table is automatically created from convert.txt file (see
351 * /docs/developers) using --makeconverttable. It contains such chars
352 * to replace in order:
353 * 1. original char (Unicode) 2. destination char (Unicode)
355 static unsigned char ConvertTable
[] =
356 "\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"\
357 "\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"\
358 "\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"\
359 "\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"\
360 "\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"\
361 "\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";
363 void EncodeDefault(unsigned char *dest
, const unsigned char *src
, int *len
, bool UseExtensions
, unsigned char *ExtraAlphabet
)
367 bool FoundSpecial
,FoundNormal
;
370 if (di
.dl
== DL_TEXTALL
|| di
.dl
== DL_TEXTALLDATE
) DumpMessage(di
.df
, src
, (*len
)*2);
373 for (i
= 0; i
< *len
; i
++) {
374 FoundSpecial
= false;
376 while (GSM_DefaultAlphabetCharsExtension
[j
][0]!=0x00 && UseExtensions
) {
377 if (src
[i
*2] == GSM_DefaultAlphabetCharsExtension
[j
][2] &&
378 src
[i
*2+1] == GSM_DefaultAlphabetCharsExtension
[j
][3]) {
379 dest
[current
++] = GSM_DefaultAlphabetCharsExtension
[j
][0];
380 dest
[current
++] = GSM_DefaultAlphabetCharsExtension
[j
][1];
390 while (GSM_DefaultAlphabetUnicode
[j
][1]!=0x00)
392 if (src
[i
*2] == GSM_DefaultAlphabetUnicode
[j
][0] &&
393 src
[i
*2+1] == GSM_DefaultAlphabetUnicode
[j
][1])
401 if (ExtraAlphabet
!=NULL
&& !FoundNormal
) {
403 while (ExtraAlphabet
[j
] != 0x00 || ExtraAlphabet
[j
+1] != 0x00 || ExtraAlphabet
[j
+2] != 0x00) {
404 if (ExtraAlphabet
[j
+1] == src
[i
*2] &&
405 ExtraAlphabet
[j
+2] == src
[i
*2 + 1])
407 ret
= ExtraAlphabet
[j
];
414 if (!FoundNormal
&& !FoundSpecial
) {
417 while (ConvertTable
[j
*4] != 0x00 ||
418 ConvertTable
[j
*4+1] != 0x00) {
419 if (src
[i
*2] == ConvertTable
[j
*4] &&
420 src
[i
*2+1] == ConvertTable
[j
*4+1]) {
422 while (GSM_DefaultAlphabetUnicode
[z
][1]!=0x00)
424 if (ConvertTable
[j
*4+2] == GSM_DefaultAlphabetUnicode
[z
][0] &&
425 ConvertTable
[j
*4+3] == GSM_DefaultAlphabetUnicode
[z
][1])
433 if (FoundNormal
) break;
443 if (di
.dl
== DL_TEXTALL
|| di
.dl
== DL_TEXTALLDATE
) DumpMessage(di
.df
, dest
, current
);
449 /* You don't have to use ConvertTable here - 1 char is replaced there by 1 char */
450 void FindDefaultAlphabetLen(const unsigned char *src
, int *srclen
, int *smslen
, int maxlen
)
456 while (src
[i
*2] != 0x00 || src
[i
*2+1] != 0x00)
458 FoundSpecial
= false;
460 while (GSM_DefaultAlphabetCharsExtension
[j
][0]!=0x00) {
461 if (src
[i
*2] == GSM_DefaultAlphabetCharsExtension
[j
][2] &&
462 src
[i
*2+1] == GSM_DefaultAlphabetCharsExtension
[j
][3]) {
464 if (current
+2 > maxlen
) {
475 if (current
+1 > maxlen
) {
488 #define ByteMask ((1 << Bits) - 1)
490 int GSM_UnpackEightBitsToSeven(int offset
, int in_length
, int out_length
,
491 unsigned char *input
, unsigned char *output
)
494 unsigned char *OUTPUT
= output
; /* Current pointer to the output buffer */
495 unsigned char *INPUT
= input
; /* Current pointer to the input buffer */
496 unsigned char Rest
= 0x00;
499 Bits
= offset
? offset
: 7;
501 while ((INPUT
- input
) < in_length
) {
503 *OUTPUT
= ((*INPUT
& ByteMask
) << (7 - Bits
)) | Rest
;
504 Rest
= *INPUT
>> Bits
;
506 /* If we don't start from 0th bit, we shouldn't go to the
507 next char. Under *OUTPUT we have now 0 and under Rest -
508 _first_ part of the char. */
509 if ((INPUT
!= input
) || (Bits
== 7)) OUTPUT
++;
512 if ((OUTPUT
- output
) >= out_length
) break;
514 /* After reading 7 octets we have read 7 full characters but
515 we have 7 bits as well. This is the next character */
526 return OUTPUT
- output
;
532 int GSM_PackSevenBitsToEight(int offset
, unsigned char *input
, unsigned char *output
, int length
)
535 unsigned char *OUTPUT
= output
; /* Current pointer to the output buffer */
536 unsigned char *INPUT
= input
; /* Current pointer to the input buffer */
537 int Bits
; /* Number of bits directly copied to
538 * the output buffer */
539 Bits
= (7 + offset
) % 8;
541 /* If we don't begin with 0th bit, we will write only a part of the
548 while ((INPUT
- input
) < length
) {
549 unsigned char Byte
= *INPUT
;
551 *OUTPUT
= Byte
>> (7 - Bits
);
552 /* If we don't write at 0th bit of the octet, we should write
553 a second part of the previous octet */
555 *(OUTPUT
-1) |= (Byte
& ((1 << (7-Bits
)) - 1)) << (Bits
+1);
559 if (Bits
== -1) Bits
= 7; else OUTPUT
++;
563 return (OUTPUT
- output
);
569 void GSM_UnpackSemiOctetNumber(unsigned char *retval
, unsigned char *Number
, bool semioctet
)
571 unsigned char Buffer
[50] = "";
572 int length
= Number
[0];
575 /* Convert number of semioctets to number of chars */
576 if (length
% 2) length
++;
577 length
=length
/ 2 + 1;
580 /*without leading byte with format of number*/
584 case GNT_ALPHANUMERIC
:
585 if (length
> 6) length
++;
586 dbgprintf("Alphanumeric number, length %i\n",length
);
587 GSM_UnpackEightBitsToSeven(0, length
, length
, Number
+2, Buffer
);
590 case GNT_INTERNATIONAL
:
591 dbgprintf("International number\n");
593 DecodeBCD(Buffer
+1,Number
+2, length
);
596 dbgprintf("Default number %02x\n",Number
[1]);
597 DecodeBCD (Buffer
, Number
+2, length
);
601 EncodeUnicode(retval
,Buffer
,strlen(Buffer
));
604 /* Packing of numbers (SMS Center number and destination number) for SMS
607 /* See GSM 03.40 9.1.1:
608 1 byte - length of number given in semioctets or bytes (when given in bytes,
609 includes one byte for byte with number format.
610 Returned by function (set semioctet to true, if want result
612 1 byte - format of number. See GSM_NumberType; in gsm-common.h. Returned
613 in unsigned char *Output.
614 n bytes - 2n or 2n-1 semioctets with number. For some types of numbers
615 in the most significant bits of the last byte with 0x0f
616 (1111 binary) are filled if the number is represented
617 with odd number of digits. Returned in unsigned char *Output. */
618 /* 1 semioctet = 4 bits = half of byte */
619 int GSM_PackSemiOctetNumber(unsigned char *Number
, unsigned char *Output
, bool semioctet
)
621 unsigned char buffer
[50];
622 unsigned char *OUTPUT
=Output
; /* Pointer to the output */
624 unsigned char format
=GNT_UNKNOWN
; /* format of number used by us */
626 length
=UnicodeLength(Number
);
627 memcpy(buffer
,DecodeUnicodeString(Number
),length
+1);
629 /* Checking for format number */
630 for (j
=0;j
<length
;j
++) {
631 /* first byte is '+'. It can be international */
632 if (j
==0 && buffer
[j
]=='+') format
=GNT_INTERNATIONAL
;
634 /*char is not number. It must be alphanumeric*/
635 if (!isdigit(buffer
[j
])) format
=GNT_ALPHANUMERIC
;
639 /* The first byte in the Semi-octet representation of the address field is
640 * the Type-of-Address. GSM 03.40 section 9.1.2.5 */
643 /* Now we will have number. GSM 03.40 section 9.1.2 */
645 case GNT_ALPHANUMERIC
:
646 length
=GSM_PackSevenBitsToEight(0, buffer
, OUTPUT
, strlen(buffer
))*2;
647 if (strlen(buffer
)==7) length
--;
649 case GNT_INTERNATIONAL
:
651 EncodeBCD (OUTPUT
, buffer
+1, length
, true);
654 EncodeBCD (OUTPUT
, buffer
, length
, true);
657 if (semioctet
) return length
;
658 /* Convert number of semioctets to number of chars */
659 if (length
% 2) length
++;
660 return length
/ 2 + 1;
663 void CopyUnicodeString(unsigned char *Dest
, unsigned char *Source
)
667 while (Source
[j
]!=0x00 || Source
[j
+1]!=0x00) {
669 Dest
[j
+1] = Source
[j
+1];
676 /* Changes minor/major order in Unicode string */
677 void ReverseUnicodeString(unsigned char *String
)
680 unsigned char byte1
, byte2
;
682 while (String
[j
]!=0x00 || String
[j
+1]!=0x00) {
693 /* All input is in Unicode. First char can show Unicode minor/major order.
694 Output is Unicode string in Gammu minor/major order */
695 void ReadUnicodeFile(unsigned char *Dest
, unsigned char *Source
)
697 int j
= 0, current
= 0;
699 if (Source
[0] == 0xFF && Source
[1] == 0xFE) j
= 2;
700 if (Source
[0] == 0xFE && Source
[1] == 0xFF) j
= 2;
702 while (Source
[j
]!=0x00 || Source
[j
+1]!=0x00) {
703 if (Source
[0] == 0xFF) {
704 Dest
[current
++] = Source
[j
+1];
705 Dest
[current
++] = Source
[j
];
707 Dest
[current
++] = Source
[j
];
708 Dest
[current
++] = Source
[j
+1];
716 int OctetAlign(unsigned char *Dest
, int CurrentBit
)
719 while((CurrentBit
+i
)%8) {
720 ClearBit(Dest
, CurrentBit
+i
);
726 int OctetAlignNumber(int CurrentBit
)
729 while((CurrentBit
+i
)%8) { i
++; }
733 int BitPack(unsigned char *Dest
, int CurrentBit
, unsigned char *Source
, int Bits
)
736 for (i
=0; i
<Bits
; i
++)
737 if (GetBit(Source
, i
))
738 SetBit(Dest
, CurrentBit
+i
);
740 ClearBit(Dest
, CurrentBit
+i
);
741 return CurrentBit
+Bits
;
744 int BitPackByte(unsigned char *Dest
, int CurrentBit
, unsigned char Command
, int Bits
)
746 unsigned char Byte
[] = {0x00};
749 return BitPack(Dest
, CurrentBit
, Byte
, Bits
);
752 int BitUnPack(unsigned char *Dest
, int CurrentBit
, unsigned char *Source
, int Bits
)
756 for (i
=0; i
<Bits
; i
++)
757 if (GetBit(Dest
, CurrentBit
+i
)) {
762 return CurrentBit
+Bits
;
765 int BitUnPackInt(unsigned char *Src
, int CurrentBit
, int *integer
, int Bits
)
769 for (i
=0; i
<Bits
; i
++) {
770 if (GetBit(Src
, CurrentBit
+i
)) l
=l
+z
;
777 int BitUnPackI (unsigned char *Src
, int CurrentBit
, int *result
, int Bits
)
782 for (i
=0; i
<Bits
; i
++) {
783 if (GetBit(Src
, CurrentBit
+i
)) l
=l
+z
;
790 int OctetUnAlign(int CurrentBit
)
794 while((CurrentBit
+i
)%8) i
++;
798 /* Unicode char 0x00 0x01 makes blinking in some Nokia phones.
799 * We replace single ~ chars into it. When user give double ~, it's replaced
802 void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest
, const unsigned char *src
, int len
)
807 for (i
= 0; i
< len
; i
++) {
809 if (src
[i
*2] == 0x00 && src
[i
*2+1] == '~') {
810 dest
[current
++] = 0x00;
811 dest
[current
++] = '~';
813 dest
[current
++] = 0x00;
814 dest
[current
++] = 0x01;
815 dest
[current
++] = src
[i
*2];
816 dest
[current
++] = src
[i
*2+1];
820 if (src
[i
*2] == 0x00 && src
[i
*2+1] == '~') {
823 dest
[current
++] = src
[i
*2];
824 dest
[current
++] = src
[i
*2+1];
829 dest
[current
++] = 0x00;
830 dest
[current
++] = 0x01;
832 dest
[current
++] = 0x00;
833 dest
[current
++] = 0x00;
836 void DecodeUnicodeSpecialNOKIAChars(unsigned char *dest
, const unsigned char *src
, int len
)
840 for (i
=0;i
<len
;i
++) {
843 switch (src
[2*i
+1]) {
845 dest
[current
++] = 0x00;
846 dest
[current
++] = '~';
849 dest
[current
++] = 0x00;
850 dest
[current
++] = '~';
851 dest
[current
++] = 0x00;
852 dest
[current
++] = '~';
855 dest
[current
++] = src
[i
*2];
856 dest
[current
++] = src
[i
*2+1];
860 dest
[current
++] = src
[i
*2];
861 dest
[current
++] = src
[i
*2+1];
864 dest
[current
++] = 0x00;
865 dest
[current
++] = 0x00;
868 bool mystrncasecmp(unsigned char *a
, unsigned char *b
, int num
)
872 // printf("comparing \"%s\" and \"%s\"\n",a,b);
875 if (b
[i
] == 0x00) return true;
878 if (tolower(a
[i
]) != tolower(b
[i
])) return false;
880 if (num
== i
) return true;
884 /* Compares two Unicode strings without regarding to case.
885 * Return true, when they're equal
887 bool mywstrncasecmp(unsigned char *a
, unsigned char *b
, int num
)
893 if (a
[i
*2] == 0x00 && a
[i
*2+1] == 0x00) {
894 if (b
[i
*2] == 0x00 && b
[i
*2+1] == 0x00) return true;
897 wc
= a
[i
*2+1] | (a
[i
*2] << 8);
898 wc2
= b
[i
*2+1] | (b
[i
*2] << 8);
899 if (mytowlower(wc
) != mytowlower(wc2
)) return false;
901 if (num
== i
) return true;
905 /* wcscmp in Mandrake 9.0 is wrong */
906 bool mywstrncmp(unsigned char *a
, unsigned char *b
, int num
)
911 if (a
[i
*2] != b
[i
*2] || a
[i
*2+1] != b
[i
*2+1]) return false;
912 if (a
[i
*2] == 0x00 && a
[i
*2+1] == 0x00) return true;
914 if (num
== i
) return true;
918 /* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */
919 bool myiswspace(unsigned char *src
)
921 #ifndef HAVE_ISWSPACE
923 unsigned char dest
[10];
927 wc
= src
[1] | (src
[0] << 8);
929 #ifndef HAVE_ISWSPACE
930 o
= DecodeWithUnicodeAlphabet(wc
, dest
);
932 if (isspace(((int)dest
[0]))!=0) return true;
941 /* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */
942 int mytowlower(wchar_t c
)
944 #ifndef HAVE_TOWLOWER
945 unsigned char dest
[10];
947 DecodeWithUnicodeAlphabet(c
, dest
);
948 return tolower(dest
[0]);
955 * Following code is based on wcsstr from the GNU C Library, original
959 * The original strstr() file contains the following comment:
961 * My personal strstr() implementation that beats most other algorithms.
962 * Until someone tells me otherwise, I assume that this is the
963 * fastest implementation of strstr() in C.
964 * I deliberately chose not to comment it. You should have at least
965 * as much fun trying to understand it, as I had to write it :-).
967 * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
969 unsigned char *mystrstr (const unsigned char *haystack
, const unsigned char *needle
)
971 /* One crazy define to convert unicode used in Gammu to standard wchar_t */
972 #define tolowerwchar(x) (mytowlower((wchar_t)( (((&(x))[0] & 0xff) << 8) | (((&(x))[1] & 0xff)) )))
973 register wchar_t b
, c
;
975 if ((b
= tolowerwchar(*needle
)) != L
'\0') {
976 haystack
-= 2; /* possible ANSI violation */
979 if ((c
= tolowerwchar(*haystack
)) == L
'\0')
984 if ((c
= tolowerwchar(*needle
)) == L
'\0')
991 register const unsigned char *rhaystack
, *rneedle
;
995 if ((a
= tolowerwchar(*haystack
)) == L
'\0')
1000 if ((a
= tolowerwchar(*haystack
)) == L
'\0')
1006 if ((a
= tolowerwchar(*haystack
)) == L
'\0')
1012 rhaystack
= haystack
+ 2;
1015 if (tolowerwchar(*rhaystack
) == (a
= tolowerwchar(*rneedle
)))
1021 if (tolowerwchar(*rhaystack
) != (a
= tolowerwchar(*needle
)))
1027 } while (tolowerwchar(*rhaystack
) == (a
= tolowerwchar(*needle
)));
1029 needle
= rneedle
; /* took the register-poor approach */
1036 return (unsigned char *)haystack
;
1042 void MyGetLine(unsigned char *Buffer
, int *Pos
, unsigned char *OutBuffer
, int MaxLen
)
1045 if (Buffer
== NULL
) return;
1047 if ((*Pos
) >= MaxLen
) return;
1048 switch (Buffer
[*Pos
]) {
1052 if (strlen(OutBuffer
) != 0) return;
1055 if (strlen(OutBuffer
) != 0) return;
1058 OutBuffer
[strlen(OutBuffer
) + 1] = 0;
1059 OutBuffer
[strlen(OutBuffer
)] = Buffer
[*Pos
];
1065 void StringToDouble(char *text
, double *d
)
1068 double multiply
= 1;
1072 for (i
=0;i
<strlen(text
);i
++) {
1073 if (isdigit(text
[i
])) {
1075 (*d
)=(*d
)*10+(text
[i
]-'0');
1077 multiply
=multiply
*0.1;
1078 (*d
)=(*d
)+(text
[i
]-'0')*multiply
;
1081 if (text
[i
]=='.' || text
[i
]==',') before
=false;
1085 /* When char can be converted, convert it from Unicode to UTF8 */
1086 bool EncodeWithUTF8Alphabet(unsigned char mychar1
, unsigned char mychar2
, unsigned char *ret1
, unsigned char *ret2
)
1088 unsigned char mychar3
,mychar4
;
1091 if (mychar1
>0x00 || mychar2
>128) {
1095 if (mychar3
==mychar1
) {
1096 if (mychar4
+64>=mychar2
) {
1098 *ret2
=0x80+(mychar2
-mychar4
);
1114 /* Make UTF8 string from Unicode input string */
1115 bool EncodeUTF8QuotedPrintable(unsigned char *dest
, const unsigned char *src
)
1118 unsigned char mychar1
, mychar2
;
1119 bool retval
= false;
1121 for (i
= 0; i
< (int)(UnicodeLength(src
)); i
++) {
1122 if (EncodeWithUTF8Alphabet(src
[i
*2],src
[i
*2+1],&mychar1
,&mychar2
)) {
1123 sprintf(dest
+j
, "=%02X=%02X",mychar1
,mychar2
);
1127 j
+= DecodeWithUnicodeAlphabet(((wchar_t)(src
[i
*2]*256+src
[i
*2+1])), dest
+ j
);
1134 bool EncodeUTF8(unsigned char *dest
, const unsigned char *src
)
1137 unsigned char mychar1
, mychar2
;
1138 bool retval
= false;
1140 for (i
= 0; i
< (int)(UnicodeLength(src
)); i
++) {
1141 if (EncodeWithUTF8Alphabet(src
[i
*2],src
[i
*2+1],&mychar1
,&mychar2
)) {
1142 sprintf(dest
+j
, "%c%c",mychar1
,mychar2
);
1146 j
+= DecodeWithUnicodeAlphabet(((wchar_t)(src
[i
*2]*256+src
[i
*2+1])), dest
+ j
);
1153 /* Decode UTF8 char to Unicode char */
1154 wchar_t DecodeWithUTF8Alphabet(unsigned char mychar3
, unsigned char mychar4
)
1156 unsigned char mychar1
, mychar2
;
1161 for(j
=0;j
<mychar3
-0xc2;j
++) {
1166 mychar2
= mychar2
+64;
1169 mychar2
= mychar2
+(mychar4
-0x80);
1170 return mychar2
| (mychar1
<< 8);
1173 /* Make Unicode string from UTF8 string */
1174 void DecodeUTF8QuotedPrintable(unsigned char *dest
, const unsigned char *src
, int len
)
1177 unsigned char mychar1
, mychar2
;
1182 /* Need to have correct chars */
1183 if (src
[i
] =='=' && DecodeWithHexBinAlphabet(src
[i
+1])!=-1
1184 && DecodeWithHexBinAlphabet(src
[i
+2])!=-1 &&
1185 src
[i
+3]=='=' && DecodeWithHexBinAlphabet(src
[i
+4])!=-1 &&
1186 DecodeWithHexBinAlphabet(src
[i
+5])!=-1) {
1187 mychar1
= 16*DecodeWithHexBinAlphabet(src
[i
+1])+DecodeWithHexBinAlphabet(src
[i
+2]);
1188 mychar2
= 16*DecodeWithHexBinAlphabet(src
[i
+4])+DecodeWithHexBinAlphabet(src
[i
+5]);
1189 ret
= DecodeWithUTF8Alphabet(mychar1
,mychar2
);
1192 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1195 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1197 dest
[j
++] = (ret
>> 8) & 0xff;
1198 dest
[j
++] = ret
& 0xff;
1204 void DecodeUTF8(unsigned char *dest
, const unsigned char *src
, int len
)
1211 if (src
[i
] >= 0xC2) {
1212 ret
= DecodeWithUTF8Alphabet(src
[i
],src
[i
+1]);
1215 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1218 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1220 dest
[j
++] = (ret
>> 8) & 0xff;
1221 dest
[j
++] = ret
& 0xff;
1227 void DecodeUTF7(unsigned char *dest
, const unsigned char *src
, int len
)
1234 if (src
[i
] == '+') {
1236 while (src
[z
+i
+1] != '-' && z
+i
+1<len
) z
++;
1237 p
=DecodeBASE64(src
+i
+1, dest
+j
, z
);
1242 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1243 dest
[j
++] = (ret
>> 8) & 0xff;
1244 dest
[j
++] = ret
& 0xff;
1247 i
+=EncodeWithUnicodeAlphabet(&src
[i
], &ret
);
1248 dest
[j
++] = (ret
>> 8) & 0xff;
1249 dest
[j
++] = ret
& 0xff;
1258 Copyright (c) Trantor Standard Systems Inc., 2001
1260 Permission is hereby granted, free of charge, to any person
1261 obtaining a copy of this software and associated
1262 documentation files (the "Software"), to deal in the
1263 Software without restriction, including without limitation
1264 the rights to use, copy, modify, merge, publish, distribute,
1265 sublicense, and/or sell copies of the Software, and to
1266 permit persons to whom the Software is furnished to do so,
1267 subject to the following conditions:
1269 The above copyright notice and this permission notice shall
1270 be included in all copies or substantial portions of the
1273 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
1274 KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
1275 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
1276 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
1277 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1278 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1279 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1280 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1283 static void EncodeBASE64Block(unsigned char in
[3], unsigned char out
[4], int len
)
1285 /* BASE64 translation Table as described in RFC1113 */
1286 unsigned char cb64
[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1288 out
[0] = cb64
[ in
[0] >> 2 ];
1289 out
[1] = cb64
[ ((in
[0] & 0x03) << 4) | ((in
[1] & 0xf0) >> 4) ];
1290 out
[2] = (unsigned char) (len
> 1 ? cb64
[ ((in
[1] & 0x0f) << 2) | ((in
[2] & 0xc0) >> 6) ] : '=');
1291 out
[3] = (unsigned char) (len
> 2 ? cb64
[ in
[2] & 0x3f ] : '=');
1294 void EncodeBASE64(const unsigned char *Input
, unsigned char *Output
, int Length
)
1296 unsigned char in
[3], out
[4];
1297 int i
, pos
= 0, len
, outpos
= 0;
1301 for (i
= 0; i
< 3; i
++) {
1310 EncodeBASE64Block(in
, out
, len
);
1311 for (i
= 0; i
< 4; i
++) Output
[outpos
++] = out
[i
];
1313 if (pos
== Length
) break;
1315 Output
[outpos
++] = 0;
1318 static void DecodeBASE64Block(unsigned char in
[4], unsigned char out
[3])
1320 out
[0] = (unsigned char) (in
[0] << 2 | in
[1] >> 4);
1321 out
[1] = (unsigned char) (in
[1] << 4 | in
[2] >> 2);
1322 out
[2] = (unsigned char) (((in
[2] << 6) & 0xc0) | in
[3]);
1325 int DecodeBASE64(const unsigned char *Input
, unsigned char *Output
, int Length
)
1327 unsigned char cd64
[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
1328 unsigned char in
[4], out
[3], v
;
1329 int i
, len
, pos
= 0, outpos
= 0;
1332 if (pos
>= Length
) break;
1334 for(i
= 0; i
< 4; i
++) {
1337 if (pos
>= Length
) break;
1338 v
= (unsigned char) Input
[pos
++];
1339 v
= (unsigned char) ((v
< 43 || v
> 122) ? 0 : cd64
[ v
- 43 ]);
1340 if (v
) v
= (unsigned char) ((v
== '$') ? 0 : v
- 61);
1345 in
[i
] = (unsigned char) (v
- 1);
1350 DecodeBASE64Block(in
, out
);
1351 for(i
= 0; i
< len
- 1; i
++) Output
[outpos
++] = out
[i
];
1358 /* How should editor hadle tabs in this file? Add editor commands here.
1359 * vim: noexpandtab sw=8 ts=8 sts=8: