679 lines
24 KiB
JavaScript
679 lines
24 KiB
JavaScript
// Copyright 2014 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
(function() {
|
|
var internal = mojo.internal;
|
|
|
|
var validationError = {
|
|
NONE: 'VALIDATION_ERROR_NONE',
|
|
MISALIGNED_OBJECT: 'VALIDATION_ERROR_MISALIGNED_OBJECT',
|
|
ILLEGAL_MEMORY_RANGE: 'VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE',
|
|
UNEXPECTED_STRUCT_HEADER: 'VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER',
|
|
UNEXPECTED_ARRAY_HEADER: 'VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER',
|
|
ILLEGAL_HANDLE: 'VALIDATION_ERROR_ILLEGAL_HANDLE',
|
|
UNEXPECTED_INVALID_HANDLE: 'VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE',
|
|
ILLEGAL_POINTER: 'VALIDATION_ERROR_ILLEGAL_POINTER',
|
|
UNEXPECTED_NULL_POINTER: 'VALIDATION_ERROR_UNEXPECTED_NULL_POINTER',
|
|
ILLEGAL_INTERFACE_ID: 'VALIDATION_ERROR_ILLEGAL_INTERFACE_ID',
|
|
UNEXPECTED_INVALID_INTERFACE_ID:
|
|
'VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID',
|
|
MESSAGE_HEADER_INVALID_FLAGS:
|
|
'VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS',
|
|
MESSAGE_HEADER_MISSING_REQUEST_ID:
|
|
'VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID',
|
|
DIFFERENT_SIZED_ARRAYS_IN_MAP:
|
|
'VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP',
|
|
INVALID_UNION_SIZE: 'VALIDATION_ERROR_INVALID_UNION_SIZE',
|
|
UNEXPECTED_NULL_UNION: 'VALIDATION_ERROR_UNEXPECTED_NULL_UNION',
|
|
UNKNOWN_ENUM_VALUE: 'VALIDATION_ERROR_UNKNOWN_ENUM_VALUE',
|
|
};
|
|
|
|
var NULL_MOJO_POINTER = "NULL_MOJO_POINTER";
|
|
var gValidationErrorObserver = null;
|
|
|
|
function reportValidationError(error) {
|
|
if (gValidationErrorObserver) {
|
|
gValidationErrorObserver.lastError = error;
|
|
} else {
|
|
console.warn('Invalid message: ' + error);
|
|
}
|
|
}
|
|
|
|
var ValidationErrorObserverForTesting = (function() {
|
|
function Observer() {
|
|
this.lastError = validationError.NONE;
|
|
}
|
|
|
|
Observer.prototype.reset = function() {
|
|
this.lastError = validationError.NONE;
|
|
};
|
|
|
|
return {
|
|
getInstance: function() {
|
|
if (!gValidationErrorObserver) {
|
|
gValidationErrorObserver = new Observer();
|
|
}
|
|
return gValidationErrorObserver;
|
|
}
|
|
};
|
|
})();
|
|
|
|
function isTestingMode() {
|
|
return Boolean(gValidationErrorObserver);
|
|
}
|
|
|
|
function clearTestingMode() {
|
|
gValidationErrorObserver = null;
|
|
}
|
|
|
|
function isEnumClass(cls) {
|
|
return cls instanceof internal.Enum;
|
|
}
|
|
|
|
function isStringClass(cls) {
|
|
return cls === internal.String || cls === internal.NullableString;
|
|
}
|
|
|
|
function isHandleClass(cls) {
|
|
return cls === internal.Handle || cls === internal.NullableHandle;
|
|
}
|
|
|
|
function isInterfaceClass(cls) {
|
|
return cls instanceof internal.Interface;
|
|
}
|
|
|
|
function isInterfaceRequestClass(cls) {
|
|
return cls === internal.InterfaceRequest ||
|
|
cls === internal.NullableInterfaceRequest;
|
|
}
|
|
|
|
function isAssociatedInterfaceClass(cls) {
|
|
return cls === internal.AssociatedInterfacePtrInfo ||
|
|
cls === internal.NullableAssociatedInterfacePtrInfo;
|
|
}
|
|
|
|
function isAssociatedInterfaceRequestClass(cls) {
|
|
return cls === internal.AssociatedInterfaceRequest ||
|
|
cls === internal.NullableAssociatedInterfaceRequest;
|
|
}
|
|
|
|
function isNullable(type) {
|
|
return type === internal.NullableString ||
|
|
type === internal.NullableHandle ||
|
|
type === internal.NullableAssociatedInterfacePtrInfo ||
|
|
type === internal.NullableAssociatedInterfaceRequest ||
|
|
type === internal.NullableInterface ||
|
|
type === internal.NullableInterfaceRequest ||
|
|
type instanceof internal.NullableArrayOf ||
|
|
type instanceof internal.NullablePointerTo;
|
|
}
|
|
|
|
function Validator(message) {
|
|
this.message = message;
|
|
this.offset = 0;
|
|
this.handleIndex = 0;
|
|
this.associatedEndpointHandleIndex = 0;
|
|
this.payloadInterfaceIds = null;
|
|
this.offsetLimit = this.message.buffer.byteLength;
|
|
}
|
|
|
|
Object.defineProperty(Validator.prototype, "handleIndexLimit", {
|
|
get: function() { return this.message.handles.length; }
|
|
});
|
|
|
|
Object.defineProperty(Validator.prototype, "associatedHandleIndexLimit", {
|
|
get: function() {
|
|
return this.payloadInterfaceIds ? this.payloadInterfaceIds.length : 0;
|
|
}
|
|
});
|
|
|
|
// True if we can safely allocate a block of bytes from start to
|
|
// to start + numBytes.
|
|
Validator.prototype.isValidRange = function(start, numBytes) {
|
|
// Only positive JavaScript integers that are less than 2^53
|
|
// (Number.MAX_SAFE_INTEGER) can be represented exactly.
|
|
if (start < this.offset || numBytes <= 0 ||
|
|
!Number.isSafeInteger(start) ||
|
|
!Number.isSafeInteger(numBytes))
|
|
return false;
|
|
|
|
var newOffset = start + numBytes;
|
|
if (!Number.isSafeInteger(newOffset) || newOffset > this.offsetLimit)
|
|
return false;
|
|
|
|
return true;
|
|
};
|
|
|
|
Validator.prototype.claimRange = function(start, numBytes) {
|
|
if (this.isValidRange(start, numBytes)) {
|
|
this.offset = start + numBytes;
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
Validator.prototype.claimHandle = function(index) {
|
|
if (index === internal.kEncodedInvalidHandleValue)
|
|
return true;
|
|
|
|
if (index < this.handleIndex || index >= this.handleIndexLimit)
|
|
return false;
|
|
|
|
// This is safe because handle indices are uint32.
|
|
this.handleIndex = index + 1;
|
|
return true;
|
|
};
|
|
|
|
Validator.prototype.claimAssociatedEndpointHandle = function(index) {
|
|
if (index === internal.kEncodedInvalidHandleValue) {
|
|
return true;
|
|
}
|
|
|
|
if (index < this.associatedEndpointHandleIndex ||
|
|
index >= this.associatedHandleIndexLimit) {
|
|
return false;
|
|
}
|
|
|
|
// This is safe because handle indices are uint32.
|
|
this.associatedEndpointHandleIndex = index + 1;
|
|
return true;
|
|
};
|
|
|
|
Validator.prototype.validateEnum = function(offset, enumClass) {
|
|
// Note: Assumes that enums are always 32 bits! But this matches
|
|
// mojom::generate::pack::PackedField::GetSizeForKind, so it should be okay.
|
|
var value = this.message.buffer.getInt32(offset);
|
|
return enumClass.validate(value);
|
|
}
|
|
|
|
Validator.prototype.validateHandle = function(offset, nullable) {
|
|
var index = this.message.buffer.getUint32(offset);
|
|
|
|
if (index === internal.kEncodedInvalidHandleValue)
|
|
return nullable ?
|
|
validationError.NONE : validationError.UNEXPECTED_INVALID_HANDLE;
|
|
|
|
if (!this.claimHandle(index))
|
|
return validationError.ILLEGAL_HANDLE;
|
|
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateAssociatedEndpointHandle = function(offset,
|
|
nullable) {
|
|
var index = this.message.buffer.getUint32(offset);
|
|
|
|
if (index === internal.kEncodedInvalidHandleValue) {
|
|
return nullable ? validationError.NONE :
|
|
validationError.UNEXPECTED_INVALID_INTERFACE_ID;
|
|
}
|
|
|
|
if (!this.claimAssociatedEndpointHandle(index)) {
|
|
return validationError.ILLEGAL_INTERFACE_ID;
|
|
}
|
|
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateInterface = function(offset, nullable) {
|
|
return this.validateHandle(offset, nullable);
|
|
};
|
|
|
|
Validator.prototype.validateInterfaceRequest = function(offset, nullable) {
|
|
return this.validateHandle(offset, nullable);
|
|
};
|
|
|
|
Validator.prototype.validateAssociatedInterface = function(offset,
|
|
nullable) {
|
|
return this.validateAssociatedEndpointHandle(offset, nullable);
|
|
};
|
|
|
|
Validator.prototype.validateAssociatedInterfaceRequest = function(
|
|
offset, nullable) {
|
|
return this.validateAssociatedEndpointHandle(offset, nullable);
|
|
};
|
|
|
|
Validator.prototype.validateStructHeader = function(offset, minNumBytes) {
|
|
if (!internal.isAligned(offset))
|
|
return validationError.MISALIGNED_OBJECT;
|
|
|
|
if (!this.isValidRange(offset, internal.kStructHeaderSize))
|
|
return validationError.ILLEGAL_MEMORY_RANGE;
|
|
|
|
var numBytes = this.message.buffer.getUint32(offset);
|
|
|
|
if (numBytes < minNumBytes)
|
|
return validationError.UNEXPECTED_STRUCT_HEADER;
|
|
|
|
if (!this.claimRange(offset, numBytes))
|
|
return validationError.ILLEGAL_MEMORY_RANGE;
|
|
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateStructVersion = function(offset, versionSizes) {
|
|
var numBytes = this.message.buffer.getUint32(offset);
|
|
var version = this.message.buffer.getUint32(offset + 4);
|
|
|
|
if (version <= versionSizes[versionSizes.length - 1].version) {
|
|
// Scan in reverse order to optimize for more recent versionSizes.
|
|
for (var i = versionSizes.length - 1; i >= 0; --i) {
|
|
if (version >= versionSizes[i].version) {
|
|
if (numBytes == versionSizes[i].numBytes)
|
|
break;
|
|
return validationError.UNEXPECTED_STRUCT_HEADER;
|
|
}
|
|
}
|
|
} else if (numBytes < versionSizes[versionSizes.length-1].numBytes) {
|
|
return validationError.UNEXPECTED_STRUCT_HEADER;
|
|
}
|
|
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.isFieldInStructVersion = function(offset, fieldVersion) {
|
|
var structVersion = this.message.buffer.getUint32(offset + 4);
|
|
return fieldVersion <= structVersion;
|
|
};
|
|
|
|
Validator.prototype.validateMessageHeader = function() {
|
|
var err = this.validateStructHeader(0, internal.kMessageV0HeaderSize);
|
|
if (err != validationError.NONE) {
|
|
return err;
|
|
}
|
|
|
|
var numBytes = this.message.getHeaderNumBytes();
|
|
var version = this.message.getHeaderVersion();
|
|
|
|
var validVersionAndNumBytes =
|
|
(version == 0 && numBytes == internal.kMessageV0HeaderSize) ||
|
|
(version == 1 && numBytes == internal.kMessageV1HeaderSize) ||
|
|
(version == 2 && numBytes == internal.kMessageV2HeaderSize) ||
|
|
(version > 2 && numBytes >= internal.kMessageV2HeaderSize);
|
|
|
|
if (!validVersionAndNumBytes) {
|
|
return validationError.UNEXPECTED_STRUCT_HEADER;
|
|
}
|
|
|
|
var expectsResponse = this.message.expectsResponse();
|
|
var isResponse = this.message.isResponse();
|
|
|
|
if (version == 0 && (expectsResponse || isResponse)) {
|
|
return validationError.MESSAGE_HEADER_MISSING_REQUEST_ID;
|
|
}
|
|
|
|
if (isResponse && expectsResponse) {
|
|
return validationError.MESSAGE_HEADER_INVALID_FLAGS;
|
|
}
|
|
|
|
if (version < 2) {
|
|
return validationError.NONE;
|
|
}
|
|
|
|
var err = this.validateArrayPointer(
|
|
internal.kMessagePayloadInterfaceIdsPointerOffset,
|
|
internal.Uint32.encodedSize, internal.Uint32, true, [0], 0);
|
|
|
|
if (err != validationError.NONE) {
|
|
return err;
|
|
}
|
|
|
|
this.payloadInterfaceIds = this.message.getPayloadInterfaceIds();
|
|
if (this.payloadInterfaceIds) {
|
|
for (var interfaceId of this.payloadInterfaceIds) {
|
|
if (!internal.isValidInterfaceId(interfaceId) ||
|
|
internal.isMasterInterfaceId(interfaceId)) {
|
|
return validationError.ILLEGAL_INTERFACE_ID;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set offset to the start of the payload and offsetLimit to the start of
|
|
// the payload interface Ids so that payload can be validated using the
|
|
// same messageValidator.
|
|
this.offset = this.message.getHeaderNumBytes();
|
|
this.offsetLimit = this.decodePointer(
|
|
internal.kMessagePayloadInterfaceIdsPointerOffset);
|
|
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateMessageIsRequestWithoutResponse = function() {
|
|
if (this.message.isResponse() || this.message.expectsResponse()) {
|
|
return validationError.MESSAGE_HEADER_INVALID_FLAGS;
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateMessageIsRequestExpectingResponse = function() {
|
|
if (this.message.isResponse() || !this.message.expectsResponse()) {
|
|
return validationError.MESSAGE_HEADER_INVALID_FLAGS;
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateMessageIsResponse = function() {
|
|
if (this.message.expectsResponse() || !this.message.isResponse()) {
|
|
return validationError.MESSAGE_HEADER_INVALID_FLAGS;
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
// Returns the message.buffer relative offset this pointer "points to",
|
|
// NULL_MOJO_POINTER if the pointer represents a null, or JS null if the
|
|
// pointer's value is not valid.
|
|
Validator.prototype.decodePointer = function(offset) {
|
|
var pointerValue = this.message.buffer.getUint64(offset);
|
|
if (pointerValue === 0)
|
|
return NULL_MOJO_POINTER;
|
|
var bufferOffset = offset + pointerValue;
|
|
return Number.isSafeInteger(bufferOffset) ? bufferOffset : null;
|
|
};
|
|
|
|
Validator.prototype.decodeUnionSize = function(offset) {
|
|
return this.message.buffer.getUint32(offset);
|
|
};
|
|
|
|
Validator.prototype.decodeUnionTag = function(offset) {
|
|
return this.message.buffer.getUint32(offset + 4);
|
|
};
|
|
|
|
Validator.prototype.validateArrayPointer = function(
|
|
offset, elementSize, elementType, nullable, expectedDimensionSizes,
|
|
currentDimension) {
|
|
var arrayOffset = this.decodePointer(offset);
|
|
if (arrayOffset === null)
|
|
return validationError.ILLEGAL_POINTER;
|
|
|
|
if (arrayOffset === NULL_MOJO_POINTER)
|
|
return nullable ?
|
|
validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
|
|
|
|
return this.validateArray(arrayOffset, elementSize, elementType,
|
|
expectedDimensionSizes, currentDimension);
|
|
};
|
|
|
|
Validator.prototype.validateStructPointer = function(
|
|
offset, structClass, nullable) {
|
|
var structOffset = this.decodePointer(offset);
|
|
if (structOffset === null)
|
|
return validationError.ILLEGAL_POINTER;
|
|
|
|
if (structOffset === NULL_MOJO_POINTER)
|
|
return nullable ?
|
|
validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
|
|
|
|
return structClass.validate(this, structOffset);
|
|
};
|
|
|
|
Validator.prototype.validateUnion = function(
|
|
offset, unionClass, nullable) {
|
|
var size = this.message.buffer.getUint32(offset);
|
|
if (size == 0) {
|
|
return nullable ?
|
|
validationError.NONE : validationError.UNEXPECTED_NULL_UNION;
|
|
}
|
|
|
|
return unionClass.validate(this, offset);
|
|
};
|
|
|
|
Validator.prototype.validateNestedUnion = function(
|
|
offset, unionClass, nullable) {
|
|
var unionOffset = this.decodePointer(offset);
|
|
if (unionOffset === null)
|
|
return validationError.ILLEGAL_POINTER;
|
|
|
|
if (unionOffset === NULL_MOJO_POINTER)
|
|
return nullable ?
|
|
validationError.NONE : validationError.UNEXPECTED_NULL_UNION;
|
|
|
|
return this.validateUnion(unionOffset, unionClass, nullable);
|
|
};
|
|
|
|
// This method assumes that the array at arrayPointerOffset has
|
|
// been validated.
|
|
|
|
Validator.prototype.arrayLength = function(arrayPointerOffset) {
|
|
var arrayOffset = this.decodePointer(arrayPointerOffset);
|
|
return this.message.buffer.getUint32(arrayOffset + 4);
|
|
};
|
|
|
|
Validator.prototype.validateMapPointer = function(
|
|
offset, mapIsNullable, keyClass, valueClass, valueIsNullable) {
|
|
// Validate the implicit map struct:
|
|
// struct {array<keyClass> keys; array<valueClass> values};
|
|
var structOffset = this.decodePointer(offset);
|
|
if (structOffset === null)
|
|
return validationError.ILLEGAL_POINTER;
|
|
|
|
if (structOffset === NULL_MOJO_POINTER)
|
|
return mapIsNullable ?
|
|
validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
|
|
|
|
var mapEncodedSize = internal.kStructHeaderSize +
|
|
internal.kMapStructPayloadSize;
|
|
var err = this.validateStructHeader(structOffset, mapEncodedSize);
|
|
if (err !== validationError.NONE)
|
|
return err;
|
|
|
|
// Validate the keys array.
|
|
var keysArrayPointerOffset = structOffset + internal.kStructHeaderSize;
|
|
err = this.validateArrayPointer(
|
|
keysArrayPointerOffset, keyClass.encodedSize, keyClass, false, [0], 0);
|
|
if (err !== validationError.NONE)
|
|
return err;
|
|
|
|
// Validate the values array.
|
|
var valuesArrayPointerOffset = keysArrayPointerOffset + 8;
|
|
var valuesArrayDimensions = [0]; // Validate the actual length below.
|
|
if (valueClass instanceof internal.ArrayOf)
|
|
valuesArrayDimensions =
|
|
valuesArrayDimensions.concat(valueClass.dimensions());
|
|
var err = this.validateArrayPointer(valuesArrayPointerOffset,
|
|
valueClass.encodedSize,
|
|
valueClass,
|
|
valueIsNullable,
|
|
valuesArrayDimensions,
|
|
0);
|
|
if (err !== validationError.NONE)
|
|
return err;
|
|
|
|
// Validate the lengths of the keys and values arrays.
|
|
var keysArrayLength = this.arrayLength(keysArrayPointerOffset);
|
|
var valuesArrayLength = this.arrayLength(valuesArrayPointerOffset);
|
|
if (keysArrayLength != valuesArrayLength)
|
|
return validationError.DIFFERENT_SIZED_ARRAYS_IN_MAP;
|
|
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateStringPointer = function(offset, nullable) {
|
|
return this.validateArrayPointer(
|
|
offset, internal.Uint8.encodedSize, internal.Uint8, nullable, [0], 0);
|
|
};
|
|
|
|
// Similar to Array_Data<T>::Validate()
|
|
// mojo/public/cpp/bindings/lib/array_internal.h
|
|
|
|
Validator.prototype.validateArray =
|
|
function (offset, elementSize, elementType, expectedDimensionSizes,
|
|
currentDimension) {
|
|
if (!internal.isAligned(offset))
|
|
return validationError.MISALIGNED_OBJECT;
|
|
|
|
if (!this.isValidRange(offset, internal.kArrayHeaderSize))
|
|
return validationError.ILLEGAL_MEMORY_RANGE;
|
|
|
|
var numBytes = this.message.buffer.getUint32(offset);
|
|
var numElements = this.message.buffer.getUint32(offset + 4);
|
|
|
|
// Note: this computation is "safe" because elementSize <= 8 and
|
|
// numElements is a uint32.
|
|
var elementsTotalSize = (elementType === internal.PackedBool) ?
|
|
Math.ceil(numElements / 8) : (elementSize * numElements);
|
|
|
|
if (numBytes < internal.kArrayHeaderSize + elementsTotalSize)
|
|
return validationError.UNEXPECTED_ARRAY_HEADER;
|
|
|
|
if (expectedDimensionSizes[currentDimension] != 0 &&
|
|
numElements != expectedDimensionSizes[currentDimension]) {
|
|
return validationError.UNEXPECTED_ARRAY_HEADER;
|
|
}
|
|
|
|
if (!this.claimRange(offset, numBytes))
|
|
return validationError.ILLEGAL_MEMORY_RANGE;
|
|
|
|
// Validate the array's elements if they are pointers or handles.
|
|
|
|
var elementsOffset = offset + internal.kArrayHeaderSize;
|
|
var nullable = isNullable(elementType);
|
|
|
|
if (isHandleClass(elementType))
|
|
return this.validateHandleElements(elementsOffset, numElements, nullable);
|
|
if (isInterfaceClass(elementType))
|
|
return this.validateInterfaceElements(
|
|
elementsOffset, numElements, nullable);
|
|
if (isInterfaceRequestClass(elementType))
|
|
return this.validateInterfaceRequestElements(
|
|
elementsOffset, numElements, nullable);
|
|
if (isAssociatedInterfaceClass(elementType))
|
|
return this.validateAssociatedInterfaceElements(
|
|
elementsOffset, numElements, nullable);
|
|
if (isAssociatedInterfaceRequestClass(elementType))
|
|
return this.validateAssociatedInterfaceRequestElements(
|
|
elementsOffset, numElements, nullable);
|
|
if (isStringClass(elementType))
|
|
return this.validateArrayElements(
|
|
elementsOffset, numElements, internal.Uint8, nullable, [0], 0);
|
|
if (elementType instanceof internal.PointerTo)
|
|
return this.validateStructElements(
|
|
elementsOffset, numElements, elementType.cls, nullable);
|
|
if (elementType instanceof internal.ArrayOf)
|
|
return this.validateArrayElements(
|
|
elementsOffset, numElements, elementType.cls, nullable,
|
|
expectedDimensionSizes, currentDimension + 1);
|
|
if (isEnumClass(elementType))
|
|
return this.validateEnumElements(elementsOffset, numElements,
|
|
elementType.cls);
|
|
|
|
return validationError.NONE;
|
|
};
|
|
|
|
// Note: the |offset + i * elementSize| computation in the validateFooElements
|
|
// methods below is "safe" because elementSize <= 8, offset and
|
|
// numElements are uint32, and 0 <= i < numElements.
|
|
|
|
Validator.prototype.validateHandleElements =
|
|
function(offset, numElements, nullable) {
|
|
var elementSize = internal.Handle.encodedSize;
|
|
for (var i = 0; i < numElements; i++) {
|
|
var elementOffset = offset + i * elementSize;
|
|
var err = this.validateHandle(elementOffset, nullable);
|
|
if (err != validationError.NONE)
|
|
return err;
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateInterfaceElements =
|
|
function(offset, numElements, nullable) {
|
|
var elementSize = internal.Interface.prototype.encodedSize;
|
|
for (var i = 0; i < numElements; i++) {
|
|
var elementOffset = offset + i * elementSize;
|
|
var err = this.validateInterface(elementOffset, nullable);
|
|
if (err != validationError.NONE)
|
|
return err;
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateInterfaceRequestElements =
|
|
function(offset, numElements, nullable) {
|
|
var elementSize = internal.InterfaceRequest.encodedSize;
|
|
for (var i = 0; i < numElements; i++) {
|
|
var elementOffset = offset + i * elementSize;
|
|
var err = this.validateInterfaceRequest(elementOffset, nullable);
|
|
if (err != validationError.NONE)
|
|
return err;
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateAssociatedInterfaceElements =
|
|
function(offset, numElements, nullable) {
|
|
var elementSize = internal.AssociatedInterfacePtrInfo.prototype.encodedSize;
|
|
for (var i = 0; i < numElements; i++) {
|
|
var elementOffset = offset + i * elementSize;
|
|
var err = this.validateAssociatedInterface(elementOffset, nullable);
|
|
if (err != validationError.NONE) {
|
|
return err;
|
|
}
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateAssociatedInterfaceRequestElements =
|
|
function(offset, numElements, nullable) {
|
|
var elementSize = internal.AssociatedInterfaceRequest.encodedSize;
|
|
for (var i = 0; i < numElements; i++) {
|
|
var elementOffset = offset + i * elementSize;
|
|
var err = this.validateAssociatedInterfaceRequest(elementOffset,
|
|
nullable);
|
|
if (err != validationError.NONE) {
|
|
return err;
|
|
}
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
// The elementClass parameter is the element type of the element arrays.
|
|
Validator.prototype.validateArrayElements =
|
|
function(offset, numElements, elementClass, nullable,
|
|
expectedDimensionSizes, currentDimension) {
|
|
var elementSize = internal.PointerTo.prototype.encodedSize;
|
|
for (var i = 0; i < numElements; i++) {
|
|
var elementOffset = offset + i * elementSize;
|
|
var err = this.validateArrayPointer(
|
|
elementOffset, elementClass.encodedSize, elementClass, nullable,
|
|
expectedDimensionSizes, currentDimension);
|
|
if (err != validationError.NONE)
|
|
return err;
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateStructElements =
|
|
function(offset, numElements, structClass, nullable) {
|
|
var elementSize = internal.PointerTo.prototype.encodedSize;
|
|
for (var i = 0; i < numElements; i++) {
|
|
var elementOffset = offset + i * elementSize;
|
|
var err =
|
|
this.validateStructPointer(elementOffset, structClass, nullable);
|
|
if (err != validationError.NONE)
|
|
return err;
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
Validator.prototype.validateEnumElements =
|
|
function(offset, numElements, enumClass) {
|
|
var elementSize = internal.Enum.prototype.encodedSize;
|
|
for (var i = 0; i < numElements; i++) {
|
|
var elementOffset = offset + i * elementSize;
|
|
var err = this.validateEnum(elementOffset, enumClass);
|
|
if (err != validationError.NONE)
|
|
return err;
|
|
}
|
|
return validationError.NONE;
|
|
};
|
|
|
|
internal.validationError = validationError;
|
|
internal.Validator = Validator;
|
|
internal.ValidationErrorObserverForTesting =
|
|
ValidationErrorObserverForTesting;
|
|
internal.reportValidationError = reportValidationError;
|
|
internal.isTestingMode = isTestingMode;
|
|
internal.clearTestingMode = clearTestingMode;
|
|
})();
|