Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validating batch table #41

Merged
merged 19 commits into from
Jul 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified tools/specs/data/TilesetOfTilesets/lr.b3dm
Binary file not shown.
Binary file modified tools/specs/data/TilesetOfTilesets/parent.b3dm
Binary file not shown.
99 changes: 94 additions & 5 deletions tools/specs/data/TilesetOfTilesets/tileset.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
{
"asset": {
"version": "0.0"
"version": "0.0",
"tilesetVersion": "1.2.3"
},
"properties": {
"id": {
"minimum": 0,
"maximum": 99
"maximum": 9
},
"Longitude": {
"minimum": -1.3197192952275933,
"maximum": -1.319644104024109
},
"Latitude": {
"minimum": 0.698848878034009,
"maximum": 0.6989046192460953
},
"Height": {
"minimum": 6.161747192963958,
"maximum": 84.83180232718587
}
},
"geometricError": 240,
Expand All @@ -23,7 +36,83 @@
"geometricError": 70,
"refine": "add",
"content": {
"url": "tileset2.json"
}
"url": "parent.b3dm",
"boundingVolume": {
"region": [
-1.3197004795898053,
0.6988582109,
-1.3196595204101946,
0.6988897891,
0,
88
]
}
},
"children": [
{
"boundingVolume": {
"region": [
-1.3197209591796106,
0.6988424218,
-1.31968,
0.698874,
0,
20
]
},
"geometricError": 0,
"content": {
"url": "ll.b3dm"
}
},
{
"boundingVolume": {
"region": [
-1.31968,
0.6988424218,
-1.3196390408203893,
0.698874,
0,
20
]
},
"geometricError": 0,
"content": {
"url": "lr.b3dm"
}
},
{
"boundingVolume": {
"region": [
-1.31968,
0.698874,
-1.3196390408203893,
0.6989055782,
0,
20
]
},
"geometricError": 0,
"content": {
"url": "ur.b3dm"
}
},
{
"boundingVolume": {
"region": [
-1.3197209591796106,
0.698874,
-1.31968,
0.6989055782,
0,
20
]
},
"geometricError": 0,
"content": {
"url": "ul.b3dm"
}
}
]
}
}
}
Binary file modified tools/specs/data/TilesetOfTilesets/ul.b3dm
Binary file not shown.
Binary file modified tools/specs/data/TilesetOfTilesets/ur.b3dm
Binary file not shown.
Binary file added tools/specs/data/TilesetofTilesets/ll.b3dm
Binary file not shown.
89 changes: 81 additions & 8 deletions validator/lib/validateB3dm.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
'use strict';
var Cesium = require('cesium');
var batchTableSchema = require('../specs/data/schema/batchTable.schema.json');
var featureTableSchema = require('../specs/data/schema/featureTable.schema.json');
var validateBatchTable = require('../lib/validateBatchTable');
var validateFeatureTable = require('../lib/validateFeatureTable');

var defined = Cesium.defined;
var DeveloperError = Cesium.DeveloperError;
Expand All @@ -19,7 +23,15 @@ function validateB3dm(content) {
}

if (!Buffer.isBuffer(content)) {
throw new DeveloperError('content must be of type buffer');
throw new DeveloperError('b3dm content must be of type buffer');
}

var headerByteLength = 28;
if (content.length < headerByteLength) {
return {
result : false,
message: 'b3dm tile header must be 28 bytes'
};
}

var magic = content.toString('utf8', 0, 4);
Expand All @@ -29,27 +41,88 @@ function validateB3dm(content) {
if (magic !== 'b3dm') {
return {
result : false,
message: 'Tile has an invalid magic'
message: 'b3dm tile has an invalid magic'
};
}

if (version !== 1) {
return {
result : false,
message: 'Tile has an invalid version'
message: 'b3dm tile has an invalid version'
};
}

if (byteLength !== content.length) {
return {
result : false,
message: 'Tile has the wrong byteLength'
message: 'b3dm tile has the wrong byteLength'
};
}

var offset = headerByteLength;
var featureTableJSONByteLength = content.readUInt32LE(12);
var featureTableBinaryByteLength = content.readUInt32LE(16);
var batchTableJSONByteLength = content.readUInt32LE(20);
var batchTableBinaryByteLength = content.readUInt32LE(24);

var featureTableJSON;

if (featureTableJSONByteLength > 0) {
featureTableJSON = content.slice(offset, offset + featureTableJSONByteLength);
offset += featureTableJSONByteLength;
var featureTableBinary = content.slice(offset, offset + featureTableBinaryByteLength);
offset += featureTableBinaryByteLength;

if ((featureTableJSON.length === featureTableJSONByteLength) && (featureTableBinary.length === featureTableBinaryByteLength)) {
featureTableJSON = JSON.parse(featureTableJSON.toString());
var validFeatureTable = validateFeatureTable(featureTableSchema, featureTableJSON, featureTableBinary);
if (!validFeatureTable.result) {
return {
result : false,
message: validFeatureTable.message
};
}
} else {
return {
result: false,
message: 'b3dm has invalid feature table lengths'
};
}
}

if (batchTableJSONByteLength > 0) {
var batchTableJSON = content.slice(offset, offset + batchTableJSONByteLength);
offset += batchTableJSONByteLength;
var batchTableBinary = content.slice(offset, offset + batchTableBinaryByteLength);

if ((batchTableJSON.length === batchTableJSONByteLength) && (batchTableBinary.length === batchTableBinaryByteLength)) {
batchTableJSON = JSON.parse(batchTableJSON.toString());

if(!defined(featureTableJSON)) {
return {
result: false,
message: 'batch table requires the BATCH_LENGTH global semantic but feature table is ' + featureTableJSON
};
}

var batchLength= featureTableJSON.BATCH_LENGTH;
var validBatchTable = validateBatchTable(batchTableSchema, batchTableJSON, batchTableBinary, batchLength);
if (!validBatchTable.result) {
return {
result: false,
message: validBatchTable.message
};
}
} else {
return {
result: false,
message: 'b3dm has invalid batch table lengths'
};
}
}

return {
result : true,
message: 'Tile is a valid b3dm tile'
result: true,
message: 'b3dm tile is a valid b3dm tile'
};

}
}
100 changes: 100 additions & 0 deletions validator/lib/validateBatchTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
'use strict';
var Ajv = require('ajv');
var Cesium = require('cesium');
var propertyComponents = require('../specs/util/propertyComponents.js');
var defined = Cesium.defined;

