summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/misc/coding/coding.c
Side-by-side diff
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.c177
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')