Bug 764436 - Shared code;r=taras

This commit is contained in:
David Rajchenbach-Teller 2012-07-05 10:20:07 +02:00
parent a93cb671b8
commit 38991b7fd2

View File

@ -440,6 +440,147 @@
ctypes.ssize_t,
projector(ctypes.ssize_t, true));
/**
* Utility class, used to build a |struct| type
* from a set of field names, types and offsets.
*
* @param {string} name The name of the |struct| type.
* @param {number} size The total size of the |struct| type in bytes.
*/
function HollowStructure(name, size) {
if (!name) {
throw new TypeError("HollowStructure expects a name");
}
if (!size || size < 0) {
throw new TypeError("HollowStructure expects a (positive) size");
}
// A mapping from offsets in the struct to name/type pairs
// (or nothing if no field starts at that offset).
this.offset_to_field_info = [];
// The name of the struct
this.name = name;
// The size of the struct, in bytes
this.size = size;
// The number of paddings inserted so far.
// Used to give distinct names to padding fields.
this._paddings = 0;
}
HollowStructure.prototype = {
/**
* Add a field at a given offset.
*
* @param {number} offset The offset at which to insert the field.
* @param {string} name The name of the field.
* @param {CType|Type} type The type of the field.
*/
add_field_at: function add_field_at(offset, name, type) {
if (offset === null) {
throw new TypeError("add_field_at requires a non-null offset");
}
if (!name) {
throw new TypeError("add_field_at requires a non-null name");
}
if (!type) {
throw new TypeError("add_field_at requires a non-null type");
}
if (type instanceof Type) {
type = type.implementation;
}
if (this.offset_to_field_info[offset]) {
throw new Error("HollowStructure " + this.name +
" already has a field at offset " + offset);
}
if (offset + type.size > this.size) {
throw new Error("HollowStructure " + this.name +
" cannot place a value of type " + type +
" at offset " + offset +
" without exceeding its size of " + this.size);
}
let field = {name: name, type:type};
this.offset_to_field_info[offset] = field;
},
/**
* Create a pseudo-field that will only serve as padding.
*
* @param {number} size The number of bytes in the field.
* @return {Object} An association field-name => field-type,
* as expected by |ctypes.StructType|.
*/
_makePaddingField: function makePaddingField(size) {
let field = ({});
field["padding_" + this._paddings] =
ctypes.ArrayType(ctypes.uint8_t, size);
this._paddings++;
return field;
},
/**
* Convert this |HollowStructure| into a |Type|.
*/
getType: function getType() {
// Contents of the structure, in the format expected
// by ctypes.StructType.
let struct = [];
let i = 0;
while (i < this.size) {
let currentField = this.offset_to_field_info[i];
if (!currentField) {
// No field was specified at this offset, we need to
// introduce some padding.
// Firstly, determine how many bytes of padding
let padding_length = 1;
while (i + padding_length < this.size
&& !this.offset_to_field_info[i + padding_length]) {
++padding_length;
}
// Then add the padding
struct.push(this._makePaddingField(padding_length));
// And proceed
i += padding_length;
} else {
// We have a field at this offset.
// Firstly, ensure that we do not have two overlapping fields
for (let j = 1; j < currentField.type.size; ++j) {
let candidateField = this.offset_to_field_info[i + j];
if (candidateField) {
throw new Error("Fields " + currentField.name +
" and " + candidateField.name +
" overlap at position " + (i + j));
}
}
// Then add the field
let field = ({});
field[currentField.name] = currentField.type;
struct.push(field);
// And proceed
i += currentField.type.size;
}
}
let result = new Type(this.name, ctypes.StructType(this.name, struct));
if (result.implementation.size != this.size) {
throw new Error("Wrong size for type " + this.name +
": expected " + this.size +
", found " + result.implementation.size +
" (" + result.implementation.toSource() + ")");
}
return result;
}
};
exports.OS.Shared.HollowStructure = HollowStructure;
/**
* Declare a function through js-ctypes
*