1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 package org.marre.sms.transport.gsm;
36
37 import java.io.ByteArrayOutputStream;
38 import java.io.IOException;
39 import java.io.OutputStream;
40
41 import org.marre.sms.SmsAddress;
42 import org.marre.sms.SmsDcs;
43 import org.marre.sms.SmsException;
44 import org.marre.sms.SmsPdu;
45 import org.marre.sms.SmsPduUtil;
46 import org.marre.sms.SmsUserData;
47
48 /***
49 * Builds GSM pdu encoded messages.
50 *
51 * @todo Add support for validity period.
52 *
53 * @author Markus Eriksson
54 * @version $Id: GsmEncoder.java,v 1.7 2005/11/26 16:39:33 c95men Exp $
55 */
56 public final class GsmEncoder
57 {
58 private GsmEncoder()
59 {
60
61 }
62
63 /***
64 * Encodes the given sms pdu into a gsm sms pdu.
65 *
66 * @param thePdu
67 * @param theDestination
68 * @param theSender
69 * @return
70 * @throws SmsException
71 */
72 public static byte[] encodePdu(SmsPdu thePdu, SmsAddress theDestination, SmsAddress theSender)
73 throws SmsException
74 {
75 if (thePdu.getDcs().getAlphabet() == SmsDcs.ALPHABET_GSM)
76 {
77 return encodeSeptetPdu(thePdu, theDestination, theSender);
78 }
79 else
80 {
81 return encodeOctetPdu(thePdu, theDestination, theSender);
82 }
83 }
84
85 /***
86 * Encodes an septet encoded pdu.
87 *
88 * @param thePdu
89 * @param theDestination
90 * @param theSender
91 * @return
92 * @throws SmsException
93 */
94 private static byte[] encodeSeptetPdu(SmsPdu thePdu, SmsAddress theDestination, SmsAddress theSender)
95 throws SmsException
96 {
97 SmsUserData userData = thePdu.getUserData();
98 byte[] ud = userData.getData();
99 byte[] udh = thePdu.getUserDataHeaders();
100
101 int nUdSeptets = userData.getLength();
102 int nUdBits = 0;
103
104 int nUdhBytes = (udh == null) ? 0 : udh.length;
105
106
107 int nUdhBits = 0;
108
109
110 int nTotalBytes = 0;
111 int nTotalBits = 0;
112 int nTotalSeptets = 0;
113
114 int nFillBits = 0;
115
116 ByteArrayOutputStream baos = new ByteArrayOutputStream(161);
117
118 try
119 {
120
121 if (nUdhBytes == 0)
122 {
123
124
125
126
127
128
129 baos.write(0x01);
130 }
131 else
132 {
133
134 nUdhBits = nUdhBytes * 8;
135
136 if ( (nUdhBits % 7) > 0 )
137 {
138 nFillBits = 7 - (nUdhBits % 7);
139 }
140
141
142
143
144
145
146
147 baos.write(0x41);
148 }
149
150 nUdBits = nUdSeptets * 7;
151
152 nTotalBits = nUdBits + nFillBits + nUdhBits;
153 nTotalSeptets = nTotalBits / 7;
154
155 nTotalBytes = nTotalBits / 8;
156 if (nTotalBits % 8 > 0)
157 {
158 nTotalBytes += 1;
159 }
160
161
162
163 baos.write(0x00);
164
165
166
167
168
169
170
171
172
173 writeDestinationAddress(baos, theDestination);
174
175
176 baos.write(0x00);
177
178
179
180 baos.write(thePdu.getDcs().getValue());
181
182
183
184
185
186 if ((udh == null) || (udh.length == 0))
187 {
188
189 baos.write(nUdSeptets);
190
191
192 baos.write(ud);
193 }
194 else
195 {
196
197 byte[] fullUd = new byte[nTotalBytes];
198
199
200
201 baos.write(nTotalSeptets);
202
203
204 System.arraycopy(udh, 0, fullUd, 0, nUdhBytes);
205
206
207 SmsPduUtil.arrayCopy(ud, 0, fullUd, nUdhBytes, nFillBits, nUdBits);
208
209 baos.write(fullUd);
210 }
211 baos.close();
212 }
213 catch (IOException ex)
214 {
215 throw new SmsException(ex);
216 }
217
218 return baos.toByteArray();
219 }
220
221 /***
222 * Encodes an octet encoded sms pdu.
223 *
224 * @param thePdu
225 * @param theDestination
226 * @param theSender
227 * @return
228 * @throws SmsException
229 */
230 private static byte[] encodeOctetPdu(SmsPdu thePdu, SmsAddress theDestination, SmsAddress theSender)
231 throws SmsException
232 {
233 SmsUserData userData = thePdu.getUserData();
234 byte[] ud = userData.getData();
235 byte[] udh = thePdu.getUserDataHeaders();
236
237 ByteArrayOutputStream baos = new ByteArrayOutputStream(200);
238
239 try
240 {
241 int nUdBytes = userData.getLength();
242 int nUdhBytes = (udh == null) ? 0 : udh.length;
243
244 int tpUdl = nUdBytes + nUdhBytes + 1;
245
246
247 if (nUdhBytes == 0)
248 {
249
250
251
252
253
254
255 baos.write(0x01);
256 }
257 else
258 {
259
260
261
262
263
264
265 baos.write(0x41);
266 }
267
268
269
270 baos.write(0x00);
271
272
273
274
275
276
277
278
279
280 writeDestinationAddress(baos, theDestination);
281
282
283 baos.write(0x00);
284
285
286 baos.write(thePdu.getDcs().getValue());
287
288
289
290
291
292 if (nUdhBytes == 0)
293 {
294
295
296
297 baos.write(nUdBytes);
298
299
300
301 baos.write(ud);
302 }
303 else
304 {
305
306 byte[] fullUd = new byte[nUdBytes + nUdhBytes];
307
308
309
310 baos.write(nUdBytes + nUdhBytes);
311
312
313 System.arraycopy(udh, 0, fullUd, 0, nUdhBytes);
314
315 System.arraycopy(ud, 0, fullUd, nUdhBytes, nUdBytes);
316
317 baos.write(fullUd);
318 }
319 baos.close();
320 }
321 catch (IOException ex)
322 {
323 throw new SmsException(ex);
324 }
325
326 return baos.toByteArray();
327 }
328
329 /***
330 * Writes a destination address to the given stream in the correct format
331 *
332 * @param theOs Stream to write to
333 * @param theDestination Destination address to encode
334 * @throws IOException Thrown if failing to write to the stream
335 */
336 private static void writeDestinationAddress(OutputStream theOs, SmsAddress theDestination)
337 throws IOException
338 {
339 String address = theDestination.getAddress();
340 int ton = theDestination.getTypeOfNumber();
341 int npi = theDestination.getNumberingPlanIdentification();
342
343
344 if (address.charAt(0) == '+')
345 {
346 address = address.substring(1);
347 }
348
349
350 theOs.write(address.length());
351
352
353 theOs.write(0x80 | ton << 4 | npi);
354
355
356 SmsPduUtil.writeBcdNumber(theOs, address);
357 }
358 }