Bug 823865 - Part 1: GsmPDUHelper.writeAlphaIdDiallingNumber. r=hsinyi
authorYoshi Huang <allstars.chh@mozilla.com>
Fri, 21 Dec 2012 16:24:25 +0800
changeset 127012 d74a5a6e1aac8d84e80cdaec3cd857dd2412fdd1
parent 127011 66a04865fe51b954645cbc9b4a16f775682461c8
child 127013 e005476eb9f602067e65712babf6d9bda50df2ab
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsinyi
bugs823865
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 823865 - Part 1: GsmPDUHelper.writeAlphaIdDiallingNumber. r=hsinyi
dom/system/gonk/ril_consts.js
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -460,19 +460,25 @@ this.EF_TYPE_CYCLIC = 3;
 
 // Status code of EFsms
 // see 3GPP TS 51.011 clause 10.5.3
 this.EFSMS_STATUS_FREE       = 0x00;
 this.EFSMS_STATUS_READ       = 0x01;
 this.EFSMS_STATUS_TO_BE_READ = 0x03;
 this.EFSMS_STATUS_TO_BE_SENT = 0x07;
 
-// For retrieving MSISDN, TS 151.011 clause 10.5.5
-this.MSISDN_FOOTER_SIZE_BYTES = 14;
-this.MSISDN_MAX_NUMBER_SIZE_BYTES = 10;
+// Total size of ADN footer(the size of Alpha identifier excluded).
+// See TS 151.011 clause 10.5.1 EF_ADN.
+this.ADN_FOOTER_SIZE_BYTES = 14;
+// Maximum size of BCD numbers in ADN.
+// See TS 151.011 clause 10.5.1 EF_ADN, 'Length of BCD number/SSC contents'.
+this.ADN_MAX_BCD_NUMBER_BYTES = 11;
+// Maximum digits of the Dialling Number in ADN.
+// See TS 151.011 clause 10.5.1 EF_ADN, 'Dialling Number'.
+this.ADN_MAX_NUMBER_DIGITS = 20;
 
 // READ_RECORD mode,  TS 102.221
 this.READ_RECORD_ABSOLUTE_MODE = 4;
 
 // GET_RESPONSE mandatory response size for EF, see TS 51.011 clause 9, 
 // 'Response data in case of an EF.'
 this.GET_RESPONSE_EF_SIZE_BYTES = 15;
 
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -5526,16 +5526,59 @@ let GsmPDUHelper = {
       }
     }
 
     Buf.seekIncoming((numOctets - i) * PDU_HEX_OCTET_SIZE);
     return ret;
   },
 
   /**
+   * Write GSM 8-bit unpacked octets.
+   *
+   * @param numOctets   Number of total octets to be writen, including trailing
+   *                    0xff.
+   * @param str         String to be written. Could be null.
+   */
+  writeStringTo8BitUnpacked: function writeStringTo8BitUnpacked(numOctets, str) {
+    const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+    const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+
+    // If the character is GSM extended alphabet, two octets will be written.
+    // So we need to keep track of number of octets to be written.
+    let i, j;
+    let len = str ? str.length : 0;
+    for (i = 0, j = 0; i < len && j < numOctets; i++) {
+      let c = str.charAt(i);
+      let octet = langTable.indexOf(c);
+
+      if (octet == -1) {
+        // Make sure we still have enough space to write two octets.
+        if (j + 2 > numOctets) {
+          break;
+        }
+
+        octet = langShiftTable.indexOf(c);
+        if (octet == -1) {
+          // Fallback to ASCII space.
+          octet = langTable.indexOf(' ');
+        }
+        this.writeHexOctet(PDU_NL_EXTENDED_ESCAPE);
+        j++;
+      }
+      this.writeHexOctet(octet);
+      j++;
+    }
+
+    // trailing 0xff
+    while (j++ < numOctets) {
+      this.writeHexOctet(0xff);
+    }
+  },
+
+  /**
    * Read user data and decode as a UCS2 string.
    *
    * @param numOctets
    *        Number of octets to be read as UCS2 string.
    *
    * @return a string.
    */
   readUCS2String: function readUCS2String(numOctets) {
@@ -5908,49 +5951,95 @@ let GsmPDUHelper = {
     if ((toa & 0xF0) == (PDU_TOA_INTERNATIONAL)) {
       addr = '+' + addr;
     }
 
     return addr;
   },
 
   /**
-   *  Read Alpha Id and Dialling number from TS 131.102
-   *
-   *  @param options
-   *         The 'options' object passed from RIL.iccIO
-   */
-  readAlphaIdDiallingNumber: function readAlphaIdDiallingNumber(options) {
-    let contact = null;
-    let ffLen; // The length of trailing 0xff to be read.
+   * Read Alpha Id and Dialling number from TS TS 151.011 clause 10.5.1
+   *
+   * @param recordSize  The size of linear fixed record.
+   */
+  readAlphaIdDiallingNumber: function readAlphaIdDiallingNumber(recordSize) {
     let length = Buf.readUint32();
 
-    let alphaLen = options.recordSize - MSISDN_FOOTER_SIZE_BYTES;
+    let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES;
     let alphaId = this.readAlphaIdentifier(alphaLen);
 
+    let number;
     let numLen = this.readHexOctet();
     if (numLen != 0xff) {
-      // +1 for TON/NPI
-      if (numLen > MSISDN_MAX_NUMBER_SIZE_BYTES + 1) {
+      if (numLen > ADN_MAX_BCD_NUMBER_BYTES) {
         throw new Error("invalid length of BCD number/SSC contents - " + numLen);
       }
 
+      number = this.readDiallingNumber(numLen);
+      Buf.seekIncoming((ADN_MAX_BCD_NUMBER_BYTES - numLen) * PDU_HEX_OCTET_SIZE);
+    } else {
+      Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * PDU_HEX_OCTET_SIZE);
+    }
+
+    // Skip 2 unused octets, CCP and EXT1.
+    Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE);
+    Buf.readStringDelimiter(length);
+
+    let contact = null;
+    if (alphaId || number) {
       contact = {alphaId: alphaId,
-                 number: this.readDiallingNumber(numLen)};
-
-      ffLen = length / 2 - alphaLen - numLen - 1; // Minus 1 for the numLen field.
+                 number: number};
+    }
+    return contact;
+  },
+
+  /**
+   * Write Alpha Identifier and Dialling number from TS 151.011 clause 10.5.1
+   *
+   * @param recordSize  The size of linear fixed record.
+   * @param alphaId     Alpha Identifier to be written.
+   * @param number      Dialling Number to be written.
+   */
+  writeAlphaIdDiallingNumber: function writeAlphaIdDiallingNumber(recordSize,
+                                                                  alphaId,
+                                                                  number) {
+    // Write String length
+    let length = recordSize * 2;
+    Buf.writeUint32(length);
+
+    let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES;
+    this.writeAlphaIdentifier(alphaLen, alphaId);
+
+    if (number) {
+      let numStart = number[0] == "+" ? 1 : 0;
+      let numDigits = number.length - numStart;
+      if (numDigits > ADN_MAX_NUMBER_DIGITS) {
+        number = number.substring(0, ADN_MAX_NUMBER_DIGITS + numStart);
+        numDigits = number.length - numStart;
+      }
+
+      // +1 for TON/NPI
+      let numLen = Math.ceil(numDigits / 2) + 1;
+      this.writeHexOctet(numLen);
+      this.writeDiallingNumber(number);
+      // Write trailing 0xff of Dialling Number.
+      for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES - numLen; i++) {
+        this.writeHexOctet(0xff);
+      }
     } else {
-      ffLen = MSISDN_FOOTER_SIZE_BYTES - 1; // Minus 1 for the numLen field.
-    }
-
-    // Consumes the remaining 0xff
-    Buf.seekIncoming(ffLen * PDU_HEX_OCTET_SIZE);
-    Buf.readStringDelimiter(length);
-
-    return contact;
+      // +1 for numLen
+      for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES + 1; i++) {
+        this.writeHexOctet(0xff);
+      }
+    }
+
+    // Write unused octets 0xff, CCP and EXT1.
+    this.writeHexOctet(0xff);
+    this.writeHexOctet(0xff);
+    Buf.writeStringDelimiter(length);
   },
 
   /**
    * Read Alpha Identifier.
    *
    * @see TS 131.102
    *
    * @param numOctets
@@ -5958,31 +6047,68 @@ let GsmPDUHelper = {
    *
    * It uses either
    *  1. SMS default 7-bit alphabet with bit 8 set to 0.
    *  2. UCS2 string.
    *
    * Unused bytes should be set to 0xff.
    */
   readAlphaIdentifier: function readAlphaIdentifier(numOctets) {
+    if (numOctets === 0) {
+      return "";
+    }
+
     let temp;
-
     // Read the 1st octet to determine the encoding.
     if ((temp = GsmPDUHelper.readHexOctet()) == 0x80 ||
          temp == 0x81 ||
          temp == 0x82) {
       numOctets--;
       return this.readICCUCS2String(temp, numOctets);
     } else {
       Buf.seekIncoming(-1 * PDU_HEX_OCTET_SIZE);
       return this.read8BitUnpackedToString(numOctets);
     }
   },
 
   /**
+   * Write Alpha Identifier.
+   *
+   * @param numOctets
+   *        Total number of octets to be written. This includes the length of
+   *        alphaId and the length of trailing unused octets(0xff).
+   * @param alphaId
+   *        Alpha Identifier to be written.
+   *
+   * Unused octets will be written as 0xff.
+   */
+  writeAlphaIdentifier: function writeAlphaIdentifier(numOctets, alphaId) {
+    if (numOctets === 0) {
+      return;
+    }
+
+    // If alphaId is empty or it's of GSM 8 bit.
+    if (!alphaId || ICCUtilsHelper.isGsm8BitAlphabet(alphaId)) {
+      this.writeStringTo8BitUnpacked(numOctets, alphaId);
+    } else {
+      // Currently only support UCS2 coding scheme 0x80.
+      this.writeHexOctet(0x80);
+      numOctets--;
+      // Now the alphaId is UCS2 string, each character will take 2 octets.
+      if (alphaId.length * 2 > numOctets) {
+        alphaId = alphaId.substring(0, Math.floor(numOctets / 2));
+      }
+      this.writeUCS2String(alphaId);
+      for (let i = alphaId.length * 2; i < numOctets; i++) {
+        this.writeHexOctet(0xff);
+      }
+    }
+  },
+
+  /**
    * Read Dialling number.
    *
    * @see TS 131.102
    *
    * @param len
    *        The Length of BCD number.
    *
    * From TS 131.102, in EF_ADN, EF_FDN, the field 'Length of BCD number'
@@ -8460,17 +8586,17 @@ let ICCRecordHelper = {
                                    callback: callback.bind(this)});
   },
 
   /**
    * Read the MSISDN from the ICC.
    */
   getMSISDN: function getMSISDN() {
     function callback(options) {
-      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options);
+      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
       if (!contact || RIL.iccInfo.msisdn === contact.number) {
         return;
       }
       RIL.iccInfo.msisdn = contact.number;
       if (DEBUG) debug("MSISDN: " + RIL.iccInfo.msisdn);
       ICCUtilsHelper.handleICCInfoChange();
     }
 
