\r\n -> \n
[gnokii.git] / common / gsm-encoding.c
1 /*
2
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 2001 Pawe³ Kot <pkot@linuxnews.pl>
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   Functions for encoding SMS, calendar and other things.
14
15   $Log$
16   Revision 1.1.1.1  2001/11/25 21:59:06  short
17   :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
18
19   Revision 1.4  2001/11/22 17:56:53  pkot
20   smslib update. sms sending
21
22   Revision 1.3  2001/11/17 20:15:31  pkot
23   Typo in default alphabet
24
25   Revision 1.2  2001/11/08 16:34:19  pkot
26   Updates to work with new libsms
27
28   Revision 1.1  2001/10/24 22:37:25  pkot
29   Moved encoding functions to a separate file
30
31
32 */
33
34 #include <stdlib.h>
35
36 #define NUMBER_OF_7_BIT_ALPHABET_ELEMENTS 128
37
38 static unsigned char GSM_DefaultAlphabet[NUMBER_OF_7_BIT_ALPHABET_ELEMENTS] = {
39
40         /* ETSI GSM 03.38, version 6.0.1, section 6.2.1; Default alphabet */
41         /* Characters in hex position 10, [12 to 1a] and 24 are not present on
42            latin1 charset, so we cannot reproduce on the screen, however they are
43            greek symbol not present even on my Nokia */
44         
45         '@',  0xa3, '$',  0xa5, 0xe8, 0xe9, 0xf9, 0xec, 
46         0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
47         '?',  '_',  '?',  '?',  '?',  '?',  '?',  '?',
48         '?',  '?',  '?',  '?',  0xc6, 0xe6, 0xdf, 0xc9,
49         ' ',  '!',  '\"', '#',  0xa4,  '%',  '&',  '\'',
50         '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
51         '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
52         '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
53         0xa1, 'A',  'B',  'C',  'D',  'E',  'F',  'G',
54         'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
55         'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',
56         'X',  'Y',  'Z',  0xc4, 0xd6, 0xd1, 0xdc, 0xa7,
57         0xbf, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
58         'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
59         'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
60         'x',  'y',  'z',  0xe4, 0xf6, 0xf1, 0xfc, 0xe0
61 };
62
63 static unsigned char EncodeWithDefaultAlphabet(unsigned char value)
64 {
65         unsigned char i;
66         
67         if (value == '?') return  0x3f;
68         
69         for (i = 0; i < NUMBER_OF_7_BIT_ALPHABET_ELEMENTS; i++)
70                 if (GSM_DefaultAlphabet[i] == value)
71                         return i;
72         
73         return '?';
74 }
75
76 static wchar_t EncodeWithUnicodeAlphabet(unsigned char value)
77 {
78         wchar_t retval;
79
80         if (mbtowc(&retval, &value, 1) == -1) return '?';
81         else return retval;
82 }
83
84 static unsigned char DecodeWithDefaultAlphabet(unsigned char value)
85 {
86         return GSM_DefaultAlphabet[value];
87 }
88
89 static unsigned char DecodeWithUnicodeAlphabet(wchar_t value)
90 {
91         unsigned char retval;
92
93         if (wctomb(&retval, value) == -1) return '?';
94         else return retval;
95 }
96
97
98 #define ByteMask ((1 << Bits) - 1)
99
100 int Unpack7BitCharacters(int offset, int in_length, int out_length,
101                          unsigned char *input, unsigned char *output)
102 {
103         unsigned char *OUT = output; /* Current pointer to the output buffer */
104         unsigned char *IN  = input;  /* Current pointer to the input buffer */
105         unsigned char Rest = 0x00;
106         int Bits;
107
108         Bits = offset ? offset : 7;
109
110         while ((IN - input) < in_length) {
111
112                 *OUT = ((*IN & ByteMask) << (7 - Bits)) | Rest;
113                 Rest = *IN >> Bits;
114
115                 /* If we don't start from 0th bit, we shouldn't go to the
116                    next char. Under *OUT we have now 0 and under Rest -
117                    _first_ part of the char. */
118                 if ((IN != input) || (Bits == 7)) OUT++;
119                 IN++;
120
121                 if ((OUT - output) >= out_length) break;
122
123                 /* After reading 7 octets we have read 7 full characters but
124                    we have 7 bits as well. This is the next character */
125                 if (Bits == 1) {
126                         *OUT = Rest;
127                         OUT++;
128                         Bits = 7;
129                         Rest = 0x00;
130                 } else {
131                         Bits--;
132                 }
133         }
134
135         return OUT - output;
136 }
137
138 int Pack7BitCharacters(int offset, unsigned char *input, unsigned char *output)
139 {
140
141         unsigned char *OUT = output; /* Current pointer to the output buffer */
142         unsigned char *IN  = input;  /* Current pointer to the input buffer */
143         int Bits;                    /* Number of bits directly copied to
144                                         the output buffer */
145
146         Bits = (7 + offset) % 8;
147
148         /* If we don't begin with 0th bit, we will write only a part of the
149            first octet */
150         if (offset) {
151                 *OUT = 0x00;
152                 OUT++;
153         }
154
155         while ((IN - input) < strlen(input)) {
156
157                 unsigned char Byte = EncodeWithDefaultAlphabet(*IN);
158                 *OUT = Byte >> (7 - Bits);
159                 /* If we don't write at 0th bit of the octet, we should write
160                    a second part of the previous octet */
161                 if (Bits != 7)
162                         *(OUT-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1);
163
164                 Bits--;
165
166                 if (Bits == -1) Bits = 7;
167                 else OUT++;
168
169                 IN++;
170         }
171
172         return (OUT - output);
173 }
174
175 void DecodeAscii (unsigned char* dest, const unsigned char* src, int len)
176 {
177         int i;
178
179         for (i = 0; i < len; i++)
180                 dest[i] = DecodeWithDefaultAlphabet(src[i]);
181         return;
182 }
183
184 void EncodeAscii (unsigned char* dest, const unsigned char* src, int len)
185 {
186         int i;
187
188         for (i = 0; i < len; i++)
189                 dest[i] = EncodeWithDefaultAlphabet(src[i]);
190         return;
191 }
192
193 void DecodeUnicode (unsigned char* dest, const unsigned char* src, int len)
194 {
195         int i;
196         wchar_t wc;
197
198         for (i = 0; i < len; i++) {
199                 wc = src[(2*i)+1] | (src[2*i] << 8);
200                 dest[i] = DecodeWithUnicodeAlphabet(wc);
201         }
202         dest[len]=0;
203         return;
204 }
205
206 void EncodeUnicode (unsigned char* dest, const unsigned char* src, int len)
207 {
208         int i;
209         wchar_t wc;
210
211         for (i = 0; i < len; i++) {
212                 wc = EncodeWithUnicodeAlphabet(src[i]);
213                 dest[i*2] = (wc >> 8) &0xff;
214                 dest[(i*2)+1] = wc & 0xff;
215         }
216         return;
217 }