Imported gammu 0.90.7
[gammu.git] / common / misc / coding / coding.c
blob01708edeb64404d580758b4995404bb3d891ef7c
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <locale.h>
7 #ifndef __OpenBSD__
8 # include <wctype.h>
9 #endif
10 #ifdef WIN32
11 # include "windows.h"
12 #endif
14 #include "../misc.h"
15 #include "coding.h"
17 unsigned int UnicodeLength(const unsigned char *str)
19 unsigned int len = 0;
21 while(1) {
22 if (str[len*2] == 0 && str[len*2+1] == 0) break;
23 len++;
25 return len;
28 /* Convert Unicode char saved in src to dest */
29 unsigned int EncodeWithUnicodeAlphabet(const unsigned char *src, wchar_t *dest)
31 char retval;
33 switch (retval = mbtowc(dest, src, MB_CUR_MAX)) {
34 case -1 :
35 case 0 : return 1;
36 default : return retval;
40 /* Convert Unicode char saved in src to dest */
41 unsigned int DecodeWithUnicodeAlphabet(wchar_t src, unsigned char *dest)
43 int retval;
45 switch (retval = wctomb(dest, src)) {
46 case -1:
47 *dest = '?';
48 return 1;
49 default:
50 return retval;
54 void DecodeUnicode (const unsigned char *src, unsigned char *dest)
56 int i=0,o=0;
57 wchar_t wc;
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);
62 i++;
64 dest[o]=0;
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);
73 return 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);
86 } else {
87 #ifdef WIN32
88 setlocale(LC_ALL, di.coding);
89 #endif
90 DecodeUnicode(src,dest);
92 } else {
93 #ifdef WIN32
94 setlocale(LC_ALL, ".OCP");
95 #endif
96 DecodeUnicode(src,dest);
97 #ifdef WIN32
98 setlocale(LC_ALL, ".ACP");
99 #endif
101 return dest;
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;
108 wchar_t wc;
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;
115 dest[o_len*2] = 0;
116 dest[(o_len*2)+1] = 0;
119 unsigned char EncodeWithBCDAlphabet(int value)
121 div_t division;
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++) {
137 digit=src[i] & 0x0f;
138 if (digit<10) dest[current++]=digit + '0';
139 digit=src[i] >> 4;
140 if (digit<10) dest[current++]=digit + '0';
142 dest[current++]=0;
145 void EncodeBCD (unsigned char *dest, const unsigned char *src, int len, bool fill)
147 int i,current=0;
149 for (i = 0; i < len; i++) {
150 if (i & 0x01) {
151 dest[current]=dest[current] | ((src[i]-'0') << 4);
152 current++;
153 } else {
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';
171 return -1;
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);
178 return 0;
181 void DecodeHexUnicode (unsigned char *dest, const unsigned char *src, int len)
183 int i,current=0;
184 bool first = false;
186 if (len != 0 && src[0] == '0' && src[1] == '0') first = true;
187 for (i = 0; i < len/4 ; i++) {
188 if (first) {
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]);
193 } else {
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]);
200 dest[current++] = 0;
201 dest[current++] = 0;
204 void EncodeHexUnicode (unsigned char *dest, const unsigned char *src, int len)
206 int i,current=0;
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);
214 dest[current++] = 0;
217 void DecodeHexBin (unsigned char *dest, const unsigned char *src, int len)
219 int i,current=0;
221 for (i = 0; i < len/2 ; i++) {
222 dest[current++] = DecodeWithHexBinAlphabet(src[i*2])*16+
223 DecodeWithHexBinAlphabet(src[i*2+1]);
225 dest[current++] = 0;
228 void EncodeHexBin (unsigned char *dest, const unsigned char *src, int len)
230 int i,current=0;
232 for (i = 0; i < len; i++) {
233 dest[current++] = EncodeWithHexBinAlphabet(src[i] >> 0x04);
234 dest[current++] = EncodeWithHexBinAlphabet(src[i] & 0x0f);
236 dest[current++] = 0;
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},
274 {0x00,0x00}
277 /* ETSI GSM 3.38
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)
301 int i,current=0,j;
302 bool FoundSpecial = false;
304 #ifdef DEBUG
305 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, src, len);
306 #endif
308 for (i = 0; i < len; i++) {
309 FoundSpecial = false;
310 if ((i < (len-1)) && UseExtensions) {
311 j=0;
312 while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00) {
313 if (GSM_DefaultAlphabetCharsExtension[j][0]==src[i] &&
314 GSM_DefaultAlphabetCharsExtension[j][1]==src[i+1]) {
315 FoundSpecial = true;
316 dest[current++] = GSM_DefaultAlphabetCharsExtension[j][2];
317 dest[current++] = GSM_DefaultAlphabetCharsExtension[j][3];
318 i++;
319 break;
321 j++;
324 if (ExtraAlphabet!=NULL && !FoundSpecial) {
325 j = 0;
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];
330 FoundSpecial = true;
331 break;
333 j=j+3;
336 if (!FoundSpecial) {
337 dest[current++] = GSM_DefaultAlphabetUnicode[src[i]][0];
338 dest[current++] = GSM_DefaultAlphabetUnicode[src[i]][1];
341 dest[current++]=0;
342 dest[current++]=0;
343 #ifdef DEBUG
344 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, dest, UnicodeLength(dest)*2);
345 #endif
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)
365 int i,current=0,j,z;
366 char ret;
367 bool FoundSpecial,FoundNormal;
369 #ifdef DEBUG
370 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, src, (*len)*2);
371 #endif
373 for (i = 0; i < *len; i++) {
374 FoundSpecial = false;
375 j = 0;
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];
381 FoundSpecial = true;
382 break;
384 j++;
386 if (!FoundSpecial) {
387 ret = '?';
388 FoundNormal = false;
389 j = 0;
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])
395 ret = j;
396 FoundNormal = true;
397 break;
399 j++;
401 if (ExtraAlphabet!=NULL && !FoundNormal) {
402 j = 0;
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];
408 FoundSpecial = true;
409 break;
411 j=j+3;
414 if (!FoundNormal && !FoundSpecial) {
415 j = 0;
416 FoundNormal = false;
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]) {
421 z = 0;
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])
427 ret = z;
428 FoundNormal = true;
429 break;
431 z++;
433 if (FoundNormal) break;
435 j++;
438 dest[current++]=ret;
441 dest[current]=0;
442 #ifdef DEBUG
443 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, dest, current);
444 #endif
446 *len = 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)
452 int current=0,j,i;
453 bool FoundSpecial;
455 i = 0;
456 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;
469 current+=2;
470 break;
472 j++;
474 if (!FoundSpecial) {
475 if (current+1 > maxlen) {
476 *srclen = i;
477 *smslen = current;
478 return;
480 current++;
482 i++;
484 *srclen = i;
485 *smslen = current;
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)
493 #ifndef ENABLE_LGPL
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;
497 int Bits;
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++;
510 INPUT++;
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 */
516 if (Bits == 1) {
517 *OUTPUT = Rest;
518 OUTPUT++;
519 Bits = 7;
520 Rest = 0x00;
521 } else {
522 Bits--;
526 return OUTPUT - output;
527 #else
528 return 0;
529 #endif
532 int GSM_PackSevenBitsToEight(int offset, unsigned char *input, unsigned char *output, int length)
534 #ifndef ENABLE_LGPL
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
542 first octet */
543 if (offset) {
544 *OUTPUT = 0x00;
545 OUTPUT++;
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 */
554 if (Bits != 7)
555 *(OUTPUT-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1);
557 Bits--;
559 if (Bits == -1) Bits = 7; else OUTPUT++;
561 INPUT++;
563 return (OUTPUT - output);
564 #else
565 return 0;
566 #endif
569 void GSM_UnpackSemiOctetNumber(unsigned char *retval, unsigned char *Number, bool semioctet)
571 unsigned char Buffer[50] = "";
572 int length = Number[0];
574 if (semioctet) {
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*/
581 length--;
583 switch (Number[1]) {
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);
588 Buffer[length]=0;
589 break;
590 case GNT_INTERNATIONAL:
591 dbgprintf("International number\n");
592 Buffer[0]='+';
593 DecodeBCD(Buffer+1,Number+2, length);
594 break;
595 default:
596 dbgprintf("Default number %02x\n",Number[1]);
597 DecodeBCD (Buffer, Number+2, length);
598 break;
601 EncodeUnicode(retval,Buffer,strlen(Buffer));
604 /* Packing of numbers (SMS Center number and destination number) for SMS
605 * sending function.
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
611 in semioctets).
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 */
623 int length=0,j;
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;
633 else {
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 */
641 *OUTPUT++=format;
643 /* Now we will have number. GSM 03.40 section 9.1.2 */
644 switch (format) {
645 case GNT_ALPHANUMERIC:
646 length=GSM_PackSevenBitsToEight(0, buffer, OUTPUT, strlen(buffer))*2;
647 if (strlen(buffer)==7) length--;
648 break;
649 case GNT_INTERNATIONAL:
650 length--;
651 EncodeBCD (OUTPUT, buffer+1, length, true);
652 break;
653 default:
654 EncodeBCD (OUTPUT, buffer, length, true);
655 break;
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)
665 int j = 0;
667 while (Source[j]!=0x00 || Source[j+1]!=0x00) {
668 Dest[j] = Source[j];
669 Dest[j+1] = Source[j+1];
670 j=j+2;
672 Dest[j] = 0;
673 Dest[j+1] = 0;
676 /* Changes minor/major order in Unicode string */
677 void ReverseUnicodeString(unsigned char *String)
679 int j = 0;
680 unsigned char byte1, byte2;
682 while (String[j]!=0x00 || String[j+1]!=0x00) {
683 byte1 = String[j];
684 byte2 = String[j+1];
685 String[j+1] = byte1;
686 String[j] = byte2;
687 j=j+2;
689 String[j] = 0;
690 String[j+1] = 0;
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];
706 } else {
707 Dest[current++] = Source[j];
708 Dest[current++] = Source[j+1];
710 j=j+2;
712 Dest[current++] = 0;
713 Dest[current++] = 0;
716 int OctetAlign(unsigned char *Dest, int CurrentBit)
718 int i=0;
719 while((CurrentBit+i)%8) {
720 ClearBit(Dest, CurrentBit+i);
721 i++;
723 return CurrentBit+i;
726 int OctetAlignNumber(int CurrentBit)
728 int i=0;
729 while((CurrentBit+i)%8) { i++; }
730 return CurrentBit+i;
733 int BitPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits)
735 int i;
736 for (i=0; i<Bits; i++)
737 if (GetBit(Source, i))
738 SetBit(Dest, CurrentBit+i);
739 else
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};
748 Byte[0] = Command;
749 return BitPack(Dest, CurrentBit, Byte, Bits);
752 int BitUnPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits)
754 int i;
756 for (i=0; i<Bits; i++)
757 if (GetBit(Dest, CurrentBit+i)) {
758 SetBit(Source, i);
759 } else {
760 ClearBit(Source, i);
762 return CurrentBit+Bits;
765 int BitUnPackInt(unsigned char *Src, int CurrentBit, int *integer, int Bits)
767 int l=0,z=128,i;
769 for (i=0; i<Bits; i++) {
770 if (GetBit(Src, CurrentBit+i)) l=l+z;
771 z=z/2;
773 *integer=l;
774 return CurrentBit+i;
777 int BitUnPackI (unsigned char *Src, int CurrentBit, int *result, int Bits)
779 int l=0,z,i;
781 z = 1<<(Bits-1);
782 for (i=0; i<Bits; i++) {
783 if (GetBit(Src, CurrentBit+i)) l=l+z;
784 z=z>>1;
786 *result=l;
787 return CurrentBit+i;
790 int OctetUnAlign(int CurrentBit)
792 int i=0;
794 while((CurrentBit+i)%8) i++;
795 return CurrentBit+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
800 * to single ~
802 void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, int len)
804 int i,current = 0;
805 bool special=false;
807 for (i = 0; i < len; i++) {
808 if (special) {
809 if (src[i*2] == 0x00 && src[i*2+1] == '~') {
810 dest[current++] = 0x00;
811 dest[current++] = '~';
812 } else {
813 dest[current++] = 0x00;
814 dest[current++] = 0x01;
815 dest[current++] = src[i*2];
816 dest[current++] = src[i*2+1];
818 special = false;
819 } else {
820 if (src[i*2] == 0x00 && src[i*2+1] == '~') {
821 special = true;
822 } else {
823 dest[current++] = src[i*2];
824 dest[current++] = src[i*2+1];
828 if (special) {
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)
838 int i=0,current=0;
840 for (i=0;i<len;i++) {
841 switch (src[2*i]) {
842 case 0x00:
843 switch (src[2*i+1]) {
844 case 0x01:
845 dest[current++] = 0x00;
846 dest[current++] = '~';
847 break;
848 case '~':
849 dest[current++] = 0x00;
850 dest[current++] = '~';
851 dest[current++] = 0x00;
852 dest[current++] = '~';
853 break;
854 default:
855 dest[current++] = src[i*2];
856 dest[current++] = src[i*2+1];
858 break;
859 default:
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)
870 int i=0;
872 // printf("comparing \"%s\" and \"%s\"\n",a,b);
873 while (1) {
874 if (a[i] == 0x00) {
875 if (b[i] == 0x00) return true;
876 return false;
878 if (tolower(a[i]) != tolower(b[i])) return false;
879 i++;
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)
889 int i=0;
890 wchar_t wc,wc2;
892 while (1) {
893 if (a[i*2] == 0x00 && a[i*2+1] == 0x00) {
894 if (b[i*2] == 0x00 && b[i*2+1] == 0x00) return true;
895 return false;
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;
900 i++;
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)
908 int i=0;
910 while (1) {
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;
913 i++;
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
922 int o;
923 unsigned char dest[10];
924 #endif
925 wchar_t wc;
927 wc = src[1] | (src[0] << 8);
929 #ifndef HAVE_ISWSPACE
930 o = DecodeWithUnicodeAlphabet(wc, dest);
931 if (o == 1) {
932 if (isspace(((int)dest[0]))!=0) return true;
933 return false;
935 return false;
936 #else
937 return iswspace(wc);
938 #endif
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]);
949 #else
950 return towlower(c);
951 #endif
955 * Following code is based on wcsstr from the GNU C Library, original
956 * comment follows:
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 */
977 do {
978 haystack += 2;
979 if ((c = tolowerwchar(*haystack)) == L'\0')
980 goto ret0;
981 } while (c != b);
983 needle += 2;
984 if ((c = tolowerwchar(*needle)) == L'\0')
985 goto foundneedle;
986 needle += 2;
987 goto jin;
989 for (;;) {
990 register wchar_t a;
991 register const unsigned char *rhaystack, *rneedle;
993 do {
994 haystack += 2;
995 if ((a = tolowerwchar(*haystack)) == L'\0')
996 goto ret0;
997 if (a == b)
998 break;
999 haystack += 2;
1000 if ((a = tolowerwchar(*haystack)) == L'\0')
1001 goto ret0;
1002 shloop: ;
1003 } while (a != b);
1005 jin: haystack += 2;
1006 if ((a = tolowerwchar(*haystack)) == L'\0')
1007 goto ret0;
1009 if (a != c)
1010 goto shloop;
1012 rhaystack = haystack + 2;
1013 haystack -= 2;
1014 rneedle = needle;
1015 if (tolowerwchar(*rhaystack) == (a = tolowerwchar(*rneedle)))
1016 do {
1017 if (a == L'\0')
1018 goto foundneedle;
1019 rhaystack += 2;
1020 needle += 2;
1021 if (tolowerwchar(*rhaystack) != (a = tolowerwchar(*needle)))
1022 break ;
1023 if (a == L'\0')
1024 goto foundneedle;
1025 rhaystack += 2;
1026 needle += 2;
1027 } while (tolowerwchar(*rhaystack) == (a = tolowerwchar(*needle)));
1029 needle = rneedle; /* took the register-poor approach */
1031 if (a == L'\0')
1032 break;
1035 foundneedle:
1036 return (unsigned char *)haystack;
1037 ret0:
1038 return NULL;
1039 #undef tolowerwchar
1042 void MyGetLine(unsigned char *Buffer, int *Pos, unsigned char *OutBuffer, int MaxLen)
1044 OutBuffer[0] = 0;
1045 if (Buffer == NULL) return;
1046 while (1) {
1047 if ((*Pos) >= MaxLen) return;
1048 switch (Buffer[*Pos]) {
1049 case 0x00:
1050 return;
1051 case 0x0A:
1052 if (strlen(OutBuffer) != 0) return;
1053 break;
1054 case 0x0D:
1055 if (strlen(OutBuffer) != 0) return;
1056 break;
1057 default :
1058 OutBuffer[strlen(OutBuffer) + 1] = 0;
1059 OutBuffer[strlen(OutBuffer)] = Buffer[*Pos];
1061 (*Pos)++;
1065 void StringToDouble(char *text, double *d)
1067 bool before=true;
1068 double multiply = 1;
1069 unsigned int i;
1071 *d = 0;
1072 for (i=0;i<strlen(text);i++) {
1073 if (isdigit(text[i])) {
1074 if (before) {
1075 (*d)=(*d)*10+(text[i]-'0');
1076 } else {
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;
1089 int j=0;
1091 if (mychar1>0x00 || mychar2>128) {
1092 mychar3=0x00;
1093 mychar4=128;
1094 while (true) {
1095 if (mychar3==mychar1) {
1096 if (mychar4+64>=mychar2) {
1097 *ret1=j+0xc2;
1098 *ret2=0x80+(mychar2-mychar4);
1099 return true;
1102 if (mychar4==192) {
1103 mychar3++;
1104 mychar4=0;
1105 } else {
1106 mychar4=mychar4+64;
1108 j++;
1111 return false;
1114 /* Make UTF8 string from Unicode input string */
1115 bool EncodeUTF8QuotedPrintable(unsigned char *dest, const unsigned char *src)
1117 int i,j=0;
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);
1124 j = j+6;
1125 retval = true;
1126 } else {
1127 j += DecodeWithUnicodeAlphabet(((wchar_t)(src[i*2]*256+src[i*2+1])), dest + j);
1130 dest[j++]=0;
1131 return retval;
1134 bool EncodeUTF8(unsigned char *dest, const unsigned char *src)
1136 int i,j=0;
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);
1143 j = j+2;
1144 retval = true;
1145 } else {
1146 j += DecodeWithUnicodeAlphabet(((wchar_t)(src[i*2]*256+src[i*2+1])), dest + j);
1149 dest[j++]=0;
1150 return retval;
1153 /* Decode UTF8 char to Unicode char */
1154 wchar_t DecodeWithUTF8Alphabet(unsigned char mychar3, unsigned char mychar4)
1156 unsigned char mychar1, mychar2;
1157 int j;
1159 mychar1=0x00;
1160 mychar2=128;
1161 for(j=0;j<mychar3-0xc2;j++) {
1162 if (mychar2==192) {
1163 mychar1++;
1164 mychar2 = 0;
1165 } else {
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)
1176 int i=0,j=0;
1177 unsigned char mychar1, mychar2;
1178 wchar_t ret;
1180 while (i<=len) {
1181 if (len-6>=i) {
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);
1190 i = i+6;
1191 } else {
1192 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1194 } else {
1195 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1197 dest[j++] = (ret >> 8) & 0xff;
1198 dest[j++] = ret & 0xff;
1200 dest[j++] = 0;
1201 dest[j++] = 0;
1204 void DecodeUTF8(unsigned char *dest, const unsigned char *src, int len)
1206 int i=0,j=0;
1207 wchar_t ret;
1209 while (i<=len) {
1210 if (len-2>=i) {
1211 if (src[i] >= 0xC2) {
1212 ret = DecodeWithUTF8Alphabet(src[i],src[i+1]);
1213 i = i+2;
1214 } else {
1215 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1217 } else {
1218 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1220 dest[j++] = (ret >> 8) & 0xff;
1221 dest[j++] = ret & 0xff;
1223 dest[j++] = 0;
1224 dest[j++] = 0;
1227 void DecodeUTF7(unsigned char *dest, const unsigned char *src, int len)
1229 int i=0,j=0,z,p;
1230 wchar_t ret;
1232 while (i<=len) {
1233 if (len-5>=i) {
1234 if (src[i] == '+') {
1235 z=0;
1236 while (src[z+i+1] != '-' && z+i+1<len) z++;
1237 p=DecodeBASE64(src+i+1, dest+j, z);
1238 if (p%2 != 0) p--;
1239 j+=p;
1240 i+=z+2;
1241 } else {
1242 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1243 dest[j++] = (ret >> 8) & 0xff;
1244 dest[j++] = ret & 0xff;
1246 } else {
1247 i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
1248 dest[j++] = (ret >> 8) & 0xff;
1249 dest[j++] = ret & 0xff;
1252 dest[j++] = 0;
1253 dest[j++] = 0;
1257 Bob Trower 08/04/01
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
1271 Software.
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;
1299 while(1) {
1300 len = 0;
1301 for (i = 0; i < 3; i++) {
1302 in[i] = 0;
1303 if (pos < Length) {
1304 in[i] = Input[pos];
1305 len++;
1306 pos++;
1309 if(len) {
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;
1331 while(1) {
1332 if (pos >= Length) break;
1333 len = 0;
1334 for(i = 0; i < 4; i++) {
1335 v = 0;
1336 while(v == 0) {
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);
1342 if(pos<=Length) {
1343 if (v) {
1344 len++;
1345 in[i] = (unsigned char) (v - 1);
1349 if (len) {
1350 DecodeBASE64Block(in, out);
1351 for(i = 0; i < len - 1; i++) Output[outpos++] = out[i];
1354 Output[outpos] = 0;
1355 return outpos;
1358 /* How should editor hadle tabs in this file? Add editor commands here.
1359 * vim: noexpandtab sw=8 ts=8 sts=8: