1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony; 18 19 import android.telephony.TelephonyManager; 20 import android.test.AndroidTestCase; 21 import android.test.suitebuilder.annotation.SmallTest; 22 23 import com.android.internal.telephony.gsm.SmsMessage; 24 import com.android.internal.util.HexDump; 25 26 import java.util.ArrayList; 27 28 public class GsmSmsTest extends AndroidTestCase { 29 30 @SmallTest testAddressing()31 public void testAddressing() throws Exception { 32 String pdu = "07914151551512f2040B916105551511f100006060605130308A04D4F29C0E"; 33 SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 34 assertEquals("+14155551212", sms.getServiceCenterAddress()); 35 assertEquals("+16505551111", sms.getOriginatingAddress()); 36 assertEquals("Test", sms.getMessageBody()); 37 38 pdu = "07914151551512f2040B916105551511f100036060924180008A0DA" 39 + "8695DAC2E8FE9296A794E07"; 40 sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 41 assertEquals("+14155551212", sms.getServiceCenterAddress()); 42 assertEquals("+16505551111", sms.getOriginatingAddress()); 43 assertEquals("(Subject)Test", sms.getMessageBody()); 44 } 45 46 @SmallTest testUdh()47 public void testUdh() throws Exception { 48 String pdu = "07914140279510F6440A8111110301003BF56080207130138A8C0B05040B8423F" 49 + "000032A02010106276170706C69636174696F6E2F766E642E7761702E6D6D732D" 50 + "6D65737361676500AF848D0185B4848C8298524E453955304A6D7135514141426" 51 + "66C414141414D7741414236514141414141008D908918802B3135313232393737" 52 + "3638332F545950453D504C4D4E008A808E022B918805810306977F83687474703" 53 + "A2F2F36"; 54 SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 55 SmsHeader header = sms.getUserDataHeader(); 56 assertNotNull(header); 57 assertNotNull(header.concatRef); 58 assertEquals(header.concatRef.refNumber, 42); 59 assertEquals(header.concatRef.msgCount, 2); 60 assertEquals(header.concatRef.seqNumber, 1); 61 assertEquals(header.concatRef.isEightBits, true); 62 assertNotNull(header.portAddrs); 63 assertEquals(header.portAddrs.destPort, 2948); 64 assertEquals(header.portAddrs.origPort, 9200); 65 assertEquals(header.portAddrs.areEightBits, false); 66 67 pdu = "07914140279510F6440A8111110301003BF56080207130238A3B0B05040B8423F" 68 + "000032A0202362E3130322E3137312E3135302F524E453955304A6D7135514141" 69 + "42666C414141414D774141423651414141414100"; 70 sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 71 header = sms.getUserDataHeader(); 72 assertNotNull(header); 73 assertNotNull(header.concatRef); 74 assertEquals(header.concatRef.refNumber, 42); 75 assertEquals(header.concatRef.msgCount, 2); 76 assertEquals(header.concatRef.seqNumber, 2); 77 assertEquals(header.concatRef.isEightBits, true); 78 assertNotNull(header.portAddrs); 79 assertEquals(header.portAddrs.destPort, 2948); 80 assertEquals(header.portAddrs.origPort, 9200); 81 assertEquals(header.portAddrs.areEightBits, false); 82 } 83 84 @SmallTest testUcs2()85 public void testUcs2() throws Exception { 86 String pdu = "07912160130300F4040B914151245584F600087010807121352B1021220" 87 + "0A900AE00680065006C006C006F"; 88 SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 89 assertEquals("\u2122\u00a9\u00aehello", sms.getMessageBody()); 90 } 91 92 @SmallTest testMultipart()93 public void testMultipart() throws Exception { 94 /* 95 * Multi-part text SMS with septet data. 96 */ 97 String pdu = "07916163838408F6440B816105224431F700007060217175830AA0050003" 98 + "00020162B1582C168BC562B1582C168BC562B1582C168BC562B1582C" 99 + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" 100 + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" 101 + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" 102 + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562"; 103 SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 104 assertEquals(sms.getMessageBody(), 105 "1111111111111111111111111111111111111111" 106 + "1111111111111111111111111111111111111111" 107 + "1111111111111111111111111111111111111111" 108 + "111111111111111111111111111111111"); 109 110 pdu = "07916163838408F6440B816105224431F700007060217185000A23050003" 111 + "00020262B1582C168BC96432994C2693C96432994C2693C96432990C"; 112 sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 113 assertEquals("1111111222222222222222222222", sms.getMessageBody()); 114 } 115 116 @SmallTest testCPHSVoiceMail()117 public void testCPHSVoiceMail() throws Exception { 118 // "set MWI flag" 119 120 String pdu = "07912160130310F20404D0110041006060627171118A0120"; 121 122 SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 123 124 assertTrue(sms.isReplace()); 125 assertEquals("_@", sms.getOriginatingAddress()); 126 assertEquals(" ", sms.getMessageBody()); 127 assertTrue(sms.isMWISetMessage()); 128 129 // "clear mwi flag" 130 131 pdu = "07912160130310F20404D0100041006021924193352B0120"; 132 133 sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 134 135 assertTrue(sms.isMWIClearMessage()); 136 137 // "clear MWI flag" 138 139 pdu = "07912160130310F20404D0100041006060627161058A0120"; 140 141 sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 142 143 assertTrue(sms.isReplace()); 144 assertEquals("\u0394@", sms.getOriginatingAddress()); 145 assertEquals(" ", sms.getMessageBody()); 146 assertTrue(sms.isMWIClearMessage()); 147 } 148 149 @SmallTest testCingularVoiceMail()150 public void testCingularVoiceMail() throws Exception { 151 // "set MWI flag" 152 153 String pdu = "07912180958750F84401800500C87020026195702B06040102000200"; 154 SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 155 156 assertTrue(sms.isMWISetMessage()); 157 assertTrue(sms.isMwiDontStore()); 158 159 // "clear mwi flag" 160 161 pdu = "07912180958750F84401800500C07020027160112B06040102000000"; 162 sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 163 164 assertTrue(sms.isMWIClearMessage()); 165 assertTrue(sms.isMwiDontStore()); 166 } 167 168 @SmallTest testEmailGateway()169 public void testEmailGateway() throws Exception { 170 String pdu = "07914151551512f204038105f300007011103164638a28e6f71b50c687db" + 171 "7076d9357eb7412f7a794e07cdeb6275794c07bde8e5391d247e93f3"; 172 173 SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 174 175 assertEquals("+14155551212", sms.getServiceCenterAddress()); 176 assertTrue(sms.isEmail()); 177 assertEquals("foo@example.com", sms.getEmailFrom()); 178 assertEquals("foo@example.com", sms.getDisplayOriginatingAddress()); 179 // As of https://android-git.corp.google.com/g/#change,9324 180 // getPseudoSubject will always be empty, and any subject is not extracted. 181 assertEquals("", sms.getPseudoSubject()); 182 assertEquals("test subject /test body", sms.getDisplayMessageBody()); 183 assertEquals("test subject /test body", sms.getEmailBody()); 184 185 // email gateway sms test, including gsm extended character set. 186 pdu = "07914151551512f204038105f400007011103105458a29e6f71b50c687db" + 187 "7076d9357eb741af0d0a442fcfe9c23739bfe16d289bdee6b5f1813629"; 188 189 sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 190 191 assertEquals("+14155551212", sms.getServiceCenterAddress()); 192 assertTrue(sms.isEmail()); 193 assertEquals("foo@example.com", sms.getDisplayOriginatingAddress()); 194 assertEquals("foo@example.com", sms.getEmailFrom()); 195 assertEquals("{ testBody[^~\\] }", sms.getDisplayMessageBody()); 196 assertEquals("{ testBody[^~\\] }", sms.getEmailBody()); 197 } 198 199 @SmallTest testExtendedCharacterTable()200 public void testExtendedCharacterTable() throws Exception { 201 String pdu = "07914151551512f2040B916105551511f100006080615131728A44D4F29C0E2" + 202 "AE3E96537B94C068DD16179784C2FCB41F4B0985D06B958ADD00FB0E94536AF9749" + 203 "74DA6D281BA00E95E26D509B946FC3DBF87A25D56A04"; 204 205 SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); 206 207 assertEquals("+14155551212", sms.getServiceCenterAddress()); 208 assertEquals("+16505551111", sms.getOriginatingAddress()); 209 assertEquals("Test extended character table .,-!?@~_\\/&\"';^|:()<{}>[]=%*+#", 210 sms.getMessageBody()); 211 } 212 213 // GSM 7 bit tables in String form, Escape (0x1B) replaced with '@' 214 private static final String[] sBasicTables = { 215 // GSM 7 bit default alphabet 216 "@\u00a3$\u00a5\u00e8\u00e9\u00f9\u00ec\u00f2\u00c7\n\u00d8\u00f8\r\u00c5\u00e5\u0394_" 217 + "\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e@\u00c6\u00e6\u00df\u00c9" 218 + " !\"#\u00a4%&'()*+,-./0123456789:;<=>?\u00a1ABCDEFGHIJKLMNOPQRSTUVWXYZ\u00c4\u00d6" 219 + "\u00d1\u00dc\u00a7\u00bfabcdefghijklmnopqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0", 220 221 // Turkish locking shift table 222 "@\u00a3$\u00a5\u20ac\u00e9\u00f9\u0131\u00f2\u00c7\n\u011e\u011f\r\u00c5\u00e5\u0394_" 223 + "\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e@\u015e\u015f\u00df\u00c9" 224 + " !\"#\u00a4%&'()*+,-./0123456789:;<=>?\u0130ABCDEFGHIJKLMNOPQRSTUVWXYZ\u00c4\u00d6" 225 + "\u00d1\u00dc\u00a7\u00e7abcdefghijklmnopqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0", 226 227 // no locking shift table defined for Spanish 228 "", 229 230 // Portuguese locking shift table 231 "@\u00a3$\u00a5\u00ea\u00e9\u00fa\u00ed\u00f3\u00e7\n\u00d4\u00f4\r\u00c1\u00e1\u0394_" 232 + "\u00aa\u00c7\u00c0\u221e^\\\u20ac\u00d3|@\u00c2\u00e2\u00ca\u00c9 !\"#\u00ba%&'()" 233 + "*+,-./0123456789:;<=>?\u00cdABCDEFGHIJKLMNOPQRSTUVWXYZ\u00c3\u00d5\u00da\u00dc" 234 + "\u00a7~abcdefghijklmnopqrstuvwxyz\u00e3\u00f5`\u00fc\u00e0" 235 }; 236 237 @SmallTest testFragmentText()238 public void testFragmentText() throws Exception { 239 boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() == 240 TelephonyManager.PHONE_TYPE_GSM); 241 242 // Valid 160 character 7-bit text. 243 String text = "123456789012345678901234567890123456789012345678901234567890" + 244 "1234567890123456789012345678901234567890123456789012345678901234567890" + 245 "123456789012345678901234567890"; 246 GsmAlphabet.TextEncodingDetails ted = SmsMessage.calculateLength(text, false); 247 assertEquals(1, ted.msgCount); 248 assertEquals(160, ted.codeUnitCount); 249 assertEquals(1, ted.codeUnitSize); 250 assertEquals(0, ted.languageTable); 251 assertEquals(0, ted.languageShiftTable); 252 if (isGsmPhone) { 253 ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); 254 assertEquals(1, fragments.size()); 255 } 256 257 // Valid 161 character 7-bit text. 258 text = "123456789012345678901234567890123456789012345678901234567890" + 259 "1234567890123456789012345678901234567890123456789012345678901234567890" + 260 "1234567890123456789012345678901"; 261 ted = SmsMessage.calculateLength(text, false); 262 assertEquals(2, ted.msgCount); 263 assertEquals(161, ted.codeUnitCount); 264 assertEquals(1, ted.codeUnitSize); 265 assertEquals(0, ted.languageTable); 266 assertEquals(0, ted.languageShiftTable); 267 if (isGsmPhone) { 268 ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); 269 assertEquals(2, fragments.size()); 270 assertEquals(text, fragments.get(0) + fragments.get(1)); 271 assertEquals(153, fragments.get(0).length()); 272 assertEquals(8, fragments.get(1).length()); 273 } 274 } 275 276 @SmallTest testFragmentTurkishText()277 public void testFragmentTurkishText() throws Exception { 278 boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() == 279 TelephonyManager.PHONE_TYPE_GSM); 280 281 int[] oldTables = GsmAlphabet.getEnabledSingleShiftTables(); 282 int[] turkishTable = { 1 }; 283 GsmAlphabet.setEnabledSingleShiftTables(turkishTable); 284 285 // Valid 77 character text with Turkish characters. 286 String text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" + 287 "ĞŞİğşıĞŞİğşıĞŞİğş"; 288 GsmAlphabet.TextEncodingDetails ted = SmsMessage.calculateLength(text, false); 289 assertEquals(1, ted.msgCount); 290 assertEquals(154, ted.codeUnitCount); 291 assertEquals(1, ted.codeUnitSize); 292 assertEquals(0, ted.languageTable); 293 assertEquals(1, ted.languageShiftTable); 294 if (isGsmPhone) { 295 ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); 296 assertEquals(1, fragments.size()); 297 assertEquals(text, fragments.get(0)); 298 assertEquals(77, fragments.get(0).length()); 299 } 300 301 // Valid 78 character text with Turkish characters. 302 text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" + 303 "ĞŞİğşıĞŞİğşıĞŞİğşı"; 304 ted = SmsMessage.calculateLength(text, false); 305 assertEquals(2, ted.msgCount); 306 assertEquals(156, ted.codeUnitCount); 307 assertEquals(1, ted.codeUnitSize); 308 assertEquals(0, ted.languageTable); 309 assertEquals(1, ted.languageShiftTable); 310 if (isGsmPhone) { 311 ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); 312 assertEquals(2, fragments.size()); 313 assertEquals(text, fragments.get(0) + fragments.get(1)); 314 assertEquals(74, fragments.get(0).length()); 315 assertEquals(4, fragments.get(1).length()); 316 } 317 318 // Valid 160 character text with Turkish characters. 319 text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" + 320 "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğ" + 321 "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı"; 322 ted = SmsMessage.calculateLength(text, false); 323 assertEquals(3, ted.msgCount); 324 assertEquals(320, ted.codeUnitCount); 325 assertEquals(1, ted.codeUnitSize); 326 assertEquals(0, ted.languageTable); 327 assertEquals(1, ted.languageShiftTable); 328 if (isGsmPhone) { 329 ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text); 330 assertEquals(3, fragments.size()); 331 assertEquals(text, fragments.get(0) + fragments.get(1) + fragments.get(2)); 332 assertEquals(74, fragments.get(0).length()); 333 assertEquals(74, fragments.get(1).length()); 334 assertEquals(12, fragments.get(2).length()); 335 } 336 337 GsmAlphabet.setEnabledSingleShiftTables(oldTables); 338 } 339 340 341 @SmallTest testDecode()342 public void testDecode() throws Exception { 343 decodeSingle(0); // default table 344 decodeSingle(1); // Turkish locking shift table 345 decodeSingle(3); // Portuguese locking shift table 346 } 347 decodeSingle(int language)348 private void decodeSingle(int language) throws Exception { 349 byte[] septets = new byte[(7 * 128 + 7) / 8]; 350 351 int bitOffset = 0; 352 353 for (int i = 0; i < 128; i++) { 354 int v; 355 if (i == 0x1b) { 356 // extended escape char 357 v = 0; 358 } else { 359 v = i; 360 } 361 362 int byteOffset = bitOffset / 8; 363 int shift = bitOffset % 8; 364 365 septets[byteOffset] |= v << shift; 366 367 if (shift > 1) { 368 septets[byteOffset + 1] = (byte) (v >> (8 - shift)); 369 } 370 371 bitOffset += 7; 372 } 373 374 String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, 128, 0, language, 0); 375 byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded, language, 0); 376 377 assertEquals(sBasicTables[language], decoded); 378 379 // reEncoded has the count septets byte at the front 380 assertEquals(septets.length + 1, reEncoded.length); 381 382 for (int i = 0; i < septets.length; i++) { 383 assertEquals(septets[i], reEncoded[i + 1]); 384 } 385 } 386 387 private static final int GSM_ESCAPE_CHARACTER = 0x1b; 388 389 private static final String[] sExtendedTables = { 390 // GSM 7 bit default alphabet extension table 391 "\f^{}\\[~]|\u20ac", 392 393 // Turkish single shift extension table 394 "\f^{}\\[~]|\u011e\u0130\u015e\u00e7\u20ac\u011f\u0131\u015f", 395 396 // Spanish single shift extension table 397 "\u00e7\f^{}\\[~]|\u00c1\u00cd\u00d3\u00da\u00e1\u20ac\u00ed\u00f3\u00fa", 398 399 // Portuguese single shift extension table 400 "\u00ea\u00e7\f\u00d4\u00f4\u00c1\u00e1\u03a6\u0393^\u03a9\u03a0\u03a8\u03a3\u0398\u00ca" 401 + "{}\\[~]|\u00c0\u00cd\u00d3\u00da\u00c3\u00d5\u00c2\u20ac\u00ed\u00f3\u00fa\u00e3" 402 + "\u00f5\u00e2" 403 }; 404 405 private static final int[][] sExtendedTableIndexes = { 406 {0x0a, 0x14, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x65}, 407 {0x0a, 0x14, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x47, 0x49, 0x53, 0x63, 408 0x65, 0x67, 0x69, 0x73}, 409 {0x09, 0x0a, 0x14, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x41, 0x49, 0x4f, 410 0x55, 0x61, 0x65, 0x69, 0x6f, 0x75}, 411 {0x05, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 412 0x18, 0x19, 0x1f, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x41, 0x49, 413 0x4f, 0x55, 0x5b, 0x5c, 0x61, 0x65, 0x69, 0x6f, 0x75, 0x7b, 0x7c, 0x7f} 414 }; 415 416 @SmallTest testDecodeExtended()417 public void testDecodeExtended() throws Exception { 418 for (int language = 0; language < 3; language++) { 419 int[] tableIndex = sExtendedTableIndexes[language]; 420 int numSeptets = tableIndex.length * 2; // two septets per extended char 421 byte[] septets = new byte[(7 * numSeptets + 7) / 8]; 422 423 int bitOffset = 0; 424 425 for (int v : tableIndex) { 426 // escape character 427 int byteOffset = bitOffset / 8; 428 int shift = bitOffset % 8; 429 430 septets[byteOffset] |= GSM_ESCAPE_CHARACTER << shift; 431 432 if (shift > 1) { 433 septets[byteOffset + 1] = (byte) (GSM_ESCAPE_CHARACTER >> (8 - shift)); 434 } 435 436 bitOffset += 7; 437 438 // extended table index 439 byteOffset = bitOffset / 8; 440 shift = bitOffset % 8; 441 442 septets[byteOffset] |= v << shift; 443 444 if (shift > 1) { 445 septets[byteOffset + 1] = (byte) (v >> (8 - shift)); 446 } 447 448 bitOffset += 7; 449 } 450 451 String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, 452 0, language); 453 byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded, 0, language); 454 455 assertEquals(sExtendedTables[language], decoded); 456 457 // reEncoded has the count septets byte at the front 458 assertEquals(septets.length + 1, reEncoded.length); 459 460 for (int i = 0; i < septets.length; i++) { 461 assertEquals(septets[i], reEncoded[i + 1]); 462 } 463 } 464 } 465 466 @SmallTest testDecodeExtendedFallback()467 public void testDecodeExtendedFallback() throws Exception { 468 // verify that unmapped characters in extension table fall back to locking shift table 469 for (int language = 0; language < 3; language++) { 470 int[] tableIndex = sExtendedTableIndexes[language]; 471 int numChars = 128 - tableIndex.length; 472 int numSeptets = numChars * 2; // two septets per extended char 473 byte[] septets = new byte[(7 * numSeptets + 7) / 8]; 474 475 int tableOffset = 0; 476 int bitOffset = 0; 477 478 StringBuilder defaultTable = new StringBuilder(128); 479 StringBuilder turkishTable = new StringBuilder(128); 480 StringBuilder portugueseTable = new StringBuilder(128); 481 482 for (char c = 0; c < 128; c++) { 483 // skip characters that are present in the current extension table 484 if (tableOffset < tableIndex.length && tableIndex[tableOffset] == c) { 485 tableOffset++; 486 continue; 487 } 488 489 // escape character 490 int byteOffset = bitOffset / 8; 491 int shift = bitOffset % 8; 492 493 septets[byteOffset] |= GSM_ESCAPE_CHARACTER << shift; 494 495 if (shift > 1) { 496 septets[byteOffset + 1] = (byte) (GSM_ESCAPE_CHARACTER >> (8 - shift)); 497 } 498 499 bitOffset += 7; 500 501 // extended table index 502 byteOffset = bitOffset / 8; 503 shift = bitOffset % 8; 504 505 septets[byteOffset] |= c << shift; 506 507 if (shift > 1) { 508 septets[byteOffset + 1] = (byte) (c >> (8 - shift)); 509 } 510 511 bitOffset += 7; 512 513 if (c == GsmAlphabet.GSM_EXTENDED_ESCAPE) { 514 // double Escape maps to space character 515 defaultTable.append(' '); 516 turkishTable.append(' '); 517 portugueseTable.append(' '); 518 } else { 519 // other unmapped chars map to the default or locking shift table 520 defaultTable.append(sBasicTables[0].charAt(c)); 521 turkishTable.append(sBasicTables[1].charAt(c)); 522 portugueseTable.append(sBasicTables[3].charAt(c)); 523 } 524 } 525 526 String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, 527 0, language); 528 529 assertEquals(defaultTable.toString(), decoded); 530 531 decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, 1, language); 532 assertEquals(turkishTable.toString(), decoded); 533 534 decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, 3, language); 535 assertEquals(portugueseTable.toString(), decoded); 536 } 537 } 538 } 539