mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 761057 - Part 2: Add required encoders for M-Send.req/M-Send.conf PDU, r=philikon
This commit is contained in:
parent
f6f2cd1a53
commit
a39061d0de
@ -26,6 +26,13 @@ function translatePduErrorToStatus(error) {
|
||||
return MMS_PDU_STATUS_UNRECOGNISED;
|
||||
}
|
||||
|
||||
function defineLazyRegExp(obj, name, pattern) {
|
||||
obj.__defineGetter__(name, function() {
|
||||
delete obj[name];
|
||||
return obj[name] = new RegExp(pattern);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal decoding function for boolean values.
|
||||
*
|
||||
@ -80,17 +87,17 @@ let Address = {
|
||||
let str = EncodedStringValue.decode(data);
|
||||
|
||||
let result;
|
||||
if (((result = str.match(/^(\+?[\d.-]+)\/TYPE=(PLMN)$/)) != null)
|
||||
|| ((result = str.match(/^(\d{1,3}(?:\.\d{1,3}){3})\/TYPE=(IPv4)$/)) != null)
|
||||
|| ((result = str.match(/^([\da-fA-F]{4}(?::[\da-fA-F]{4}){7})\/TYPE=(IPv6)$/)) != null)
|
||||
|| ((result = str.match(/^([\w\+\-.%]+)\/TYPE=(\w+)$/)) != null)) {
|
||||
if (((result = str.match(this.REGEXP_DECODE_PLMN)) != null)
|
||||
|| ((result = str.match(this.REGEXP_DECODE_IPV4)) != null)
|
||||
|| ((result = str.match(this.REGEXP_DECODE_IPV6)) != null)
|
||||
|| ((result = str.match(this.REGEXP_DECODE_CUSTOM)) != null)) {
|
||||
return {address: result[1], type: result[2]};
|
||||
}
|
||||
|
||||
let type;
|
||||
if (str.match(/^[\+*#]\d+$/)) {
|
||||
if (str.match(this.REGEXP_NUM)) {
|
||||
type = "num";
|
||||
} else if (str.match(/^\w+$/)) {
|
||||
} else if (str.match(this.REGEXP_ALPHANUM)) {
|
||||
type = "alphanum";
|
||||
} else if (str.indexOf("@") > 0) {
|
||||
// E-mail should match the definition of `mailbox` as described in section
|
||||
@ -103,8 +110,78 @@ let Address = {
|
||||
|
||||
return {address: str, type: type};
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An object of two string-typed attributes: address and type.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if (!value || !value.type || !value.address) {
|
||||
throw new WSP.CodeError("Address: invalid value");
|
||||
}
|
||||
|
||||
let str;
|
||||
switch (value.type) {
|
||||
case "email":
|
||||
if (value.address.indexOf("@") > 0) {
|
||||
str = value.address;
|
||||
}
|
||||
break;
|
||||
case "num":
|
||||
if (value.address.match(this.REGEXP_NUM)) {
|
||||
str = value.address;
|
||||
}
|
||||
break;
|
||||
case "alphanum":
|
||||
if (value.address.match(this.REGEXP_ALPHANUM)) {
|
||||
str = value.address;
|
||||
}
|
||||
break;
|
||||
case "IPv4":
|
||||
if (value.address.match(this.REGEXP_ENCODE_IPV4)) {
|
||||
str = value.address + "/TYPE=IPv4";
|
||||
}
|
||||
break;
|
||||
case "IPv6":
|
||||
if (value.address.match(this.REGEXP_ENCODE_IPV6)) {
|
||||
str = value.address + "/TYPE=IPv6";
|
||||
}
|
||||
break;
|
||||
case "PLMN":
|
||||
if (value.address.match(this.REGEXP_ENCODE_PLMN)) {
|
||||
str = value.address + "/TYPE=PLMN";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (value.type.match(this.REGEXP_ENCODE_CUSTOM_TYPE)
|
||||
&& value.address.match(this.REGEXP_ENCODE_CUSTOM_ADDR)) {
|
||||
str = value.address + "/TYPE=" + value.type;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!str) {
|
||||
throw new WSP.CodeError("Address: invalid value: " + JSON.stringify(value));
|
||||
}
|
||||
|
||||
EncodedStringValue.encode(data, str);
|
||||
},
|
||||
};
|
||||
|
||||
defineLazyRegExp(Address, "REGEXP_DECODE_PLMN", "^(\\+?[\\d.-]+)\\/TYPE=(PLMN)$");
|
||||
defineLazyRegExp(Address, "REGEXP_DECODE_IPV4", "^(\\d{1,3}(?:\\.\\d{1,3}){3})\\/TYPE=(IPv4)$");
|
||||
defineLazyRegExp(Address, "REGEXP_DECODE_IPV6", "^([\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7})\\/TYPE=(IPv6)$");
|
||||
defineLazyRegExp(Address, "REGEXP_DECODE_CUSTOM", "^([\\w\\+\\-.%]+)\\/TYPE=(\\w+)$");
|
||||
defineLazyRegExp(Address, "REGEXP_ENCODE_PLMN", "^\\+?[\\d.-]+$");
|
||||
defineLazyRegExp(Address, "REGEXP_ENCODE_IPV4", "^\\d{1,3}(?:\\.\\d{1,3}){3}$");
|
||||
defineLazyRegExp(Address, "REGEXP_ENCODE_IPV6", "^[\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7}$");
|
||||
defineLazyRegExp(Address, "REGEXP_ENCODE_CUSTOM_TYPE", "^\\w+$");
|
||||
defineLazyRegExp(Address, "REGEXP_ENCODE_CUSTOM_ADDR", "^[\\w\\+\\-.%]+$");
|
||||
defineLazyRegExp(Address, "REGEXP_NUM", "^[\\+*#]\\d+$");
|
||||
defineLazyRegExp(Address, "REGEXP_ALPHANUM", "^\\w+$");
|
||||
|
||||
/**
|
||||
* Header-field = MMS-header | Application-header
|
||||
*
|
||||
@ -240,6 +317,20 @@ let ContentClassValue = {
|
||||
|
||||
throw new WSP.CodeError("Content-class-value: invalid class " + value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* A numeric content class value to be encoded.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if ((value < 128) || (value > 135)) {
|
||||
throw new WSP.CodeError("Content-class-value: invalid class " + value);
|
||||
}
|
||||
|
||||
WSP.Octet.encode(data, value);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -406,6 +497,30 @@ let Parameter = {
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param param
|
||||
* An object containing two attributes: `name` and `value`.
|
||||
* @param options
|
||||
* Extra context for encoding.
|
||||
*/
|
||||
encode: function encode(data, param, options) {
|
||||
if (!param || !param.name) {
|
||||
throw new WSP.CodeError("Parameter-name: empty param name");
|
||||
}
|
||||
|
||||
let entry = MMS_WELL_KNOWN_PARAMS[param.name.toLowerCase()];
|
||||
if (entry) {
|
||||
WSP.ShortInteger.encode(data, entry.number);
|
||||
} else {
|
||||
WSP.TextString.encode(data, param.name);
|
||||
}
|
||||
|
||||
WSP.encodeAlternatives(data, param.value, options,
|
||||
WSP.ConstrainedEncoding, WSP.TextString);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -489,6 +604,63 @@ let EncodedStringValue = {
|
||||
return this.decodeCharsetEncodedString(data);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Always encode target string with UTF-8 encoding.
|
||||
*
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param str
|
||||
* A string.
|
||||
*/
|
||||
encodeCharsetEncodedString: function encodeCharsetEncodedString(data, str) {
|
||||
let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
// `When the text string cannot be represented as us-ascii, the character
|
||||
// set SHALL be encoded as utf-8(IANA MIBenum 106) which has unique byte
|
||||
// ordering.` ~ OMA-TS-MMS_CONF-V1_3-20110913-A clause 10.2.1
|
||||
conv.charset = "UTF-8";
|
||||
|
||||
let raw;
|
||||
try {
|
||||
raw = conv.convertToByteArray(str);
|
||||
} catch (e) {
|
||||
throw new WSP.CodeError("Charset-encoded-string: " + e.message);
|
||||
}
|
||||
|
||||
let length = raw.length + 2; // Charset number and NUL character
|
||||
// Prepend <Octet 127> if necessary.
|
||||
if (raw[0] >= 128) {
|
||||
++length;
|
||||
}
|
||||
|
||||
WSP.ValueLength.encode(data, length);
|
||||
|
||||
let entry = WSP.WSP_WELL_KNOWN_CHARSETS["utf-8"];
|
||||
WSP.IntegerValue.encode(data, entry.number);
|
||||
|
||||
if (raw[0] >= 128) {
|
||||
WSP.Octet.encode(data, 127);
|
||||
}
|
||||
WSP.Octet.encodeMultiple(data, raw);
|
||||
WSP.Octet.encode(data, 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param str
|
||||
* A string.
|
||||
*/
|
||||
encode: function encode(data, str) {
|
||||
let begin = data.offset;
|
||||
try {
|
||||
WSP.TextString.encode(data, str);
|
||||
} catch (e) {
|
||||
data.offset = begin;
|
||||
this.encodeCharsetEncodedString(data, str);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -529,6 +701,39 @@ let ExpiryValue = {
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* A Date object for absolute expiry or an integer for relative one.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
let isDate, begin = data.offset;
|
||||
if (value instanceof Date) {
|
||||
isDate = true;
|
||||
WSP.DateValue.encode(data, value);
|
||||
} else if (typeof value == "number") {
|
||||
isDate = false;
|
||||
WSP.DeltaSecondsValue.encode(data, value);
|
||||
} else {
|
||||
throw new CodeError("Expiry-value: invalid value type");
|
||||
}
|
||||
|
||||
// Calculate how much octets will be written and seek back.
|
||||
// TODO: use memmove, see bug 730873
|
||||
let len = data.offset - begin;
|
||||
data.offset = begin;
|
||||
|
||||
WSP.ValueLength.encode(data, len + 1);
|
||||
if (isDate) {
|
||||
WSP.Octet.encode(data, 128);
|
||||
WSP.DateValue.encode(data, value);
|
||||
} else {
|
||||
WSP.Octet.encode(data, 129);
|
||||
WSP.DeltaSecondsValue.encode(data, value);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -568,6 +773,31 @@ let FromValue = {
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* A Address-value or null for MMS Proxy-Relay Insert-Address mode.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if (!value) {
|
||||
WSP.ValueLength.encode(data, 1);
|
||||
WSP.Octet.encode(data, 129);
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate how much octets will be written and seek back.
|
||||
// TODO: use memmove, see bug 730873
|
||||
let begin = data.offset;
|
||||
Address.encode(data, value);
|
||||
let len = data.offset - begin;
|
||||
data.offset = begin;
|
||||
|
||||
WSP.ValueLength.encode(data, len + 1);
|
||||
WSP.Octet.encode(data, 128);
|
||||
Address.encode(data, value);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -641,6 +871,8 @@ let PreviouslySentDateValue = {
|
||||
* @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.27
|
||||
*/
|
||||
let MessageClassValue = {
|
||||
WELL_KNOWN_CLASSES: ["personal", "advertisement", "informational", "auto"],
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
@ -651,11 +883,8 @@ let MessageClassValue = {
|
||||
*/
|
||||
decodeClassIdentifier: function decodeClassIdentifier(data) {
|
||||
let value = WSP.Octet.decode(data);
|
||||
switch (value) {
|
||||
case 128: return "personal";
|
||||
case 129: return "advertisement";
|
||||
case 130: return "informational";
|
||||
case 131: return "auto";
|
||||
if ((value >= 128) && (value < (128 + this.WELL_KNOWN_CLASSES.length))) {
|
||||
return this.WELL_KNOWN_CLASSES[value - 128];
|
||||
}
|
||||
|
||||
throw new WSP.CodeError("Class-identifier: invalid id " + value);
|
||||
@ -676,6 +905,20 @@ let MessageClassValue = {
|
||||
return WSP.TokenText.decode(data);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param klass
|
||||
*/
|
||||
encode: function encode(data, klass) {
|
||||
let index = this.WELL_KNOWN_CLASSES.indexOf(klass.toLowerCase());
|
||||
if (index >= 0) {
|
||||
WSP.Octet.encode(data, index + 128);
|
||||
} else {
|
||||
WSP.TokenText.encode(data, klass);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -753,6 +996,30 @@ let MmFlagsValue = {
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An object containing an integer `type` and an string-typed
|
||||
* `text` attributes.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if ((value.type < 128) || (value.type > 130)) {
|
||||
throw new WSP.CodeError("MM-flags-value: invalid type " + value.type);
|
||||
}
|
||||
|
||||
// Calculate how much octets will be written and seek back.
|
||||
// TODO: use memmove, see bug 730873
|
||||
let begin = data.offset;
|
||||
EncodedStringValue.encode(data, value.text);
|
||||
let len = data.offset - begin;
|
||||
data.offset = begin;
|
||||
|
||||
WSP.ValueLength.encode(data, len + 1);
|
||||
WSP.Octet.encode(data, value.type);
|
||||
EncodedStringValue.encode(data, value.text);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -782,6 +1049,22 @@ let MmStateValue = {
|
||||
|
||||
throw new WSP.CodeError("MM-state-value: invalid state " + state);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param state
|
||||
* A numeric state value to be encoded.
|
||||
*
|
||||
* @throws CodeError if state is not in the range 128..132.
|
||||
*/
|
||||
encode: function encode(data, state) {
|
||||
if ((state < 128) || (state > 132)) {
|
||||
throw new WSP.CodeError("MM-state-value: invalid state " + state);
|
||||
}
|
||||
|
||||
WSP.Octet.encode(data, state);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -809,6 +1092,20 @@ let PriorityValue = {
|
||||
|
||||
throw new WSP.CodeError("Priority-value: invalid priority " + priority);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param priority
|
||||
* A numeric priority value to be encoded.
|
||||
*/
|
||||
encode: function encode(data, priority) {
|
||||
if ((priority < 128) || (priority > 130)) {
|
||||
throw new WSP.CodeError("Priority-value: invalid priority " + priority);
|
||||
}
|
||||
|
||||
WSP.Octet.encode(data, priority);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -856,6 +1153,64 @@ let ReplyChargingValue = {
|
||||
|
||||
throw new WSP.CodeError("Reply-charging-value: invalid value " + value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An integer value within thr range 128..131.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if ((value < 128) || (value > 131)) {
|
||||
throw new WSP.CodeError("Reply-charging-value: invalid value " + value);
|
||||
}
|
||||
|
||||
WSP.Octet.encode(data, value);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* When used in a PDU other than M-Mbox-Delete.conf and M-Delete.conf:
|
||||
*
|
||||
* Response-text-value = Encoded-string-value
|
||||
*
|
||||
* When used in the M-Mbox-Delete.conf and M-Delete.conf PDUs:
|
||||
*
|
||||
* Response-text-Del-value = Value-length Status-count-value Response-text-value
|
||||
*
|
||||
* @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.49
|
||||
*/
|
||||
let ResponseText = {
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
* @param options
|
||||
* Extra context for decoding.
|
||||
*
|
||||
* @return An object containing a string-typed `text` attribute and a
|
||||
* integer-typed `statusCount` one.
|
||||
*/
|
||||
decode: function decode(data, options) {
|
||||
let type = WSP.ensureHeader(options, "x-mms-message-type");
|
||||
|
||||
let result = {};
|
||||
if ((type == MMS_PDU_TYPE_MBOX_DELETE_CONF)
|
||||
|| (type == MMS_PDU_TYPE_DELETE_CONF)) {
|
||||
let length = WSP.ValueLength.decode(data);
|
||||
let end = data.offset + length;
|
||||
|
||||
result.statusCount = WSP.IntegerValue.decode(data);
|
||||
result.text = EncodedStringValue.decode(data);
|
||||
|
||||
if (data.offset != end) {
|
||||
data.offset = end;
|
||||
}
|
||||
} else {
|
||||
result.text = EncodedStringValue.decode(data);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1078,20 +1433,35 @@ let PduHelper = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert javascript Array to an nsIInputStream.
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param headers
|
||||
* A dictionary object containing multiple name/value mapping.
|
||||
* @param name
|
||||
* Name of the header field to be encoded.
|
||||
*/
|
||||
convertArrayToInputStream: function convertDataToInputStream(array) {
|
||||
let storageStream = Cc["@mozilla.org/storagestream;1"]
|
||||
.createInstance(Ci.nsIStorageStream);
|
||||
storageStream.init(4096, array.length, null);
|
||||
encodeHeader: function encodeHeader(data, headers, name) {
|
||||
let value = headers[name];
|
||||
if (Array.isArray(value)) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
HeaderField.encode(data, {name: name, value: value[i]}, headers);
|
||||
}
|
||||
} else {
|
||||
HeaderField.encode(data, {name: name, value: value}, headers);
|
||||
}
|
||||
},
|
||||
|
||||
let boStream = Cc["@mozilla.org/binaryoutputstream;1"]
|
||||
.createInstance(Ci.nsIBinaryOutputStream);
|
||||
boStream.setOutputStream(storageStream.getOutputStream(0));
|
||||
boStream.writeByteArray(array, array.length)
|
||||
boStream.close();
|
||||
|
||||
return storageStream.newInputStream(0);
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param headers
|
||||
* A dictionary object containing multiple name/value mapping.
|
||||
*/
|
||||
encodeHeaderIfExists: function encodeHeaderIfExists(data, headers, name) {
|
||||
// Header value could be zero or null.
|
||||
if (headers[name] !== undefined) {
|
||||
this.encodeHeader(data, headers, name);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1107,26 +1477,15 @@ let PduHelper = {
|
||||
data = {array: [], offset: 0};
|
||||
}
|
||||
|
||||
function encodeHeader(name) {
|
||||
HeaderField.encode(data, {name: name, value: headers[name]});
|
||||
}
|
||||
|
||||
function encodeHeaderIfExists(name) {
|
||||
// Header value could be zero or null.
|
||||
if (headers[name] !== undefined) {
|
||||
encodeHeader(name);
|
||||
}
|
||||
}
|
||||
|
||||
// `In the encoding of the header fields, the order of the fields is not
|
||||
// significant, except that X-Mms-Message-Type, X-Mms-Transaction-ID (when
|
||||
// present) and X-Mms-MMS-Version MUST be at the beginning of the message
|
||||
// headers, in that order, and if the PDU contains a message body the
|
||||
// Content Type MUST be the last header field, followed by message body.`
|
||||
// ~ OMA-TS-MMS_ENC-V1_3-20110913-A section 7
|
||||
encodeHeader("x-mms-message-type");
|
||||
encodeHeaderIfExists("x-mms-transaction-id");
|
||||
encodeHeaderIfExists("x-mms-mms-version");
|
||||
this.encodeHeader(data, headers, "x-mms-message-type");
|
||||
this.encodeHeaderIfExists(data, headers, "x-mms-transaction-id");
|
||||
this.encodeHeaderIfExists(data, headers, "x-mms-mms-version");
|
||||
|
||||
for (let key in headers) {
|
||||
if ((key == "x-mms-message-type")
|
||||
@ -1135,15 +1494,10 @@ let PduHelper = {
|
||||
|| (key == "content-type")) {
|
||||
continue;
|
||||
}
|
||||
encodeHeader(key);
|
||||
this.encodeHeader(data, headers, key);
|
||||
}
|
||||
|
||||
encodeHeaderIfExists("content-type");
|
||||
|
||||
// Remove extra space consumed during encoding.
|
||||
while (data.array.length > data.offset) {
|
||||
data.array.pop();
|
||||
}
|
||||
this.encodeHeaderIfExists(data, headers, "content-type");
|
||||
|
||||
return data;
|
||||
},
|
||||
@ -1168,8 +1522,15 @@ let PduHelper = {
|
||||
|
||||
let data = this.encodeHeaders(null, msg.headers);
|
||||
debug("Composed PDU Header: " + JSON.stringify(data.array));
|
||||
let headerStream = this.convertArrayToInputStream(data.array);
|
||||
multiStream.appendStream(headerStream);
|
||||
WSP.PduHelper.appendArrayToMultiStream(multiStream, data.array, data.offset);
|
||||
|
||||
if (msg.content) {
|
||||
WSP.PduHelper.appendArrayToMultiStream(multiStream, msg.content, msg.content.length);
|
||||
} else if (msg.parts) {
|
||||
WSP.PduHelper.composeMultiPart(multiStream, msg.parts);
|
||||
} else if (typeinfo.hasContent) {
|
||||
throw new WSP.CodeError("Missing message content");
|
||||
}
|
||||
|
||||
return multiStream;
|
||||
} catch (e) {
|
||||
@ -1230,7 +1591,7 @@ const MMS_HEADER_FIELDS = (function () {
|
||||
add("content-type", 0x04, WSP.ContentTypeValue);
|
||||
add("date", 0x05, WSP.DateValue);
|
||||
add("x-mms-delivery-report", 0x06, BooleanValue);
|
||||
//add("x-mms-delivery-time", 0x07);
|
||||
add("x-mms-delivery-time", 0x07, ExpiryValue);
|
||||
add("x-mms-expiry", 0x08, ExpiryValue);
|
||||
add("from", 0x09, FromValue);
|
||||
add("x-mms-message-class", 0x0A, MessageClassValue);
|
||||
@ -1241,9 +1602,9 @@ const MMS_HEADER_FIELDS = (function () {
|
||||
add("x-mms-priority", 0x0F, PriorityValue);
|
||||
add("x-mms-read-report", 0x10, BooleanValue);
|
||||
add("x-mms-report-allowed", 0x11, BooleanValue);
|
||||
//add("x-mms-response-status", 0x12);
|
||||
//add("x-mms-response-text", 0x13);
|
||||
//add("x-mms-sender-visibility", 0x14);
|
||||
add("x-mms-response-status", 0x12, RetrieveStatusValue);
|
||||
add("x-mms-response-text", 0x13, ResponseText);
|
||||
add("x-mms-sender-visibility", 0x14, BooleanValue);
|
||||
add("x-mms-status", 0x15, StatusValue);
|
||||
add("subject", 0x16, EncodedStringValue);
|
||||
add("to", 0x17, Address);
|
||||
@ -1260,8 +1621,8 @@ const MMS_HEADER_FIELDS = (function () {
|
||||
add("x-mms-store", 0x22, BooleanValue);
|
||||
add("x-mms-mm-state", 0x23, MmStateValue);
|
||||
add("x-mms-mm-flags", 0x24, MmFlagsValue);
|
||||
//add("x-mms-store-status", 0x25);
|
||||
//add("x-mms-store-status-text", 0x26);
|
||||
add("x-mms-store-status", 0x25, RetrieveStatusValue);
|
||||
add("x-mms-store-status-text", 0x26, EncodedStringValue);
|
||||
add("x-mms-stored", 0x27, BooleanValue);
|
||||
//add("x-mms-attributes", 0x28);
|
||||
add("x-mms-totals", 0x29, BooleanValue);
|
||||
@ -1344,6 +1705,7 @@ const EXPORTED_SYMBOLS = ALL_CONST_SYMBOLS.concat([
|
||||
"PriorityValue",
|
||||
"RecommendedRetrievalModeValue",
|
||||
"ReplyChargingValue",
|
||||
"ResponseText",
|
||||
"RetrieveStatusValue",
|
||||
"StatusValue",
|
||||
|
||||
|
@ -289,6 +289,18 @@ let Octet = {
|
||||
data.array[data.offset++] = octet;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param octet
|
||||
* An octet array object.
|
||||
*/
|
||||
encodeMultiple: function encodeMultiple(data, array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
this.encode(data, array[i]);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -659,6 +671,17 @@ let QuotedString = {
|
||||
|
||||
return NullTerminatedTexts.decode(data);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param str
|
||||
* A String to be encoded.
|
||||
*/
|
||||
encode: function encode(data, str) {
|
||||
Octet.encode(data, 34);
|
||||
NullTerminatedTexts.encode(data, str);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -757,6 +780,42 @@ let LongInteger = {
|
||||
|
||||
return this.decodeMultiOctetInteger(data, length);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param numOrArray
|
||||
* An octet array of less-equal than 30 elements or an integer
|
||||
* greater-equal than 128.
|
||||
*/
|
||||
encode: function encode(data, numOrArray) {
|
||||
if (typeof numOrArray === "number") {
|
||||
let num = numOrArray;
|
||||
if (num >= 0x1000000000000) {
|
||||
throw new CodeError("Long-integer: number too large " + num);
|
||||
}
|
||||
|
||||
let stack = [];
|
||||
do {
|
||||
stack.push(Math.floor(num % 256));
|
||||
num = Math.floor(num / 256);
|
||||
} while (num);
|
||||
|
||||
Octet.encode(data, stack.length);
|
||||
while (stack.length) {
|
||||
Octet.encode(data, stack.pop());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let array = numOrArray;
|
||||
if ((array.length < 1) || (array.length > 30)) {
|
||||
throw new CodeError("Long-integer: invalid length " + array.length);
|
||||
}
|
||||
|
||||
Octet.encode(data, array.length);
|
||||
Octet.encodeMultiple(data, array);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -779,6 +838,30 @@ let UintVar = {
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An integer value.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if (value < 0) {
|
||||
throw new CodeError("UintVar: invalid value " + value);
|
||||
}
|
||||
|
||||
let stack = [];
|
||||
while (value >= 128) {
|
||||
stack.push(Math.floor(value % 128));
|
||||
value = Math.floor(value / 128);
|
||||
}
|
||||
|
||||
while (stack.length) {
|
||||
Octet.encode(data, value | 0x80);
|
||||
value = stack.pop();
|
||||
}
|
||||
Octet.encode(data, value);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -801,6 +884,20 @@ let ConstrainedEncoding = {
|
||||
decode: function decode(data) {
|
||||
return decodeAlternatives(data, null, NullTerminatedTexts, ShortInteger);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An integer or a string value.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if (typeof value == "number") {
|
||||
ShortInteger.encode(data, value);
|
||||
} else {
|
||||
NullTerminatedTexts.encode(data, value);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -832,6 +929,20 @@ let ValueLength = {
|
||||
|
||||
throw new CodeError("Value-length: invalid value " + value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if (value <= 30) {
|
||||
Octet.encode(data, value);
|
||||
} else {
|
||||
Octet.encode(data, 31);
|
||||
UintVar.encode(data, value);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -850,6 +961,19 @@ let NoValue = {
|
||||
Octet.decodeEqualTo(data, 0);
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* A null or undefined value.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if (value != null) {
|
||||
throw new CodeError("No-value: invalid value " + value);
|
||||
}
|
||||
Octet.encode(data, 0);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -867,6 +991,16 @@ let TextValue = {
|
||||
decode: function decode(data) {
|
||||
return decodeAlternatives(data, null, NoValue, TokenText, QuotedString);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param text
|
||||
* A null or undefined or text string.
|
||||
*/
|
||||
encode: function encode(data, text) {
|
||||
encodeAlternatives(data, text, null, NoValue, TokenText, QuotedString);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -884,6 +1018,22 @@ let IntegerValue = {
|
||||
decode: function decode(data) {
|
||||
return decodeAlternatives(data, null, ShortInteger, LongInteger);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An integer value or an octet array of less-equal than 31 elements.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if (typeof value === "number") {
|
||||
encodeAlternatives(data, value, null, ShortInteger, LongInteger);
|
||||
} else if (Array.isArray(value) || (value instanceof Uint8Array)) {
|
||||
LongInteger.encode(data, value);
|
||||
} else {
|
||||
throw new CodeError("Integer-Value: invalid value type");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -915,6 +1065,21 @@ let DateValue = {
|
||||
|
||||
return new Date(seconds * 1000);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param date
|
||||
* A Date object.
|
||||
*/
|
||||
encode: function encode(data, date) {
|
||||
let seconds = date.getTime() / 1000;
|
||||
if (seconds < 0) {
|
||||
throw new CodeError("Date-value: negative seconds " + seconds);
|
||||
}
|
||||
|
||||
LongInteger.encode(data, seconds);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -954,6 +1119,27 @@ let QValue = {
|
||||
|
||||
throw new CodeError("Q-value: invalid value " + value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An integer within the range 1..1099.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if ((value < 0) || (value >= 1)) {
|
||||
throw new CodeError("Q-value: invalid value " + value);
|
||||
}
|
||||
|
||||
value *= 1000;
|
||||
if ((value % 10) == 0) {
|
||||
// Two digits only.
|
||||
UintVar.encode(data, Math.floor(value / 10 + 1));
|
||||
} else {
|
||||
// Three digits.
|
||||
UintVar.encode(data, Math.floor(value + 100));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1007,6 +1193,20 @@ let VersionValue = {
|
||||
|
||||
return major << 4 | minor;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param version
|
||||
* A binary encoded version number.
|
||||
*/
|
||||
encode: function encode(data, version) {
|
||||
if ((version < 0x10) || (version >= 0x80)) {
|
||||
throw new CodeError("Version-value: invalid version " + version);
|
||||
}
|
||||
|
||||
ShortInteger.encode(data, version);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1067,6 +1267,21 @@ let TypeValue = {
|
||||
|
||||
return entry.type;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param type
|
||||
* A content type string.
|
||||
*/
|
||||
encode: function encode(data, type) {
|
||||
let entry = WSP_WELL_KNOWN_CONTENT_TYPES[type.toLowerCase()];
|
||||
if (entry) {
|
||||
ShortInteger.encode(data, entry.number);
|
||||
} else {
|
||||
NullTerminatedTexts.encode(data, type);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1220,6 +1435,63 @@ let Parameter = {
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param param
|
||||
* An object containing `name` and `value` properties.
|
||||
*/
|
||||
encodeTypedParameter: function decodeTypedParameter(data, param) {
|
||||
let entry = WSP_WELL_KNOWN_PARAMS[param.name.toLowerCase()];
|
||||
if (!entry) {
|
||||
throw new NotWellKnownEncodingError(
|
||||
"Typed-parameter: not well known parameter " + param.name);
|
||||
}
|
||||
|
||||
IntegerValue.encode(data, entry.number);
|
||||
encodeAlternatives(data, param.value, null,
|
||||
entry.coder, TextValue, TextString);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param param
|
||||
* An object containing `name` and `value` properties.
|
||||
*/
|
||||
encodeUntypedParameter: function encodeUntypedParameter(data, param) {
|
||||
TokenText.encode(data, param.name);
|
||||
encodeAlternatives(data, param.value, null, IntegerValue, TextValue);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param param
|
||||
* An array of parameter objects.
|
||||
*/
|
||||
encodeMultiple: function encodeMultiple(data, params) {
|
||||
for (let name in params) {
|
||||
this.encode(data, {name: name, value: params[name]});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param param
|
||||
* An object containing `name` and `value` properties.
|
||||
*/
|
||||
encode: function encode(data, param) {
|
||||
let begin = data.offset;
|
||||
try {
|
||||
this.encodeTypedParameter(data, param);
|
||||
} catch (e) {
|
||||
data.offset = begin;
|
||||
this.encodeUntypedParameter(data, param);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1255,6 +1527,22 @@ let Header = {
|
||||
// TODO: support header code page shift-sequence
|
||||
return this.decodeMessageHeader(data);
|
||||
},
|
||||
|
||||
encodeMessageHeader: function encodeMessageHeader(data, header) {
|
||||
encodeAlternatives(data, header, null, WellKnownHeader, ApplicationHeader);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param header
|
||||
* An object containing two attributes: a string-typed `name` and a
|
||||
* `value` of arbitrary type.
|
||||
*/
|
||||
encode: function encode(data, header) {
|
||||
// TODO: support header code page shift-sequence
|
||||
this.encodeMessageHeader(data, header);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1303,6 +1591,24 @@ let WellKnownHeader = {
|
||||
value: value,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param header
|
||||
* An object containing two attributes: a string-typed `name` and a
|
||||
* `value` of arbitrary type.
|
||||
*/
|
||||
encode: function encode(data, header) {
|
||||
let entry = WSP_HEADER_FIELDS[header.name.toLowerCase()];
|
||||
if (!entry) {
|
||||
throw new NotWellKnownEncodingError(
|
||||
"Well-known-header: not well known header " + header.name);
|
||||
}
|
||||
|
||||
ShortInteger.encode(data, entry.number);
|
||||
encodeAlternatives(data, header.value, null, entry.coder, TextValue);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1395,6 +1701,21 @@ let FieldName = {
|
||||
|
||||
return entry.name;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param name
|
||||
* A field name string.
|
||||
*/
|
||||
encode: function encode(data, name) {
|
||||
let entry = WSP_HEADER_FIELDS[name.toLowerCase()];
|
||||
if (entry) {
|
||||
ShortInteger.encode(data, entry.number);
|
||||
} else {
|
||||
TokenText.encode(data, name);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1498,6 +1819,21 @@ let AcceptCharsetValue = {
|
||||
return this.decodeAcceptCharsetGeneralForm(data);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An object with a string property `charset`.
|
||||
*/
|
||||
encodeAnyCharset: function encodeAnyCharset(data, value) {
|
||||
if (!value || !value.charset || (value.charset === "*")) {
|
||||
Octet.encode(data, 128);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new CodeError("Any-charset: invalid value " + value);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1540,6 +1876,28 @@ let WellKnownCharset = {
|
||||
|
||||
return {charset: entry.name};
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
let begin = data.offset;
|
||||
try {
|
||||
AcceptCharsetValue.encodeAnyCharset(data, value);
|
||||
return;
|
||||
} catch (e) {}
|
||||
|
||||
data.offset = begin;
|
||||
let entry = WSP_WELL_KNOWN_CHARSETS[value.charset.toLowerCase()];
|
||||
if (!entry) {
|
||||
throw new NotWellKnownEncodingError(
|
||||
"Well-known-charset: not well known charset " + value.charset);
|
||||
}
|
||||
|
||||
IntegerValue.encode(data, entry.number);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1670,6 +2028,73 @@ let ContentTypeValue = {
|
||||
return this.decodeContentGeneralForm(data);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An object containing `media` and `params` properties.
|
||||
*/
|
||||
encodeConstrainedMedia: function encodeConstrainedMedia(data, value) {
|
||||
if (value.params) {
|
||||
throw new CodeError("Constrained-media: should use general form instread");
|
||||
}
|
||||
|
||||
TypeValue.encode(data, value.media);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An object containing `media` and `params` properties.
|
||||
*/
|
||||
encodeMediaType: function encodeMediaType(data, value) {
|
||||
let entry = WSP_WELL_KNOWN_CONTENT_TYPES[value.media.toLowerCase()];
|
||||
if (entry) {
|
||||
IntegerValue.encode(data, entry.number);
|
||||
} else {
|
||||
NullTerminatedTexts.encode(data, value.media);
|
||||
}
|
||||
|
||||
Parameter.encodeMultiple(data, value.params);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An object containing `media` and `params` properties.
|
||||
*/
|
||||
encodeContentGeneralForm: function encodeContentGeneralForm(data, value) {
|
||||
let begin = data.offset;
|
||||
this.encodeMediaType(data, value);
|
||||
|
||||
// Calculate how much octets will be written and seek back.
|
||||
// TODO: use memmove, see bug 730873
|
||||
let len = data.offset - begin;
|
||||
data.offset = begin;
|
||||
|
||||
ValueLength.encode(data, len);
|
||||
this.encodeMediaType(data, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
* @param value
|
||||
* An object containing `media` and `params` properties.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
let begin = data.offset;
|
||||
|
||||
try {
|
||||
this.encodeConstrainedMedia(data, value);
|
||||
} catch (e) {
|
||||
data.offset = begin;
|
||||
this.encodeContentGeneralForm(data, value);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1869,6 +2294,85 @@ let PduHelper = {
|
||||
|
||||
return msg;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param multiStream
|
||||
* An exsiting nsIMultiplexInputStream.
|
||||
* @param array
|
||||
* An octet array.
|
||||
* @param length
|
||||
* Max number of octets to be coverted into an input stream.
|
||||
*/
|
||||
appendArrayToMultiStream: function appendArrayToMultiStream(multiStream, array, length) {
|
||||
let storageStream = Cc["@mozilla.org/storagestream;1"]
|
||||
.createInstance(Ci.nsIStorageStream);
|
||||
storageStream.init(4096, length, null);
|
||||
|
||||
let boStream = Cc["@mozilla.org/binaryoutputstream;1"]
|
||||
.createInstance(Ci.nsIBinaryOutputStream);
|
||||
boStream.setOutputStream(storageStream.getOutputStream(0));
|
||||
boStream.writeByteArray(array, length);
|
||||
boStream.close();
|
||||
|
||||
multiStream.appendStream(storageStream.newInputStream(0));
|
||||
},
|
||||
|
||||
/**
|
||||
* @param multiStream
|
||||
* An exsiting nsIMultiplexInputStream.
|
||||
* @param parts
|
||||
* An array of objects representing multipart entries.
|
||||
*
|
||||
* @see WAP-230-WSP-20010705-a section 8.5
|
||||
*/
|
||||
composeMultiPart: function composeMultiPart(multiStream, parts) {
|
||||
// Encode multipart header
|
||||
{
|
||||
let data = {array: [], offset: 0};
|
||||
UintVar.encode(data, parts.length);
|
||||
debug("Encoded multipart header: " + JSON.stringify(data.array));
|
||||
this.appendArrayToMultiStream(multiStream, data.array, data.offset);
|
||||
}
|
||||
|
||||
// Encode each part
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
let part = parts[i];
|
||||
let data = {array: [], offset: 0};
|
||||
|
||||
// Encode Content-Type
|
||||
let contentType = part.headers["content-type"];
|
||||
ContentTypeValue.encode(data, contentType);
|
||||
|
||||
// Encode other headers
|
||||
if (Object.keys(part).length > 1) {
|
||||
// Remove Content-Type temporarily
|
||||
delete part.headers["content-type"];
|
||||
|
||||
for (let name in part.headers) {
|
||||
Header.encode(data, {name: name, value: part.headers[name]});
|
||||
}
|
||||
|
||||
// Restore Content-Type back
|
||||
part.headers["content-type"] = contentType;
|
||||
}
|
||||
|
||||
// Encode headersLen, DataLen
|
||||
let headersLen = data.offset;
|
||||
UintVar.encode(data, headersLen);
|
||||
UintVar.encode(data, part.content.length);
|
||||
|
||||
// Move them to the beginning of encoded octet array.
|
||||
let slice1 = data.array.slice(headersLen);
|
||||
let slice2 = data.array.slice(0, headersLen);
|
||||
data.array = slice1.concat(slice2);
|
||||
debug("Encoded per-part header: " + JSON.stringify(data.array));
|
||||
|
||||
// Append per-part header
|
||||
this.appendArrayToMultiStream(multiStream, data.array, data.offset);
|
||||
// Append part content
|
||||
this.appendArrayToMultiStream(multiStream, part.content, part.content.length);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// WSP Header Field Name Assignments
|
||||
|
@ -38,14 +38,51 @@ const MMS_PDU_ERROR_OK = 128;
|
||||
const MMS_PDU_ERROR_TRANSIENT_FAILURE = 192;
|
||||
const MMS_PDU_ERROR_PERMANENT_FAILURE = 224;
|
||||
|
||||
// X-Mms-Response-Status values
|
||||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.48
|
||||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A Table 28, 29, 30
|
||||
//const MMS_PDU_RESPONSE_ERROR_UNSPECIFIED = 129; (obsolete)
|
||||
//const MMS_PDU_RESPONSE_ERROR_SERVICE_DENIED = 130; (obsolete)
|
||||
//const MMS_PDU_RESPONSE_ERROR_MESSAGE_FORMAT_CORRUPT = 131; (obsolete)
|
||||
//const MMS_PDU_RESPONSE_ERROR_SENDING_ADDRESS_UNRESOLVED = 132; (obsolete)
|
||||
//const MMS_PDU_RESPONSE_ERROR_MESSAGE_NOT_FOUND = 133; (obsolete)
|
||||
//const MMS_PDU_RESPONSE_ERROR_NETWORK_PROBLEM = 134; (obsolete)
|
||||
//const MMS_PDU_RESPONSE_ERROR_CONTENT_NOT_ACCEPTED = 135; (obsolete)
|
||||
const MMS_PDU_RESPONSE_ERROR_UNSUPPORTED_MESSAGE = 136;
|
||||
const MMS_PDU_RESPONSE_ERROR_TRANSIENT_SENDING_ADDRESS_UNRESOLVED = 193;
|
||||
const MMS_PDU_RESPONSE_ERROR_TRANSIENT_MESSAGE_NOT_FOUND = 194;
|
||||
const MMS_PDU_RESPONSE_ERROR_TRANSIENT_NETWORK_PROBLEM = 195;
|
||||
const MMS_PDU_RESPONSE_ERROR_TRANSIENT_PARTIAL_SUCCESS = 196;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_SERVICE_DENIED = 225;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT = 226;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_SENDING_ADDRESS_UNRESOLVED = 227;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_MESSAGE_NOT_FOUND = 228;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_CONTENT_NOT_ACCEPTED = 229;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_REPLY_CHARGING_LIMITATIONS_NOT_MET = 230;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_REPLY_CHARGING_REQUEST_NOT_ACCEPTED = 231;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_REPLY_CHARGING_FORWARDING_DENIED = 232;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_REPLY_CHARGING_NOT_SUPPORTED = 233;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_ADDRESS_HIDING_NOT_SUPPORTED = 234;
|
||||
const MMS_PDU_RESPONSE_ERROR_PERMANENT_LACK_OF_PREPAID = 235;
|
||||
|
||||
// X-Mms-Retrieve-Status values
|
||||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.50
|
||||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A Table 31
|
||||
const MMS_PDU_RETRIEVE_ERROR_TRANSIENT_MESSAGE_NOT_FOUND = 193;
|
||||
const MMS_PDU_RETRIEVE_ERROR_TRANSIENT_NETWORK_PROBLEM = 194;
|
||||
const MMS_PDU_RETRIEVE_ERROR_PERMANENT_SERVICE_DENIED = 225;
|
||||
const MMS_PDU_RETRIEVE_ERROR_PERMANENT_MESSAGE_NOT_FOUND = 226;
|
||||
const MMS_PDU_RETRIEVE_ERROR_PERMANENT_CONTENT_UNSUPPORTED = 227;
|
||||
|
||||
// X-Mms-Store-Status values
|
||||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.58
|
||||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A Table 35
|
||||
const MMS_PDU_STORE_ERROR_TRANSIENT_NETWORK_PROBLEM = 193;
|
||||
const MMS_PDU_STORE_ERROR_PERMANENT_SERVICE_DENIED = 225;
|
||||
const MMS_PDU_STORE_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT = 226;
|
||||
const MMS_PDU_STORE_ERROR_PERMANENT_MESSAGE_NOT_FOUND = 227;
|
||||
const MMS_PDU_STORE_ERROR_PERMANENT_MMBOX_FULL = 228;
|
||||
|
||||
// X-Mms-Status values
|
||||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.54
|
||||
const MMS_PDU_STATUS_EXPIRED = 128;
|
||||
|
@ -81,6 +81,42 @@ add_test(function test_Address_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// Address.encode ////
|
||||
|
||||
add_test(function test_Address_encode() {
|
||||
// Test for PLMN address
|
||||
wsp_encode_test(MMS.Address, {address: "+123.456-789", type: "PLMN"},
|
||||
strToCharCodeArray("+123.456-789/TYPE=PLMN"));
|
||||
wsp_encode_test(MMS.Address, {address: "123456789", type: "PLMN"},
|
||||
strToCharCodeArray("123456789/TYPE=PLMN"));
|
||||
// Test for IPv4
|
||||
wsp_encode_test(MMS.Address, {address: "1.2.3.4", type: "IPv4"},
|
||||
strToCharCodeArray("1.2.3.4/TYPE=IPv4"));
|
||||
// Test for IPv6
|
||||
wsp_encode_test(MMS.Address,
|
||||
{address: "1111:AAAA:bbbb:CdEf:1ABC:2cde:3Def:0000", type: "IPv6"},
|
||||
strToCharCodeArray("1111:AAAA:bbbb:CdEf:1ABC:2cde:3Def:0000/TYPE=IPv6")
|
||||
);
|
||||
// Test for other device-address
|
||||
wsp_encode_test(MMS.Address, {address: "+H-e.l%l_o", type: "W0r1d_"},
|
||||
strToCharCodeArray("+H-e.l%l_o/TYPE=W0r1d_"));
|
||||
// Test for num-shortcode
|
||||
wsp_encode_test(MMS.Address, {address: "+123", type: "num"},
|
||||
strToCharCodeArray("+123"));
|
||||
wsp_encode_test(MMS.Address, {address: "*123", type: "num"},
|
||||
strToCharCodeArray("*123"));
|
||||
wsp_encode_test(MMS.Address, {address: "#123", type: "num"},
|
||||
strToCharCodeArray("#123"));
|
||||
// Test for alphanum-shortcode
|
||||
wsp_encode_test(MMS.Address, {address: "H0wD0Y0uTurnTh1s0n", type: "alphanum"},
|
||||
strToCharCodeArray("H0wD0Y0uTurnTh1s0n"));
|
||||
// Test for email address
|
||||
wsp_encode_test(MMS.Address, {address: "Joe User <joe@user.org>", type: "email"},
|
||||
strToCharCodeArray("Joe User <joe@user.org>"));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: HeaderField
|
||||
//
|
||||
@ -159,6 +195,20 @@ add_test(function test_ContentClassValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// ContentClassValue.encode ////
|
||||
|
||||
add_test(function test_ContentClassValue_encode() {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if ((i >= 128) && (i <= 135)) {
|
||||
wsp_encode_test(MMS.ContentClassValue, i, [i]);
|
||||
} else {
|
||||
wsp_encode_test(MMS.ContentClassValue, i, null, "CodeError");
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: ContentLocationValue
|
||||
//
|
||||
@ -266,6 +316,24 @@ add_test(function test_Parameter_decodeMultiple() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// Parameter.encode ////
|
||||
|
||||
add_test(function test_Parameter_encode() {
|
||||
// Test for invalid parameter value
|
||||
wsp_encode_test(MMS.Parameter, null, null, "CodeError");
|
||||
wsp_encode_test(MMS.Parameter, undefined, null, "CodeError");
|
||||
wsp_encode_test(MMS.Parameter, {}, null, "CodeError");
|
||||
// Test for case-insensitive parameter name
|
||||
wsp_encode_test(MMS.Parameter, {name: "TYPE", value: 0}, [130, 128]);
|
||||
wsp_encode_test(MMS.Parameter, {name: "type", value: 0}, [130, 128]);
|
||||
// Test for non-well-known parameter name
|
||||
wsp_encode_test(MMS.Parameter, {name: "name", value: 0}, [110, 97, 109, 101, 0, 128]);
|
||||
// Test for constrained encoding value
|
||||
wsp_encode_test(MMS.Parameter, {name: "type", value: "0"}, [130, 48, 0]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: EncodedStringValue
|
||||
//
|
||||
@ -294,6 +362,28 @@ add_test(function test_EncodedStringValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// EncodedStringValue.encode ////
|
||||
|
||||
add_test(function test_EncodedStringValue_encode() {
|
||||
// Test for normal TextString
|
||||
wsp_encode_test(MMS.EncodedStringValue, "Hello", strToCharCodeArray("Hello"));
|
||||
// Test for utf-8
|
||||
let (entry = MMS.WSP.WSP_WELL_KNOWN_CHARSETS["utf-8"]) {
|
||||
// "Mozilla" in full width.
|
||||
let str = "\uff2d\uff4f\uff5a\uff49\uff4c\uff4c\uff41";
|
||||
|
||||
let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
conv.charset = entry.converter;
|
||||
|
||||
let raw = conv.convertToByteArray(str).concat([0]);
|
||||
wsp_encode_test(MMS.EncodedStringValue, str,
|
||||
[raw.length + 2, 0x80 | entry.number, 127].concat(raw));
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: ExpiryValue
|
||||
//
|
||||
@ -309,6 +399,17 @@ add_test(function test_ExpiryValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// ExpiryValue.encode ////
|
||||
|
||||
add_test(function test_ExpiryValue_encode() {
|
||||
// Test for Absolute-token Date-value
|
||||
wsp_encode_test(MMS.ExpiryValue, new Date(0x80 * 1000), [3, 128, 1, 0x80]);
|
||||
// Test for Relative-token Delta-seconds-value
|
||||
wsp_encode_test(MMS.ExpiryValue, 0, [2, 129, 0x80]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: PreviouslySentByValue
|
||||
//
|
||||
@ -354,6 +455,20 @@ add_test(function test_FromValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// FromValue.encode ////
|
||||
|
||||
add_test(function test_FromValue_encode() {
|
||||
// Test for Insert-address-token:
|
||||
wsp_encode_test(MMS.FromValue, null, [1, 129]);
|
||||
// Test for Address-present-token:
|
||||
let (addr = strToCharCodeArray("+123/TYPE=PLMN")) {
|
||||
wsp_encode_test(MMS.FromValue, {address: "+123", type: "PLMN"},
|
||||
[addr.length + 1, 128].concat(addr));
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: MessageClassValue
|
||||
//
|
||||
@ -389,6 +504,18 @@ add_test(function test_MessageClassValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// MessageClassValue.encode ////
|
||||
|
||||
add_test(function test_MessageClassValue_encode() {
|
||||
wsp_encode_test(MMS.MessageClassValue, "personal", [128]);
|
||||
wsp_encode_test(MMS.MessageClassValue, "advertisement", [129]);
|
||||
wsp_encode_test(MMS.MessageClassValue, "informational", [130]);
|
||||
wsp_encode_test(MMS.MessageClassValue, "auto", [131]);
|
||||
wsp_encode_test(MMS.MessageClassValue, "A", [65, 0]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: MessageTypeValue
|
||||
//
|
||||
@ -439,6 +566,20 @@ add_test(function test_MmFlagsValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// MmFlagsValue.encode ////
|
||||
|
||||
add_test(function test_MmFlagsValue_encode() {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if ((i >= 128) && (i <= 130)) {
|
||||
wsp_encode_test(MMS.MmFlagsValue, {type: i, text: "A"}, [3, i, 65, 0]);
|
||||
} else {
|
||||
wsp_encode_test(MMS.MmFlagsValue, {type: i, text: "A"}, null, "CodeError");
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: MmStateValue
|
||||
//
|
||||
@ -457,6 +598,20 @@ add_test(function test_MmStateValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// MmStateValue.encode ////
|
||||
|
||||
add_test(function test_MmStateValue_encode() {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if ((i >= 128) && (i <= 132)) {
|
||||
wsp_encode_test(MMS.MmStateValue, i, [i]);
|
||||
} else {
|
||||
wsp_encode_test(MMS.MmStateValue, i, null, "CodeError");
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: PriorityValue
|
||||
//
|
||||
@ -475,6 +630,20 @@ add_test(function test_PriorityValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// PriorityValue.encode ////
|
||||
|
||||
add_test(function test_PriorityValue_encode() {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if ((i >= 128) && (i <= 130)) {
|
||||
wsp_encode_test(MMS.PriorityValue, i, [i]);
|
||||
} else {
|
||||
wsp_encode_test(MMS.PriorityValue, i, null, "CodeError");
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: RecommendedRetrievalModeValue
|
||||
//
|
||||
@ -511,6 +680,58 @@ add_test(function test_ReplyChargingValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// ReplyChargingValue.encode ////
|
||||
|
||||
add_test(function test_ReplyChargingValue_encode() {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if ((i >= 128) && (i <= 131)) {
|
||||
wsp_encode_test(MMS.ReplyChargingValue, i, [i]);
|
||||
} else {
|
||||
wsp_encode_test(MMS.ReplyChargingValue, i, null, "CodeError");
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: ResponseText
|
||||
//
|
||||
|
||||
//// ResponseText.decode ////
|
||||
|
||||
add_test(function test_ResponseText_decode() {
|
||||
// Test for MMS_PDU_TYPE_MBOX_DELETE_CONF & MMS_PDU_TYPE_DELETE_CONF
|
||||
wsp_decode_test_ex(function (data) {
|
||||
data.array[0] = data.array.length - 1;
|
||||
|
||||
let options = {};
|
||||
options["x-mms-message-type"] = MMS_PDU_TYPE_MBOX_DELETE_CONF;
|
||||
return MMS.ResponseText.decode(data, options);
|
||||
}, [0, 0x80 | 0x00].concat(strToCharCodeArray("http://no.such.com/path")),
|
||||
{statusCount: 0, text: "http://no.such.com/path"}
|
||||
);
|
||||
wsp_decode_test_ex(function (data) {
|
||||
data.array[0] = data.array.length - 1;
|
||||
|
||||
let options = {};
|
||||
options["x-mms-message-type"] = MMS_PDU_TYPE_DELETE_CONF;
|
||||
return MMS.ResponseText.decode(data, options);
|
||||
}, [0, 0x80 | 0x00].concat(strToCharCodeArray("http://no.such.com/path")),
|
||||
{statusCount: 0, text: "http://no.such.com/path"}
|
||||
);
|
||||
// Test for other situations
|
||||
wsp_decode_test_ex(function (data) {
|
||||
let options = {};
|
||||
options["x-mms-message-type"] = MMS_PDU_TYPE_SEND_REQ;
|
||||
return MMS.ResponseText.decode(data, options);
|
||||
}, strToCharCodeArray("http://no.such.com/path"),
|
||||
{text: "http://no.such.com/path"}
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: RetrieveStatusValue
|
||||
//
|
||||
@ -585,7 +806,7 @@ add_test(function test_PduHelper_parseHeaders() {
|
||||
};
|
||||
parse([0x80 | 0x0D, 0x80 | MMS_VERSION, // X-Mms-Mms-Version: 1.3
|
||||
0x80 | 0x04, 0x80 | 0x33, // Content-Type: application/vnd.wap.multipart.related
|
||||
0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ // X-Mms-Message-Type: M-Send.req
|
||||
0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ // X-Mms-Message-Type: M-Send.req
|
||||
], expect);
|
||||
|
||||
// Parse header fields with multiple entries
|
||||
@ -606,3 +827,83 @@ add_test(function test_PduHelper_parseHeaders() {
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// PduHelper.encodeHeader ////
|
||||
|
||||
add_test(function test_PduHelper_encodeHeader() {
|
||||
function func(name, data, headers) {
|
||||
MMS.PduHelper.encodeHeader(data, headers, name);
|
||||
|
||||
// Remove extra space consumed during encoding.
|
||||
while (data.array.length > data.offset) {
|
||||
data.array.pop();
|
||||
}
|
||||
|
||||
return data.array;
|
||||
}
|
||||
|
||||
// Encode header fields with multiple entries
|
||||
let headers = {
|
||||
to: [
|
||||
{ address: "+123", type: "PLMN" },
|
||||
{ address: "+456", type: "num" },
|
||||
],
|
||||
};
|
||||
wsp_encode_test_ex(func.bind(null, "to"), headers,
|
||||
Array.concat([0x80 | 0x17]).concat(strToCharCodeArray("+123/TYPE=PLMN"))
|
||||
.concat([0x80 | 0x17]).concat(strToCharCodeArray("+456")));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// PduHelper.encodeHeaderIfExists ////
|
||||
|
||||
add_test(function test_PduHelper_encodeHeaderIfExists() {
|
||||
function func(name, data, headers) {
|
||||
MMS.PduHelper.encodeHeaderIfExists(data, headers, name);
|
||||
|
||||
// Remove extra space consumed during encoding.
|
||||
while (data.array.length > data.offset) {
|
||||
data.array.pop();
|
||||
}
|
||||
|
||||
return data.array;
|
||||
}
|
||||
|
||||
wsp_encode_test_ex(func.bind(null, "to"), {}, []);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// PduHelper.encodeHeaders ////
|
||||
|
||||
add_test(function test_PduHelper_encodeHeaders() {
|
||||
function func(data, headers) {
|
||||
MMS.PduHelper.encodeHeaders(data, headers);
|
||||
|
||||
// Remove extra space consumed during encoding.
|
||||
while (data.array.length > data.offset) {
|
||||
data.array.pop();
|
||||
}
|
||||
|
||||
return data.array;
|
||||
}
|
||||
|
||||
let headers = {};
|
||||
headers["x-mms-message-type"] = MMS_PDU_TYPE_SEND_REQ;
|
||||
headers["x-mms-mms-version"] = MMS_VERSION;
|
||||
headers["x-mms-transaction-id"] = "asdf";
|
||||
headers["to"] = { address: "+123", type: "PLMN" };
|
||||
headers["content-type"] = {
|
||||
media: "application/vnd.wap.multipart.related",
|
||||
};
|
||||
wsp_encode_test_ex(func, headers,
|
||||
Array.concat([0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ])
|
||||
.concat([0x80 | 0x18]).concat(strToCharCodeArray(headers["x-mms-transaction-id"]))
|
||||
.concat([0x80 | 0x0D, 0x80 | MMS_VERSION])
|
||||
.concat([0x80 | 0x17]).concat(strToCharCodeArray("+123/TYPE=PLMN"))
|
||||
.concat([0x80 | 0x04, 0x80 | 0x33]));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
@ -107,6 +107,17 @@ add_test(function test_Octet_encode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// Octet.encodeMultiple ////
|
||||
|
||||
add_test(function test_Octet_encodeMultiple() {
|
||||
wsp_encode_test_ex(function (data, input) {
|
||||
WSP.Octet.encodeMultiple(data, input);
|
||||
return data.array;
|
||||
}, [0, 1, 2, 3], [0, 1, 2, 3]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: Text
|
||||
//
|
||||
@ -303,6 +314,14 @@ add_test(function test_QuotedString_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// QuotedString.encode ////
|
||||
|
||||
add_test(function test_QuotedString_encode() {
|
||||
wsp_encode_test(WSP.QuotedString, "B2G", [34].concat(strToCharCodeArray("B2G")));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: ShortInteger
|
||||
//
|
||||
@ -341,7 +360,7 @@ add_test(function test_ShortInteger_encode() {
|
||||
|
||||
//// LongInteger.decode ////
|
||||
|
||||
function LongInteger_testcases(target) {
|
||||
function LongInteger_decode_testcases(target) {
|
||||
// Test LongInteger of zero octet
|
||||
wsp_decode_test(target, [0, 0], null, "CodeError");
|
||||
wsp_decode_test(target, [1, 0x80], 0x80);
|
||||
@ -356,7 +375,38 @@ function LongInteger_testcases(target) {
|
||||
wsp_decode_test(target, [31], null, "CodeError");
|
||||
}
|
||||
add_test(function test_LongInteger_decode() {
|
||||
LongInteger_testcases(WSP.LongInteger);
|
||||
LongInteger_decode_testcases(WSP.LongInteger);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// LongInteger.encode ////
|
||||
|
||||
function LongInteger_encode_testcases(target) {
|
||||
wsp_encode_test(target, 0x80, [1, 0x80]);
|
||||
wsp_encode_test(target, 0x8002, [2, 0x80, 2]);
|
||||
wsp_encode_test(target, 0x800203, [3, 0x80, 2, 3]);
|
||||
wsp_encode_test(target, 0x80020304, [4, 0x80, 2, 3, 4]);
|
||||
wsp_encode_test(target, 0x8002030405, [5, 0x80, 2, 3, 4, 5]);
|
||||
wsp_encode_test(target, 0x800203040506, [6, 0x80, 2, 3, 4, 5, 6]);
|
||||
// Test LongInteger of more than 6 octets
|
||||
wsp_encode_test(target, 0x1000000000000, null, "CodeError");
|
||||
// Test input empty array
|
||||
wsp_encode_test(target, [], null, "CodeError");
|
||||
// Test input octets array of length 1..30
|
||||
let array = [];
|
||||
for (let i = 1; i <= 30; i++) {
|
||||
array.push(i);
|
||||
wsp_encode_test(target, array, [i].concat(array));
|
||||
}
|
||||
// Test input octets array of 31 elements.
|
||||
array.push(31);
|
||||
wsp_encode_test(target, array, null, "CodeError");
|
||||
}
|
||||
add_test(function test_LongInteger_encode() {
|
||||
wsp_encode_test(WSP.LongInteger, 0, [1, 0]);
|
||||
|
||||
LongInteger_encode_testcases(WSP.LongInteger);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
@ -385,8 +435,25 @@ add_test(function test_UintVar_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// UintVar.encode ////
|
||||
|
||||
add_test(function test_UintVar_encode() {
|
||||
// Test up to max 53 bits integer
|
||||
wsp_encode_test(WSP.UintVar, 0, [0]);
|
||||
wsp_encode_test(WSP.UintVar, 0x7F, [0x7F]);
|
||||
wsp_encode_test(WSP.UintVar, 0x3FFF, [0xFF, 0x7F]);
|
||||
wsp_encode_test(WSP.UintVar, 0x1FFFFF, [0xFF, 0xFF, 0x7F]);
|
||||
wsp_encode_test(WSP.UintVar, 0xFFFFFFF, [0xFF, 0xFF, 0xFF, 0x7F]);
|
||||
wsp_encode_test(WSP.UintVar, 0x7FFFFFFFF, [0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
|
||||
wsp_encode_test(WSP.UintVar, 0x3FFFFFFFFFF, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
|
||||
wsp_encode_test(WSP.UintVar, 0x1FFFFFFFFFFFF, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
|
||||
wsp_encode_test(WSP.UintVar, 0x1FFFFFFFFFFFFF, [0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: ConstrainedEncoding (decodeAlternatives)
|
||||
// Test target: ConstrainedEncoding
|
||||
//
|
||||
|
||||
//// ConstrainedEncoding.decode ////
|
||||
@ -398,6 +465,15 @@ add_test(function test_ConstrainedEncoding_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// ConstrainedEncoding.encode ////
|
||||
|
||||
add_test(function test_ConstrainedEncoding_encode() {
|
||||
wsp_encode_test(WSP.ConstrainedEncoding, 0, [0x80 | 0]);
|
||||
wsp_encode_test(WSP.ConstrainedEncoding, "A", [65, 0]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: ValueLength
|
||||
//
|
||||
@ -418,6 +494,22 @@ add_test(function test_ValueLength_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// ValueLength.encode ////
|
||||
|
||||
add_test(function test_ValueLength_encode() {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if (i < 31) {
|
||||
wsp_encode_test(WSP.ValueLength, i, [i]);
|
||||
} else if (i < 128) {
|
||||
wsp_encode_test(WSP.ValueLength, i, [31, i]);
|
||||
} else {
|
||||
wsp_encode_test(WSP.ValueLength, i, [31, (0x80 | (i / 128)), i % 128]);
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: NoValue
|
||||
//
|
||||
@ -433,6 +525,19 @@ add_test(function test_NoValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// NoValue.encode ////
|
||||
|
||||
add_test(function test_NoValue_encode() {
|
||||
wsp_encode_test(WSP.NoValue, undefined, [0]);
|
||||
wsp_encode_test(WSP.NoValue, null, [0]);
|
||||
wsp_encode_test(WSP.NoValue, 0, null, "CodeError");
|
||||
wsp_encode_test(WSP.NoValue, "", null, "CodeError");
|
||||
wsp_encode_test(WSP.NoValue, [], null, "CodeError");
|
||||
wsp_encode_test(WSP.NoValue, {}, null, "CodeError");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: TextValue
|
||||
//
|
||||
@ -448,6 +553,18 @@ add_test(function test_TextValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// TextValue.encode ////
|
||||
|
||||
add_test(function test_TextValue_encode() {
|
||||
wsp_encode_test(WSP.TextValue, undefined, [0]);
|
||||
wsp_encode_test(WSP.TextValue, null, [0]);
|
||||
wsp_encode_test(WSP.TextValue, "", [0]);
|
||||
wsp_encode_test(WSP.TextValue, "A", [65, 0]);
|
||||
wsp_encode_test(WSP.TextValue, "\x80", [34, 128, 0]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: IntegerValue
|
||||
//
|
||||
@ -459,7 +576,19 @@ add_test(function test_IntegerValue_decode() {
|
||||
wsp_decode_test(WSP.IntegerValue, [i], i & 0x7F);
|
||||
}
|
||||
|
||||
LongInteger_testcases(WSP.IntegerValue);
|
||||
LongInteger_decode_testcases(WSP.IntegerValue);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// IntegerValue.decode ////
|
||||
|
||||
add_test(function test_IntegerValue_encode() {
|
||||
for (let i = 0; i < 128; i++) {
|
||||
wsp_encode_test(WSP.IntegerValue, i, [0x80 | i]);
|
||||
}
|
||||
|
||||
LongInteger_encode_testcases(WSP.IntegerValue);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
@ -478,6 +607,14 @@ add_test(function test_DateValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// DateValue.encode ////
|
||||
|
||||
add_test(function test_DateValue_encode() {
|
||||
wsp_encode_test(WSP.DateValue, new Date(0x80 * 1000), [1, 0x80]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: DeltaSecondsValue
|
||||
//
|
||||
@ -500,6 +637,18 @@ add_test(function test_QValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// QValue.encode ////
|
||||
|
||||
add_test(function test_QValue_encode() {
|
||||
wsp_encode_test(WSP.QValue, 0, [1]);
|
||||
wsp_encode_test(WSP.QValue, 0.99, [100]);
|
||||
wsp_encode_test(WSP.QValue, 0.001, [101]);
|
||||
wsp_encode_test(WSP.QValue, 0.999, [0x88, 0x4B]);
|
||||
wsp_encode_test(WSP.QValue, 1, null, "CodeError");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: VersionValue
|
||||
//
|
||||
@ -526,6 +675,22 @@ add_test(function test_VersionValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// VersionValue.encode ////
|
||||
|
||||
add_test(function test_VersionValue_encode() {
|
||||
for (let major = 1; major < 8; major++) {
|
||||
let version = (major << 4) | 0x0F;
|
||||
wsp_encode_test(WSP.VersionValue, version, [0x80 | version]);
|
||||
|
||||
for (let minor = 0; minor < 15; minor++) {
|
||||
version = (major << 4) | minor;
|
||||
wsp_encode_test(WSP.VersionValue, version, [0x80 | version]);
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: UriValue
|
||||
//
|
||||
@ -558,6 +723,17 @@ add_test(function test_TypeValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// TypeValue.encode ////
|
||||
|
||||
add_test(function test_TypeValue_encode() {
|
||||
wsp_encode_test(WSP.TypeValue, "no/such.type",
|
||||
[110, 111, 47, 115, 117, 99, 104, 46, 116, 121, 112, 101, 0]);
|
||||
wsp_encode_test(WSP.TypeValue, "application/vnd.wap.multipart.related",
|
||||
[0x33 | 0x80]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: Parameter
|
||||
//
|
||||
@ -627,6 +803,59 @@ add_test(function test_Parameter_decodeMultiple() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// Parameter.encodeTypedParameter ////
|
||||
|
||||
add_test(function test_Parameter_encodeTypedParameter() {
|
||||
function func(data, input) {
|
||||
WSP.Parameter.encodeTypedParameter(data, input);
|
||||
return data.array;
|
||||
}
|
||||
|
||||
// Test for NotWellKnownEncodingError
|
||||
wsp_encode_test_ex(func, {name: "xxx", value: 0}, null, "NotWellKnownEncodingError");
|
||||
wsp_encode_test_ex(func, {name: "q", value: 0}, [0x80, 1]);
|
||||
wsp_encode_test_ex(func, {name: "name", value: "A"}, [0x85, 65, 0]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// Parameter.encodeUntypedParameter ////
|
||||
|
||||
add_test(function test_Parameter_encodeUntypedParameter() {
|
||||
function func(data, input) {
|
||||
WSP.Parameter.encodeUntypedParameter(data, input);
|
||||
return data.array;
|
||||
}
|
||||
|
||||
wsp_encode_test_ex(func, {name: "q", value: 0}, [113, 0, 0x80]);
|
||||
wsp_encode_test_ex(func, {name: "name", value: "A"}, [110, 97, 109, 101, 0, 65, 0]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// Parameter.encodeMultiple ////
|
||||
|
||||
add_test(function test_Parameter_encodeMultiple() {
|
||||
function func(data, input) {
|
||||
WSP.Parameter.encodeMultiple(data, input);
|
||||
return data.array;
|
||||
}
|
||||
|
||||
wsp_encode_test_ex(func, {q: 0, n: "A"}, [0x80, 1, 110, 0, 65, 0]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// Parameter.encode ////
|
||||
|
||||
add_test(function test_Parameter_encode() {
|
||||
|
||||
wsp_encode_test(WSP.Parameter, {name: "q", value: 0}, [0x80, 1]);
|
||||
wsp_encode_test(WSP.Parameter, {name: "n", value: "A"}, [110, 0, 65, 0]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: Header
|
||||
//
|
||||
@ -722,6 +951,15 @@ add_test(function test_FieldName_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// FieldName.encode ////
|
||||
|
||||
add_test(function test_FieldName_encode() {
|
||||
wsp_encode_test(WSP.FieldName, "", [0]);
|
||||
wsp_encode_test(WSP.FieldName, "date", [0x92]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: AcceptCharsetValue
|
||||
//
|
||||
@ -748,6 +986,24 @@ add_test(function test_AcceptCharsetValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// AcceptCharsetValue.encodeAnyCharset ////
|
||||
|
||||
add_test(function test_AcceptCharsetValue_encodeAnyCharset() {
|
||||
function func(data, input) {
|
||||
WSP.AcceptCharsetValue.encodeAnyCharset(data, input);
|
||||
return data.array;
|
||||
}
|
||||
|
||||
wsp_encode_test_ex(func, null, [0x80]);
|
||||
wsp_encode_test_ex(func, undefined, [0x80]);
|
||||
wsp_encode_test_ex(func, {}, [0x80]);
|
||||
wsp_encode_test_ex(func, {charset: null}, [0x80]);
|
||||
wsp_encode_test_ex(func, {charset: "*"}, [0x80]);
|
||||
wsp_encode_test_ex(func, {charset: "en"}, null, "CodeError");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: WellKnownCharset
|
||||
//
|
||||
@ -766,6 +1022,16 @@ add_test(function test_WellKnownCharset_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// WellKnownCharset.encode ////
|
||||
|
||||
add_test(function test_WellKnownCharset_encode() {
|
||||
// Test for Any-charset
|
||||
wsp_encode_test(WSP.WellKnownCharset, {charset: "*"}, [0x80]);
|
||||
wsp_encode_test(WSP.WellKnownCharset, {charset: "UTF-8"}, [128 + 106]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: ContentTypeValue
|
||||
//
|
||||
@ -848,6 +1114,70 @@ add_test(function test_ContentTypeValue_decode() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// ContentTypeValue.encodeConstrainedMedia ////
|
||||
|
||||
add_test(function test_ContentTypeValue_encodeConstrainedMedia() {
|
||||
function func(data, input) {
|
||||
WSP.ContentTypeValue.encodeConstrainedMedia(data, input);
|
||||
return data.array;
|
||||
}
|
||||
|
||||
// Test media type with additional parameters.
|
||||
wsp_encode_test_ex(func, {media: "a", params: [{a: "b"}]}, null, "CodeError");
|
||||
wsp_encode_test_ex(func, {media: "no/such.type"},
|
||||
[110, 111, 47, 115, 117, 99, 104, 46, 116, 121, 112, 101, 0]);
|
||||
wsp_encode_test_ex(func, {media: "application/vnd.wap.multipart.related"},
|
||||
[0x33 | 0x80]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// ContentTypeValue.encodeMediaType ////
|
||||
|
||||
add_test(function test_ContentTypeValue_encodeMediaType() {
|
||||
function func(data, input) {
|
||||
WSP.ContentTypeValue.encodeMediaType(data, input);
|
||||
return data.array;
|
||||
}
|
||||
|
||||
wsp_encode_test_ex(func, {media: "no/such.type"},
|
||||
[110, 111, 47, 115, 117, 99, 104, 46, 116, 121, 112, 101, 0]);
|
||||
wsp_encode_test_ex(func, {media: "application/vnd.wap.multipart.related"},
|
||||
[0x33 | 0x80]);
|
||||
wsp_encode_test_ex(func, {media: "a", params: {b: "c", q: 0}},
|
||||
[97, 0, 98, 0, 99, 0, 128, 1]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// ContentTypeValue.encodeContentGeneralForm ////
|
||||
|
||||
add_test(function test_ContentTypeValue_encodeContentGeneralForm() {
|
||||
function func(data, input) {
|
||||
WSP.ContentTypeValue.encodeContentGeneralForm(data, input);
|
||||
return data.array;
|
||||
}
|
||||
|
||||
wsp_encode_test_ex(func, {media: "a", params: {b: "c", q: 0}},
|
||||
[8, 97, 0, 98, 0, 99, 0, 128, 1]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// ContentTypeValue.encode ////
|
||||
|
||||
add_test(function test_ContentTypeValue_encode() {
|
||||
wsp_encode_test(WSP.ContentTypeValue, {media: "no/such.type"},
|
||||
[110, 111, 47, 115, 117, 99, 104, 46, 116, 121, 112, 101, 0]);
|
||||
wsp_encode_test(WSP.ContentTypeValue,
|
||||
{media: "application/vnd.wap.multipart.related"},
|
||||
[0x33 | 0x80]);
|
||||
wsp_encode_test(WSP.ContentTypeValue, {media: "a", params: {b: "c", q: 0}},
|
||||
[8, 97, 0, 98, 0, 99, 0, 128, 1]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: ApplicationIdValue
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user