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 | 177 |
1 files changed, 165 insertions, 12 deletions
diff --git a/gammu/emb/common/misc/coding/coding.c b/gammu/emb/common/misc/coding/coding.c index 62543ac..b30b645 100644 --- a/gammu/emb/common/misc/coding/coding.c +++ b/gammu/emb/common/misc/coding/coding.c @@ -1,66 +1,219 @@ /* (c) 2002-2004 by Marcin Wiacek, Michal Cihar and others */ -/* based on some work from MyGnokii and Gnokii */ +/* based on some work from MyGnokii (www.mwiacek.com) */ +/* based on some work from Gnokii (www.gnokii.org) + * (C) 1999-2000 Hugh Blemings & Pavel Janik ml. (C) 2001-2004 Pawel Kot + * GNU GPL version 2 or later + */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <locale.h> #ifndef __OpenBSD__ # include <wctype.h> #endif #ifdef WIN32 # include "windows.h" #endif #include "../misc.h" #include "coding.h" +/* function changes #10 #13 chars to \n \r */ +char *EncodeUnicodeSpecialChars(unsigned char *buffer) +{ + int Pos=0, Pos2=0; + static unsigned char Buf[20000]; + + while (buffer[Pos*2]!=0x00 || buffer[Pos*2+1]!=0x00) { + if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 10) { + Buf[Pos2*2] = 0x00; + Buf[Pos2*2+1] = '\\'; + Pos2++; + Buf[Pos2*2] = 0x00; + Buf[Pos2*2+1] = 'n'; + Pos2++; + } else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 13) { + Buf[Pos2*2] = 0x00; + Buf[Pos2*2+1] = '\\'; + Pos2++; + Buf[Pos2*2] = 0x00; + Buf[Pos2*2+1] = 'r'; + Pos2++; + } else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == '\\') { + Buf[Pos2*2] = 0x00; + Buf[Pos2*2+1] = '\\'; + Pos2++; + Buf[Pos2*2] = 0x00; + Buf[Pos2*2+1] = '\\'; + Pos2++; + } else { + Buf[Pos2*2] = buffer[Pos*2]; + Buf[Pos2*2+1] = buffer[Pos*2+1]; + Pos2++; + } + Pos++; + } + Buf[Pos2*2] = 0; + Buf[Pos2*2+1] = 0; + return Buf; +} + +/* function changes #10 #13 chars to \n \r */ +char *EncodeSpecialChars(unsigned char *buffer) +{ + int Pos=0, Pos2=0; + static unsigned char Buf[10000]; + + while (buffer[Pos]!=0x00) { + switch (buffer[Pos]) { + case 10: + Buf[Pos2++] = '\\'; + Buf[Pos2++] = 'n'; + break; + case 13: + Buf[Pos2++] = '\\'; + Buf[Pos2++] = 'r'; + break; + case '\\': + Buf[Pos2++] = '\\'; + Buf[Pos2++] = '\\'; + break; + default: + Buf[Pos2++] = buffer[Pos]; + } + Pos++; + } + Buf[Pos2] = 0; + return Buf; +} + +char *DecodeUnicodeSpecialChars(unsigned char *buffer) +{ + int Pos=0, Pos2=0, level=0; + static unsigned char Buf[10000]; + + while (buffer[Pos*2]!=0x00 || buffer[Pos*2+1]!=0x00) { + Buf[Pos2*2] = buffer[Pos*2]; + Buf[Pos2*2+1] = buffer[Pos*2+1]; + switch (level) { + case 0: + if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == '\\') { + level = 1; + } else { + Pos2++; + } + break; + case 1: + if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 'n') { + Buf[Pos2*2] = 0; + Buf[Pos2*2+1] = 10; + } + if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 'r') { + Buf[Pos2*2] = 0; + Buf[Pos2*2+1] = 13; + } + if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == '\\') { + Buf[Pos2*2] = 0; + Buf[Pos2*2+1] = '\\'; + } + Pos2++; + level = 0; + } + Pos++; + } + Buf[Pos2*2] = 0; + Buf[Pos2*2+1] = 0; + return Buf; +} + +char *DecodeSpecialChars(unsigned char *buffer) +{ + int Pos=0, Pos2=0, level=0; + static unsigned char Buf[10000]; + + while (buffer[Pos]!=0x00) { + Buf[Pos2] = buffer[Pos]; + switch (level) { + case 0: + if (buffer[Pos] == '\\') { + level = 1; + } else { + Pos2++; + } + break; + case 1: + if (buffer[Pos] == 'n') Buf[Pos2] = 10; + if (buffer[Pos] == 'r') Buf[Pos2] = 13; + if (buffer[Pos] == '\\') Buf[Pos2] = '\\'; + Pos2++; + level = 0; + } + Pos++; + } + Buf[Pos2] = 0; + return Buf; +} + +char *mystrcasestr(unsigned const char *a, unsigned const char *b) +{ + unsigned char A[2000], B[200]; + int i; + + memset(A,0,sizeof(A)); + memset(B,0,sizeof(B)); + for (i=0;i<(int)strlen(a);i++) A[i] = tolower(a[i]); + for (i=0;i<(int)strlen(b);i++) B[i] = tolower(b[i]); + + return strstr(A,B); +} + unsigned int UnicodeLength(const unsigned char *str) { unsigned int len = 0; if (str == NULL) return 0; while(str[len*2] != 0 || str[len*2+1] != 0) len++; return len; } /* Convert Unicode char saved in src to dest */ unsigned int EncodeWithUnicodeAlphabet(const unsigned char *src, wchar_t *dest) { char retval; switch (retval = mbtowc(dest, src, MB_CUR_MAX)) { case -1 : case 0 : return 1; default : return retval; } } /* Convert Unicode char saved in src to dest */ unsigned int DecodeWithUnicodeAlphabet(wchar_t src, unsigned char *dest) { int retval; switch (retval = wctomb(dest, src)) { case -1: *dest = '?'; return 1; default: return retval; } } void DecodeUnicode (const unsigned char *src, unsigned char *dest) { int i=0,o=0; wchar_t wc; while (src[(2*i)+1]!=0x00 || src[2*i]!=0x00) { wc = src[(2*i)+1] | (src[2*i] << 8); o += DecodeWithUnicodeAlphabet(wc, dest + o); i++; } dest[o]=0; @@ -541,165 +694,165 @@ int GSM_PackSevenBitsToEight(int offset, unsigned char *input, unsigned char *ou unsigned char *OUTPUT = output; /* Current pointer to the output buffer */ unsigned char *INPUT = input; /* Current pointer to the input buffer */ int Bits; /* Number of bits directly copied to * the output buffer */ Bits = (7 + offset) % 8; /* If we don't begin with 0th bit, we will write only a part of the first octet */ if (offset) { *OUTPUT = 0x00; OUTPUT++; } while ((INPUT - input) < length) { unsigned char Byte = *INPUT; *OUTPUT = Byte >> (7 - Bits); /* If we don't write at 0th bit of the octet, we should write a second part of the previous octet */ if (Bits != 7) *(OUTPUT-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1); Bits--; if (Bits == -1) Bits = 7; else OUTPUT++; INPUT++; } return (OUTPUT - output); #else return 0; #endif } void GSM_UnpackSemiOctetNumber(unsigned char *retval, unsigned char *Number, bool semioctet) { unsigned char Buffer[50] = ""; int length = Number[0]; if (semioctet) { /* Convert number of semioctets to number of chars */ if (length % 2) length++; length=length / 2 + 1; } /*without leading byte with format of number*/ length--; - switch (Number[1]) { - case NUMBER_ALPHANUMERIC: + switch ((Number[1] & 112)) { + case (NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN & 112): if (length > 6) length++; dbgprintf("Alphanumeric number, length %i\n",length); GSM_UnpackEightBitsToSeven(0, length, length, Number+2, Buffer); Buffer[length]=0; break; - case NUMBER_INTERNATIONAL: + case (NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN & 112): dbgprintf("International number\n"); Buffer[0]='+'; DecodeBCD(Buffer+1,Number+2, length); break; default: dbgprintf("Default number %02x\n",Number[1]); DecodeBCD (Buffer, Number+2, length); break; } EncodeUnicode(retval,Buffer,strlen(Buffer)); } /** * Packing some phone numbers (SMSC, SMS destination and others) * * See GSM 03.40 9.1.1: * 1 byte - length of number given in semioctets or bytes (when given in * bytes, includes one byte for byte with number format). * Returned by function (set semioctet to true, if want result * in semioctets). * 1 byte - format of number (see GSM_NumberType in coding.h). Returned * in unsigned char *Output. * n bytes - 2n or 2n-1 semioctets with number. Returned in unsigned char * *Output. * * 1 semioctet = 4 bits = half of byte */ int GSM_PackSemiOctetNumber(unsigned char *Number, unsigned char *Output, bool semioctet) { unsigned char format, buffer[50]; int length, i; length=UnicodeLength(Number); memcpy(buffer,DecodeUnicodeString(Number),length+1); /* Checking for format number */ - format = NUMBER_UNKNOWN; + format = NUMBER_UNKNOWN_NUMBERING_PLAN_ISDN; for (i=0;i<length;i++) { /* first byte is '+'. Number can be international */ if (i==0 && buffer[i]=='+') { - format=NUMBER_INTERNATIONAL; + format=NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN; } else { /*char is not number. It must be alphanumeric*/ - if (!isdigit(buffer[i])) format=NUMBER_ALPHANUMERIC; + if (!isdigit(buffer[i])) format=NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN; } } /** * First byte is used for saving type of number. See GSM 03.40 * section 9.1.2.5 */ Output[0]=format; /* After number type we will have number. GSM 03.40 section 9.1.2 */ switch (format) { - case NUMBER_ALPHANUMERIC: + case NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN: length=GSM_PackSevenBitsToEight(0, buffer, Output+1, strlen(buffer))*2; if (strlen(buffer)==7) length--; break; - case NUMBER_INTERNATIONAL: + case NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN: length--; EncodeBCD (Output+1, buffer+1, length, true); break; default: EncodeBCD (Output+1, buffer, length, true); break; } if (semioctet) return length; /* Convert number of semioctets to number of chars */ if (length % 2) length++; return length / 2 + 1; } void CopyUnicodeString(unsigned char *Dest, unsigned char *Source) { int j = 0; while (Source[j]!=0x00 || Source[j+1]!=0x00) { Dest[j] = Source[j]; Dest[j+1] = Source[j+1]; j=j+2; } Dest[j] = 0; Dest[j+1] = 0; } /* Changes minor/major order in Unicode string */ void ReverseUnicodeString(unsigned char *String) { int j = 0; unsigned char byte1, byte2; while (String[j]!=0x00 || String[j+1]!=0x00) { byte1 = String[j]; byte2 = String[j+1]; String[j+1] = byte1; String[j] = byte2; j=j+2; } String[j] = 0; String[j+1] = 0; } /* All input is in Unicode. First char can show Unicode minor/major order. Output is Unicode string in Gammu minor/major order */ void ReadUnicodeFile(unsigned char *Dest, unsigned char *Source) @@ -874,193 +1027,193 @@ void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *sr } } if (special) { dest[current++] = 0x00; dest[current++] = 0x01; } dest[current++] = 0x00; dest[current++] = 0x00; } void DecodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, int len) { int i=0,current=0; for (i=0;i<len;i++) { switch (src[2*i]) { case 0x00: switch (src[2*i+1]) { case 0x01: dest[current++] = 0x00; dest[current++] = '~'; break; case '~': dest[current++] = 0x00; dest[current++] = '~'; dest[current++] = 0x00; dest[current++] = '~'; break; default: dest[current++] = src[i*2]; dest[current++] = src[i*2+1]; } break; default: dest[current++] = src[i*2]; dest[current++] = src[i*2+1]; } } dest[current++] = 0x00; dest[current++] = 0x00; } bool mystrncasecmp(unsigned const char *a, unsigned const char *b, int num) { int i; if (a == NULL || b == NULL) return false; - num--; + if (num == 0) num = -1; for (i = 0; i != num; i++) { if (a[i] == 0x00 && b[i] == 0x00) return true; if (a[i] == 0x00 || b[i] == 0x00) return false; if (tolower(a[i]) != tolower(b[i])) return false; } return true; } /* Compares two Unicode strings without regarding to case. * Return true, when they're equal */ bool mywstrncasecmp(unsigned const char *a, unsigned const char *b, int num) { int i; wchar_t wc,wc2; if (a == NULL || b == NULL) return false; - num--; + if (num == 0) num = -1; for (i = 0; i != num; i++) { if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) && (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return true; if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) || (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return false; wc = a[i*2+1] | (a[i*2] << 8); wc2 = b[i*2+1] | (b[i*2] << 8); if (mytowlower(wc) != mytowlower(wc2)) return false; } return true; } /* wcscmp in Mandrake 9.0 is wrong */ bool mywstrncmp(unsigned const char *a, unsigned const char *b, int num) { int i=0; while (1) { if (a[i*2] != b[i*2] || a[i*2+1] != b[i*2+1]) return false; if (a[i*2] == 0x00 && a[i*2+1] == 0x00) return true; i++; if (num == i) return true; } } /* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */ bool myiswspace(unsigned const char *src) { #ifndef HAVE_ISWSPACE int o; unsigned char dest[10]; #endif wchar_t wc; wc = src[1] | (src[0] << 8); #ifndef HAVE_ISWSPACE o = DecodeWithUnicodeAlphabet(wc, dest); if (o == 1) { if (isspace(((int)dest[0]))!=0) return true; return false; } return false; #else return iswspace(wc); #endif } /* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */ int mytowlower(wchar_t c) { #ifndef HAVE_TOWLOWER unsigned char dest[10]; DecodeWithUnicodeAlphabet(c, dest); return tolower(dest[0]); #else return towlower(c); #endif } /* * Following code is based on wcsstr from the GNU C Library, original * comment follows: */ /* * The original strstr() file contains the following comment: * * My personal strstr() implementation that beats most other algorithms. * Until someone tells me otherwise, I assume that this is the * fastest implementation of strstr() in C. * I deliberately chose not to comment it. You should have at least * as much fun trying to understand it, as I had to write it :-). * * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */ -unsigned char *mystrstr (const unsigned char *haystack, const unsigned char *needle) +unsigned char *mywstrstr (const unsigned char *haystack, const unsigned char *needle) { /* One crazy define to convert unicode used in Gammu to standard wchar_t */ #define tolowerwchar(x) (mytowlower((wchar_t)( (((&(x))[0] & 0xff) << 8) | (((&(x))[1] & 0xff)) ))) register wchar_t b, c; if ((b = tolowerwchar(*needle)) != L'\0') { haystack -= 2; /* possible ANSI violation */ do { haystack += 2; if ((c = tolowerwchar(*haystack)) == L'\0') goto ret0; } while (c != b); needle += 2; if ((c = tolowerwchar(*needle)) == L'\0') goto foundneedle; needle += 2; goto jin; for (;;) { register wchar_t a; register const unsigned char *rhaystack, *rneedle; do { haystack += 2; if ((a = tolowerwchar(*haystack)) == L'\0') goto ret0; if (a == b) break; haystack += 2; if ((a = tolowerwchar(*haystack)) == L'\0') goto ret0; shloop: ; } while (a != b); jin: haystack += 2; if ((a = tolowerwchar(*haystack)) == L'\0') goto ret0; if (a != c) goto shloop; rhaystack = haystack + 2; haystack -= 2; rneedle = needle; if (tolowerwchar(*rhaystack) == (a = tolowerwchar(*rneedle))) do { if (a == L'\0') |