@@ -8611,17 +8737,17 @@ let ICCRecordHelper = {
   /**
    *  Get ICC FDN.
    *
    *  @param requestId
    *         Request id from RadioInterfaceLayer.
    */
   getFDN: function getFDN(options) {
     function callback(options) {
-      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options);
+      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
       if (contact) {
         RIL.iccInfo.fdn.push(contact);
       }
 
       if (options.p1 < options.totalRecords) {
         ICCIOHelper.loadNextRecord(options);
       } else {
         if (DEBUG) {
@@ -8652,17 +8778,17 @@ let ICCRecordHelper = {
    *
    *  @param fileId
    *         EF id of the ADN.
    *  @param requestId
    *         Request id from RadioInterfaceLayer.
    */
   getADN: function getADN(options) {
     function callback(options) {
-      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options);
+      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
       if (contact) {
         RIL.iccInfo.adn.push(contact);
       }
 
       if (options.p1 < options.totalRecords) {
         ICCIOHelper.loadNextRecord(options);
       } else {
         if (DEBUG) {
@@ -8696,17 +8822,17 @@ let ICCRecordHelper = {
 
   /**
    * Get ICC MBDN. (Mailbox Dialling Number)
    *
    * @see TS 131.102, clause 4.2.60
    */
   getMBDN: function getMBDN() {
     function callback(options) {
-      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options);
+      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
       if (!contact || RIL.iccInfo.mbdn === contact.number){
         return;
       }
       RIL.iccInfo.mbdn = contact.number;
       if (DEBUG) {
         debug("MBDN, alphaId="+contact.alphaId+" number="+contact.number);
       }
       contact.rilMessageType = "iccmbdn";
@@ -9282,16 +9408,44 @@ let ICCUtilsHelper = {
       index = Math.floor(usimService / 8);
       bitmask = 1 << ((usimService % 8) << 0);
     }
 
     return (serviceTable &&
            (index < serviceTable.length) &&
            (serviceTable[index] & bitmask)) != 0;
   },
+
+  /**
+   * Check if the string is of GSM default 7-bit coded alphabets with bit 8
+   * set to 0.
+   *
+   * @param str  String to be checked.
+   */
+  isGsm8BitAlphabet: function isGsm8BitAlphabet(str) {
+    if (!str) {
+      return false;
+    }
+
+    const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+    const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+
+    for (let i = 0; i < str.length; i++) {
+      let c = str.charAt(i);
+      let octet = langTable.indexOf(c);
+      if (octet == -1) {
+        octet = langShiftTable.indexOf(c);
+        if (octet == -1) {
+          return false;
+        }
+      }
+    }
+
+    return true;
+  },
 };
 
 /**
  * Global stuff.
  */
 
 if (!this.debug) {
   // Debugging stub that goes nowhere.