View Javadoc
1   package net.sf.atmodem4j.core.gsm;
2   
3   /*
4    * #%L
5    * ATModem4J Core
6    * %%
7    * Copyright (C) 2009 - 2014 atmodem4j
8    * %%
9    * atmodem4j - Drivers for the AT modem - http://atmodem4j.sourceforge.net/
10   * Copyright (C) 2009-2014, atmodem4j.sf.net, and individual contributors as indicated
11   * by the @authors tag. See the copyright.txt in the distribution for a
12   * full listing of individual contributors.
13   * 
14   * This is free software; you can redistribute it and/or modify it
15   * under the terms of the GNU General Public License as
16   * published by the Free Software Foundation; either version 3 of
17   * the License, or (at your option) any later version.
18   * 
19   * This software is distributed in the hope that it will be useful,
20   * but WITHOUT ANY WARRANTY; without even the implied warranty of
21   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22   * Lesser General Public License for more details.
23   * 
24   * You should have received a copy of the GNU Lesser General Public
25   * License along with this software; if not, write to the Free
26   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
27   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
28   * #L%
29   */
30  
31  import java.util.Arrays;
32  import net.sf.atmodem4j.core.gsm.Pdu.EncodingException;
33  
34  abstract class UserData {
35  
36      public abstract Pdu.Encoding getEncoding();
37  
38      public abstract void setText(String text);
39  
40      public abstract String getText();
41  
42      public abstract int getUserDataLength(int userDataHeaderLength);
43  
44      public abstract void setBytes(byte[] data);
45  
46      public abstract byte[] getBytes();
47  
48      public abstract void decodePduData(byte[] data, int userDataLength,
49              int userDataHeaderLength);
50  
51      public abstract String encodePduData(int userDataHeaderLength);
52  
53      public static String formatOctet(int octet) {
54          return String.format("%02X", (octet & 0x00FF));
55      }
56  
57  
58      static class Text7Bit extends UserData {
59  
60          static int[] getSplitPos(String messageText) throws
61                  Pdu.EncodingException {
62              int[] chunks = new int[1];
63              int chunksize = 0;
64              int septetsize = 0;
65              for (int i = 0; i < messageText.length(); i++) {
66                  Entry7BitEncoding e = Entry7BitEncoding.findByChar(messageText.
67                          charAt(i));
68                  if (e == null) {
69                      throw new Pdu.EncodingException("Cant encode char " +
70                              messageText.charAt(i));
71                  }
72                  if (e.isEscaped()) {
73                      septetsize += 2;
74                      if (chunksize >= 152) {
75                          chunks[chunks.length - 1] = i;
76                          chunks = Arrays.copyOf(chunks, chunks.length + 1);
77                          chunksize = 0;
78                      }
79                      chunksize += 2;
80                  } else {
81                      septetsize++;
82                      if (chunksize >= 153) {
83                          chunks[chunks.length - 1] = i;
84                          chunks = Arrays.copyOf(chunks, chunks.length + 1);
85                          chunksize = 0;
86                      }
87                      chunksize++;
88                  }
89              }
90              if (septetsize <= 160) {
91                  return new int[]{messageText.length()};
92              }
93              if (chunksize > 0) {
94                  chunks[chunks.length - 1] = messageText.length();
95              }
96              return chunks;
97          }
98          private String text;
99  
100         public Pdu.Encoding getEncoding() {
101             return Pdu.Encoding.TEXT_7BIT;
102         }
103 
104         @Override
105         public String getText() {
106             return text;
107         }
108 
109         @Override
110         public void decodePduData(byte[] data, int userDataLength,
111                 int userDataHeaderLength) {
112             StringBuilder sb = new StringBuilder(data.length * 8 / 7);
113 
114             int bitPos = (userDataHeaderLength * 8) % 7;
115             int expectedtChars = userDataLength - calcBytesToSeptets(userDataHeaderLength);
116             if (bitPos != 0) {
117                 bitPos -= 7;
118             }
119             int buffer = 0;
120             int currentChar = 0;
121             boolean escaped = false;
122 
123             for (int pos = 0; pos < data.length; pos++) {
124 
125                 if (bitPos < 0) {
126                     // begin ... move septet alignment bits out...
127                     buffer |= (data[pos] & 0xFF) >> -bitPos;
128                 } else {
129                     buffer |= (data[pos] & 0xFF) << bitPos;
130                 }
131                 bitPos += 8;
132 
133                 while (bitPos >= 7) {
134                     currentChar = buffer & 0x7F;
135                     buffer >>= 7;
136                     bitPos -= 7;
137 
138                     if (escaped) {
139                         escaped = false;
140                         sb.append(Entry7BitEncoding.findByPdu(currentChar |
141                                 Entry7BitEncoding.ESC_SHORT).c);
142                     } else {
143                         escaped = currentChar ==
144                                 Entry7BitEncoding.ESC_IN_PDU_OCTET;
145                         if (!escaped) {
146                             sb.append(Entry7BitEncoding.findByPdu(currentChar).c);
147                         }
148                     }
149                     if (sb.length() == expectedtChars) {
150                         if (pos != data.length - 1) {
151                             throw new RuntimeException(String.format("expectedtChars %d reached, but pos %d mismatch length %d",  expectedtChars, pos, data.length -1));
152                         }
153                         break;
154                     }
155                 }
156                     if (sb.length() == expectedtChars) {
157                         if (pos != data.length - 1) {
158                             throw new RuntimeException(String.format("expectedtChars %d reached, but pos %d mismatch length %d",  expectedtChars, pos, data.length -1));
159                         }
160                 }
161             }
162             text = sb.toString();
163         }
164 
165         @Override
166         public void setText(String text) {
167             this.text = text;
168         }
169 
170         int calcBytesToSeptets(int lengthInBytes) {
171             return (lengthInBytes * 8) / 7 + (((lengthInBytes * 8) % 7) > 0 ? 1 : 0);
172         }
173 
174         @Override
175         public int getUserDataLength(int userDataHeaderLength) {
176             try {
177                 return getSeptets() + calcBytesToSeptets(userDataHeaderLength);
178             } catch (EncodingException ex) {
179                 throw new RuntimeException(ex);
180             }
181         }
182 
183         @Override
184         public void setBytes(byte[] data) {
185             throw new UnsupportedOperationException("Not supported yet.");
186         }
187 
188         @Override
189         public byte[] getBytes() {
190             throw new UnsupportedOperationException("Not supported yet.");
191         }
192 
193         private int getSeptets() throws Pdu.EncodingException {
194             int result = 0;
195             for (int i = 0; i < text.length(); i++) {
196                 Entry7BitEncoding e = Entry7BitEncoding.findByChar(
197                         text.charAt(i));
198                 if (e == null) {
199                     throw new Pdu.EncodingException("Cant encode char " +
200                             text.charAt(i));
201                 }
202                 if (e.isEscaped()) {
203                     result += 2;
204                 } else {
205                     result++;
206                 }
207             }
208             return result;
209         }
210 
211         @Override
212         public String encodePduData(int userDataHeaderLength) {
213             //TODO SPLIT IF MULTI !!!
214             StringBuilder sb = new StringBuilder();
215             int bitPos = 7 - (userDataHeaderLength * 8) % 7;
216             if (bitPos == 7) {
217                 bitPos = 0;
218             }
219             int octet = 0;
220             int currentChar;
221             for (int pos = 0; pos < text.length(); pos++) {
222 
223                 Entry7BitEncoding e = Entry7BitEncoding.findByChar(
224                         text.charAt(pos));
225                 if (e == null) {
226                     throw new RuntimeException("Cant encode char " +
227                             text.charAt(pos));
228                 }
229                 if (e.isEscaped()) {
230                     currentChar = e.ESC_IN_PDU_OCTET;
231                     currentChar <<= bitPos;
232                     octet += currentChar;
233                     bitPos += 7;
234 
235                     currentChar = e.pdu & 0x00FF;
236                     currentChar <<= bitPos;
237                     octet += currentChar;
238                     bitPos += 7;
239 
240                 } else {
241                     currentChar = e.pdu;
242                     currentChar <<= bitPos;
243                     octet += currentChar;
244                     bitPos += 7;
245                 }
246 
247 
248                 while (bitPos > 15) {
249                     sb.append(shortToOctetString((short) octet));
250                     octet >>= 16;
251                     bitPos -= 16;
252                 }
253 
254             }
255 
256             if (bitPos > 8) {
257                 sb.append(shortToOctetString((short) octet));
258                 octet >>= 16;
259                 bitPos = 0;
260             }
261 
262             if (bitPos > 0) {
263                 sb.append(formatOctet(octet));
264                 octet >>= 8;
265                 bitPos = 0;
266             }
267 
268             return sb.toString();
269         }
270     }
271 
272     public static String shortToOctetString(short octet) {
273             return String.format("%02X%02X", (octet & 0x00FF), ((octet >> 8) &
274                     0x00FF));
275         }
276 
277     static class Text16Bit extends UserData {
278 
279         static Iterable<UserData> split(String messageText) {
280             throw new UnsupportedOperationException("Not yet implemented");
281         }
282         private String text;
283 
284         public Pdu.Encoding getEncoding() {
285             return Pdu.Encoding.TEXT_16BIT;
286         }
287 
288         @Override
289         public String getText() {
290             return text;
291         }
292 
293         @Override
294         public void decodePduData(byte[] data, int userDataLength,
295                 int userDataHeaderLength) {
296             throw new UnsupportedOperationException("Not supported yet.");
297         }
298 
299         @Override
300         public void setText(String text) {
301             throw new UnsupportedOperationException("Not supported yet.");
302         }
303 
304         @Override
305         public int getUserDataLength(int userDataHeaderLength) {
306             throw new UnsupportedOperationException("Not supported yet.");
307         }
308 
309         @Override
310         public void setBytes(byte[] data) {
311             throw new UnsupportedOperationException("Not supported yet.");
312         }
313 
314         @Override
315         public byte[] getBytes() {
316             throw new UnsupportedOperationException("Not supported yet.");
317         }
318 
319         @Override
320         public String encodePduData(int userDataHeaderLength) {
321             throw new UnsupportedOperationException("Not supported yet.");
322         }
323     }
324 
325     static class Data8Bit extends UserData {
326 
327         private byte[] data;
328 
329         public Pdu.Encoding getEncoding() {
330             return Pdu.Encoding.DATA_8BIT;
331         }
332 
333         @Override
334         public String getText() {
335             throw new UnsupportedOperationException("Not supported yet.");
336         }
337 
338         @Override
339         public void decodePduData(byte[] data, int userDataLength,
340                 int userDataHeaderLength) {
341             throw new UnsupportedOperationException("Not supported yet.");
342         }
343 
344         @Override
345         public void setText(String text) {
346             throw new UnsupportedOperationException("Not supported yet.");
347         }
348 
349         @Override
350         public int getUserDataLength(int userDataHeaderLength) {
351             throw new UnsupportedOperationException("Not supported yet.");
352         }
353 
354         @Override
355         public void setBytes(byte[] data) {
356             throw new UnsupportedOperationException("Not supported yet.");
357         }
358 
359         @Override
360         public byte[] getBytes() {
361             throw new UnsupportedOperationException("Not supported yet.");
362         }
363 
364         @Override
365         public String encodePduData(int userDataHeaderLength) {
366             throw new UnsupportedOperationException("Not supported yet.");
367         }
368     }
369 }