var componentTypeByteLength = propertyComponents.componentTypeByteLength;
var typeToNumberOfComponents = propertyComponents.typeToNumberOfComponents;

module.exports = validateBatchTable;

/**
* Checks if provided buffers follow the batch table schema
*
* @param {Object} schema - A JSON object containing the schema for the batch table.
* @param {Object} batchTableJSON - Batch table JSON
* @param {Buffer} [batchTableBinary] - A buffer containing the batch table binary
* @param {int} batchLength - The number of distinguishable models in the batch
* @returns {Object} An object with two parameters - (1) a boolean for whether the batch table follows the schema
* (2) a message to indicate the validation result
*/
function validateBatchTable(schema, batchTableJSON, batchTableBinary, batchLength) {
var ajv = new Ajv();
var validSchema = ajv.validate(schema, batchTableJSON);
var valid = validSchema;
var message;

if (!validSchema) {
return {
result: false,
message: 'batch table JSON failed schema validation'
};
}

if (batchLength < 0) {
return {
result: false,
message: 'batch table has invalid batch length of ' + batchLength
};
}

if (defined(batchTableBinary) && (batchTableBinary.length > 0)) {
var binaryBodyLength = batchTableBinary.length;
var totalOffset = 0;
for (var key in batchTableJSON) {
if (!batchTableJSON.hasOwnProperty(key)) {
continue;
}

var property = batchTableJSON[key];
if (Array.isArray(property)) {
if(property.length !== batchLength) {
valid = false;
message = 'batch table property ' + key + '\'s length expected to be ' + batchLength + ' but is ' + property.length;
break;
} else {
continue;
}
}

var byteOffset = property.byteOffset;
var componentType = property.componentType;
var numberOfComponents = property.type;

if (byteOffset < totalOffset) {
valid = false;
message = 'batch table property ' + key + ' has offset within another property\'s range at ' + byteOffset;
break;
}

if (!componentTypeByteLength.hasOwnProperty(componentType)) {
valid = false;
message = 'batch table property ' + key + ' has an invalid component type ' + componentType;
break;
}

if (!typeToNumberOfComponents.hasOwnProperty(numberOfComponents)) {
valid = false;
message = 'batch table property ' + key + ' has an invalid type ' + numberOfComponents;
}

var propertyByteLength = batchLength * componentTypeByteLength[componentType] * typeToNumberOfComponents[numberOfComponents];
if (propertyByteLength + byteOffset > binaryBodyLength) {
valid = false;
message = 'batch table property ' + key + ' is out of binary body length of ' + binaryBodyLength;
break;
}
totalOffset += propertyByteLength;
}

if (valid) {
message = 'batch table is valid';
}
}

return {
result: valid,
message: message
};
}
36 changes: 36 additions & 0 deletions validator/lib/validateFeatureTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';
var Ajv = require('ajv');
var Cesium = require('cesium');

var defined = Cesium.defined;

module.exports = validateFeatureTable;

/**
* Checks if provided buffers follow the batch table schema
*
* @param {Object} schema - A JSON object containing the schema for the feature table.
* @param {Object} featureTableJSON - Feature table JSON
* @param {Buffer} [featureTableBinary] - A buffer containing the batch table binary
* @returns {Object} An object with two parameters - (1) a boolean for whether the batch table follows the schema
* (2) a message to indicate the validation result
*/

function validateFeatureTable(schema, featureTableJSON, featureTableBinary) {
var ajv = new Ajv();
var validSchema = ajv.validate(schema, featureTableJSON);
var valid = validSchema;
var message;

if (!validSchema) {
return {
result: false,
message: 'feature table JSON failed schema validation'
};
}

return {
result: valid,
message: message
};
}
Loading