зеркало из https://github.com/mozilla/gecko-dev.git
Bug 824611 - Part 1: Add ICC PDU Helper. r=yoshi
This commit is contained in:
Родитель
7ba509dc4d
Коммит
a7e8a7d504
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче