GsmAlphabet.java revision 64c499113a758cf80cddfd4d0183f944a1a6645a
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 17package com.android.internal.telephony; 18 19import android.telephony.SmsMessage; 20import android.util.SparseIntArray; 21 22import android.util.Log; 23 24/** 25 * This class implements the character set mapping between 26 * the GSM SMS 7-bit alphabet specifed in TS 23.038 6.2.1 27 * and UTF-16 28 * 29 * {@hide} 30 */ 31public class GsmAlphabet { 32 static final String LOG_TAG = "GSM"; 33 34 35 36 //***** Constants 37 38 /** 39 * This escapes extended characters, and when present indicates that the 40 * following character should 41 * be looked up in the "extended" table 42 * 43 * gsmToChar(GSM_EXTENDED_ESCAPE) returns 0xffff 44 */ 45 46 public static final byte GSM_EXTENDED_ESCAPE = 0x1B; 47 48 49 /** 50 * char to GSM alphabet char 51 * Returns ' ' in GSM alphabet if there's no possible match 52 * Returns GSM_EXTENDED_ESCAPE if this character is in the extended table 53 * In this case, you must call charToGsmExtended() for the value that 54 * should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string 55 */ 56 public static int 57 charToGsm(char c) { 58 try { 59 return charToGsm(c, false); 60 } catch (EncodeException ex) { 61 // this should never happen 62 return sGsmSpaceChar; 63 } 64 } 65 66 /** 67 * char to GSM alphabet char 68 * @param throwException If true, throws EncodeException on invalid char. 69 * If false, returns GSM alphabet ' ' char. 70 * 71 * Returns GSM_EXTENDED_ESCAPE if this character is in the extended table 72 * In this case, you must call charToGsmExtended() for the value that 73 * should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string 74 */ 75 76 public static int 77 charToGsm(char c, boolean throwException) throws EncodeException { 78 int ret; 79 80 ret = charToGsm.get(c, -1); 81 82 if (ret == -1) { 83 ret = charToGsmExtended.get(c, -1); 84 85 if (ret == -1) { 86 if (throwException) { 87 throw new EncodeException(c); 88 } else { 89 return sGsmSpaceChar; 90 } 91 } else { 92 return GSM_EXTENDED_ESCAPE; 93 } 94 } 95 96 return ret; 97 98 } 99 100 101 /** 102 * char to extended GSM alphabet char 103 * 104 * Extended chars should be escaped with GSM_EXTENDED_ESCAPE 105 * 106 * Returns ' ' in GSM alphabet if there's no possible match 107 * 108 */ 109 public static int 110 charToGsmExtended(char c) { 111 int ret; 112 113 ret = charToGsmExtended.get(c, -1); 114 115 if (ret == -1) { 116 return sGsmSpaceChar; 117 } 118 119 return ret; 120 } 121 122 /** 123 * Converts a character in the GSM alphabet into a char 124 * 125 * if GSM_EXTENDED_ESCAPE is passed, 0xffff is returned. In this case, 126 * the following character in the stream should be decoded with 127 * gsmExtendedToChar() 128 * 129 * If an unmappable value is passed (one greater than 127), ' ' is returned 130 */ 131 132 public static char 133 gsmToChar(int gsmChar) { 134 return (char)gsmToChar.get(gsmChar, ' '); 135 } 136 137 /** 138 * Converts a character in the extended GSM alphabet into a char 139 * 140 * if GSM_EXTENDED_ESCAPE is passed, ' ' is returned since no second 141 * extension page has yet been defined (see Note 1 in table 6.2.1.1 of 142 * TS 23.038 v7.00) 143 * 144 * If an unmappable value is passed , ' ' is returned 145 */ 146 147 public static char 148 gsmExtendedToChar(int gsmChar) { 149 int ret; 150 151 ret = gsmExtendedToChar.get(gsmChar, -1); 152 153 if (ret == -1) { 154 return ' '; 155 } 156 157 return (char)ret; 158 } 159 160 /** 161 * Converts a String into a byte array containing the 7-bit packed 162 * GSM Alphabet representation of the string. If a header is provided, 163 * this is included in the returned byte array and padded to a septet 164 * boundary. 165 * 166 * Unencodable chars are encoded as spaces 167 * 168 * Byte 0 in the returned byte array is the count of septets used, 169 * including the header and header padding. The returned byte array is 170 * the minimum size required to store the packed septets. The returned 171 * array cannot contain more than 255 septets. 172 * 173 * @param data The text string to encode. 174 * @param header Optional header (includeing length byte) that precedes 175 * the encoded data, padded to septet boundary. 176 * @return Byte array containing header and encoded data. 177 */ 178 public static byte[] stringToGsm7BitPackedWithHeader(String data, byte[] header) 179 throws EncodeException { 180 181 if (header == null || header.length == 0) { 182 return stringToGsm7BitPacked(data); 183 } 184 185 int headerBits = (header.length + 1) * 8; 186 int headerSeptets = headerBits / 7; 187 headerSeptets += (headerBits % 7) > 0 ? 1 : 0; 188 189 int sz = data.length(); 190 int septetCount; 191 septetCount = countGsmSeptets(data, true) + headerSeptets; 192 193 byte[] ret = stringToGsm7BitPacked(data, 0, septetCount, 194 (headerSeptets*7), true); 195 196 // Paste in the header 197 ret[1] = (byte)header.length; 198 System.arraycopy(header, 0, ret, 2, header.length); 199 return ret; 200 } 201 202 /** 203 * Converts a String into a byte array containing 204 * the 7-bit packed GSM Alphabet representation of the string. 205 * 206 * Unencodable chars are encoded as spaces 207 * 208 * Byte 0 in the returned byte array is the count of septets used 209 * The returned byte array is the minimum size required to store 210 * the packed septets. The returned array cannot contain more than 255 211 * septets. 212 * 213 * @param data the data string to endcode 214 * @throws EncodeException if String is too large to encode 215 */ 216 public static byte[] stringToGsm7BitPacked(String data) 217 throws EncodeException { 218 return stringToGsm7BitPacked(data, 0, -1, 0, true); 219 } 220 221 /** 222 * Converts a String into a byte array containing 223 * the 7-bit packed GSM Alphabet representation of the string. 224 * 225 * Byte 0 in the returned byte array is the count of septets used 226 * The returned byte array is the minimum size required to store 227 * the packed septets. The returned array cannot contain more than 255 228 * septets. 229 * 230 * @param data the text to convert to septets 231 * @param dataOffset the character offset in data to start the encoding from 232 * @param maxSeptets the maximum number of septets to convert, or -1 for no 233 * enforced maximum. 234 * @param startingBitOffset the number of padding bits to put before 235 * the start of the first septet at the begining of the array 236 * @param throwException If true, throws EncodeException on invalid char. 237 * If false, replaces unencodable char with GSM alphabet space char. 238 * 239 * @throws EncodeException if String is too large to encode 240 */ 241 public static byte[] stringToGsm7BitPacked(String data, int dataOffset, 242 int maxSeptets, int startingBitOffset, boolean throwException) 243 throws EncodeException { 244 245 int sz = data.length(); 246 int septetCount; 247 if (maxSeptets == -1) { 248 septetCount = countGsmSeptets(data, true); 249 } else { 250 septetCount = maxSeptets; 251 } 252 253 if(septetCount > 0xff) { 254 throw new EncodeException("Payload cannot exceed " + Short.MAX_VALUE 255 + " septets"); 256 } 257 258 // Enough for all the septets and the length 2 byte prefix 259 byte[] ret = new byte[1 + (((septetCount * 7) + 7) / 8)]; 260 261 int bitOffset = startingBitOffset; 262 int septets = startingBitOffset/7; 263 for (int i = dataOffset; i < sz && septets < septetCount; i++, bitOffset += 7) { 264 char c = data.charAt(i); 265 266 int v = GsmAlphabet.charToGsm(c, throwException); 267 if (v == GSM_EXTENDED_ESCAPE) { 268 // Lookup the extended char 269 v = GsmAlphabet.charToGsmExtended(c); 270 271 packSmsChar(ret, bitOffset, GSM_EXTENDED_ESCAPE); 272 bitOffset += 7; 273 septets++; 274 } 275 276 packSmsChar(ret, bitOffset, v); 277 septets++; 278 } 279 280 // See check for > 0xff above 281 ret[0] = (byte)septets; 282 283 return ret; 284 } 285 286 /** 287 * Pack a 7-bit char into its appropirate place in a byte array 288 * 289 * @param bitOffset the bit offset that the septet should be packed at 290 * (septet index * 7) 291 */ 292 private static void 293 packSmsChar(byte[] packedChars, int bitOffset, int value) { 294 int byteOffset = bitOffset / 8; 295 int shift = bitOffset % 8; 296 297 packedChars[++byteOffset] |= value << shift; 298 299 if (shift > 1) { 300 packedChars[++byteOffset] = (byte)(value >> (8 - shift)); 301 } 302 } 303 304 /** 305 * Convert a GSM alphabet 7 bit packed string (SMS string) into a 306 * {@link java.lang.String}. 307 * 308 * See TS 23.038 6.1.2.1 for SMS Character Packing 309 * 310 * @param pdu the raw data from the pdu 311 * @param offset the byte offset of 312 * @param lengthSeptets string length in septets, not bytes 313 * @return String representation or null on decoding exception 314 */ 315 public static String gsm7BitPackedToString(byte[] pdu, int offset, 316 int lengthSeptets) { 317 return gsm7BitPackedToString(pdu, offset, lengthSeptets, 0); 318 } 319 320 /** 321 * Convert a GSM alphabet 7 bit packed string (SMS string) into a 322 * {@link java.lang.String}. 323 * 324 * See TS 23.038 6.1.2.1 for SMS Character Packing 325 * 326 * @param pdu the raw data from the pdu 327 * @param offset the byte offset of 328 * @param lengthSeptets string length in septets, not bytes 329 * @param numPaddingBits the number of padding bits before the start of the 330 * string in the first byte 331 * @return String representation or null on decoding exception 332 */ 333 public static String gsm7BitPackedToString(byte[] pdu, int offset, 334 int lengthSeptets, int numPaddingBits) { 335 StringBuilder ret = new StringBuilder(lengthSeptets); 336 boolean prevCharWasEscape; 337 338 try { 339 prevCharWasEscape = false; 340 341 for (int i = 0 ; i < lengthSeptets ; i++) { 342 int bitOffset = (7 * i) + numPaddingBits; 343 344 int byteOffset = bitOffset / 8; 345 int shift = bitOffset % 8; 346 int gsmVal; 347 348 gsmVal = (0x7f & (pdu[offset + byteOffset] >> shift)); 349 350 // if it crosses a byte boundry 351 if (shift > 1) { 352 // set msb bits to 0 353 gsmVal &= 0x7f >> (shift - 1); 354 355 gsmVal |= 0x7f & (pdu[offset + byteOffset + 1] << (8 - shift)); 356 } 357 358 if (prevCharWasEscape) { 359 ret.append(GsmAlphabet.gsmExtendedToChar(gsmVal)); 360 prevCharWasEscape = false; 361 } else if (gsmVal == GSM_EXTENDED_ESCAPE) { 362 prevCharWasEscape = true; 363 } else { 364 ret.append(GsmAlphabet.gsmToChar(gsmVal)); 365 } 366 } 367 } catch (RuntimeException ex) { 368 Log.e(LOG_TAG, "Error GSM 7 bit packed: ", ex); 369 return null; 370 } 371 372 return ret.toString(); 373 } 374 375 376 /** 377 * Convert a GSM alphabet string that's stored in 8-bit unpacked 378 * format (as it often appears in SIM records) into a String 379 * 380 * Field may be padded with trailing 0xff's. The decode stops 381 * at the first 0xff encountered. 382 */ 383 public static String 384 gsm8BitUnpackedToString(byte[] data, int offset, int length) { 385 boolean prevWasEscape; 386 StringBuilder ret = new StringBuilder(length); 387 388 prevWasEscape = false; 389 for (int i = offset ; i < offset + length ; i++) { 390 // Never underestimate the pain that can be caused 391 // by signed bytes 392 int c = data[i] & 0xff; 393 394 if (c == 0xff) { 395 break; 396 } else if (c == GSM_EXTENDED_ESCAPE) { 397 if (prevWasEscape) { 398 // Two escape chars in a row 399 // We treat this as a space 400 // See Note 1 in table 6.2.1.1 of TS 23.038 v7.00 401 ret.append(' '); 402 prevWasEscape = false; 403 } else { 404 prevWasEscape = true; 405 } 406 } else { 407 if (prevWasEscape) { 408 ret.append((char)gsmExtendedToChar.get(c, ' ')); 409 } else { 410 ret.append((char)gsmToChar.get(c, ' ')); 411 } 412 prevWasEscape = false; 413 } 414 } 415 416 return ret.toString(); 417 } 418 419 /** 420 * Convert a string into an 8-bit unpacked GSM alphabet byte 421 * array 422 */ 423 public static byte[] 424 stringToGsm8BitPacked(String s) { 425 byte[] ret; 426 427 int septets = 0; 428 429 septets = countGsmSeptets(s); 430 431 // Enough for all the septets and the length byte prefix 432 ret = new byte[septets]; 433 434 stringToGsm8BitUnpackedField(s, ret, 0, ret.length); 435 436 return ret; 437 } 438 439 440 /** 441 * Write a String into a GSM 8-bit unpacked field of 442 * @param length size at @param offset in @param dest 443 * 444 * Field is padded with 0xff's, string is truncated if necessary 445 */ 446 447 public static void 448 stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) { 449 int outByteIndex = offset; 450 451 // Septets are stored in byte-aligned octets 452 for (int i = 0, sz = s.length() 453 ; i < sz && (outByteIndex - offset) < length 454 ; i++ 455 ) { 456 char c = s.charAt(i); 457 458 int v = GsmAlphabet.charToGsm(c); 459 460 if (v == GSM_EXTENDED_ESCAPE) { 461 // make sure we can fit an escaped char 462 if (! (outByteIndex + 1 - offset < length)) { 463 break; 464 } 465 466 dest[outByteIndex++] = GSM_EXTENDED_ESCAPE; 467 468 v = GsmAlphabet.charToGsmExtended(c); 469 } 470 471 dest[outByteIndex++] = (byte)v; 472 } 473 474 // pad with 0xff's 475 while((outByteIndex - offset) < length) { 476 dest[outByteIndex++] = (byte)0xff; 477 } 478 } 479 480 /** 481 * Returns the count of 7-bit GSM alphabet characters 482 * needed to represent this character. Counts unencodable char as 1 septet. 483 */ 484 public static int 485 countGsmSeptets(char c) { 486 try { 487 return countGsmSeptets(c, false); 488 } catch (EncodeException ex) { 489 // This should never happen. 490 return 0; 491 } 492 } 493 494 /** 495 * Returns the count of 7-bit GSM alphabet characters 496 * needed to represent this character 497 * @param throwsException If true, throws EncodeException if unencodable 498 * char. Otherwise, counts invalid char as 1 septet 499 */ 500 public static int 501 countGsmSeptets(char c, boolean throwsException) throws EncodeException { 502 if (charToGsm.get(c, -1) != -1) { 503 return 1; 504 } 505 506 if (charToGsmExtended.get(c, -1) != -1) { 507 return 2; 508 } 509 510 if (throwsException) { 511 throw new EncodeException(c); 512 } else { 513 // count as a space char 514 return 1; 515 } 516 } 517 518 /** 519 * Returns the count of 7-bit GSM alphabet characters 520 * needed to represent this string. Counts unencodable char as 1 septet. 521 */ 522 public static int 523 countGsmSeptets(CharSequence s) { 524 try { 525 return countGsmSeptets(s, false); 526 } catch (EncodeException ex) { 527 // this should never happen 528 return 0; 529 } 530 } 531 532 /** 533 * Returns the count of 7-bit GSM alphabet characters 534 * needed to represent this string. 535 * @param throwsException If true, throws EncodeException if unencodable 536 * char. Otherwise, counts invalid char as 1 septet 537 */ 538 public static int 539 countGsmSeptets(CharSequence s, boolean throwsException) throws EncodeException { 540 int charIndex = 0; 541 int sz = s.length(); 542 int count = 0; 543 544 while (charIndex < sz) { 545 count += countGsmSeptets(s.charAt(charIndex), throwsException); 546 charIndex++; 547 } 548 549 return count; 550 } 551 552 /** 553 * Returns the index into <code>s</code> of the first character 554 * after <code>limit</code> septets have been reached, starting at 555 * index <code>start</code>. This is used when dividing messages 556 * into units within the SMS message size limit. 557 * 558 * @param s source string 559 * @param start index of where to start counting septets 560 * @param limit maximum septets to include, 561 * e.g. <code>MAX_USER_DATA_SEPTETS</code> 562 * @return index of first character that won't fit, or the length 563 * of the entire string if everything fits 564 */ 565 public static int 566 findGsmSeptetLimitIndex(String s, int start, int limit) { 567 int accumulator = 0; 568 int size = s.length(); 569 570 for (int i = start; i < size; i++) { 571 accumulator += countGsmSeptets(s.charAt(i)); 572 if (accumulator > limit) { 573 return i; 574 } 575 } 576 return size; 577 } 578 579 /** 580 * Returns the index into <code>s</code> of the first character 581 * after <code>limit</code> octets have been reached, starting at 582 * index <code>start</code>. This is used when dividing messages 583 * in UCS2 encoding into units within the SMS message size limit. 584 * 585 * @param s source string 586 * @param start index of where to start counting septets 587 * @param limit maximum septets to include, 588 * e.g. <code>MAX_USER_DATA_BYTES</code> 589 * @return index of first character that won't fit, or the length 590 * of the entire string if everything fits 591 */ 592 public static int 593 findUCS2LimitIndex(String s, int start, int limit) { 594 int numCharToBeEncoded = s.length() - start; 595 return ((numCharToBeEncoded*2 > limit)? limit/2: numCharToBeEncoded) + start; 596 } 597 598 /** 599 * Returns the index into <code>s</code> of the first character 600 * after <code>limit</code> septets/octets have been reached 601 * according to the <code>encodingType</code>, starting at 602 * index <code>start</code>. This is used when dividing messages 603 * units within the SMS message size limit. 604 * 605 * @param s source string 606 * @param start index of where to start counting septets 607 * @param limit maximum septets to include, 608 * e.g. <code>MAX_USER_DATA_BYTES</code> 609 * @return index of first character that won't fit, or the length 610 * of the entire string if everything fits 611 */ 612 public static int 613 findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException { 614 if (encodingType == SmsMessage.ENCODING_7BIT) { 615 return findGsmSeptetLimitIndex(s, start, limit); 616 } 617 else if (encodingType == SmsMessage.ENCODING_16BIT) { 618 return findUCS2LimitIndex(s, start, limit); 619 } 620 else { 621 throw new EncodeException("Unsupported encoding type: " + encodingType); 622 } 623 } 624 625 // Set in the static initializer 626 private static int sGsmSpaceChar; 627 628 private static final SparseIntArray charToGsm = new SparseIntArray(); 629 private static final SparseIntArray gsmToChar = new SparseIntArray(); 630 private static final SparseIntArray charToGsmExtended = new SparseIntArray(); 631 private static final SparseIntArray gsmExtendedToChar = new SparseIntArray(); 632 633 static { 634 int i = 0; 635 636 charToGsm.put('@', i++); 637 charToGsm.put('\u00a3', i++); 638 charToGsm.put('$', i++); 639 charToGsm.put('\u00a5', i++); 640 charToGsm.put('\u00e8', i++); 641 charToGsm.put('\u00e9', i++); 642 charToGsm.put('\u00f9', i++); 643 charToGsm.put('\u00ec', i++); 644 charToGsm.put('\u00f2', i++); 645 charToGsm.put('\u00c7', i++); 646 charToGsm.put('\n', i++); 647 charToGsm.put('\u00d8', i++); 648 charToGsm.put('\u00f8', i++); 649 charToGsm.put('\r', i++); 650 charToGsm.put('\u00c5', i++); 651 charToGsm.put('\u00e5', i++); 652 653 charToGsm.put('\u0394', i++); 654 charToGsm.put('_', i++); 655 charToGsm.put('\u03a6', i++); 656 charToGsm.put('\u0393', i++); 657 charToGsm.put('\u039b', i++); 658 charToGsm.put('\u03a9', i++); 659 charToGsm.put('\u03a0', i++); 660 charToGsm.put('\u03a8', i++); 661 charToGsm.put('\u03a3', i++); 662 charToGsm.put('\u0398', i++); 663 charToGsm.put('\u039e', i++); 664 charToGsm.put('\uffff', i++); 665 charToGsm.put('\u00c6', i++); 666 charToGsm.put('\u00e6', i++); 667 charToGsm.put('\u00df', i++); 668 charToGsm.put('\u00c9', i++); 669 670 charToGsm.put(' ', i++); 671 charToGsm.put('!', i++); 672 charToGsm.put('"', i++); 673 charToGsm.put('#', i++); 674 charToGsm.put('\u00a4', i++); 675 charToGsm.put('%', i++); 676 charToGsm.put('&', i++); 677 charToGsm.put('\'', i++); 678 charToGsm.put('(', i++); 679 charToGsm.put(')', i++); 680 charToGsm.put('*', i++); 681 charToGsm.put('+', i++); 682 charToGsm.put(',', i++); 683 charToGsm.put('-', i++); 684 charToGsm.put('.', i++); 685 charToGsm.put('/', i++); 686 687 charToGsm.put('0', i++); 688 charToGsm.put('1', i++); 689 charToGsm.put('2', i++); 690 charToGsm.put('3', i++); 691 charToGsm.put('4', i++); 692 charToGsm.put('5', i++); 693 charToGsm.put('6', i++); 694 charToGsm.put('7', i++); 695 charToGsm.put('8', i++); 696 charToGsm.put('9', i++); 697 charToGsm.put(':', i++); 698 charToGsm.put(';', i++); 699 charToGsm.put('<', i++); 700 charToGsm.put('=', i++); 701 charToGsm.put('>', i++); 702 charToGsm.put('?', i++); 703 704 charToGsm.put('\u00a1', i++); 705 charToGsm.put('A', i++); 706 charToGsm.put('B', i++); 707 charToGsm.put('C', i++); 708 charToGsm.put('D', i++); 709 charToGsm.put('E', i++); 710 charToGsm.put('F', i++); 711 charToGsm.put('G', i++); 712 charToGsm.put('H', i++); 713 charToGsm.put('I', i++); 714 charToGsm.put('J', i++); 715 charToGsm.put('K', i++); 716 charToGsm.put('L', i++); 717 charToGsm.put('M', i++); 718 charToGsm.put('N', i++); 719 charToGsm.put('O', i++); 720 721 charToGsm.put('P', i++); 722 charToGsm.put('Q', i++); 723 charToGsm.put('R', i++); 724 charToGsm.put('S', i++); 725 charToGsm.put('T', i++); 726 charToGsm.put('U', i++); 727 charToGsm.put('V', i++); 728 charToGsm.put('W', i++); 729 charToGsm.put('X', i++); 730 charToGsm.put('Y', i++); 731 charToGsm.put('Z', i++); 732 charToGsm.put('\u00c4', i++); 733 charToGsm.put('\u00d6', i++); 734 charToGsm.put('\u0147', i++); 735 charToGsm.put('\u00dc', i++); 736 charToGsm.put('\u00a7', i++); 737 738 charToGsm.put('\u00bf', i++); 739 charToGsm.put('a', i++); 740 charToGsm.put('b', i++); 741 charToGsm.put('c', i++); 742 charToGsm.put('d', i++); 743 charToGsm.put('e', i++); 744 charToGsm.put('f', i++); 745 charToGsm.put('g', i++); 746 charToGsm.put('h', i++); 747 charToGsm.put('i', i++); 748 charToGsm.put('j', i++); 749 charToGsm.put('k', i++); 750 charToGsm.put('l', i++); 751 charToGsm.put('m', i++); 752 charToGsm.put('n', i++); 753 charToGsm.put('o', i++); 754 755 charToGsm.put('p', i++); 756 charToGsm.put('q', i++); 757 charToGsm.put('r', i++); 758 charToGsm.put('s', i++); 759 charToGsm.put('t', i++); 760 charToGsm.put('u', i++); 761 charToGsm.put('v', i++); 762 charToGsm.put('w', i++); 763 charToGsm.put('x', i++); 764 charToGsm.put('y', i++); 765 charToGsm.put('z', i++); 766 charToGsm.put('\u00e4', i++); 767 charToGsm.put('\u00f6', i++); 768 charToGsm.put('\u00f1', i++); 769 charToGsm.put('\u00fc', i++); 770 charToGsm.put('\u00e0', i++); 771 772 773 charToGsmExtended.put('\f', 10); 774 charToGsmExtended.put('^', 20); 775 charToGsmExtended.put('{', 40); 776 charToGsmExtended.put('}', 41); 777 charToGsmExtended.put('\\', 47); 778 charToGsmExtended.put('[', 60); 779 charToGsmExtended.put('~', 61); 780 charToGsmExtended.put(']', 62); 781 charToGsmExtended.put('|', 64); 782 charToGsmExtended.put('\u20ac', 101); 783 784 int size = charToGsm.size(); 785 for (int j=0; j<size; j++) { 786 gsmToChar.put(charToGsm.valueAt(j), charToGsm.keyAt(j)); 787 } 788 789 size = charToGsmExtended.size(); 790 for (int j=0; j<size; j++) { 791 gsmExtendedToChar.put(charToGsmExtended.valueAt(j), charToGsmExtended.keyAt(j)); 792 } 793 794 795 sGsmSpaceChar = charToGsm.get(' '); 796 } 797 798 799} 800