mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout 5ad0ee32f855 (bug 710259) for build failures on all platforms
This commit is contained in:
parent
da37640c57
commit
1b0a6be9dc
@ -111,52 +111,6 @@ Dict.prototype = Object.freeze({
|
||||
items[prop] = aValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets a lazy getter function for a key's value. If the key is a not a string,
|
||||
* it will be converted to a string before the set happens.
|
||||
* @param aKey
|
||||
* The key to set
|
||||
* @param aThunk
|
||||
* A getter function to be called the first time the value for aKey is
|
||||
* retrieved. It is guaranteed that aThunk wouldn't be called more
|
||||
* than once. Note that the key value may be retrieved either
|
||||
* directly, by |get|, or indirectly, by |listvalues| or by iterating
|
||||
* |values|. For the later, the value is only retrieved if and when
|
||||
* the iterator gets to the value in question. Also note that calling
|
||||
* |has| for a lazy-key does not invoke aThunk.
|
||||
*
|
||||
* @note No context is provided for aThunk when it's invoked.
|
||||
* Use Function.bind if you wish to run it in a certain context.
|
||||
*/
|
||||
setAsLazyGetter: function Dict_setAsLazyGetter(aKey, aThunk) {
|
||||
let prop = convert(aKey);
|
||||
let items = this._state.items;
|
||||
if (!items.hasOwnProperty(prop))
|
||||
this._state.count++;
|
||||
|
||||
Object.defineProperty(items, prop, {
|
||||
get: function() {
|
||||
delete items[prop];
|
||||
return items[prop] = aThunk();
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether a key is set as a lazy getter. This returns
|
||||
* true only if the getter function was not called already.
|
||||
* @param aKey
|
||||
* The key to look up.
|
||||
* @returns whether aKey is set as a lazy getter.
|
||||
*/
|
||||
isLazyGetter: function Dict_isLazyGetter(aKey) {
|
||||
let descriptor = Object.getOwnPropertyDescriptor(this._state.items,
|
||||
convert(aKey));
|
||||
return (descriptor && descriptor.get != null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether a key is in the dictionary. If the key is a not a string,
|
||||
* it will be converted to a string before the lookup happens.
|
||||
|
@ -90,7 +90,6 @@ EXTRA_JS_MODULES = \
|
||||
InlineSpellChecker.jsm \
|
||||
PopupNotifications.jsm \
|
||||
Dict.jsm \
|
||||
PropertyListUtils.jsm \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_PP_JS_MODULES = \
|
||||
|
@ -1,771 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Module for reading Property Lists (.plist) files
|
||||
* ------------------------------------------------
|
||||
* This module functions as a reader for Apple Property Lists (.plist files).
|
||||
* It supports both binary and xml formatted property lists. It does not
|
||||
* support the legacy ASCII format. Reading of Cocoa's Keyed Archives serialized
|
||||
* to binary property lists isn't supported either.
|
||||
*
|
||||
* Property Lists objects are represented by standard JS and Mozilla types,
|
||||
* namely:
|
||||
*
|
||||
* XML type Cocoa Class Returned type(s)
|
||||
* --------------------------------------------------------------------------
|
||||
* <true/> / <false/> NSNumber TYPE_PRIMITIVE boolean
|
||||
* <integer> / <real> NSNumber TYPE_PRIMITIVE number
|
||||
* TYPE_INT64 String [1]
|
||||
* Not Available NSNull TYPE_PRIMITIVE null [2]
|
||||
* TYPE_PRIMITIVE undefined [3]
|
||||
* <date/> NSDate TYPE_DATE Date
|
||||
* <data/> NSData TYPE_UINT8_ARRAY Uint8Array
|
||||
* <array/> NSArray TYPE_ARRAY Array
|
||||
* Not Available NSSet TYPE_ARRAY Array [2][4]
|
||||
* <dict/> NSDictionary TYPE_DICTIONARY Dict (from Dict.jsm)
|
||||
*
|
||||
* Use PropertyListUtils.getObjectType to detect the type of a Property list
|
||||
* object.
|
||||
*
|
||||
* -------------
|
||||
* 1) Property lists supports storing U/Int64 numbers, while JS can only handle
|
||||
* numbers that are in this limits of float-64 (±2^53). For numbers that
|
||||
* do not outbound this limits, simple primitive number are always used.
|
||||
* Otherwise, a String object.
|
||||
* 2) About NSNull and NSSet values: While the xml format has no support for
|
||||
* representing null and set values, the documentation for the binary format
|
||||
* states that it supports storing both types. However, the Cocoa APIs for
|
||||
* serializing property lists do not seem to support either types (test with
|
||||
* NSPropertyListSerialization::propertyList:isValidForFormat). Furthermore,
|
||||
* if an array or a dictioanry contains a NSNull or a NSSet value, they cannot
|
||||
* be serialized to a property list.
|
||||
* As for usage within OS X, not surprisingly there's no known usage of
|
||||
* storing either of these types in a property list. It seems that, for now,
|
||||
* Apple is keeping the features of binary and xml formats in sync, probably as
|
||||
* long as the XML format is not officially deprecated.
|
||||
* 3) Not used anywhere.
|
||||
* 4) About NSSet representation: For the time being, we represent those
|
||||
* theoretical NSSet objects the same way NSArray is represented.
|
||||
* While this would most certainly work, it is not the right way to handle
|
||||
* it. A more correct representation for a set is a js generator, which would
|
||||
* read the set lazily and has no indices semantics.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let EXPORTED_SYMBOLS = ["PropertyListUtils"];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Dict",
|
||||
"resource://gre/modules/Dict.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
|
||||
"resource://gre/modules/ctypes.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
let PropertyListUtils = Object.freeze({
|
||||
/**
|
||||
* Asynchronously reads a file as a property list.
|
||||
*
|
||||
* @param aFile (nsIDOMBlob/nsILocalFile)
|
||||
* the file to be read as a property list.
|
||||
* @param aCallback
|
||||
* If the property list is read successfully, aPropertyListRoot is set
|
||||
* to the root object of the property list.
|
||||
* Use getPropertyListObjectType to detect its type.
|
||||
* If it's not read successfully, aPropertyListRoot is set to null.
|
||||
* The reaon for failure is reported to the Error Console.
|
||||
*/
|
||||
read: function PLU_read(aFile, aCallback) {
|
||||
if (!(aFile instanceof Ci.nsILocalFile || aFile instanceof Ci.nsIDOMFile))
|
||||
throw new Error("aFile is not a file object");
|
||||
if (typeof(aCallback) != "function")
|
||||
throw new Error("Invalid value for aCallback");
|
||||
|
||||
// We guarantee not to throw directly for any other exceptions, and always
|
||||
// call aCallback.
|
||||
Services.tm.mainThread.dispatch(function() {
|
||||
let file = aFile;
|
||||
try {
|
||||
if (file instanceof Ci.nsILocalFile) {
|
||||
if (!file.exists())
|
||||
throw new Error("The file pointed by aFile does not exist");
|
||||
|
||||
file = new File(file);
|
||||
}
|
||||
|
||||
let fileReader = Cc["@mozilla.org/files/filereader;1"].
|
||||
createInstance(Ci.nsIDOMFileReader);
|
||||
let onLoadEnd = function() {
|
||||
let root = null;
|
||||
try {
|
||||
fileReader.removeEventListener("loadend", onLoadEnd, false);
|
||||
if (fileReader.readyState != fileReader.DONE)
|
||||
throw new Error("Could not read file contents: " + fileReader.error);
|
||||
|
||||
root = this._readFromArrayBufferSync(fileReader.result);
|
||||
}
|
||||
finally {
|
||||
aCallback(root);
|
||||
}
|
||||
}.bind(this);
|
||||
fileReader.addEventListener("loadend", onLoadEnd, false);
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
catch(ex) {
|
||||
aCallback(null);
|
||||
throw ex;
|
||||
}
|
||||
}.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
|
||||
},
|
||||
|
||||
/**
|
||||
* DO NOT USE ME. Once Bug 718189 is fixed, this method won't be public.
|
||||
*
|
||||
* Synchronously read an ArrayBuffer contents as a property list.
|
||||
*/
|
||||
_readFromArrayBufferSync: function PLU__readFromArrayBufferSync(aBuffer) {
|
||||
if (BinaryPropertyListReader.prototype.canProcess(aBuffer))
|
||||
return new BinaryPropertyListReader(aBuffer).root;
|
||||
|
||||
// Convert the buffer into an XML tree.
|
||||
let domParser = Cc["@mozilla.org/xmlextras/domparser;1"].
|
||||
createInstance(Ci.nsIDOMParser);
|
||||
let bytesView = Uint8Array(aBuffer);
|
||||
try {
|
||||
let doc = domParser.parseFromBuffer(bytesView, bytesView.length,
|
||||
"application/xml");
|
||||
return new XMLPropertyListReader(doc).root;
|
||||
}
|
||||
catch(ex) {
|
||||
throw new Error("aBuffer cannot be parsed as a DOM document: " + ex);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
TYPE_PRIMITIVE: 0,
|
||||
TYPE_DATE: 1,
|
||||
TYPE_UINT8_ARRAY: 2,
|
||||
TYPE_ARRAY: 3,
|
||||
TYPE_DICTIONARY: 4,
|
||||
TYPE_INT64: 5,
|
||||
|
||||
/**
|
||||
* Get the type in which the given property list object is represented.
|
||||
* Check the header for the mapping between the TYPE* constants to js types
|
||||
* and objects.
|
||||
*
|
||||
* @return one of the TYPE_* constants listed above.
|
||||
* @note this method is merely for convenience. It has no magic to detect
|
||||
* that aObject is indeed a property list object created by this module.
|
||||
*/
|
||||
getObjectType: function PLU_getObjectType(aObject) {
|
||||
if (aObject === null || typeof(aObject) != "object")
|
||||
return this.TYPE_PRIMITIVE;
|
||||
|
||||
// Given current usage, we could assume that aObject was created in the
|
||||
// scope of this module, but in future, this util may be used as part of
|
||||
// serializing js objects to a property list - in which case the object
|
||||
// would most likely be created in the caller's scope.
|
||||
let global = Cu.getGlobalForObject(aObject);
|
||||
|
||||
if (global.Dict && aObject instanceof global.Dict)
|
||||
return this.TYPE_DICTIONARY;
|
||||
if (Array.isArray(aObject))
|
||||
return this.TYPE_ARRAY;
|
||||
if (aObject instanceof global.Date)
|
||||
return this.TYPE_DATE;
|
||||
if (aObject instanceof global.Uint8Array)
|
||||
return this.TYPE_UINT8_ARRAY;
|
||||
if (aObject instanceof global.String && "__INT_64_WRAPPER__" in aObject)
|
||||
return this.TYPE_INT64;
|
||||
|
||||
throw new Error("aObject is not as a property list object.");
|
||||
},
|
||||
|
||||
/**
|
||||
* Wraps a 64-bit stored in the form of a string primitive as a String object,
|
||||
* which we can later distiguish from regular string values.
|
||||
* @param aPrimitive
|
||||
* a number in the form of either a primitive string or a primitive number.
|
||||
* @return a String wrapper around aNumberStr that can later be identified
|
||||
* as holding 64-bit number using getObjectType.
|
||||
*/
|
||||
wrapInt64: function PLU_wrapInt64(aPrimitive) {
|
||||
if (typeof(aPrimitive) != "string" && typeof(aPrimitive) != "number")
|
||||
throw new Error("aPrimitive should be a string primitive");
|
||||
|
||||
let wrapped = new String(aPrimitive);
|
||||
Object.defineProperty(wrapped, "__INT_64_WRAPPER__", { value: true });
|
||||
return wrapped;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Here's the base structure of binary-format property lists.
|
||||
* 1) Header - magic number
|
||||
* - 6 bytes - "bplist"
|
||||
* - 2 bytes - version number. This implementation only supports version 00.
|
||||
* 2) Objects Table
|
||||
* Variable-sized objects, see _readObject for how various types of objects
|
||||
* are constructed.
|
||||
* 3) Offsets Table
|
||||
* The offset of each object in the objects table. The integer size is
|
||||
* specified in the trailer.
|
||||
* 4) Trailer
|
||||
* - 6 unused bytes
|
||||
* - 1 byte: the size of integers in the offsets table
|
||||
* - 1 byte: the size of object references for arrays, sets and
|
||||
* dictionaries.
|
||||
* - 8 bytes: the number of objects in the objects table
|
||||
* - 8 bytes: the index of the root object's offset in the offsets table.
|
||||
* - 8 bytes: the offset of the offsets table.
|
||||
*
|
||||
* Note: all integers are stored in big-endian form.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reader for binary-format property lists.
|
||||
*
|
||||
* @param aBuffer
|
||||
* ArrayBuffer object from which the binary plist should be read.
|
||||
*/
|
||||
function BinaryPropertyListReader(aBuffer) {
|
||||
this._buffer = aBuffer;
|
||||
|
||||
const JS_MAX_INT = Math.pow(2,53);
|
||||
this._JS_MAX_INT_SIGNED = ctypes.Int64(JS_MAX_INT);
|
||||
this._JS_MAX_INT_UNSIGNED = ctypes.UInt64(JS_MAX_INT);
|
||||
this._JS_MIN_INT = ctypes.Int64(-JS_MAX_INT);
|
||||
|
||||
try {
|
||||
this._readTrailerInfo();
|
||||
this._readObjectsOffsets();
|
||||
}
|
||||
catch(ex) {
|
||||
throw new Error("Could not read aBuffer as a binary property list");
|
||||
}
|
||||
this._objects = [];
|
||||
}
|
||||
|
||||
BinaryPropertyListReader.prototype = {
|
||||
/**
|
||||
* Checks if the given ArrayBuffer can be read as a binary property list.
|
||||
* It can be called on the prototype.
|
||||
*/
|
||||
canProcess: function BPLR_canProcess(aBuffer)
|
||||
[String.fromCharCode(c) for each (c in Uint8Array(aBuffer, 0, 8))].
|
||||
join("") == "bplist00",
|
||||
|
||||
get root() this._readObject(this._rootObjectIndex),
|
||||
|
||||
_readTrailerInfo: function BPLR__readTrailer() {
|
||||
// The first 6 bytes of the 32-bytes trailer are unused
|
||||
let trailerOffset = this._buffer.byteLength - 26;
|
||||
[this._offsetTableIntegerSize, this._objectRefSize] =
|
||||
this._readUnsignedInts(trailerOffset, 1, 2);
|
||||
|
||||
[this._numberOfObjects, this._rootObjectIndex, this._offsetTableOffset] =
|
||||
this._readUnsignedInts(trailerOffset + 2, 8, 3);
|
||||
},
|
||||
|
||||
_readObjectsOffsets: function BPLR__readObjectsOffsets() {
|
||||
this._offsetTable = this._readUnsignedInts(this._offsetTableOffset,
|
||||
this._offsetTableIntegerSize,
|
||||
this._numberOfObjects);
|
||||
},
|
||||
|
||||
// TODO: This should be removed once DataView is implemented (Bug 575688).
|
||||
_swapForBigEndian:
|
||||
function BPLR__swapForBigEndian(aByteOffset, aIntSize, aNumberOfInts) {
|
||||
let bytesCount = aIntSize * aNumberOfInts;
|
||||
let bytes = new Uint8Array(this._buffer, aByteOffset, bytesCount);
|
||||
let swapped = new Uint8Array(bytesCount);
|
||||
for (let i = 0; i < aNumberOfInts; i++) {
|
||||
for (let j = 0; j < aIntSize; j++) {
|
||||
swapped[(i * aIntSize) + j] = bytes[(i * aIntSize) + (aIntSize - 1 - j)];
|
||||
}
|
||||
}
|
||||
return swapped;
|
||||
},
|
||||
|
||||
_readSignedInt64: function BPLR__readSignedInt64(aByteOffset) {
|
||||
let swapped = this._swapForBigEndian(aByteOffset, 8, 1);
|
||||
let lo = new Uint32Array(swapped.buffer, 0, 1)[0];
|
||||
let hi = new Int32Array(swapped.buffer, 4, 1)[0];
|
||||
let int64 = ctypes.Int64.join(hi, lo);
|
||||
if (ctypes.Int64.compare(int64, this._JS_MAX_INT_SIGNED) == 1 ||
|
||||
ctypes.Int64.compare(int64, this._JS_MIN_INT) == -1)
|
||||
return PropertyListUtils.wrapInt64(int64.toString());
|
||||
|
||||
return parseInt(int64.toString(), 10);
|
||||
},
|
||||
|
||||
_readReal: function BPLR__readReal(aByteOffset, aRealSize) {
|
||||
let swapped = this._swapForBigEndian(aByteOffset, aRealSize, 1);
|
||||
if (aRealSize == 4)
|
||||
return Float32Array(swapped.buffer, 0, 1)[0];
|
||||
if (aRealSize == 8)
|
||||
return Float64Array(swapped.buffer, 0, 1)[0];
|
||||
|
||||
throw new Error("Unsupported real size: " + aRealSize);
|
||||
},
|
||||
|
||||
OBJECT_TYPE_BITS: {
|
||||
SIMPLE: parseInt("0000", 2),
|
||||
INTEGER: parseInt("0001", 2),
|
||||
REAL: parseInt("0010", 2),
|
||||
DATE: parseInt("0011", 2),
|
||||
DATA: parseInt("0100", 2),
|
||||
ASCII_STRING: parseInt("0101", 2),
|
||||
UNICODE_STRING: parseInt("0110", 2),
|
||||
UID: parseInt("1000", 2),
|
||||
ARRAY: parseInt("1010", 2),
|
||||
SET: parseInt("1100", 2),
|
||||
DICTIONARY: parseInt("1101", 2)
|
||||
},
|
||||
|
||||
ADDITIONAL_INFO_BITS: {
|
||||
// Applies to OBJECT_TYPE_BITS.SIMPLE
|
||||
NULL: parseInt("0000", 2),
|
||||
FALSE: parseInt("1000", 2),
|
||||
TRUE: parseInt("1001", 2),
|
||||
FILL_BYTE: parseInt("1111", 2),
|
||||
// Applies to OBJECT_TYPE_BITS.DATE
|
||||
DATE: parseInt("0011", 2),
|
||||
// Applies to OBJECT_TYPE_BITS.DATA, ASCII_STRING, UNICODE_STRING, ARRAY,
|
||||
// SET and DICTIONARY.
|
||||
LENGTH_INT_SIZE_FOLLOWS: parseInt("1111", 2)
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an object descriptor in the form of two integers: object type and
|
||||
* additional info.
|
||||
*
|
||||
* @param aByteOffset
|
||||
* the descriptor's offset.
|
||||
* @return [objType, additionalInfo] - the object type and additional info.
|
||||
* @see OBJECT_TYPE_BITS and ADDITIONAL_INFO_BITS
|
||||
*/
|
||||
_readObjectDescriptor: function BPLR__readObjectDescriptor(aByteOffset) {
|
||||
// The first four bits hold the object type. For some types, additional
|
||||
// info is held in the other 4 bits.
|
||||
let byte = this._readUnsignedInts(aByteOffset, 1, 1)[0];
|
||||
return [(byte & 0xF0) >> 4, byte & 0x0F];
|
||||
},
|
||||
|
||||
_readDate: function BPLR__readDate(aByteOffset) {
|
||||
// That's the reference date of NSDate.
|
||||
let date = new Date("1 January 2001, GMT");
|
||||
|
||||
// NSDate values are float values, but setSeconds takes an integer.
|
||||
date.setMilliseconds(this._readReal(aByteOffset, 8) * 1000);
|
||||
return date;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads a portion of the buffer as a string.
|
||||
*
|
||||
* @param aByteOffset
|
||||
* The offset in the buffer at which the string starts
|
||||
* @param aNumberOfChars
|
||||
* The length of the string to be read (that is the number of
|
||||
* characters, not bytes).
|
||||
* @param aUnicode
|
||||
* Whether or not it is a unicode string.
|
||||
* @return the string read.
|
||||
*
|
||||
* @note this is tested to work well with unicode surrogate pairs. Because
|
||||
* all unicode characters are read as 2-byte integers, unicode surrogate
|
||||
* pairs are read from the buffer in the form of two integers, as required
|
||||
* by String.fromCharCode.
|
||||
*/
|
||||
_readString:
|
||||
function BPLR__readString(aByteOffset, aNumberOfChars, aUnicode) {
|
||||
let codes = this._readUnsignedInts(aByteOffset, aUnicode ? 2 : 1,
|
||||
aNumberOfChars);
|
||||
return [String.fromCharCode(c) for each (c in codes)].join("");
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads an array of unsigned integers from the buffer. Integers larger than
|
||||
* one byte are read in big endian form.
|
||||
*
|
||||
* @param aByteOffset
|
||||
* The offset in the buffer at which the array starts.
|
||||
* @param aIntSize
|
||||
* The size of each int in the array.
|
||||
* @param aLength
|
||||
* The number of ints in the array.
|
||||
* @param [optional] aBigIntAllowed (default: false)
|
||||
* Whether or not to accept integers which outbounds JS limits for
|
||||
* numbers (±2^53) in the form of a String.
|
||||
* @return an array of integers (number primitive and/or Strings for large
|
||||
* numbers (see header)).
|
||||
* @throws if aBigIntAllowed is false and one of the integers in the array
|
||||
* cannot be represented by a primitive js number.
|
||||
*/
|
||||
_readUnsignedInts:
|
||||
function BPLR__readUnsignedInts(aByteOffset, aIntSize, aLength, aBigIntAllowed) {
|
||||
if (aIntSize == 1)
|
||||
return Uint8Array(this._buffer, aByteOffset, aLength);
|
||||
|
||||
// There are two reasons for the complexity you see here:
|
||||
// (1) 64-bit integers - For which we use ctypes. When possible, the
|
||||
// number is converted back to js's default float-64 type.
|
||||
// (2) The DataView object for ArrayBuffer, which takes care of swaping
|
||||
// bytes, is not yet implemented (bug 575688).
|
||||
let swapped = this._swapForBigEndian(aByteOffset, aIntSize, aLength);
|
||||
if (aIntSize == 2)
|
||||
return Uint16Array(swapped.buffer);
|
||||
if (aIntSize == 4)
|
||||
return Uint32Array(swapped.buffer);
|
||||
if (aIntSize == 8) {
|
||||
let intsArray = [];
|
||||
let lo_hi_view = new Uint32Array(swapped.buffer);
|
||||
for (let i = 0; i < lo_hi_view.length; i += 2) {
|
||||
let [lo, hi] = [lo_hi_view[i], lo_hi_view[i+1]];
|
||||
let uint64 = ctypes.UInt64.join(hi, lo);
|
||||
if (ctypes.UInt64.compare(uint64, this._JS_MAX_INT_UNSIGNED) == 1) {
|
||||
if (aBigIntAllowed === true)
|
||||
intsArray.push(PropertyListUtils.wrapInt64(uint64.toString()));
|
||||
else
|
||||
throw new Error("Integer too big to be read as float 64");
|
||||
}
|
||||
else {
|
||||
intsArray.push(parseInt(uint64.toString(), 10));
|
||||
}
|
||||
}
|
||||
return intsArray;
|
||||
}
|
||||
throw new Error("Unsupported size: " + aIntSize);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads from the buffer the data object-count and the offset at which the
|
||||
* first object starts.
|
||||
*
|
||||
* @param aObjectOffset
|
||||
* the object's offset.
|
||||
* @return [offset, count] - the offset in the buffer at which the first
|
||||
* object in data starts, and the number of objects.
|
||||
*/
|
||||
_readDataOffsetAndCount:
|
||||
function BPLR__readDataOffsetAndCount(aObjectOffset) {
|
||||
// The length of some objects in the data can be stored in two ways:
|
||||
// * If it is small enough, it is stored in the second four bits of the
|
||||
// object descriptors.
|
||||
// * Otherwise, those bits are set to 1111, indicating that the next byte
|
||||
// consists of the integer size of the data-length (also stored in the form
|
||||
// of an object descriptor). The length follows this byte.
|
||||
let [, maybeLength] = this._readObjectDescriptor(aObjectOffset);
|
||||
if (maybeLength != this.ADDITIONAL_INFO_BITS.LENGTH_INT_SIZE_FOLLOWS)
|
||||
return [aObjectOffset + 1, maybeLength];
|
||||
|
||||
let [, intSizeInfo] = this._readObjectDescriptor(aObjectOffset + 1);
|
||||
|
||||
// The int size is 2^intSizeInfo.
|
||||
let intSize = Math.pow(2, intSizeInfo);
|
||||
let dataLength = this._readUnsignedInts(aObjectOffset + 2, intSize, 1)[0];
|
||||
return [aObjectOffset + 2 + intSize, dataLength];
|
||||
},
|
||||
|
||||
/**
|
||||
* Read array from the buffer and wrap it as a js array.
|
||||
* @param aObjectOffset
|
||||
* the offset in the buffer at which the array starts.
|
||||
* @param aNumberOfObjects
|
||||
* the number of objects in the array.
|
||||
* @return a js array.
|
||||
*/
|
||||
_wrapArray: function BPLR__wrapArray(aObjectOffset, aNumberOfObjects) {
|
||||
let refs = this._readUnsignedInts(aObjectOffset,
|
||||
this._objectRefSize,
|
||||
aNumberOfObjects);
|
||||
|
||||
let array = new Array(aNumberOfObjects);
|
||||
let readObjectBound = this._readObject.bind(this);
|
||||
|
||||
// Each index in the returned array is a lazy getter for its object.
|
||||
Array.prototype.forEach.call(refs, function(ref, objIndex) {
|
||||
Object.defineProperty(array, objIndex, {
|
||||
get: function() {
|
||||
delete array[objIndex];
|
||||
return array[objIndex] = readObjectBound(ref);
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
}, this);
|
||||
return array;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads dictionary from the buffer and wraps it as a Dict object (as defined
|
||||
* in Dict.jsm).
|
||||
* @param aObjectOffset
|
||||
* the offset in the buffer at which the dictionary starts
|
||||
* @param aNumberOfObjects
|
||||
* the number of keys in the dictionary
|
||||
* @return Dict.jsm-style dictionary.
|
||||
*/
|
||||
_wrapDictionary: function(aObjectOffset, aNumberOfObjects) {
|
||||
// A dictionary in the binary format is stored as a list of references to
|
||||
// key-objects, followed by a list of references to the value-objects for
|
||||
// those keys. The size of each list is aNumberOfObjects * this._objectRefSize.
|
||||
let dict = new Dict();
|
||||
if (aNumberOfObjects == 0)
|
||||
return dict;
|
||||
|
||||
let keyObjsRefs = this._readUnsignedInts(aObjectOffset, this._objectRefSize,
|
||||
aNumberOfObjects);
|
||||
let valObjsRefs =
|
||||
this._readUnsignedInts(aObjectOffset + aNumberOfObjects * this._objectRefSize,
|
||||
this._objectRefSize, aNumberOfObjects);
|
||||
for (let i = 0; i < aNumberOfObjects; i++) {
|
||||
let key = this._readObject(keyObjsRefs[i]);
|
||||
let readBound = this._readObject.bind(this, valObjsRefs[i]);
|
||||
dict.setAsLazyGetter(key, readBound);
|
||||
}
|
||||
return dict;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads an object at the spcified index in the object table
|
||||
* @param aObjectIndex
|
||||
* index at the object table
|
||||
* @return the property list object at the given index.
|
||||
*/
|
||||
_readObject: function BPLR__readObject(aObjectIndex) {
|
||||
// If the object was previously read, return the cached object.
|
||||
if (this._objects[aObjectIndex] !== undefined)
|
||||
return this._objects[aObjectIndex];
|
||||
|
||||
let objOffset = this._offsetTable[aObjectIndex];
|
||||
let [objType, additionalInfo] = this._readObjectDescriptor(objOffset);
|
||||
let value;
|
||||
switch (objType) {
|
||||
case this.OBJECT_TYPE_BITS.SIMPLE: {
|
||||
switch (additionalInfo) {
|
||||
case this.ADDITIONAL_INFO_BITS.NULL:
|
||||
value = null;
|
||||
break;
|
||||
case this.ADDITIONAL_INFO_BITS.FILL_BYTE:
|
||||
value = undefined;
|
||||
break;
|
||||
case this.ADDITIONAL_INFO_BITS.FALSE:
|
||||
value = false;
|
||||
break;
|
||||
case this.ADDITIONAL_INFO_BITS.TRUE:
|
||||
value = true;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unexpected value!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case this.OBJECT_TYPE_BITS.INTEGER: {
|
||||
// The integer is sized 2^additionalInfo.
|
||||
let intSize = Math.pow(2, additionalInfo);
|
||||
|
||||
// For objects, 64-bit integers are always signed. Negative integers
|
||||
// are always represented by a 64-bit integer.
|
||||
if (intSize == 8)
|
||||
value = this._readSignedInt64(objOffset + 1);
|
||||
else
|
||||
value = this._readUnsignedInts(objOffset + 1, intSize, 1, true)[0];
|
||||
break;
|
||||
}
|
||||
|
||||
case this.OBJECT_TYPE_BITS.REAL: {
|
||||
// The real is sized 2^additionalInfo.
|
||||
value = this._readReal(objOffset + 1, Math.pow(2, additionalInfo));
|
||||
break;
|
||||
}
|
||||
|
||||
case this.OBJECT_TYPE_BITS.DATE: {
|
||||
if (additionalInfo != this.ADDITIONAL_INFO_BITS.DATE)
|
||||
throw new Error("Unexpected value");
|
||||
|
||||
value = this._readDate(objOffset + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case this.OBJECT_TYPE_BITS.DATA: {
|
||||
let [offset, bytesCount] = this._readDataOffsetAndCount(objOffset);
|
||||
value = this._readUnsignedInts(offset, 1, bytesCount);
|
||||
break;
|
||||
}
|
||||
|
||||
case this.OBJECT_TYPE_BITS.ASCII_STRING: {
|
||||
let [offset, charsCount] = this._readDataOffsetAndCount(objOffset);
|
||||
value = this._readString(offset, charsCount, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case this.OBJECT_TYPE_BITS.UNICODE_STRING: {
|
||||
let [offset, unicharsCount] = this._readDataOffsetAndCount(objOffset);
|
||||
value = this._readString(offset, unicharsCount, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case this.OBJECT_TYPE_BITS.UID: {
|
||||
// UIDs are only used in Keyed Archives, which are not yet supported.
|
||||
throw new Error("Keyed Archives are not supported");
|
||||
}
|
||||
|
||||
case this.OBJECT_TYPE_BITS.ARRAY:
|
||||
case this.OBJECT_TYPE_BITS.SET: {
|
||||
// Note: For now, we fallback to handle sets the same way we handle
|
||||
// arrays. See comments in the header of this file.
|
||||
|
||||
// The bytes following the count are references to objects (indices).
|
||||
// Each reference is an unsigned int with size=this._objectRefSize.
|
||||
let [offset, objectsCount] = this._readDataOffsetAndCount(objOffset);
|
||||
value = this._wrapArray(offset, objectsCount);
|
||||
break;
|
||||
}
|
||||
|
||||
case this.OBJECT_TYPE_BITS.DICTIONARY: {
|
||||
let [offset, objectsCount] = this._readDataOffsetAndCount(objOffset);
|
||||
value = this._wrapDictionary(offset, objectsCount);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new Error("Unknown object type: " + objType);
|
||||
}
|
||||
}
|
||||
|
||||
return this._objects[aObjectIndex] = value;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reader for XML property lists.
|
||||
*
|
||||
* @param aDOMDoc
|
||||
* the DOM document to be read as a property list.
|
||||
*/
|
||||
function XMLPropertyListReader(aDOMDoc) {
|
||||
let docElt = aDOMDoc.documentElement;
|
||||
if (!docElt || docElt.localName != "plist" || !docElt.firstElementChild)
|
||||
throw new Error("aDoc is not a property list document");
|
||||
|
||||
this._plistRootElement = docElt.firstElementChild;
|
||||
}
|
||||
|
||||
XMLPropertyListReader.prototype = {
|
||||
get root() this._readObject(this._plistRootElement),
|
||||
|
||||
/**
|
||||
* Convert a dom element to a property list object.
|
||||
* @param aDOMElt
|
||||
* a dom element in a xml tree of a property list.
|
||||
* @return a js object representing the property list object.
|
||||
*/
|
||||
_readObject: function XPLR__readObject(aDOMElt) {
|
||||
switch (aDOMElt.localName) {
|
||||
case "true":
|
||||
return true;
|
||||
case "false":
|
||||
return false;
|
||||
case "string":
|
||||
case "key":
|
||||
return aDOMElt.textContent;
|
||||
case "integer":
|
||||
return this._readInteger(aDOMElt);
|
||||
case "real": {
|
||||
let number = parseFloat(aDOMElt.textContent.trim());
|
||||
if (isNaN(number))
|
||||
throw "Could not parse float value";
|
||||
return number;
|
||||
}
|
||||
case "date":
|
||||
return new Date(aDOMElt.textContent);
|
||||
case "data":
|
||||
// Strip spaces and new lines.
|
||||
let base64str = aDOMElt.textContent.replace(/\s*/g, "");
|
||||
let decoded = atob(base64str);
|
||||
return Uint8Array([decoded.charCodeAt(i) for (i in decoded)]);
|
||||
case "dict":
|
||||
return this._wrapDictionary(aDOMElt);
|
||||
case "array":
|
||||
return this._wrapArray(aDOMElt);
|
||||
default:
|
||||
throw new Error("Unexpected tagname");
|
||||
}
|
||||
},
|
||||
|
||||
_readInteger: function XPLR__readInteger(aDOMElt) {
|
||||
// The integer may outbound js's max/min integer value. We recognize this
|
||||
// case by comparing the parsed number to the original string value.
|
||||
// In case of an outbound, we fallback to return the number as a string.
|
||||
let numberAsString = aDOMElt.textContent.toString();
|
||||
let parsedNumber = parseInt(numberAsString, 10);
|
||||
if (isNaN(parsedNumber))
|
||||
throw new Error("Could not parse integer value");
|
||||
|
||||
if (parsedNumber.toString() == numberAsString)
|
||||
return parsedNumber;
|
||||
|
||||
return PropertyListUtils.wrapInt64(numberAsString);
|
||||
},
|
||||
|
||||
_wrapDictionary: function XPLR__wrapDictionary(aDOMElt) {
|
||||
// <dict>
|
||||
// <key>my true bool</key>
|
||||
// <true/>
|
||||
// <key>my string key</key>
|
||||
// <string>My String Key</string>
|
||||
// </dict>
|
||||
if (aDOMElt.children.length % 2 != 0)
|
||||
throw new Error("Invalid dictionary");
|
||||
let dict = new Dict();
|
||||
for (let i = 0; i < aDOMElt.children.length; i += 2) {
|
||||
let keyElem = aDOMElt.children[i];
|
||||
let valElem = aDOMElt.children[i + 1];
|
||||
|
||||
if (keyElem.localName != "key")
|
||||
throw new Error("Invalid dictionary");
|
||||
|
||||
let keyName = this._readObject(keyElem);
|
||||
let readBound = this._readObject.bind(this, valElem);
|
||||
dict.setAsLazyGetter(keyName, readBound);
|
||||
}
|
||||
return dict;
|
||||
},
|
||||
|
||||
_wrapArray: function XPLR__wrapArray(aDOMElt) {
|
||||
// <array>
|
||||
// <string>...</string>
|
||||
// <integer></integer>
|
||||
// <dict>
|
||||
// ....
|
||||
// </dict>
|
||||
// </array>
|
||||
|
||||
// Each element in the array is a lazy getter for its property list object.
|
||||
let array = [];
|
||||
let readObjectBound = this._readObject.bind(this);
|
||||
Array.prototype.forEach.call(aDOMElt.children, function(elem, elemIndex) {
|
||||
Object.defineProperty(array, elemIndex, {
|
||||
get: function() {
|
||||
delete array[elemIndex];
|
||||
return array[elemIndex] = readObjectBound(elem);
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
});
|
||||
return array;
|
||||
}
|
||||
};
|
Binary file not shown.
@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Boolean</key>
|
||||
<false/>
|
||||
<key>Array</key>
|
||||
<array>
|
||||
<string>abc</string>
|
||||
<string>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</string>
|
||||
<string>אאא</string>
|
||||
<string>אאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאא</string>
|
||||
<string>𐀀𐀀𐀀</string>
|
||||
<date>2011-12-31T11:15:23Z</date>
|
||||
<data>MjAxMS0xMi0zMVQxMToxNTozM1o=</data>
|
||||
<dict>
|
||||
<key>Negative Number</key>
|
||||
<integer>-400</integer>
|
||||
<key>Real Number</key>
|
||||
<real>2.71828183</real>
|
||||
<key>Big Int</key>
|
||||
<integer>9007199254740993</integer>
|
||||
<key>Negative Big Int</key>
|
||||
<integer>-9007199254740993</integer>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
@ -208,83 +208,6 @@ function test_set_property_non_strict() {
|
||||
do_check_eq(dict.get, realget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting a property by a lazy getter.
|
||||
*/
|
||||
function test_set_property_lazy_getter() {
|
||||
let thunkCalled = false;
|
||||
|
||||
let setThunk = function(dict) {
|
||||
thunkCalled = false;
|
||||
dict.setAsLazyGetter("foo", function() {
|
||||
thunkCalled = true;
|
||||
return "bar";
|
||||
});
|
||||
};
|
||||
|
||||
let (dict = new Dict()) {
|
||||
setThunk(dict);
|
||||
|
||||
// Test that checking for the key existence does not invoke
|
||||
// the getter function.
|
||||
do_check_true(dict.has("foo"));
|
||||
do_check_false(thunkCalled);
|
||||
do_check_true(dict.isLazyGetter("foo"));
|
||||
|
||||
// Calling get the first time should invoke the getter function
|
||||
// and unmark the key as a lazy getter.
|
||||
do_check_eq(dict.get("foo"), "bar");
|
||||
do_check_true(thunkCalled);
|
||||
do_check_false(dict.isLazyGetter("foo"));
|
||||
|
||||
// Calling get again should not invoke the getter function
|
||||
thunkCalled = false;
|
||||
do_check_eq(dict.get("foo"), "bar");
|
||||
do_check_false(thunkCalled);
|
||||
do_check_false(dict.isLazyGetter("foo"));
|
||||
}
|
||||
|
||||
// Test that listvalues works for lazy keys.
|
||||
let (dict = new Dict()) {
|
||||
setThunk(dict);
|
||||
do_check_true(dict.isLazyGetter("foo"));
|
||||
|
||||
let (listvalues = dict.listvalues()) {
|
||||
do_check_false(dict.isLazyGetter("foo"));
|
||||
do_check_true(thunkCalled);
|
||||
do_check_true(listvalues.length, 1);
|
||||
do_check_eq(listvalues[0], "bar");
|
||||
}
|
||||
|
||||
thunkCalled = false;
|
||||
|
||||
// Retrieving the list again shouldn't invoke our getter.
|
||||
let (listvalues = dict.listvalues()) {
|
||||
do_check_false(dict.isLazyGetter("foo"));
|
||||
do_check_false(thunkCalled);
|
||||
do_check_true(listvalues.length, 1);
|
||||
do_check_eq(listvalues[0], "bar");
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the values iterator also works as expected.
|
||||
let (dict = new Dict()) {
|
||||
setThunk(dict);
|
||||
let values = dict.values;
|
||||
|
||||
// Our getter shouldn't be called before the iterator reaches it.
|
||||
do_check_true(dict.isLazyGetter("foo"));
|
||||
do_check_false(thunkCalled);
|
||||
do_check_eq(values.next(), "bar");
|
||||
do_check_true(thunkCalled);
|
||||
|
||||
thunkCalled = false;
|
||||
do_check_false(dict.isLazyGetter("foo"));
|
||||
do_check_eq(dict.get("foo"), "bar");
|
||||
do_check_false(thunkCalled);
|
||||
}
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test_get_set_has_del,
|
||||
test_get_default,
|
||||
@ -295,7 +218,6 @@ var tests = [
|
||||
test_iterators,
|
||||
test_set_property_strict,
|
||||
test_set_property_non_strict,
|
||||
test_set_property_lazy_getter
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
|
@ -5,4 +5,3 @@ tail =
|
||||
[test_contentAreaUtils.js]
|
||||
[test_dict.js]
|
||||
[test_privatebrowsing_downloadLastDir_c.js]
|
||||
[test_propertyListsUtils.js]
|
||||
|
Loading…
Reference in New Issue
Block a user