Source code: fi/kvanttisofta/sms/SmsPduCodec.java
1 //
2 // Copyright (c) 2001 Kvanttisofta oy. All rights reserved.
3 //
4 //
5 // SMS PDU coder/encoder class.
6 // (aspa@users.sourceforge.net).
7 //
8 // $Id: SmsPduCodec.java,v 1.1.1.1 2001/04/18 04:19:00 aspa Exp $.
9 //
10 // (based on info from: http://www.sics.se/~lpe/help/sms/)
11 //
12 // TODO:
13 // - more characters in GSM <==> ISO-8859-1 mapping.
14 // - GSM 7-bit alphabet extension table character support.
15 //
16 //
17
18 //
19 // NB1: with jikes you have to use the '-encoding 8859_1' option.
20 //
21
22 package fi.kvanttisofta.sms;
23
24 public class SmsPduCodec {
25 private static final char EMPTYCHAR = 0x100;
26 private static final char EXTTABLEESCAPE = 0x1B;
27 private static char[] gsmToIsoMap; // GSM ==> ISO88591
28 private static char[] gsmToIsoExtMap;
29 private static char[] isoToGsmMap; // ISO88591 ==> GSM
30 private static char[] isoToGsmExtMap;
31
32 private static char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7',
33 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
34 };
35
36 // swaps characters of every two character substring of a string.
37 public static String swapDigits(String str) {
38 if( str == null )
39 return str;
40
41 int strlen = str.length();
42 StringBuffer sb = new StringBuffer(strlen);
43
44 for(int i=0; (i+1) < strlen; i=i+2) {
45 sb.append(str.charAt(i+1));
46 sb.append(str.charAt(i));
47 }
48 return new String(sb);
49 }
50
51 // returns a hex string representation of a 8 bit integer.
52 public static String toHexString(int b) {
53 char[] digits = new char[2];
54 b = b & 255;
55
56 digits[0] = hexDigits[b / 0x10];
57 digits[1] = hexDigits[b % 0x10];
58
59 return new String(digits);
60 }
61
62 // returns an input string as a hex string. for debugging.
63 public static String hexDump(String s) {
64 StringBuffer dump = new StringBuffer();
65 for(int i = 0; i<s.length(); i++)
66 dump.append(SmsPduCodec.toHexString(s.charAt(i)));
67 return new String(dump);
68 }
69
70 // converts a string of 7 bit characters to a sequence of
71 // of 8 bit bytes encoded as hex strings.
72 public static String sevenBitEncode(String message) {
73 if(message == null)
74 return message;
75 StringBuffer msg = new StringBuffer(message);
76
77 StringBuffer encmsg = new StringBuffer(2*160);
78 int bb = 0, bblen = 0, i;
79 char o=0, c=0, tc;
80
81 for(i=0; i < msg.length() || bblen>=8; i++) {
82 if(i<msg.length()) {
83 c = msg.charAt(i);
84 tc = isoToGsmMap[c];
85 /*
86 if(tc == EXTTABLEESCAPE) {
87 //msg.insert(i+1, isoToGsmExtMap[c]);
88 }
89 */
90 c = tc;
91
92 c &= ~(1 << 7); // clear (discard) eight bit.
93 bb |= (c << bblen); // insert c to bb.
94 bblen += 7;
95 }
96
97 while(bblen >= 8) { // we have a full octet.
98 o = (char) (bb & 255); // take 8 bits.
99 encmsg.append(SmsPduCodec.toHexString(o));
100 bb >>>= 8;
101 bblen -= 8;
102 }
103
104 } // end: for(i=0; i<msglen || bblen>=8; i++) {
105
106 if( (bblen > 0) )
107 encmsg.append(SmsPduCodec.toHexString(bb));
108
109 return encmsg.toString();
110 }
111
112 public static String sevenBitDecode(String encmsg) {
113 return sevenBitDecode(encmsg, encmsg.length());
114 }
115
116 // converts a sequence of 8 bit bytes encoded as hex
117 // strings to a string of 7 bit characters.
118 public static String sevenBitDecode(String encmsg, int msglen)
119 throws NumberFormatException {
120 // encmsg: encoded string to decode.
121 // msglen: the requested number of characters to decode.
122
123 int i, o, r=0, rlen=0, olen=0, charcnt=0; // ints are 32 bit long.
124 StringBuffer msg = new StringBuffer(160);
125 int encmsglen = encmsg.length();
126 String ostr;
127 boolean exttableescape = false;
128 char c;
129
130 // assumes even number of chars in octet string.
131 for(i=0; ((i+1)<encmsglen) && (charcnt<msglen); i=i+2) {
132 ostr = encmsg.substring(i, i+2);
133 o = Integer.parseInt(ostr, 16);
134 olen = 8;
135
136 if(rlen >= 7) { // take a full char off remainder.
137 c = (char) (r & 127);
138 r >>>= 7;
139 rlen -= 7;
140 msg.append(c);
141 charcnt++;
142 }
143
144 o <<= rlen; // push remainding bits from r to o.
145 o |= r;
146 olen += rlen;
147
148 c = (char) (o & 127); // get first 7 bits from o.
149 o >>>= 7;
150 olen -= 7;
151
152 r = o; // put remainding bits from o to r.
153 rlen = olen;
154
155 // handle character conversion.
156 c = gsmToIsoMap[c];
157
158 if( c == EXTTABLEESCAPE ) { // ext table character handling.
159 exttableescape = true;
160 continue;
161 } else if( exttableescape == true) {
162 exttableescape = false;
163 c = gsmToIsoExtMap[c];
164 }
165
166 msg.append(c);
167 charcnt++;
168 } // end: for(i=0; ((i+1)<encmsglen) && (charcnt<msglen); i=i+2) {
169
170 if( (rlen>0) && (charcnt<msglen) )
171 msg.append((char)r);
172
173 return msg.toString();
174 }
175
176 // class initialization.
177 static {
178 // construct GSM alphabet to/from ISO mappings.
179 char[] gsmiso = { 0, '@', 1, '£', 2, '$', 14, 'Å', 15, 'å', 17, '_',
180 91, 'Ä', 92, 'Ö', 95, '§', 123, 'ä', 124, 'ö'
181 };
182 char[] gsmisoext = { 0x14, '^', 0x28, '{', 0x29, '}', 0x2f, '\\',
183 0x3c, '[', 0x3d, '~', 0x3e, ']', 0x40, '|'
184 };
185
186 final int lastindex = 255;
187 gsmToIsoMap = new char[lastindex+1]; // one too many allocated
188 gsmToIsoExtMap = new char[lastindex+1];
189 isoToGsmMap = new char[lastindex+1];
190 isoToGsmExtMap = new char[lastindex+1];
191 int i, gsmisolen, gsmisoextlen;
192
193 for(i=0; i<=lastindex; i++) {
194 gsmToIsoMap[i] = gsmToIsoExtMap[i] = isoToGsmMap[i] = (char)i;
195 }
196
197 gsmisolen = gsmiso.length;
198 for(i = 0; (i+1) < gsmisolen; i=i+2) {
199 gsmToIsoMap[(int)gsmiso[i]] = gsmiso[i+1];
200 isoToGsmMap[(int)gsmiso[i+1]] = gsmiso[i];
201 }
202
203 gsmisoextlen = gsmisoext.length;
204 for(i = 0; (i+1) < gsmisoextlen; i=i+2) {
205 gsmToIsoExtMap[gsmisoext[i]] = gsmisoext[i+1];
206 //isoToGsmExtMap[gsmisoext[i+1]] = gsmisoext[i];
207 //isoToGsmMap[gsmisoext[i+1]] = EXTTABLEESCAPE;
208 }
209
210 }
211
212 public static void main(String[] args) {
213 // test encoding and decoding a string.
214 String s1 = "hellohello";
215 String s1enc_orig = new String("E8329BFD4697D9EC37");
216 String s1enc_my = sevenBitEncode(s1);
217 String s1dec = sevenBitDecode(s1enc_my, s1.length());
218 System.err.println("s1enc str: " + s1enc_my + ", dec: " + s1dec);
219 System.err.println("hellohello: " + s1enc_orig);
220
221 // test encoding and decoding a string. len: 7*8.
222 System.err.println("");
223 String s3 = "tama on pitka viesti. tuleeko tama oikein. jos ei miksi?";
224 System.err.println("s3 len: " + s3.length());
225 String s3enc = sevenBitEncode(s3);
226 String s3dec = sevenBitDecode(s3enc, s3.length());
227 System.err.println("s3: " + s3);
228 System.err.println("s3enc: " + s3enc);
229 System.err.println("s3dec: " + s3dec);
230
231 }
232
233 }