author | zautrix <zautrix> | 2004-08-07 17:24:40 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2004-08-07 17:24:40 (UTC) |
commit | 88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22 (patch) (unidiff) | |
tree | 6331418973714243beb674abc87692277b83869d /gammu/emb/common/misc/coding/coding.c | |
parent | ef8a09ce74ad3f0a51484d03fdf009bd5b3677bf (diff) | |
download | kdepimpi-88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22.zip kdepimpi-88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22.tar.gz kdepimpi-88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22.tar.bz2 |
Initial revision
Diffstat (limited to 'gammu/emb/common/misc/coding/coding.c') (more/less context) (show whitespace changes)
-rw-r--r-- | gammu/emb/common/misc/coding/coding.c | 1409 |
1 files changed, 1409 insertions, 0 deletions
diff --git a/gammu/emb/common/misc/coding/coding.c b/gammu/emb/common/misc/coding/coding.c new file mode 100644 index 0000000..62543ac --- a/dev/null +++ b/gammu/emb/common/misc/coding/coding.c | |||
@@ -0,0 +1,1409 @@ | |||
1 | /* (c) 2002-2004 by Marcin Wiacek, Michal Cihar and others */ | ||
2 | /* based on some work from MyGnokii and Gnokii */ | ||
3 | |||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | #include <ctype.h> | ||
8 | #include <locale.h> | ||
9 | #ifndef __OpenBSD__ | ||
10 | # include <wctype.h> | ||
11 | #endif | ||
12 | #ifdef WIN32 | ||
13 | # include "windows.h" | ||
14 | #endif | ||
15 | |||
16 | #include "../misc.h" | ||
17 | #include "coding.h" | ||
18 | |||
19 | unsigned int UnicodeLength(const unsigned char *str) | ||
20 | { | ||
21 | unsigned int len = 0; | ||
22 | |||
23 | if (str == NULL) return 0; | ||
24 | |||
25 | while(str[len*2] != 0 || str[len*2+1] != 0) len++; | ||
26 | |||
27 | return len; | ||
28 | } | ||
29 | |||
30 | /* Convert Unicode char saved in src to dest */ | ||
31 | unsigned int EncodeWithUnicodeAlphabet(const unsigned char *src, wchar_t *dest) | ||
32 | { | ||
33 | char retval; | ||
34 | |||
35 | switch (retval = mbtowc(dest, src, MB_CUR_MAX)) { | ||
36 | case -1 : | ||
37 | case 0 : return 1; | ||
38 | default : return retval; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | /* Convert Unicode char saved in src to dest */ | ||
43 | unsigned int DecodeWithUnicodeAlphabet(wchar_t src, unsigned char *dest) | ||
44 | { | ||
45 | int retval; | ||
46 | |||
47 | switch (retval = wctomb(dest, src)) { | ||
48 | case -1: | ||
49 | *dest = '?'; | ||
50 | return 1; | ||
51 | default: | ||
52 | return retval; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | void DecodeUnicode (const unsigned char *src, unsigned char *dest) | ||
57 | { | ||
58 | int i=0,o=0; | ||
59 | wchar_t wc; | ||
60 | |||
61 | while (src[(2*i)+1]!=0x00 || src[2*i]!=0x00) { | ||
62 | wc = src[(2*i)+1] | (src[2*i] << 8); | ||
63 | o += DecodeWithUnicodeAlphabet(wc, dest + o); | ||
64 | i++; | ||
65 | } | ||
66 | dest[o]=0; | ||
67 | } | ||
68 | |||
69 | /* Decode Unicode string and return as function result */ | ||
70 | unsigned char *DecodeUnicodeString (const unsigned char *src) | ||
71 | { | ||
72 | static char dest[500]; | ||
73 | |||
74 | DecodeUnicode(src,dest); | ||
75 | return dest; | ||
76 | } | ||
77 | |||
78 | /* Decode Unicode string to UTF8 or other console charset | ||
79 | * and return as function result | ||
80 | */ | ||
81 | unsigned char *DecodeUnicodeConsole(const unsigned char *src) | ||
82 | { | ||
83 | static char dest[500]; | ||
84 | |||
85 | if (di.coding[0] != 0) { | ||
86 | if (!strcmp(di.coding,"utf8")) { | ||
87 | EncodeUTF8(dest, src); | ||
88 | } else { | ||
89 | #ifdef WIN32 | ||
90 | setlocale(LC_ALL, di.coding); | ||
91 | #endif | ||
92 | DecodeUnicode(src,dest); | ||
93 | } | ||
94 | } else { | ||
95 | #ifdef WIN32 | ||
96 | setlocale(LC_ALL, ".OCP"); | ||
97 | #endif | ||
98 | DecodeUnicode(src,dest); | ||
99 | #ifdef WIN32 | ||
100 | setlocale(LC_ALL, ".ACP"); | ||
101 | #endif | ||
102 | } | ||
103 | return dest; | ||
104 | } | ||
105 | |||
106 | /* Encode string to Unicode. Len is number of input chars */ | ||
107 | void EncodeUnicode (unsigned char *dest, const unsigned char *src, int len) | ||
108 | { | ||
109 | int i_len = 0, o_len; | ||
110 | wchar_t wc; | ||
111 | |||
112 | for (o_len = 0; i_len < len; o_len++) { | ||
113 | i_len += EncodeWithUnicodeAlphabet(&src[i_len], &wc); | ||
114 | dest[o_len*2] = (wc >> 8) & 0xff; | ||
115 | dest[(o_len*2)+1]= wc & 0xff; | ||
116 | } | ||
117 | dest[o_len*2] = 0; | ||
118 | dest[(o_len*2)+1]= 0; | ||
119 | } | ||
120 | |||
121 | unsigned char EncodeWithBCDAlphabet(int value) | ||
122 | { | ||
123 | div_t division; | ||
124 | |||
125 | division=div(value,10); | ||
126 | return ( ( (value-division.quot*10) & 0x0f) << 4) | (division.quot & 0xf); | ||
127 | } | ||
128 | |||
129 | int DecodeWithBCDAlphabet(unsigned char value) | ||
130 | { | ||
131 | return 10*(value & 0x0f)+(value >> 4); | ||
132 | } | ||
133 | |||
134 | void DecodeBCD (unsigned char *dest, const unsigned char *src, int len) | ||
135 | { | ||
136 | int i,current=0,digit; | ||
137 | |||
138 | for (i = 0; i < len; i++) { | ||
139 | digit=src[i] & 0x0f; | ||
140 | if (digit<10) dest[current++]=digit + '0'; | ||
141 | digit=src[i] >> 4; | ||
142 | if (digit<10) dest[current++]=digit + '0'; | ||
143 | } | ||
144 | dest[current++]=0; | ||
145 | } | ||
146 | |||
147 | void EncodeBCD (unsigned char *dest, const unsigned char *src, int len, bool fill) | ||
148 | { | ||
149 | int i,current=0; | ||
150 | |||
151 | for (i = 0; i < len; i++) { | ||
152 | if (i & 0x01) { | ||
153 | dest[current]=dest[current] | ((src[i]-'0') << 4); | ||
154 | current++; | ||
155 | } else { | ||
156 | dest[current]=src[i]-'0'; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | /* When fill is set: if number consist of odd number of digits, | ||
161 | we fill last bits in last byte with 0x0f | ||
162 | */ | ||
163 | if (fill && (len & 0x01)) dest[current]=dest[current] | 0xf0; | ||
164 | } | ||
165 | |||
166 | int DecodeWithHexBinAlphabet (unsigned char mychar) | ||
167 | { | ||
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'; | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | unsigned char EncodeWithHexBinAlphabet (int digit) | ||
175 | { | ||
176 | if (digit >= 0 && digit <= 9) return '0'+(digit); | ||
177 | if (digit >=10 && digit <=15) return 'A'+(digit-10); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | void DecodeHexUnicode (unsigned char *dest, const unsigned char *src, int len) | ||
182 | { | ||
183 | int i,current=0; | ||
184 | bool first = false; | ||
185 | |||
186 | if (len != 0 && src[0] == '0' && src[1] == '0') { | ||
187 | first = true; | ||
188 | } else if (len != 0 && src[2] == '0' && src[3] == '0') { | ||
189 | first = false; | ||
190 | } else { | ||
191 | first = (10 * (src[0] - '0') + (src[1] - '0')) < (10 * (src[2] - '0')+ (src[3] - '0')); | ||
192 | } | ||
193 | for (i = 0; i < len/4 ; i++) { | ||
194 | if (first) { | ||
195 | dest[current++] = DecodeWithHexBinAlphabet(src[i*4+0])*16+ | ||
196 | DecodeWithHexBinAlphabet(src[i*4+1]); | ||
197 | dest[current++] = DecodeWithHexBinAlphabet(src[i*4+2])*16+ | ||
198 | DecodeWithHexBinAlphabet(src[i*4+3]); | ||
199 | } else { | ||
200 | dest[current++] = DecodeWithHexBinAlphabet(src[i*4+2])*16+ | ||
201 | DecodeWithHexBinAlphabet(src[i*4+3]); | ||
202 | dest[current++] = DecodeWithHexBinAlphabet(src[i*4+0])*16+ | ||
203 | DecodeWithHexBinAlphabet(src[i*4+1]); | ||
204 | } | ||
205 | } | ||
206 | dest[current++] = 0; | ||
207 | dest[current++] = 0; | ||
208 | } | ||
209 | |||
210 | void EncodeHexUnicode (unsigned char *dest, const unsigned char *src, int len) | ||
211 | { | ||
212 | int i,current=0; | ||
213 | |||
214 | for (i = 0; i < len; i++) { | ||
215 | dest[current++] = EncodeWithHexBinAlphabet(src[2*i] >> 0x04); | ||
216 | dest[current++] = EncodeWithHexBinAlphabet(src[2*i] & 0x0f); | ||
217 | dest[current++] = EncodeWithHexBinAlphabet(src[2*i+1] >> 0x04); | ||
218 | dest[current++] = EncodeWithHexBinAlphabet(src[2*i+1] & 0x0f); | ||
219 | } | ||
220 | dest[current++] = 0; | ||
221 | } | ||
222 | |||
223 | void DecodeHexBin (unsigned char *dest, const unsigned char *src, int len) | ||
224 | { | ||
225 | int i,current=0; | ||
226 | |||
227 | for (i = 0; i < len/2 ; i++) { | ||
228 | dest[current++] = DecodeWithHexBinAlphabet(src[i*2])*16+ | ||
229 | DecodeWithHexBinAlphabet(src[i*2+1]); | ||
230 | } | ||
231 | dest[current++] = 0; | ||
232 | } | ||
233 | |||
234 | void EncodeHexBin (unsigned char *dest, const unsigned char *src, int len) | ||
235 | { | ||
236 | int i,current=0; | ||
237 | |||
238 | for (i = 0; i < len; i++) { | ||
239 | dest[current++] = EncodeWithHexBinAlphabet(src[i] >> 0x04); | ||
240 | dest[current++] = EncodeWithHexBinAlphabet(src[i] & 0x0f); | ||
241 | } | ||
242 | dest[current++] = 0; | ||
243 | } | ||
244 | |||
245 | /* ETSI GSM 03.38, section 6.2.1: Default alphabet for SMS messages */ | ||
246 | static unsigned char GSM_DefaultAlphabetUnicode[128+1][2] = | ||
247 | { | ||
248 | {0x00,0x40},{0x00,0xa3},{0x00,0x24},{0x00,0xA5}, | ||
249 | {0x00,0xE8},{0x00,0xE9},{0x00,0xF9},{0x00,0xEC},/*0x08*/ | ||
250 | {0x00,0xF2},{0x00,0xC7},{0x00,'\n'},{0x00,0xD8}, | ||
251 | {0x00,0xF8},{0x00,'\r'},{0x00,0xC5},{0x00,0xE5}, | ||
252 | {0x03,0x94},{0x00,0x5f},{0x03,0xA6},{0x03,0x93}, | ||
253 | {0x03,0x9B},{0x03,0xA9},{0x03,0xA0},{0x03,0xA8}, | ||
254 | {0x03,0xA3},{0x03,0x98},{0x03,0x9E},{0x00,0xb9}, | ||
255 | {0x00,0xC6},{0x00,0xE6},{0x00,0xDF},{0x00,0xC9},/*0x20*/ | ||
256 | {0x00,' ' },{0x00,'!' },{0x00,'\"'},{0x00,'#' }, | ||
257 | {0x00,0xA4},{0x00,'%' },{0x00,'&' },{0x00,'\''}, | ||
258 | {0x00,'(' },{0x00,')' },{0x00,'*' },{0x00,'+' }, | ||
259 | {0x00,',' },{0x00,'-' },{0x00,'.' },{0x00,'/' },/*0x30*/ | ||
260 | {0x00,'0' },{0x00,'1' },{0x00,'2' },{0x00,'3' }, | ||
261 | {0x00,'4' },{0x00,'5' },{0x00,'6' },{0x00,'7' }, | ||
262 | {0x00,'8' },{0x00,'9' },{0x00,':' },{0x00,';' }, | ||
263 | {0x00,'<' },{0x00,'=' },{0x00,'>' },{0x00,'?' },/*0x40*/ | ||
264 | {0x00,0xA1},{0x00,'A' },{0x00,'B' },{0x00,'C' }, | ||
265 | {0x00,'D' },{0x00,'E' },{0x00,'F' },{0x00,'G' }, | ||
266 | {0x00,'H' },{0x00,'I' },{0x00,'J' },{0x00,'K' }, | ||
267 | {0x00,'L' },{0x00,'M' },{0x00,'N' },{0x00,'O' }, | ||
268 | {0x00,'P' },{0x00,'Q' },{0x00,'R' },{0x00,'S' }, | ||
269 | {0x00,'T' },{0x00,'U' },{0x00,'V' },{0x00,'W' }, | ||
270 | {0x00,'X' },{0x00,'Y' },{0x00,'Z' },{0x00,0xC4}, | ||
271 | {0x00,0xD6},{0x00,0xD1},{0x00,0xDC},{0x00,0xA7}, | ||
272 | {0x00,0xBF},{0x00,'a' },{0x00,'b' },{0x00,'c' }, | ||
273 | {0x00,'d' },{0x00,'e' },{0x00,'f' },{0x00,'g' }, | ||
274 | {0x00,'h' },{0x00,'i' },{0x00,'j' },{0x00,'k' }, | ||
275 | {0x00,'l' },{0x00,'m' },{0x00,'n' },{0x00,'o' }, | ||
276 | {0x00,'p' },{0x00,'q' },{0x00,'r' },{0x00,'s' }, | ||
277 | {0x00,'t' },{0x00,'u' },{0x00,'v' },{0x00,'w' }, | ||
278 | {0x00,'x' },{0x00,'y' },{0x00,'z' },{0x00,0xE4}, | ||
279 | {0x00,0xF6},{0x00,0xF1},{0x00,0xFC},{0x00,0xE0}, | ||
280 | {0x00,0x00} | ||
281 | }; | ||
282 | |||
283 | /* ETSI GSM 3.38 | ||
284 | * Some sequences of 2 default alphabet chars (for example, | ||
285 | * 0x1b, 0x65) are visible as one single additional char (for example, | ||
286 | * 0x1b, 0x65 gives Euro char saved in Unicode as 0x20, 0xAC) | ||
287 | * This table contains: | ||
288 | * 1. two first chars means sequence of chars from GSM default alphabet | ||
289 | * 2. two second is target (encoded) char saved in Unicode | ||
290 | */ | ||
291 | static unsigned char GSM_DefaultAlphabetCharsExtension[][4] = | ||
292 | { | ||
293 | {0x1b,0x14,0x00,0x5e}, /* ^*/ | ||
294 | {0x1b,0x28,0x00,0x7b}, /* {*/ | ||
295 | {0x1b,0x29,0x00,0x7d}, /* }*/ | ||
296 | {0x1b,0x2f,0x00,0x5c}, /* \*/ | ||
297 | {0x1b,0x3c,0x00,0x5b}, /* [*/ | ||
298 | {0x1b,0x3d,0x00,0x7E}, /* ~*/ | ||
299 | {0x1b,0x3e,0x00,0x5d}, /* ]*/ | ||
300 | {0x1b,0x40,0x00,0x7C}, /* |*/ | ||
301 | {0x1b,0x65,0x20,0xAC},/* Euro */ | ||
302 | {0x00,0x00,0x00,0x00} | ||
303 | }; | ||
304 | |||
305 | void DecodeDefault (unsigned char *dest, const unsigned char *src, int len, bool UseExtensions, unsigned char *ExtraAlphabet) | ||
306 | { | ||
307 | int i,current=0,j; | ||
308 | boolFoundSpecial = false; | ||
309 | |||
310 | #ifdef DEBUG | ||
311 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, src, len); | ||
312 | #endif | ||
313 | |||
314 | for (i = 0; i < len; i++) { | ||
315 | FoundSpecial = false; | ||
316 | if ((i < (len-1)) && UseExtensions) { | ||
317 | j=0; | ||
318 | while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00) { | ||
319 | if (GSM_DefaultAlphabetCharsExtension[j][0]==src[i] && | ||
320 | GSM_DefaultAlphabetCharsExtension[j][1]==src[i+1]) { | ||
321 | FoundSpecial = true; | ||
322 | dest[current++] = GSM_DefaultAlphabetCharsExtension[j][2]; | ||
323 | dest[current++] = GSM_DefaultAlphabetCharsExtension[j][3]; | ||
324 | i++; | ||
325 | break; | ||
326 | } | ||
327 | j++; | ||
328 | } | ||
329 | } | ||
330 | if (ExtraAlphabet!=NULL && !FoundSpecial) { | ||
331 | j = 0; | ||
332 | while (ExtraAlphabet[j] != 0x00 || ExtraAlphabet[j+1] != 0x00 || ExtraAlphabet[j+2] != 0x00) { | ||
333 | if (ExtraAlphabet[j] == src[i]) { | ||
334 | dest[current++] = ExtraAlphabet[j+1]; | ||
335 | dest[current++] = ExtraAlphabet[j+2]; | ||
336 | FoundSpecial = true; | ||
337 | break; | ||
338 | } | ||
339 | j=j+3; | ||
340 | } | ||
341 | } | ||
342 | if (!FoundSpecial) { | ||
343 | dest[current++] = GSM_DefaultAlphabetUnicode[src[i]][0]; | ||
344 | dest[current++] = GSM_DefaultAlphabetUnicode[src[i]][1]; | ||
345 | } | ||
346 | } | ||
347 | dest[current++]=0; | ||
348 | dest[current++]=0; | ||
349 | #ifdef DEBUG | ||
350 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, dest, UnicodeLength(dest)*2); | ||
351 | #endif | ||
352 | } | ||
353 | |||
354 | /* There are many national chars with "adds". In phone they're normally | ||
355 | * changed to "plain" Latin chars. We have such functionality too. | ||
356 | * This table is automatically created from convert.txt file (see | ||
357 | * /docs/developers) using --makeconverttable. It contains such chars | ||
358 | * to replace in order: | ||
359 | * 1. original char (Unicode) 2. destination char (Unicode) | ||
360 | */ | ||
361 | static unsigned char ConvertTable[] = | ||
362 | "\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"\ | ||
363 | "\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"\ | ||
364 | "\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"\ | ||
365 | "\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"\ | ||
366 | "\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"\ | ||
367 | "\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"; | ||
368 | |||
369 | void EncodeDefault(unsigned char *dest, const unsigned char *src, int *len, bool UseExtensions, unsigned char *ExtraAlphabet) | ||
370 | { | ||
371 | int i,current=0,j,z; | ||
372 | char ret; | ||
373 | boolFoundSpecial,FoundNormal; | ||
374 | |||
375 | #ifdef DEBUG | ||
376 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, src, (*len)*2); | ||
377 | #endif | ||
378 | |||
379 | for (i = 0; i < *len; i++) { | ||
380 | FoundSpecial = false; | ||
381 | j = 0; | ||
382 | while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00 && UseExtensions) { | ||
383 | if (src[i*2] == GSM_DefaultAlphabetCharsExtension[j][2] && | ||
384 | src[i*2+1] == GSM_DefaultAlphabetCharsExtension[j][3]) { | ||
385 | dest[current++] = GSM_DefaultAlphabetCharsExtension[j][0]; | ||
386 | dest[current++] = GSM_DefaultAlphabetCharsExtension[j][1]; | ||
387 | FoundSpecial = true; | ||
388 | break; | ||
389 | } | ||
390 | j++; | ||
391 | } | ||
392 | if (!FoundSpecial) { | ||
393 | ret = '?'; | ||
394 | FoundNormal = false; | ||
395 | j = 0; | ||
396 | while (GSM_DefaultAlphabetUnicode[j][1]!=0x00) { | ||
397 | if (src[i*2]== GSM_DefaultAlphabetUnicode[j][0] && | ||
398 | src[i*2+1]== GSM_DefaultAlphabetUnicode[j][1]) { | ||
399 | ret = j; | ||
400 | FoundNormal = true; | ||
401 | break; | ||
402 | } | ||
403 | j++; | ||
404 | } | ||
405 | if (ExtraAlphabet!=NULL && !FoundNormal) { | ||
406 | j = 0; | ||
407 | while (ExtraAlphabet[j] != 0x00 || ExtraAlphabet[j+1] != 0x00 || ExtraAlphabet[j+2] != 0x00) { | ||
408 | if (ExtraAlphabet[j+1] == src[i*2] && | ||
409 | ExtraAlphabet[j+2] == src[i*2 + 1]) { | ||
410 | ret = ExtraAlphabet[j]; | ||
411 | FoundSpecial= true; | ||
412 | break; | ||
413 | } | ||
414 | j=j+3; | ||
415 | } | ||
416 | } | ||
417 | if (!FoundNormal && !FoundSpecial) { | ||
418 | j = 0; | ||
419 | FoundNormal = false; | ||
420 | while (ConvertTable[j*4] != 0x00 || | ||
421 | ConvertTable[j*4+1] != 0x00) { | ||
422 | if (src[i*2] == ConvertTable[j*4] && | ||
423 | src[i*2+1] == ConvertTable[j*4+1]) { | ||
424 | z = 0; | ||
425 | while (GSM_DefaultAlphabetUnicode[z][1]!=0x00) { | ||
426 | if (ConvertTable[j*4+2]== GSM_DefaultAlphabetUnicode[z][0] && | ||
427 | ConvertTable[j*4+3]== GSM_DefaultAlphabetUnicode[z][1]) { | ||
428 | ret = z; | ||
429 | FoundNormal = true; | ||
430 | break; | ||
431 | } | ||
432 | z++; | ||
433 | } | ||
434 | if (FoundNormal) break; | ||
435 | } | ||
436 | j++; | ||
437 | } | ||
438 | } | ||
439 | dest[current++]=ret; | ||
440 | } | ||
441 | } | ||
442 | dest[current]=0; | ||
443 | #ifdef DEBUG | ||
444 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, dest, current); | ||
445 | #endif | ||
446 | |||
447 | *len = current; | ||
448 | } | ||
449 | |||
450 | /* You don't have to use ConvertTable here - 1 char is replaced there by 1 char */ | ||
451 | void FindDefaultAlphabetLen(const unsigned char *src, int *srclen, int *smslen, int maxlen) | ||
452 | { | ||
453 | int current=0,j,i; | ||
454 | boolFoundSpecial; | ||
455 | |||
456 | i = 0; | ||
457 | while (src[i*2] != 0x00 || src[i*2+1] != 0x00) { | ||
458 | FoundSpecial = false; | ||
459 | j = 0; | ||
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]) { | ||
463 | FoundSpecial = true; | ||
464 | if (current+2 > maxlen) { | ||
465 | *srclen = i; | ||
466 | *smslen = current; | ||
467 | return; | ||
468 | } | ||
469 | current+=2; | ||
470 | break; | ||
471 | } | ||
472 | j++; | ||
473 | } | ||
474 | if (!FoundSpecial) { | ||
475 | if (current+1 > maxlen) { | ||
476 | *srclen = i; | ||
477 | *smslen = current; | ||
478 | return; | ||
479 | } | ||
480 | current++; | ||
481 | } | ||
482 | i++; | ||
483 | } | ||
484 | *srclen = i; | ||
485 | *smslen = current; | ||
486 | } | ||
487 | |||
488 | #ifndef ENABLE_LGPL | ||
489 | # define ByteMask ((1 << Bits) - 1) | ||
490 | #endif | ||
491 | |||
492 | int GSM_UnpackEightBitsToSeven(int offset, int in_length, int out_length, | ||
493 | unsigned char *input, unsigned char *output) | ||
494 | { | ||
495 | #ifndef ENABLE_LGPL | ||
496 | /* (c) by Pavel Janik and Pawel Kot */ | ||
497 | |||
498 | unsigned char *OUTPUT = output; /* Current pointer to the output buffer */ | ||
499 | unsigned char *INPUT = input; /* Current pointer to the input buffer */ | ||
500 | unsigned char Rest = 0x00; | ||
501 | int Bits; | ||
502 | |||
503 | Bits = offset ? offset : 7; | ||
504 | |||
505 | while ((INPUT - input) < in_length) { | ||
506 | |||
507 | *OUTPUT = ((*INPUT & ByteMask) << (7 - Bits)) | Rest; | ||
508 | Rest = *INPUT >> Bits; | ||
509 | |||
510 | /* If we don't start from 0th bit, we shouldn't go to the | ||
511 | next char. Under *OUTPUT we have now 0 and under Rest - | ||
512 | _first_ part of the char. */ | ||
513 | if ((INPUT != input) || (Bits == 7)) OUTPUT++; | ||
514 | INPUT++; | ||
515 | |||
516 | if ((OUTPUT - output) >= out_length) break; | ||
517 | |||
518 | /* After reading 7 octets we have read 7 full characters but | ||
519 | we have 7 bits as well. This is the next character */ | ||
520 | if (Bits == 1) { | ||
521 | *OUTPUT = Rest; | ||
522 | OUTPUT++; | ||
523 | Bits = 7; | ||
524 | Rest = 0x00; | ||
525 | } else { | ||
526 | Bits--; | ||
527 | } | ||
528 | } | ||
529 | |||
530 | return OUTPUT - output; | ||
531 | #else | ||
532 | return 0; | ||
533 | #endif | ||
534 | } | ||
535 | |||
536 | int GSM_PackSevenBitsToEight(int offset, unsigned char *input, unsigned char *output, int length) | ||
537 | { | ||
538 | #ifndef ENABLE_LGPL | ||
539 | /* (c) by Pavel Janik and Pawel Kot */ | ||
540 | |||
541 | unsigned char *OUTPUT = output; /* Current pointer to the output buffer */ | ||
542 | unsigned char *INPUT = input; /* Current pointer to the input buffer */ | ||
543 | int Bits; /* Number of bits directly copied to | ||
544 | * the output buffer */ | ||
545 | Bits = (7 + offset) % 8; | ||
546 | |||
547 | /* If we don't begin with 0th bit, we will write only a part of the | ||
548 | first octet */ | ||
549 | if (offset) { | ||
550 | *OUTPUT = 0x00; | ||
551 | OUTPUT++; | ||
552 | } | ||
553 | |||
554 | while ((INPUT - input) < length) { | ||
555 | unsigned char Byte = *INPUT; | ||
556 | |||
557 | *OUTPUT = Byte >> (7 - Bits); | ||
558 | /* If we don't write at 0th bit of the octet, we should write | ||
559 | a second part of the previous octet */ | ||
560 | if (Bits != 7) | ||
561 | *(OUTPUT-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1); | ||
562 | |||
563 | Bits--; | ||
564 | |||
565 | if (Bits == -1) Bits = 7; else OUTPUT++; | ||
566 | |||
567 | INPUT++; | ||
568 | } | ||
569 | return (OUTPUT - output); | ||
570 | #else | ||
571 | return 0; | ||
572 | #endif | ||
573 | } | ||
574 | |||
575 | void GSM_UnpackSemiOctetNumber(unsigned char *retval, unsigned char *Number, bool semioctet) | ||
576 | { | ||
577 | unsigned char Buffer[50]= ""; | ||
578 | int length = Number[0]; | ||
579 | |||
580 | if (semioctet) { | ||
581 | /* Convert number of semioctets to number of chars */ | ||
582 | if (length % 2) length++; | ||
583 | length=length / 2 + 1; | ||
584 | } | ||
585 | |||
586 | /*without leading byte with format of number*/ | ||
587 | length--; | ||
588 | |||
589 | switch (Number[1]) { | ||
590 | case NUMBER_ALPHANUMERIC: | ||
591 | if (length > 6) length++; | ||
592 | dbgprintf("Alphanumeric number, length %i\n",length); | ||
593 | GSM_UnpackEightBitsToSeven(0, length, length, Number+2, Buffer); | ||
594 | Buffer[length]=0; | ||
595 | break; | ||
596 | case NUMBER_INTERNATIONAL: | ||
597 | dbgprintf("International number\n"); | ||
598 | Buffer[0]='+'; | ||
599 | DecodeBCD(Buffer+1,Number+2, length); | ||
600 | break; | ||
601 | default: | ||
602 | dbgprintf("Default number %02x\n",Number[1]); | ||
603 | DecodeBCD (Buffer, Number+2, length); | ||
604 | break; | ||
605 | } | ||
606 | |||
607 | EncodeUnicode(retval,Buffer,strlen(Buffer)); | ||
608 | } | ||
609 | |||
610 | /** | ||
611 | * Packing some phone numbers (SMSC, SMS destination and others) | ||
612 | * | ||
613 | * See GSM 03.40 9.1.1: | ||
614 | * 1 byte - length of number given in semioctets or bytes (when given in | ||
615 | * bytes, includes one byte for byte with number format). | ||
616 | * Returned by function (set semioctet to true, if want result | ||
617 | * in semioctets). | ||
618 | * 1 byte - format of number (see GSM_NumberType in coding.h). Returned | ||
619 | * in unsigned char *Output. | ||
620 | * n bytes - 2n or 2n-1 semioctets with number. Returned in unsigned char | ||
621 | * *Output. | ||
622 | * | ||
623 | * 1 semioctet = 4 bits = half of byte | ||
624 | */ | ||
625 | int GSM_PackSemiOctetNumber(unsigned char *Number, unsigned char *Output, bool semioctet) | ||
626 | { | ||
627 | unsigned charformat, buffer[50]; | ||
628 | int length, i; | ||
629 | |||
630 | length=UnicodeLength(Number); | ||
631 | memcpy(buffer,DecodeUnicodeString(Number),length+1); | ||
632 | |||
633 | /* Checking for format number */ | ||
634 | format = NUMBER_UNKNOWN; | ||
635 | for (i=0;i<length;i++) { | ||
636 | /* first byte is '+'. Number can be international */ | ||
637 | if (i==0 && buffer[i]=='+') { | ||
638 | format=NUMBER_INTERNATIONAL; | ||
639 | } else { | ||
640 | /*char is not number. It must be alphanumeric*/ | ||
641 | if (!isdigit(buffer[i])) format=NUMBER_ALPHANUMERIC; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | /** | ||
646 | * First byte is used for saving type of number. See GSM 03.40 | ||
647 | * section 9.1.2.5 | ||
648 | */ | ||
649 | Output[0]=format; | ||
650 | |||
651 | /* After number type we will have number. GSM 03.40 section 9.1.2 */ | ||
652 | switch (format) { | ||
653 | case NUMBER_ALPHANUMERIC: | ||
654 | length=GSM_PackSevenBitsToEight(0, buffer, Output+1, strlen(buffer))*2; | ||
655 | if (strlen(buffer)==7) length--; | ||
656 | break; | ||
657 | case NUMBER_INTERNATIONAL: | ||
658 | length--; | ||
659 | EncodeBCD (Output+1, buffer+1, length, true); | ||
660 | break; | ||
661 | default: | ||
662 | EncodeBCD (Output+1, buffer, length, true); | ||
663 | break; | ||
664 | } | ||
665 | |||
666 | if (semioctet) return length; | ||
667 | |||
668 | /* Convert number of semioctets to number of chars */ | ||
669 | if (length % 2) length++; | ||
670 | return length / 2 + 1; | ||
671 | } | ||
672 | |||
673 | void CopyUnicodeString(unsigned char *Dest, unsigned char *Source) | ||
674 | { | ||
675 | int j = 0; | ||
676 | |||
677 | while (Source[j]!=0x00 || Source[j+1]!=0x00) { | ||
678 | Dest[j] = Source[j]; | ||
679 | Dest[j+1]= Source[j+1]; | ||
680 | j=j+2; | ||
681 | } | ||
682 | Dest[j] = 0; | ||
683 | Dest[j+1]= 0; | ||
684 | } | ||
685 | |||
686 | /* Changes minor/major order in Unicode string */ | ||
687 | void ReverseUnicodeString(unsigned char *String) | ||
688 | { | ||
689 | int j = 0; | ||
690 | unsigned charbyte1, byte2; | ||
691 | |||
692 | while (String[j]!=0x00 || String[j+1]!=0x00) { | ||
693 | byte1 = String[j]; | ||
694 | byte2 = String[j+1]; | ||
695 | String[j+1]= byte1; | ||
696 | String[j]= byte2; | ||
697 | j=j+2; | ||
698 | } | ||
699 | String[j]= 0; | ||
700 | String[j+1]= 0; | ||
701 | } | ||
702 | |||
703 | /* All input is in Unicode. First char can show Unicode minor/major order. | ||
704 | Output is Unicode string in Gammu minor/major order */ | ||
705 | void ReadUnicodeFile(unsigned char *Dest, unsigned char *Source) | ||
706 | { | ||
707 | int j = 0, current = 0; | ||
708 | |||
709 | if (Source[0] == 0xFF && Source[1] == 0xFE) j = 2; | ||
710 | if (Source[0] == 0xFE && Source[1] == 0xFF) j = 2; | ||
711 | |||
712 | while (Source[j]!=0x00 || Source[j+1]!=0x00) { | ||
713 | if (Source[0] == 0xFF) { | ||
714 | Dest[current++] = Source[j+1]; | ||
715 | Dest[current++]= Source[j]; | ||
716 | } else { | ||
717 | Dest[current++] = Source[j]; | ||
718 | Dest[current++]= Source[j+1]; | ||
719 | } | ||
720 | j=j+2; | ||
721 | } | ||
722 | Dest[current++] = 0; | ||
723 | Dest[current++]= 0; | ||
724 | } | ||
725 | |||
726 | int GetBit(unsigned char *Buffer, int BitNum) | ||
727 | { | ||
728 | return Buffer[BitNum/8] & 1<<(7-(BitNum%8)); | ||
729 | } | ||
730 | |||
731 | int SetBit(unsigned char *Buffer, int BitNum) | ||
732 | { | ||
733 | return Buffer[BitNum/8] |= 1<<(7-(BitNum%8)); | ||
734 | } | ||
735 | |||
736 | int ClearBit(unsigned char *Buffer, int BitNum) | ||
737 | { | ||
738 | return Buffer[BitNum/8] &= 255 - (1 << (7-(BitNum%8))); | ||
739 | } | ||
740 | |||
741 | void BufferAlign(unsigned char *Destination, int *CurrentBit) | ||
742 | { | ||
743 | int i=0; | ||
744 | |||
745 | while(((*CurrentBit) + i) % 8 != 0) { | ||
746 | ClearBit(Destination, (*CurrentBit)+i); | ||
747 | i++; | ||
748 | } | ||
749 | |||
750 | (*CurrentBit) = (*CurrentBit) + i; | ||
751 | } | ||
752 | |||
753 | void BufferAlignNumber(int *CurrentBit) | ||
754 | { | ||
755 | int i=0; | ||
756 | |||
757 | while(((*CurrentBit) + i) % 8 != 0) { | ||
758 | i++; | ||
759 | } | ||
760 | |||
761 | (*CurrentBit) = (*CurrentBit) + i; | ||
762 | } | ||
763 | |||
764 | void AddBuffer(unsigned char *Destination, | ||
765 | int *CurrentBit, | ||
766 | unsigned char *Source, | ||
767 | int BitsToProcess) | ||
768 | { | ||
769 | int i=0; | ||
770 | |||
771 | while (i!=BitsToProcess) { | ||
772 | if (GetBit(Source, i)) { | ||
773 | SetBit(Destination, (*CurrentBit)+i); | ||
774 | } else { | ||
775 | ClearBit(Destination, (*CurrentBit)+i); | ||
776 | } | ||
777 | i++; | ||
778 | } | ||
779 | (*CurrentBit) = (*CurrentBit) + BitsToProcess; | ||
780 | } | ||
781 | |||
782 | void AddBufferByte(unsigned char *Destination, | ||
783 | int *CurrentBit, | ||
784 | unsigned char Source, | ||
785 | int BitsToProcess) | ||
786 | { | ||
787 | unsigned char Byte; | ||
788 | |||
789 | Byte = Source; | ||
790 | |||
791 | AddBuffer(Destination, CurrentBit, &Byte, BitsToProcess); | ||
792 | } | ||
793 | |||
794 | void GetBuffer(unsigned char *Source, | ||
795 | int *CurrentBit, | ||
796 | unsigned char *Destination, | ||
797 | int BitsToProcess) | ||
798 | { | ||
799 | int i=0; | ||
800 | |||
801 | while (i!=BitsToProcess) { | ||
802 | if (GetBit(Source, (*CurrentBit)+i)) { | ||
803 | SetBit(Destination, i); | ||
804 | } else { | ||
805 | ClearBit(Destination, i); | ||
806 | } | ||
807 | i++; | ||
808 | } | ||
809 | (*CurrentBit) = (*CurrentBit) + BitsToProcess; | ||
810 | } | ||
811 | |||
812 | void GetBufferInt(unsigned char *Source, | ||
813 | int *CurrentBit, | ||
814 | int *integer, | ||
815 | int BitsToProcess) | ||
816 | { | ||
817 | int l=0,z=128,i=0; | ||
818 | |||
819 | while (i!=BitsToProcess) { | ||
820 | if (GetBit(Source, (*CurrentBit)+i)) l=l+z; | ||
821 | z=z/2; | ||
822 | i++; | ||
823 | } | ||
824 | *integer=l; | ||
825 | (*CurrentBit) = (*CurrentBit) + i; | ||
826 | } | ||
827 | |||
828 | void GetBufferI(unsigned char *Source, | ||
829 | int *CurrentBit, | ||
830 | int *result, | ||
831 | int BitsToProcess) | ||
832 | { | ||
833 | int l=0,z,i=0; | ||
834 | |||
835 | z = 1<<(BitsToProcess-1); | ||
836 | |||
837 | while (i!=BitsToProcess) { | ||
838 | if (GetBit(Source, (*CurrentBit)+i)) l=l+z; | ||
839 | z=z>>1; | ||
840 | i++; | ||
841 | } | ||
842 | *result=l; | ||
843 | (*CurrentBit) = (*CurrentBit) + i; | ||
844 | } | ||
845 | |||
846 | /* Unicode char 0x00 0x01 makes blinking in some Nokia phones. | ||
847 | * We replace single ~ chars into it. When user give double ~, it's replaced | ||
848 | * to single ~ | ||
849 | */ | ||
850 | void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, int len) | ||
851 | { | ||
852 | int i,current = 0; | ||
853 | bool special=false; | ||
854 | |||
855 | for (i = 0; i < len; i++) { | ||
856 | if (special) { | ||
857 | if (src[i*2] == 0x00 && src[i*2+1] == '~') { | ||
858 | dest[current++]= 0x00; | ||
859 | dest[current++]= '~'; | ||
860 | } else { | ||
861 | dest[current++]= 0x00; | ||
862 | dest[current++] = 0x01; | ||
863 | dest[current++]= src[i*2]; | ||
864 | dest[current++]= src[i*2+1]; | ||
865 | } | ||
866 | special = false; | ||
867 | } else { | ||
868 | if (src[i*2] == 0x00 && src[i*2+1] == '~') { | ||
869 | special = true; | ||
870 | } else { | ||
871 | dest[current++]= src[i*2]; | ||
872 | dest[current++]= src[i*2+1]; | ||
873 | } | ||
874 | } | ||
875 | } | ||
876 | if (special) { | ||
877 | dest[current++]= 0x00; | ||
878 | dest[current++]= 0x01; | ||
879 | } | ||
880 | dest[current++] = 0x00; | ||
881 | dest[current++] = 0x00; | ||
882 | } | ||
883 | |||
884 | void DecodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, int len) | ||
885 | { | ||
886 | int i=0,current=0; | ||
887 | |||
888 | for (i=0;i<len;i++) { | ||
889 | switch (src[2*i]) { | ||
890 | case 0x00: | ||
891 | switch (src[2*i+1]) { | ||
892 | case 0x01: | ||
893 | dest[current++] = 0x00; | ||
894 | dest[current++] = '~'; | ||
895 | break; | ||
896 | case '~': | ||
897 | dest[current++] = 0x00; | ||
898 | dest[current++] = '~'; | ||
899 | dest[current++] = 0x00; | ||
900 | dest[current++] = '~'; | ||
901 | break; | ||
902 | default: | ||
903 | dest[current++] = src[i*2]; | ||
904 | dest[current++] = src[i*2+1]; | ||
905 | } | ||
906 | break; | ||
907 | default: | ||
908 | dest[current++] = src[i*2]; | ||
909 | dest[current++] = src[i*2+1]; | ||
910 | } | ||
911 | } | ||
912 | dest[current++] = 0x00; | ||
913 | dest[current++] = 0x00; | ||
914 | } | ||
915 | |||
916 | bool mystrncasecmp(unsigned const char *a, unsigned const char *b, int num) | ||
917 | { | ||
918 | int i; | ||
919 | |||
920 | if (a == NULL || b == NULL) return false; | ||
921 | |||
922 | num--; | ||
923 | |||
924 | for (i = 0; i != num; i++) { | ||
925 | if (a[i] == 0x00 && b[i] == 0x00) return true; | ||
926 | if (a[i] == 0x00 || b[i] == 0x00) return false; | ||
927 | if (tolower(a[i]) != tolower(b[i])) return false; | ||
928 | } | ||
929 | return true; | ||
930 | } | ||
931 | |||
932 | /* Compares two Unicode strings without regarding to case. | ||
933 | * Return true, when they're equal | ||
934 | */ | ||
935 | bool mywstrncasecmp(unsigned const char *a, unsigned const char *b, int num) | ||
936 | { | ||
937 | int i; | ||
938 | wchar_t wc,wc2; | ||
939 | |||
940 | if (a == NULL || b == NULL) return false; | ||
941 | |||
942 | num--; | ||
943 | |||
944 | for (i = 0; i != num; i++) { | ||
945 | if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) && (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return true; | ||
946 | if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) || (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return false; | ||
947 | wc = a[i*2+1] | (a[i*2] << 8); | ||
948 | wc2 = b[i*2+1] | (b[i*2] << 8); | ||
949 | if (mytowlower(wc) != mytowlower(wc2)) return false; | ||
950 | } | ||
951 | return true; | ||
952 | } | ||
953 | |||
954 | /* wcscmp in Mandrake 9.0 is wrong */ | ||
955 | bool mywstrncmp(unsigned const char *a, unsigned const char *b, int num) | ||
956 | { | ||
957 | int i=0; | ||
958 | |||
959 | while (1) { | ||
960 | if (a[i*2] != b[i*2] || a[i*2+1] != b[i*2+1]) return false; | ||
961 | if (a[i*2] == 0x00 && a[i*2+1] == 0x00) return true; | ||
962 | i++; | ||
963 | if (num == i) return true; | ||
964 | } | ||
965 | } | ||
966 | |||
967 | /* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */ | ||
968 | bool myiswspace(unsigned const char *src) | ||
969 | { | ||
970 | #ifndef HAVE_ISWSPACE | ||
971 | int o; | ||
972 | unsigned chardest[10]; | ||
973 | #endif | ||
974 | wchar_t wc; | ||
975 | |||
976 | wc = src[1] | (src[0] << 8); | ||
977 | |||
978 | #ifndef HAVE_ISWSPACE | ||
979 | o = DecodeWithUnicodeAlphabet(wc, dest); | ||
980 | if (o == 1) { | ||
981 | if (isspace(((int)dest[0]))!=0) return true; | ||
982 | return false; | ||
983 | } | ||
984 | return false; | ||
985 | #else | ||
986 | return iswspace(wc); | ||
987 | #endif | ||
988 | } | ||
989 | |||
990 | /* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */ | ||
991 | int mytowlower(wchar_t c) | ||
992 | { | ||
993 | #ifndef HAVE_TOWLOWER | ||
994 | unsigned char dest[10]; | ||
995 | |||
996 | DecodeWithUnicodeAlphabet(c, dest); | ||
997 | return tolower(dest[0]); | ||
998 | #else | ||
999 | return towlower(c); | ||
1000 | #endif | ||
1001 | } | ||
1002 | |||
1003 | /* | ||
1004 | * Following code is based on wcsstr from the GNU C Library, original | ||
1005 | * comment follows: | ||
1006 | */ | ||
1007 | /* | ||
1008 | * The original strstr() file contains the following comment: | ||
1009 | * | ||
1010 | * My personal strstr() implementation that beats most other algorithms. | ||
1011 | * Until someone tells me otherwise, I assume that this is the | ||
1012 | * fastest implementation of strstr() in C. | ||
1013 | * I deliberately chose not to comment it. You should have at least | ||
1014 | * as much fun trying to understand it, as I had to write it :-). | ||
1015 | * | ||
1016 | * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */ | ||
1017 | |||
1018 | unsigned char *mystrstr (const unsigned char *haystack, const unsigned char *needle) | ||
1019 | { | ||
1020 | /* One crazy define to convert unicode used in Gammu to standard wchar_t */ | ||
1021 | #define tolowerwchar(x) (mytowlower((wchar_t)( (((&(x))[0] & 0xff) << 8) | (((&(x))[1] & 0xff)) ))) | ||
1022 | register wchar_t b, c; | ||
1023 | |||
1024 | if ((b = tolowerwchar(*needle)) != L'\0') { | ||
1025 | haystack -= 2; /* possible ANSI violation */ | ||
1026 | do { | ||
1027 | haystack += 2; | ||
1028 | if ((c = tolowerwchar(*haystack)) == L'\0') | ||
1029 | goto ret0; | ||
1030 | } while (c != b); | ||
1031 | |||
1032 | needle += 2; | ||
1033 | if ((c = tolowerwchar(*needle)) == L'\0') | ||
1034 | goto foundneedle; | ||
1035 | needle += 2; | ||
1036 | goto jin; | ||
1037 | |||
1038 | for (;;) { | ||
1039 | register wchar_t a; | ||
1040 | register const unsigned char *rhaystack, *rneedle; | ||
1041 | |||
1042 | do { | ||
1043 | haystack += 2; | ||
1044 | if ((a = tolowerwchar(*haystack)) == L'\0') | ||
1045 | goto ret0; | ||
1046 | if (a == b) | ||
1047 | break; | ||
1048 | haystack += 2; | ||
1049 | if ((a = tolowerwchar(*haystack)) == L'\0') | ||
1050 | goto ret0; | ||
1051 | shloop: ; | ||
1052 | } while (a != b); | ||
1053 | |||
1054 | jin: haystack += 2; | ||
1055 | if ((a = tolowerwchar(*haystack)) == L'\0') | ||
1056 | goto ret0; | ||
1057 | |||
1058 | if (a != c) | ||
1059 | goto shloop; | ||
1060 | |||
1061 | rhaystack = haystack + 2; | ||
1062 | haystack -= 2; | ||
1063 | rneedle = needle; | ||
1064 | if (tolowerwchar(*rhaystack) == (a = tolowerwchar(*rneedle))) | ||
1065 | do { | ||
1066 | if (a == L'\0') | ||
1067 | goto foundneedle; | ||
1068 | rhaystack += 2; | ||
1069 | needle += 2; | ||
1070 | if (tolowerwchar(*rhaystack) != (a = tolowerwchar(*needle))) | ||
1071 | break ; | ||
1072 | if (a == L'\0') | ||
1073 | goto foundneedle; | ||
1074 | rhaystack += 2; | ||
1075 | needle += 2; | ||
1076 | } while (tolowerwchar(*rhaystack) == (a = tolowerwchar(*needle))); | ||
1077 | |||
1078 | needle = rneedle; /* took the register-poor approach */ | ||
1079 | |||
1080 | if (a == L'\0') | ||
1081 | break; | ||
1082 | } | ||
1083 | } | ||
1084 | foundneedle: | ||
1085 | return (unsigned char *)haystack; | ||
1086 | ret0: | ||
1087 | return NULL; | ||
1088 | #undef tolowerwchar | ||
1089 | } | ||
1090 | |||
1091 | void MyGetLine(unsigned char *Buffer, int *Pos, unsigned char *OutBuffer, int MaxLen) | ||
1092 | { | ||
1093 | OutBuffer[0] = 0; | ||
1094 | if (Buffer == NULL) return; | ||
1095 | while (1) { | ||
1096 | if ((*Pos) >= MaxLen) return; | ||
1097 | switch (Buffer[*Pos]) { | ||
1098 | case 0x00: | ||
1099 | return; | ||
1100 | case 0x0A: | ||
1101 | if (strlen(OutBuffer) != 0) return; | ||
1102 | break; | ||
1103 | case 0x0D: | ||
1104 | if (strlen(OutBuffer) != 0) return; | ||
1105 | break; | ||
1106 | default : | ||
1107 | OutBuffer[strlen(OutBuffer) + 1] = 0; | ||
1108 | OutBuffer[strlen(OutBuffer)] = Buffer[*Pos]; | ||
1109 | } | ||
1110 | (*Pos)++; | ||
1111 | } | ||
1112 | } | ||
1113 | |||
1114 | void StringToDouble(char *text, double *d) | ||
1115 | { | ||
1116 | bool before=true; | ||
1117 | double multiply = 1; | ||
1118 | unsigned int i; | ||
1119 | |||
1120 | *d = 0; | ||
1121 | for (i=0;i<strlen(text);i++) { | ||
1122 | if (isdigit(text[i])) { | ||
1123 | if (before) { | ||
1124 | (*d)=(*d)*10+(text[i]-'0'); | ||
1125 | } else { | ||
1126 | multiply=multiply*0.1; | ||
1127 | (*d)=(*d)+(text[i]-'0')*multiply; | ||
1128 | } | ||
1129 | } | ||
1130 | if (text[i]=='.' || text[i]==',') before=false; | ||
1131 | } | ||
1132 | } | ||
1133 | |||
1134 | /* When char can be converted, convert it from Unicode to UTF8 */ | ||
1135 | bool EncodeWithUTF8Alphabet(unsigned char mychar1, unsigned char mychar2, unsigned char *ret1, unsigned char *ret2) | ||
1136 | { | ||
1137 | unsigned charmychar3,mychar4; | ||
1138 | int j=0; | ||
1139 | |||
1140 | if (mychar1>0x00 || mychar2>128) { | ||
1141 | mychar3=0x00; | ||
1142 | mychar4=128; | ||
1143 | while (true) { | ||
1144 | if (mychar3==mychar1) { | ||
1145 | if (mychar4+64>=mychar2) { | ||
1146 | *ret1=j+0xc2; | ||
1147 | *ret2=0x80+(mychar2-mychar4); | ||
1148 | return true; | ||
1149 | } | ||
1150 | } | ||
1151 | if (mychar4==192) { | ||
1152 | mychar3++; | ||
1153 | mychar4=0; | ||
1154 | } else { | ||
1155 | mychar4=mychar4+64; | ||
1156 | } | ||
1157 | j++; | ||
1158 | } | ||
1159 | } | ||
1160 | return false; | ||
1161 | } | ||
1162 | |||
1163 | /* Make UTF8 string from Unicode input string */ | ||
1164 | bool EncodeUTF8QuotedPrintable(unsigned char *dest, const unsigned char *src) | ||
1165 | { | ||
1166 | int i,j=0; | ||
1167 | unsigned charmychar1, mychar2; | ||
1168 | bool retval = false; | ||
1169 | |||
1170 | for (i = 0; i < (int)(UnicodeLength(src)); i++) { | ||
1171 | if (EncodeWithUTF8Alphabet(src[i*2],src[i*2+1],&mychar1,&mychar2)) { | ||
1172 | sprintf(dest+j, "=%02X=%02X",mychar1,mychar2); | ||
1173 | j= j+6; | ||
1174 | retval = true; | ||
1175 | } else { | ||
1176 | j += DecodeWithUnicodeAlphabet(((wchar_t)(src[i*2]*256+src[i*2+1])), dest + j); | ||
1177 | } | ||
1178 | } | ||
1179 | dest[j++]=0; | ||
1180 | return retval; | ||
1181 | } | ||
1182 | |||
1183 | bool EncodeUTF8(unsigned char *dest, const unsigned char *src) | ||
1184 | { | ||
1185 | int i,j=0; | ||
1186 | unsigned charmychar1, mychar2; | ||
1187 | bool retval = false; | ||
1188 | |||
1189 | for (i = 0; i < (int)(UnicodeLength(src)); i++) { | ||
1190 | if (EncodeWithUTF8Alphabet(src[i*2],src[i*2+1],&mychar1,&mychar2)) { | ||
1191 | sprintf(dest+j, "%c%c",mychar1,mychar2); | ||
1192 | j= j+2; | ||
1193 | retval = true; | ||
1194 | } else { | ||
1195 | j += DecodeWithUnicodeAlphabet(((wchar_t)(src[i*2]*256+src[i*2+1])), dest + j); | ||
1196 | } | ||
1197 | } | ||
1198 | dest[j++]=0; | ||
1199 | return retval; | ||
1200 | } | ||
1201 | |||
1202 | /* Decode UTF8 char to Unicode char */ | ||
1203 | wchar_t DecodeWithUTF8Alphabet(unsigned char mychar3, unsigned char mychar4) | ||
1204 | { | ||
1205 | unsigned charmychar1, mychar2; | ||
1206 | int j; | ||
1207 | |||
1208 | mychar1=0x00; | ||
1209 | mychar2=128; | ||
1210 | for(j=0;j<mychar3-0xc2;j++) { | ||
1211 | if (mychar2==192) { | ||
1212 | mychar1++; | ||
1213 | mychar2 = 0; | ||
1214 | } else { | ||
1215 | mychar2 = mychar2+64; | ||
1216 | } | ||
1217 | } | ||
1218 | mychar2 = mychar2+(mychar4-0x80); | ||
1219 | return mychar2 | (mychar1 << 8); | ||
1220 | } | ||
1221 | |||
1222 | /* Make Unicode string from UTF8 string */ | ||
1223 | void DecodeUTF8QuotedPrintable(unsigned char *dest, const unsigned char *src, int len) | ||
1224 | { | ||
1225 | int i=0,j=0; | ||
1226 | unsigned charmychar1, mychar2; | ||
1227 | wchar_t ret; | ||
1228 | |||
1229 | while (i<=len) { | ||
1230 | if (len-6>=i) { | ||
1231 | /* Need to have correct chars */ | ||
1232 | if (src[i] =='=' && DecodeWithHexBinAlphabet(src[i+1])!=-1 | ||
1233 | && DecodeWithHexBinAlphabet(src[i+2])!=-1 && | ||
1234 | src[i+3]=='=' && DecodeWithHexBinAlphabet(src[i+4])!=-1 && | ||
1235 | DecodeWithHexBinAlphabet(src[i+5])!=-1) { | ||
1236 | mychar1= 16*DecodeWithHexBinAlphabet(src[i+1])+DecodeWithHexBinAlphabet(src[i+2]); | ||
1237 | mychar2= 16*DecodeWithHexBinAlphabet(src[i+4])+DecodeWithHexBinAlphabet(src[i+5]); | ||
1238 | ret = DecodeWithUTF8Alphabet(mychar1,mychar2); | ||
1239 | i = i+6; | ||
1240 | } else { | ||
1241 | i+=EncodeWithUnicodeAlphabet(&src[i], &ret); | ||
1242 | } | ||
1243 | } else { | ||
1244 | i+=EncodeWithUnicodeAlphabet(&src[i], &ret); | ||
1245 | } | ||
1246 | dest[j++] = (ret >> 8) & 0xff; | ||
1247 | dest[j++] = ret & 0xff; | ||
1248 | } | ||
1249 | dest[j++] = 0; | ||
1250 | dest[j++] = 0; | ||
1251 | } | ||
1252 | |||
1253 | void DecodeUTF8(unsigned char *dest, const unsigned char *src, int len) | ||
1254 | { | ||
1255 | int i=0,j=0; | ||
1256 | wchar_t ret; | ||
1257 | |||
1258 | while (i<=len) { | ||
1259 | if (len-2>=i) { | ||
1260 | if (src[i] >= 0xC2) { | ||
1261 | ret = DecodeWithUTF8Alphabet(src[i],src[i+1]); | ||
1262 | i = i+2; | ||
1263 | } else { | ||
1264 | i+=EncodeWithUnicodeAlphabet(&src[i], &ret); | ||
1265 | } | ||
1266 | } else { | ||
1267 | i+=EncodeWithUnicodeAlphabet(&src[i], &ret); | ||
1268 | } | ||
1269 | dest[j++] = (ret >> 8) & 0xff; | ||
1270 | dest[j++] = ret & 0xff; | ||
1271 | } | ||
1272 | dest[j++] = 0; | ||
1273 | dest[j++] = 0; | ||
1274 | } | ||
1275 | |||
1276 | void DecodeUTF7(unsigned char *dest, const unsigned char *src, int len) | ||
1277 | { | ||
1278 | int i=0,j=0,z,p; | ||
1279 | wchar_t ret; | ||
1280 | |||
1281 | while (i<=len) { | ||
1282 | if (len-5>=i) { | ||
1283 | if (src[i] == '+') { | ||
1284 | z=0; | ||
1285 | while (src[z+i+1] != '-' && z+i+1<len) z++; | ||
1286 | p=DecodeBASE64(src+i+1, dest+j, z); | ||
1287 | if (p%2 != 0) p--; | ||
1288 | j+=p; | ||
1289 | i+=z+2; | ||
1290 | } else { | ||
1291 | i+=EncodeWithUnicodeAlphabet(&src[i], &ret); | ||
1292 | dest[j++] = (ret >> 8) & 0xff; | ||
1293 | dest[j++] = ret & 0xff; | ||
1294 | } | ||
1295 | } else { | ||
1296 | i+=EncodeWithUnicodeAlphabet(&src[i], &ret); | ||
1297 | dest[j++] = (ret >> 8) & 0xff; | ||
1298 | dest[j++] = ret & 0xff; | ||
1299 | } | ||
1300 | } | ||
1301 | dest[j++] = 0; | ||
1302 | dest[j++] = 0; | ||
1303 | } | ||
1304 | |||
1305 | /* | ||
1306 | Bob Trower 08/04/01 | ||
1307 | Copyright (c) Trantor Standard Systems Inc., 2001 | ||
1308 | |||
1309 | Permission is hereby granted, free of charge, to any person | ||
1310 | obtaining a copy of this software and associated | ||
1311 | documentation files (the "Software"), to deal in the | ||
1312 | Software without restriction, including without limitation | ||
1313 | the rights to use, copy, modify, merge, publish, distribute, | ||
1314 | sublicense, and/or sell copies of the Software, and to | ||
1315 | permit persons to whom the Software is furnished to do so, | ||
1316 | subject to the following conditions: | ||
1317 | |||
1318 | The above copyright notice and this permission notice shall | ||
1319 | be included in all copies or substantial portions of the | ||
1320 | Software. | ||
1321 | |||
1322 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | ||
1323 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | ||
1324 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
1325 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS | ||
1326 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
1327 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
1328 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
1329 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
1330 | */ | ||
1331 | |||
1332 | static void EncodeBASE64Block(unsigned char in[3], unsigned char out[4], int len) | ||
1333 | { | ||
1334 | /* BASE64 translation Table as described in RFC1113 */ | ||
1335 | unsigned char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
1336 | |||
1337 | out[0] = cb64[ in[0] >> 2 ]; | ||
1338 | out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; | ||
1339 | out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='); | ||
1340 | out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '='); | ||
1341 | } | ||
1342 | |||
1343 | void EncodeBASE64(const unsigned char *Input, unsigned char *Output, int Length) | ||
1344 | { | ||
1345 | unsigned char in[3], out[4]; | ||
1346 | int i, pos = 0, len, outpos = 0; | ||
1347 | |||
1348 | while (pos < Length) { | ||
1349 | len = 0; | ||
1350 | for (i = 0; i < 3; i++) { | ||
1351 | in[i] = 0; | ||
1352 | if (pos < Length) { | ||
1353 | in[i] = Input[pos]; | ||
1354 | len++; | ||
1355 | pos++; | ||
1356 | } | ||
1357 | } | ||
1358 | if(len) { | ||
1359 | EncodeBASE64Block(in, out, len); | ||
1360 | for (i = 0; i < 4; i++) Output[outpos++] = out[i]; | ||
1361 | } | ||
1362 | } | ||
1363 | |||
1364 | Output[outpos++] = 0; | ||
1365 | } | ||
1366 | |||
1367 | static void DecodeBASE64Block(unsigned char in[4], unsigned char out[3]) | ||
1368 | { | ||
1369 | out[0] = (unsigned char) (in[0] << 2 | in[1] >> 4); | ||
1370 | out[1] = (unsigned char) (in[1] << 4 | in[2] >> 2); | ||
1371 | out[2] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]); | ||
1372 | } | ||
1373 | |||
1374 | int DecodeBASE64(const unsigned char *Input, unsigned char *Output, int Length) | ||
1375 | { | ||
1376 | unsigned char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; | ||
1377 | unsigned char in[4], out[3], v; | ||
1378 | int i, len, pos = 0, outpos = 0; | ||
1379 | |||
1380 | while (pos < Length) { | ||
1381 | len = 0; | ||
1382 | for(i = 0; i < 4; i++) { | ||
1383 | v = 0; | ||
1384 | while(v == 0) { | ||
1385 | if (pos >= Length) break; | ||
1386 | v = (unsigned char) Input[pos++]; | ||
1387 | v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]); | ||
1388 | if (v) v = (unsigned char) ((v == '$') ? 0 : v - 61); | ||
1389 | } | ||
1390 | if(pos<=Length) { | ||
1391 | if (v) { | ||
1392 | len++; | ||
1393 | in[i] = (unsigned char) (v - 1); | ||
1394 | } | ||
1395 | } | ||
1396 | } | ||
1397 | if (len) { | ||
1398 | DecodeBASE64Block(in, out); | ||
1399 | for(i = 0; i < len - 1; i++) Output[outpos++] = out[i]; | ||
1400 | } | ||
1401 | } | ||
1402 | Output[outpos] = 0; | ||
1403 | return outpos; | ||
1404 | } | ||
1405 | |||
1406 | /* How should editor hadle tabs in this file? Add editor commands here. | ||
1407 | * vim: noexpandtab sw=8 ts=8 sts=8: | ||
1408 | */ | ||
1409 | |||