diff --git a/lib/loadObj.js b/lib/loadObj.js index c46b13b..e893ab5 100644 --- a/lib/loadObj.js +++ b/lib/loadObj.js @@ -196,6 +196,9 @@ function loadObj(objPath, options) { function createVertex(p, u, n) { // Positions if (defined(p) && (globalPositions.length > 0)) { + if (p * 3 >= globalPositions.length) { + throw new RuntimeError(`Position index ${p} is out of bounds`); + } const px = globalPositions.get(p * 3); const py = globalPositions.get(p * 3 + 1); const pz = globalPositions.get(p * 3 + 2); @@ -206,6 +209,9 @@ function loadObj(objPath, options) { // Normals if (defined(n) && (globalNormals.length > 0)) { + if (n * 3 >= globalNormals.length) { + throw new RuntimeError(`Normal index ${n} is out of bounds`); + } const nx = globalNormals.get(n * 3); const ny = globalNormals.get(n * 3 + 1); const nz = globalNormals.get(n * 3 + 2); @@ -216,6 +222,9 @@ function loadObj(objPath, options) { // UVs if (defined(u) && (globalUvs.length > 0)) { + if (u * 2 >= globalUvs.length) { + throw new RuntimeError(`UV index ${u} is out of bounds`); + } const ux = globalUvs.get(u * 2); const uy = globalUvs.get(u * 2 + 1); primitive.uvs.push(ux); diff --git a/lib/readLines.js b/lib/readLines.js index d4a4c1b..e740ef1 100644 --- a/lib/readLines.js +++ b/lib/readLines.js @@ -23,6 +23,15 @@ function readLines(path, callback) { const lineReader = readline.createInterface({ input : stream }); - lineReader.on('line', callback); + + const callbackWrapper = function(line) { + try { + callback(line); + } catch (error) { + reject(error); + } + }; + + lineReader.on('line', callbackWrapper); }); } diff --git a/specs/data/box-incomplete-attributes/box-incomplete-normals.obj b/specs/data/box-incomplete-attributes/box-incomplete-normals.obj new file mode 100644 index 0000000..328214c --- /dev/null +++ b/specs/data/box-incomplete-attributes/box-incomplete-normals.obj @@ -0,0 +1,36 @@ +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 0.0000 +vt 0.0000 1.0000 +vn 0.000000 0.000000 1.000000 +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/5/2 4/6/2 8/7/2 7/8/2 +f 7/9/3 8/10/3 6/11/3 5/12/3 +f 5/13/4 6/14/4 2/15/4 1/16/4 +f 3/5/5 7/17/5 5/18/5 1/16/5 +f 8/19/6 4/6/6 2/15/6 6/20/6 diff --git a/specs/data/box-incomplete-attributes/box-incomplete-positions.obj b/specs/data/box-incomplete-attributes/box-incomplete-positions.obj new file mode 100644 index 0000000..789bb2d --- /dev/null +++ b/specs/data/box-incomplete-attributes/box-incomplete-positions.obj @@ -0,0 +1,34 @@ +o Cube +v -1.000000 -1.000000 1.000000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 0.0000 +vt 0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/5/2 4/6/2 8/7/2 7/8/2 +f 7/9/3 8/10/3 6/11/3 5/12/3 +f 5/13/4 6/14/4 2/15/4 1/16/4 +f 3/5/5 7/17/5 5/18/5 1/16/5 +f 8/19/6 4/6/6 2/15/6 6/20/6 diff --git a/specs/data/box-incomplete-attributes/box-incomplete-uvs.obj b/specs/data/box-incomplete-attributes/box-incomplete-uvs.obj new file mode 100644 index 0000000..fb87835 --- /dev/null +++ b/specs/data/box-incomplete-attributes/box-incomplete-uvs.obj @@ -0,0 +1,22 @@ +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +vt 0.0000 0.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/5/2 4/6/2 8/7/2 7/8/2 +f 7/9/3 8/10/3 6/11/3 5/12/3 +f 5/13/4 6/14/4 2/15/4 1/16/4 +f 3/5/5 7/17/5 5/18/5 1/16/5 +f 8/19/6 4/6/6 2/15/6 6/20/6 diff --git a/specs/lib/loadObjSpec.js b/specs/lib/loadObjSpec.js index a51611e..deef264 100644 --- a/specs/lib/loadObjSpec.js +++ b/specs/lib/loadObjSpec.js @@ -42,6 +42,9 @@ const objConcavePath = 'specs/data/concave/concave.obj'; const objUnnormalizedPath = 'specs/data/box-unnormalized/box-unnormalized.obj'; const objMixedAttributesPath = 'specs/data/box-mixed-attributes/box-mixed-attributes.obj'; const objMissingAttributesPath = 'specs/data/box-missing-attributes/box-missing-attributes.obj'; +const objIncompletePositionsPath = 'specs/data/box-incomplete-attributes/box-incomplete-positions.obj' +const objIncompleteNormalsPath = 'specs/data/box-incomplete-attributes/box-incomplete-normals.obj' +const objIncompleteUvsPath = 'specs/data/box-incomplete-attributes/box-incomplete-uvs.obj' const objInvalidPath = 'invalid.obj'; function getMeshes(data) { @@ -505,6 +508,36 @@ describe('loadObj', () => { expect(primitive.uvs.length).toBe(0); }); + it('throws when position index is out of bounds', async () => { + let thrownError; + try { + await loadObj(objIncompletePositionsPath, options); + } catch (e) { + thrownError = e; + } + expect(thrownError).toEqual(new RuntimeError('Position index 1 is out of bounds')); + }); + + it('throws when normal index is out of bounds', async () => { + let thrownError; + try { + await loadObj(objIncompleteNormalsPath, options); + } catch (e) { + thrownError = e; + } + expect(thrownError).toEqual(new RuntimeError('Normal index 1 is out of bounds')); + }); + + it('throws when uv index is out of bounds', async () => { + let thrownError; + try { + await loadObj(objIncompleteUvsPath, options); + } catch (e) { + thrownError = e; + } + expect(thrownError).toEqual(new RuntimeError('UV index 1 is out of bounds')); + }); + it('throws when file has invalid contents', async () => { let thrownError; try {