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 com.android.internal.telephony.GsmAlphabet; 20 import com.android.internal.telephony.uicc.IccUtils; 21 22 import junit.framework.TestCase; 23 24 import android.test.suitebuilder.annotation.LargeTest; 25 import android.test.suitebuilder.annotation.SmallTest; 26 27 public class GsmAlphabetTest extends TestCase { 28 29 private static final String sGsmExtendedChars = "{|}\\[~]\f\u20ac"; 30 31 @SmallTest 32 public void test7bitWithHeader() throws Exception { 33 SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); 34 concatRef.refNumber = 1; 35 concatRef.seqNumber = 2; 36 concatRef.msgCount = 2; 37 concatRef.isEightBits = true; 38 SmsHeader header = new SmsHeader(); 39 header.concatRef = concatRef; 40 41 String message = "aaaaaaaaaabbbbbbbbbbcccccccccc"; 42 byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, 43 SmsHeader.toByteArray(header), 0, 0); 44 int septetCount = GsmAlphabet.countGsmSeptetsUsingTables(message, true, 0, 0); 45 String parsedMessage = GsmAlphabet.gsm7BitPackedToString( 46 userData, SmsHeader.toByteArray(header).length+2, septetCount, 1, 0, 0); 47 assertEquals(message, parsedMessage); 48 } 49 50 // TODO: This method should *really* be a series of individual test methods. 51 // However, it's a SmallTest because it executes quickly. 52 @SmallTest 53 public void testBasic() throws Exception { 54 // '@' maps to char 0 55 assertEquals(0, GsmAlphabet.charToGsm('@')); 56 57 // `a (a with grave accent) maps to last GSM character 58 assertEquals(0x7f, GsmAlphabet.charToGsm('\u00e0')); 59 60 // 61 // These are the extended chars 62 // They should all return GsmAlphabet.GSM_EXTENDED_ESCAPE 63 // 64 65 for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { 66 assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE, 67 GsmAlphabet.charToGsm(sGsmExtendedChars.charAt(i))); 68 69 } 70 71 // euro symbol 72 assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE, 73 GsmAlphabet.charToGsm('\u20ac')); 74 75 // An unmappable char (the 'cent' char) maps to a space 76 assertEquals(GsmAlphabet.charToGsm(' '), 77 GsmAlphabet.charToGsm('\u00a2')); 78 79 // unmappable = space = 1 septet 80 assertEquals(1, GsmAlphabet.countGsmSeptets('\u00a2')); 81 82 // 83 // Test extended table 84 // 85 86 for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { 87 assertEquals(sGsmExtendedChars.charAt(i), 88 GsmAlphabet.gsmExtendedToChar( 89 GsmAlphabet.charToGsmExtended(sGsmExtendedChars.charAt(i)))); 90 91 } 92 93 // Unmappable extended char 94 assertEquals(GsmAlphabet.charToGsm(' '), 95 GsmAlphabet.charToGsmExtended('@')); 96 97 // 98 // gsmToChar() 99 // 100 101 assertEquals('@', GsmAlphabet.gsmToChar(0)); 102 103 // `a (a with grave accent) maps to last GSM character 104 assertEquals('\u00e0', GsmAlphabet.gsmToChar(0x7f)); 105 106 assertEquals('\uffff', 107 GsmAlphabet.gsmToChar(GsmAlphabet.GSM_EXTENDED_ESCAPE)); 108 109 // Out-of-range/unmappable value 110 assertEquals(' ', GsmAlphabet.gsmToChar(0x80)); 111 112 // 113 // gsmExtendedToChar() 114 // 115 116 assertEquals('{', GsmAlphabet.gsmExtendedToChar(0x28)); 117 118 // No double-escapes 119 assertEquals(' ', GsmAlphabet.gsmExtendedToChar( 120 GsmAlphabet.GSM_EXTENDED_ESCAPE)); 121 122 // Reserved for extension to extension table (mapped to space) 123 assertEquals(' ', GsmAlphabet.gsmExtendedToChar(GsmAlphabet.GSM_EXTENDED_ESCAPE)); 124 125 // Unmappable (mapped to character in default or national locking shift table) 126 assertEquals('@', GsmAlphabet.gsmExtendedToChar(0)); 127 assertEquals('\u00e0', GsmAlphabet.gsmExtendedToChar(0x7f)); 128 129 // 130 // stringTo7BitPacked, gsm7BitPackedToString 131 // 132 133 byte[] packed; 134 StringBuilder testString = new StringBuilder(300); 135 136 // Check all alignment cases 137 for (int i = 0; i < 9; i++, testString.append('@')) { 138 packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); 139 assertEquals(testString.toString(), 140 GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); 141 } 142 143 // Check full non-extended alphabet 144 for (int i = 0; i < 0x80; i++) { 145 char c; 146 147 if (i == GsmAlphabet.GSM_EXTENDED_ESCAPE) { 148 continue; 149 } 150 151 c = GsmAlphabet.gsmToChar(i); 152 testString.append(c); 153 154 // These are all non-extended chars, so it should be 155 // one septet per char 156 assertEquals(1, GsmAlphabet.countGsmSeptets(c)); 157 } 158 159 packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); 160 assertEquals(testString.toString(), 161 GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); 162 163 // Test extended chars too 164 165 testString.append(sGsmExtendedChars); 166 167 for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { 168 // These are all extended chars, so it should be 169 // two septets per char 170 assertEquals(2, GsmAlphabet.countGsmSeptets(sGsmExtendedChars.charAt(i))); 171 172 } 173 174 packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); 175 assertEquals(testString.toString(), 176 GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); 177 178 // stringTo7BitPacked handles up to 255 septets 179 180 testString.setLength(0); 181 for (int i = 0; i < 255; i++) { 182 testString.append('@'); 183 } 184 185 packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); 186 assertEquals(testString.toString(), 187 GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); 188 189 // > 255 septets throws runtime exception 190 testString.append('@'); 191 192 try { 193 GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); 194 fail("expected exception"); 195 } catch (EncodeException ex) { 196 // exception expected 197 } 198 199 // Try 254 septets with 127 extended chars 200 201 testString.setLength(0); 202 for (int i = 0; i < (255 / 2); i++) { 203 testString.append('{'); 204 } 205 206 packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); 207 assertEquals(testString.toString(), 208 GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); 209 210 // > 255 septets throws runtime exception 211 testString.append('{'); 212 213 try { 214 GsmAlphabet.stringToGsm7BitPacked(testString.toString(), 0, 0); 215 fail("expected exception"); 216 } catch (EncodeException ex) { 217 // exception expected 218 } 219 220 // Reserved for extension to extension table (mapped to space) 221 packed = new byte[]{(byte)(0x1b | 0x80), 0x1b >> 1}; 222 assertEquals(" ", GsmAlphabet.gsm7BitPackedToString(packed, 0, 2)); 223 224 // Unmappable (mapped to character in default alphabet table) 225 packed[0] = 0x1b; 226 packed[1] = 0x00; 227 assertEquals("@", GsmAlphabet.gsm7BitPackedToString(packed, 0, 2)); 228 packed[0] = (byte)(0x1b | 0x80); 229 packed[1] = (byte)(0x7f >> 1); 230 assertEquals("\u00e0", GsmAlphabet.gsm7BitPackedToString(packed, 0, 2)); 231 232 // 233 // 8 bit unpacked format 234 // 235 // Note: we compare hex strings here 236 // because Assert doesn't have array comparisons 237 238 byte unpacked[]; 239 240 unpacked = IccUtils.hexStringToBytes("566F696365204D61696C"); 241 assertEquals("Voice Mail", 242 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); 243 244 assertEquals(IccUtils.bytesToHexString(unpacked), 245 IccUtils.bytesToHexString( 246 GsmAlphabet.stringToGsm8BitPacked("Voice Mail"))); 247 248 unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars); 249 // two bytes for every extended char 250 assertEquals(2 * sGsmExtendedChars.length(), unpacked.length); 251 assertEquals(sGsmExtendedChars, 252 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); 253 254 // should be two bytes per extended char 255 assertEquals(2 * sGsmExtendedChars.length(), unpacked.length); 256 257 // Test truncation of unaligned extended chars 258 unpacked = new byte[3]; 259 GsmAlphabet.stringToGsm8BitUnpackedField(sGsmExtendedChars, unpacked, 260 0, unpacked.length); 261 262 // Should be one extended char and an 0xff at the end 263 264 assertEquals(0xff, 0xff & unpacked[2]); 265 assertEquals(sGsmExtendedChars.substring(0, 1), 266 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); 267 268 // Test truncation of normal chars 269 unpacked = new byte[3]; 270 GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked, 271 0, unpacked.length); 272 273 assertEquals("abc", 274 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); 275 276 // Test truncation of mixed normal and extended chars 277 unpacked = new byte[3]; 278 GsmAlphabet.stringToGsm8BitUnpackedField("a{cd", unpacked, 279 0, unpacked.length); 280 281 assertEquals("a{", 282 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); 283 284 // Test padding after normal char 285 unpacked = new byte[3]; 286 GsmAlphabet.stringToGsm8BitUnpackedField("a", unpacked, 287 0, unpacked.length); 288 289 assertEquals("a", 290 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); 291 292 assertEquals(0xff, 0xff & unpacked[1]); 293 assertEquals(0xff, 0xff & unpacked[2]); 294 295 // Test malformed input -- escape char followed by end of field 296 unpacked[0] = 0; 297 unpacked[1] = 0; 298 unpacked[2] = GsmAlphabet.GSM_EXTENDED_ESCAPE; 299 300 assertEquals("@@", 301 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); 302 303 // non-zero offset 304 assertEquals("@", 305 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); 306 307 // test non-zero offset 308 unpacked[0] = 0; 309 GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked, 310 1, unpacked.length - 1); 311 312 313 assertEquals(0, unpacked[0]); 314 315 assertEquals("ab", 316 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); 317 318 // test non-zero offset with truncated extended char 319 unpacked[0] = 0; 320 321 GsmAlphabet.stringToGsm8BitUnpackedField("a{", unpacked, 322 1, unpacked.length - 1); 323 324 assertEquals(0, unpacked[0]); 325 326 assertEquals("a", 327 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); 328 329 // Reserved for extension to extension table (mapped to space) 330 unpacked[0] = 0x1b; 331 unpacked[1] = 0x1b; 332 assertEquals(" ", GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, 2)); 333 334 // Unmappable (mapped to character in default or national locking shift table) 335 unpacked[1] = 0x00; 336 assertEquals("@", GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, 2)); 337 unpacked[1] = 0x7f; 338 assertEquals("\u00e0", GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, 2)); 339 } 340 341 @SmallTest 342 public void testGsm8BitUpackedWithEuckr() throws Exception { 343 // Some feature phones in Korea store contacts as euc-kr. 344 // Test this situations. 345 byte unpacked[]; 346 347 // Test general alphabet strings. 348 unpacked = IccUtils.hexStringToBytes("61626320646566FF"); 349 assertEquals("abc def", 350 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr")); 351 352 // Test korean strings. 353 unpacked = IccUtils.hexStringToBytes("C5D7BDBAC6AEFF"); 354 assertEquals("\uD14C\uC2A4\uD2B8", 355 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr")); 356 357 // Test gsm Extented Characters. 358 unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars); 359 assertEquals(sGsmExtendedChars, 360 GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr")); 361 } 362 } 363