From a7e8a7d504dcc41dcb27ca65deded19fd37500c8 Mon Sep 17 00:00:00 2001 From: Georgia Wang Date: Mon, 11 Nov 2013 14:28:20 +0800 Subject: [PATCH] Bug 824611 - Part 1: Add ICC PDU Helper. r=yoshi --- dom/system/gonk/ril_worker.js | 837 +++++++++++++++++----------------- 1 file changed, 421 insertions(+), 416 deletions(-) diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index b599c4b3295b..e5a9f3ba6b1c 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -2857,7 +2857,7 @@ let RIL = { ComprehensionTlvHelper.writeLength( Math.ceil(options.address.length/2) + 1 // address BCD + TON ); - GsmPDUHelper.writeDiallingNumber(options.address); + ICCPDUHelper.writeDiallingNumber(options.address); } // Cause of disconnection. @@ -6684,96 +6684,6 @@ let GsmPDUHelper = { } }, - /** - * Read GSM 8-bit unpacked octets, - * which are SMS default 7-bit alphabets with bit 8 set to 0. - * - * @param numOctets - * Number of octets to be read. - */ - read8BitUnpackedToString: function read8BitUnpackedToString(numOctets) { - let ret = ""; - let escapeFound = false; - let i; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - for(i = 0; i < numOctets; i++) { - let octet = this.readHexOctet(); - if (octet == 0xff) { - i++; - break; - } - - if (escapeFound) { - escapeFound = false; - if (octet == PDU_NL_EXTENDED_ESCAPE) { - // According to 3GPP TS 23.038, section 6.2.1.1, NOTE 1, "On - // receipt of this code, a receiving entity shall display a space - // until another extensiion table is defined." - ret += " "; - } else if (octet == PDU_NL_RESERVED_CONTROL) { - // According to 3GPP TS 23.038 B.2, "This code represents a control - // character and therefore must not be used for language specific - // characters." - ret += " "; - } else { - ret += langShiftTable[octet]; - } - } else if (octet == PDU_NL_EXTENDED_ESCAPE) { - escapeFound = true; - } else { - ret += langTable[octet]; - } - } - - Buf.seekIncoming((numOctets - i) * Buf.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. * @@ -6809,103 +6719,6 @@ let GsmPDUHelper = { } }, - /** - * Read UCS2 String on UICC. - * - * @see TS 101.221, Annex A. - * @param scheme - * Coding scheme for UCS2 on UICC. One of 0x80, 0x81 or 0x82. - * @param numOctets - * Number of octets to be read as UCS2 string. - */ - readICCUCS2String: function readICCUCS2String(scheme, numOctets) { - let str = ""; - switch (scheme) { - /** - * +------+---------+---------+---------+---------+------+------+ - * | 0x80 | Ch1_msb | Ch1_lsb | Ch2_msb | Ch2_lsb | 0xff | 0xff | - * +------+---------+---------+---------+---------+------+------+ - */ - case 0x80: - let isOdd = numOctets % 2; - let i; - for (i = 0; i < numOctets - isOdd; i += 2) { - let code = (this.readHexOctet() << 8) | this.readHexOctet(); - if (code == 0xffff) { - i += 2; - break; - } - str += String.fromCharCode(code); - } - - // Skip trailing 0xff - Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE); - break; - case 0x81: // Fall through - case 0x82: - /** - * +------+-----+--------+-----+-----+-----+--------+------+ - * | 0x81 | len | offset | Ch1 | Ch2 | ... | Ch_len | 0xff | - * +------+-----+--------+-----+-----+-----+--------+------+ - * - * len : The length of characters. - * offset : 0hhh hhhh h000 0000 - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n & 0x7f) + offset - * - * +------+-----+------------+------------+-----+-----+-----+--------+ - * | 0x82 | len | offset_msb | offset_lsb | Ch1 | Ch2 | ... | Ch_len | - * +------+-----+------------+------------+-----+-----+-----+--------+ - * - * len : The length of characters. - * offset_msb, offset_lsn: offset - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n & 0x7f) + offset - */ - let len = this.readHexOctet(); - let offset, headerLen; - if (scheme == 0x81) { - offset = this.readHexOctet() << 7; - headerLen = 2; - } else { - offset = (this.readHexOctet() << 8) | this.readHexOctet(); - headerLen = 3; - } - - for (let i = 0; i < len; i++) { - let ch = this.readHexOctet(); - if (ch & 0x80) { - // UCS2 - str += String.fromCharCode((ch & 0x7f) + offset); - } else { - // GSM 8bit - let count = 0, gotUCS2 = 0; - while ((i + count + 1 < len)) { - count++; - if (this.readHexOctet() & 0x80) { - gotUCS2 = 1; - break; - } - } - // Unread. - // +1 for the GSM alphabet indexed at i, - Buf.seekIncoming(-1 * (count + 1) * Buf.PDU_HEX_OCTET_SIZE); - str += this.read8BitUnpackedToString(count + 1 - gotUCS2); - i += count - gotUCS2; - } - } - - // Skipping trailing 0xff - Buf.seekIncoming((numOctets - len - headerLen) * Buf.PDU_HEX_OCTET_SIZE); - break; - } - return str; - }, - /** * Read 1 + UDHL octets and construct user data header. * @@ -7156,219 +6969,6 @@ let GsmPDUHelper = { return addr; }, - /** - * 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.readInt32(); - - let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES; - let alphaId = this.readAlphaIdentifier(alphaLen); - - let number = this.readNumberWithLength(); - - // Skip 2 unused octets, CCP and EXT1. - Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(length); - - let contact = null; - if (alphaId || number) { - contact = {alphaId: alphaId, - 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 strLen = recordSize * 2; - Buf.writeInt32(strLen); - - let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES; - this.writeAlphaIdentifier(alphaLen, alphaId); - this.writeNumberWithLength(number); - - // Write unused octets 0xff, CCP and EXT1. - this.writeHexOctet(0xff); - this.writeHexOctet(0xff); - Buf.writeStringDelimiter(strLen); - }, - - /** - * Read Alpha Identifier. - * - * @see TS 131.102 - * - * @param numOctets - * Number of octets to be read. - * - * 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 * Buf.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' - * means the total bytes should be allocated to store the TON/NPI and - * the dialing number. - * For example, if the dialing number is 1234567890, - * and the TON/NPI is 0x81, - * The field 'Length of BCD number' should be 06, which is - * 1 byte to store the TON/NPI, 0x81 - * 5 bytes to store the BCD number 2143658709. - * - * Here the definition of the length is different from SMS spec, - * TS 23.040 9.1.2.5, which the length means - * "number of useful semi-octets within the Address-Value field". - */ - readDiallingNumber: function readDiallingNumber(len) { - if (DEBUG) debug("PDU: Going to read Dialling number: " + len); - if (len === 0) { - return ""; - } - - // TOA = TON + NPI - let toa = this.readHexOctet(); - - let number = this.readSwappedNibbleBcdString(len - 1); - if (number.length <= 0) { - if (DEBUG) debug("No number provided"); - return ""; - } - if ((toa >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) { - number = '+' + number; - } - return number; - }, - - /** - * Write Dialling Number. - * - * @param number The Dialling number - */ - writeDiallingNumber: function writeDiallingNumber(number) { - let toa = PDU_TOA_ISDN; // 81 - if (number[0] == '+') { - toa = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91 - number = number.substring(1); - } - this.writeHexOctet(toa); - this.writeSwappedNibbleBCD(number); - }, - - readNumberWithLength: function readNumberWithLength() { - let number; - let numLen = this.readHexOctet(); - if (numLen != 0xff) { - 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) * Buf.PDU_HEX_OCTET_SIZE); - } else { - Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE); - } - - return number; - }, - - writeNumberWithLength: function writeNumberWithLength(number) { - 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 { - // +1 for numLen - for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES + 1; i++) { - this.writeHexOctet(0xff); - } - } - }, - /** * Read TP-Protocol-Indicator(TP-PID). * @@ -9590,6 +9190,411 @@ let CdmaPDUHelper = { } }; +/** + * Helper for processing ICC PDUs. + */ +let ICCPDUHelper = { + /** + * Read GSM 8-bit unpacked octets, + * which are default 7-bit alphabets with bit 8 set to 0. + * + * @param numOctets + * Number of octets to be read. + */ + read8BitUnpackedToString: function read8BitUnpackedToString(numOctets) { + let ret = ""; + let escapeFound = false; + let i; + const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; + const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; + + for(i = 0; i < numOctets; i++) { + let octet = GsmPDUHelper.readHexOctet(); + if (octet == 0xff) { + i++; + break; + } + + if (escapeFound) { + escapeFound = false; + if (octet == PDU_NL_EXTENDED_ESCAPE) { + // According to 3GPP TS 23.038, section 6.2.1.1, NOTE 1, "On + // receipt of this code, a receiving entity shall display a space + // until another extensiion table is defined." + ret += " "; + } else if (octet == PDU_NL_RESERVED_CONTROL) { + // According to 3GPP TS 23.038 B.2, "This code represents a control + // character and therefore must not be used for language specific + // characters." + ret += " "; + } else { + ret += langShiftTable[octet]; + } + } else if (octet == PDU_NL_EXTENDED_ESCAPE) { + escapeFound = true; + } else { + ret += langTable[octet]; + } + } + + Buf.seekIncoming((numOctets - i) * Buf.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(' '); + } + GsmPDUHelper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); + j++; + } + GsmPDUHelper.writeHexOctet(octet); + j++; + } + + // trailing 0xff + while (j++ < numOctets) { + GsmPDUHelper.writeHexOctet(0xff); + } + }, + + /** + * Read UCS2 String on UICC. + * + * @see TS 101.221, Annex A. + * @param scheme + * Coding scheme for UCS2 on UICC. One of 0x80, 0x81 or 0x82. + * @param numOctets + * Number of octets to be read as UCS2 string. + */ + readICCUCS2String: function readICCUCS2String(scheme, numOctets) { + let str = ""; + switch (scheme) { + /** + * +------+---------+---------+---------+---------+------+------+ + * | 0x80 | Ch1_msb | Ch1_lsb | Ch2_msb | Ch2_lsb | 0xff | 0xff | + * +------+---------+---------+---------+---------+------+------+ + */ + case 0x80: + let isOdd = numOctets % 2; + let i; + for (i = 0; i < numOctets - isOdd; i += 2) { + let code = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); + if (code == 0xffff) { + i += 2; + break; + } + str += String.fromCharCode(code); + } + + // Skip trailing 0xff + Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE); + break; + case 0x81: // Fall through + case 0x82: + /** + * +------+-----+--------+-----+-----+-----+--------+------+ + * | 0x81 | len | offset | Ch1 | Ch2 | ... | Ch_len | 0xff | + * +------+-----+--------+-----+-----+-----+--------+------+ + * + * len : The length of characters. + * offset : 0hhh hhhh h000 0000 + * Ch_n: bit 8 = 0 + * GSM default alphabets + * bit 8 = 1 + * UCS2 character whose char code is (Ch_n & 0x7f) + offset + * + * +------+-----+------------+------------+-----+-----+-----+--------+ + * | 0x82 | len | offset_msb | offset_lsb | Ch1 | Ch2 | ... | Ch_len | + * +------+-----+------------+------------+-----+-----+-----+--------+ + * + * len : The length of characters. + * offset_msb, offset_lsn: offset + * Ch_n: bit 8 = 0 + * GSM default alphabets + * bit 8 = 1 + * UCS2 character whose char code is (Ch_n & 0x7f) + offset + */ + let len = GsmPDUHelper.readHexOctet(); + let offset, headerLen; + if (scheme == 0x81) { + offset = GsmPDUHelper.readHexOctet() << 7; + headerLen = 2; + } else { + offset = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); + headerLen = 3; + } + + for (let i = 0; i < len; i++) { + let ch = GsmPDUHelper.readHexOctet(); + if (ch & 0x80) { + // UCS2 + str += String.fromCharCode((ch & 0x7f) + offset); + } else { + // GSM 8bit + let count = 0, gotUCS2 = 0; + while ((i + count + 1 < len)) { + count++; + if (GsmPDUHelper.readHexOctet() & 0x80) { + gotUCS2 = 1; + break; + } + } + // Unread. + // +1 for the GSM alphabet indexed at i, + Buf.seekIncoming(-1 * (count + 1) * Buf.PDU_HEX_OCTET_SIZE); + str += this.read8BitUnpackedToString(count + 1 - gotUCS2); + i += count - gotUCS2; + } + } + + // Skipping trailing 0xff + Buf.seekIncoming((numOctets - len - headerLen) * Buf.PDU_HEX_OCTET_SIZE); + break; + } + return str; + }, + + /** + * 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.readInt32(); + + let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES; + let alphaId = this.readAlphaIdentifier(alphaLen); + + let number = this.readNumberWithLength(); + + // Skip 2 unused octets, CCP and EXT1. + Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); + Buf.readStringDelimiter(length); + + let contact = null; + if (alphaId || number) { + contact = {alphaId: alphaId, + 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 strLen = recordSize * 2; + Buf.writeInt32(strLen); + + let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES; + this.writeAlphaIdentifier(alphaLen, alphaId); + this.writeNumberWithLength(number); + + // Write unused octets 0xff, CCP and EXT1. + GsmPDUHelper.writeHexOctet(0xff); + GsmPDUHelper.writeHexOctet(0xff); + Buf.writeStringDelimiter(strLen); + }, + + /** + * Read Alpha Identifier. + * + * @see TS 131.102 + * + * @param numOctets + * Number of octets to be read. + * + * 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 * Buf.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. + GsmPDUHelper.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)); + } + GsmPDUHelper.writeUCS2String(alphaId); + for (let i = alphaId.length * 2; i < numOctets; i++) { + GsmPDUHelper.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' + * means the total bytes should be allocated to store the TON/NPI and + * the dialing number. + * For example, if the dialing number is 1234567890, + * and the TON/NPI is 0x81, + * The field 'Length of BCD number' should be 06, which is + * 1 byte to store the TON/NPI, 0x81 + * 5 bytes to store the BCD number 2143658709. + * + * Here the definition of the length is different from SMS spec, + * TS 23.040 9.1.2.5, which the length means + * "number of useful semi-octets within the Address-Value field". + */ + readDiallingNumber: function readDiallingNumber(len) { + if (DEBUG) debug("PDU: Going to read Dialling number: " + len); + if (len === 0) { + return ""; + } + + // TOA = TON + NPI + let toa = GsmPDUHelper.readHexOctet(); + + let number = GsmPDUHelper.readSwappedNibbleBcdString(len - 1); + if (number.length <= 0) { + if (DEBUG) debug("No number provided"); + return ""; + } + if ((toa >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) { + number = '+' + number; + } + return number; + }, + + /** + * Write Dialling Number. + * + * @param number The Dialling number + */ + writeDiallingNumber: function writeDiallingNumber(number) { + let toa = PDU_TOA_ISDN; // 81 + if (number[0] == '+') { + toa = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91 + number = number.substring(1); + } + GsmPDUHelper.writeHexOctet(toa); + GsmPDUHelper.writeSwappedNibbleBCD(number); + }, + + readNumberWithLength: function readNumberWithLength() { + let number; + let numLen = GsmPDUHelper.readHexOctet(); + if (numLen != 0xff) { + 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) * Buf.PDU_HEX_OCTET_SIZE); + } else { + Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE); + } + + return number; + }, + + writeNumberWithLength: function writeNumberWithLength(number) { + 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; + GsmPDUHelper.writeHexOctet(numLen); + this.writeDiallingNumber(number); + // Write trailing 0xff of Dialling Number. + for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES - numLen; i++) { + GsmPDUHelper.writeHexOctet(0xff); + } + } else { + // +1 for numLen + for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES + 1; i++) { + GsmPDUHelper.writeHexOctet(0xff); + } + } + } +}; + let StkCommandParamsFactory = { createParam: function createParam(cmdDetails, ctlvs) { let method = StkCommandParamsFactory[cmdDetails.typeOfCommand]; @@ -10157,7 +10162,7 @@ let StkProactiveCmdHelper = { */ retrieveAlphaId: function retrieveAlphaId(length) { let alphaId = { - identifier: GsmPDUHelper.readAlphaIdentifier(length) + identifier: ICCPDUHelper.readAlphaIdentifier(length) }; return alphaId; }, @@ -10191,7 +10196,7 @@ let StkProactiveCmdHelper = { */ retrieveAddress: function retrieveAddress(length) { let address = { - number : GsmPDUHelper.readDiallingNumber(length) + number : ICCPDUHelper.readDiallingNumber(length) }; return address; }, @@ -10222,7 +10227,7 @@ let StkProactiveCmdHelper = { text.textString = GsmPDUHelper.readSeptetsToString(length * 8 / 7, 0, 0, 0); break; case STK_TEXT_CODING_GSM_8BIT: - text.textString = GsmPDUHelper.read8BitUnpackedToString(length); + text.textString = ICCPDUHelper.read8BitUnpackedToString(length); break; case STK_TEXT_CODING_UCS2: text.textString = GsmPDUHelper.readUCS2String(length); @@ -10266,7 +10271,7 @@ let StkProactiveCmdHelper = { } let item = { identifier: GsmPDUHelper.readHexOctet(), - text: GsmPDUHelper.readAlphaIdentifier(length - 1) + text: ICCPDUHelper.readAlphaIdentifier(length - 1) }; return item; }, @@ -11246,7 +11251,7 @@ let ICCRecordHelper = { */ readMSISDN: function readMSISDN() { function callback(options) { - let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize); + let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); if (!contact || (RIL.iccInfo.msisdn !== undefined && RIL.iccInfo.msisdn === contact.number)) { @@ -11304,7 +11309,7 @@ let ICCRecordHelper = { let octetLen = strLen / 2; let spnDisplayCondition = GsmPDUHelper.readHexOctet(); // Minus 1 because the first octet is used to store display condition. - let spn = GsmPDUHelper.readAlphaIdentifier(octetLen - 1); + let spn = ICCPDUHelper.readAlphaIdentifier(octetLen - 1); Buf.readStringDelimiter(strLen); if (DEBUG) { @@ -11416,7 +11421,7 @@ let ICCRecordHelper = { */ readADNLike: function readADNLike(fileId, onsuccess, onerror) { function callback(options) { - let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize); + let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); if (contact) { contact.recordId = options.p1; contacts.push(contact); @@ -11453,7 +11458,7 @@ let ICCRecordHelper = { */ updateADNLike: function updateADNLike(fileId, contact, pin2, onsuccess, onerror) { function dataWriter(recordSize) { - GsmPDUHelper.writeAlphaIdDiallingNumber(recordSize, + ICCPDUHelper.writeAlphaIdDiallingNumber(recordSize, contact.alphaId, contact.number); } @@ -11485,7 +11490,7 @@ let ICCRecordHelper = { */ readMBDN: function readMBDN() { function callback(options) { - let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize); + let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); if (!contact || (RIL.iccInfoPrivate.mbdn !== undefined && RIL.iccInfoPrivate.mbdn === contact.number)) { @@ -11658,9 +11663,9 @@ let ICCRecordHelper = { // Note: The fields marked as C above are mandatort if the file // is not type 1 (as specified in EF_PBR) if (fileType == ICC_USIM_TYPE1_TAG) { - email = GsmPDUHelper.read8BitUnpackedToString(octetLen); + email = ICCPDUHelper.read8BitUnpackedToString(octetLen); } else { - email = GsmPDUHelper.read8BitUnpackedToString(octetLen - 2); + email = ICCPDUHelper.read8BitUnpackedToString(octetLen - 2); // Consumes the remaining buffer Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); // For ADN SFI and Record Identifier @@ -11701,9 +11706,9 @@ let ICCRecordHelper = { Buf.writeInt32(strLen); if (fileType == ICC_USIM_TYPE1_TAG) { - GsmPDUHelper.writeStringTo8BitUnpacked(recordSize, email); + ICCPDUHelper.writeStringTo8BitUnpacked(recordSize, email); } else { - GsmPDUHelper.writeStringTo8BitUnpacked(recordSize - 2, email); + ICCPDUHelper.writeStringTo8BitUnpacked(recordSize - 2, email); GsmPDUHelper.writeHexOctet(pbr.adn.sfi || 0xff); GsmPDUHelper.writeHexOctet(adnRecordId); } @@ -11743,7 +11748,7 @@ let ICCRecordHelper = { // Skip EF_AAS Record ID. Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE); - number = GsmPDUHelper.readNumberWithLength(); + number = ICCPDUHelper.readNumberWithLength(); // Skip 2 unused octets, CCP and EXT1. Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); @@ -11790,7 +11795,7 @@ let ICCRecordHelper = { // EF_AAS record Id. Unused for now. GsmPDUHelper.writeHexOctet(0xff); - GsmPDUHelper.writeNumberWithLength(number); + ICCPDUHelper.writeNumberWithLength(number); // Write unused octets 0xff, CCP and EXT1. GsmPDUHelper.writeHexOctet(0xff);