Skip to content

Commit

Permalink
loader-utils: Improved JSON parsding error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Ib Green committed Sep 23, 2019
1 parent bc5f216 commit bb4435e
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 3 deletions.
3 changes: 2 additions & 1 deletion modules/gltf/src/lib/deprecated/gltf-parser.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {TextDecoder, fetchFile} from '@loaders.gl/core';
import {parseJSON} from '@loaders.gl/loader-utils';
import {getFullUri} from '../gltf-utils/gltf-utils';
import {getGLTFAccessors, getGLTFAccessor} from '../gltf-utils/gltf-attribute-utils';
import {KHR_DRACO_MESH_COMPRESSION, UBER_POINT_CLOUD_EXTENSION} from '../gltf-constants';
Expand Down Expand Up @@ -53,7 +54,7 @@ export default class GLTFParser {

// If string, try to parse as JSON
if (typeof gltf === 'string') {
gltf = JSON.parse(gltf);
gltf = parseJSON(gltf);
}

if (gltf instanceof ArrayBuffer) {
Expand Down
3 changes: 2 additions & 1 deletion modules/gltf/src/lib/parse-gltf.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable camelcase, max-statements, no-restricted-globals */
/* global TextDecoder */
import {parseJSON} from '@loaders.gl/loader-utils';
import assert from './utils/assert';
import {getFullUri} from './gltf-utils/gltf-utils';
import {decodeExtensions, decodeExtensionsSync} from './extensions/gltf-extensions';
Expand Down Expand Up @@ -73,7 +74,7 @@ function parseGLTFContainerSync(gltf, data, byteOffset, options) {

if (typeof data === 'string') {
// If string, try to parse as JSON
gltf.json = JSON.parse(data);
gltf.json = parseJSON(data);
} else if (data instanceof ArrayBuffer) {
// If still ArrayBuffer, parse as GLB container
gltf._glb = {};
Expand Down
11 changes: 10 additions & 1 deletion modules/loader-utils/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,23 @@
export {default as createWorker} from './worker-utils/create-worker';

// MEMORY COPY UTILS
export {padTo4Bytes, copyToArray, copyArrayBuffer} from './lib/memory-copy-utils';
export {
padTo4Bytes,
copyToArray,
copyArrayBuffer,
getZeroOffsetArrayBuffer
} from './lib/memory-copy-utils';
export {copyPaddedArrayBufferToDataView, copyPaddedStringToDataView} from './lib/binary-copy-utils';
export {
padStringToByteAlignment,
copyStringToDataView,
copyBinaryToDataView
} from './lib/encode-utils';

export {getFirstCharacters, getMagicString} from './lib/get-first-characters';

export {parseJSON} from './lib/parse-json';

// MESH CATEGORY UTILS
export {getMeshSize as _getMeshSize} from './categories/mesh/mesh-utils';

Expand Down
24 changes: 24 additions & 0 deletions modules/loader-utils/src/lib/get-first-characters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export function getFirstCharacters(data, length = 5) {
if (typeof data === 'string') {
return data.slice(0, length);
} else if (ArrayBuffer.isView(data)) {
// Typed Arrays can have offsets into underlying buffer
return getMagicString(data.buffer, data.byteOffset, length);
} else if (data instanceof ArrayBuffer) {
const byteOffset = 0;
return getMagicString(data, byteOffset, length);
}
return '';
}

export function getMagicString(arrayBuffer, byteOffset, length) {
if (arrayBuffer.byteLength <= byteOffset + length) {
return '';
}
const dataView = new DataView(arrayBuffer);
let magic = '';
for (let i = 0; i < length; i++) {
magic += String.fromCharCode(dataView.getUint8(byteOffset + i));
}
return magic;
}
9 changes: 9 additions & 0 deletions modules/loader-utils/src/lib/memory-copy-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ export function padTo4Bytes(byteLength) {
return (byteLength + 3) & ~3;
}

// Copy a view of an ArrayBuffer into new ArrayBuffer with byteOffset = 0
export function getZeroOffsetArrayBuffer(arrayBuffer, byteOffset, byteLength) {
const subArray = byteLength
? new Uint8Array(arrayBuffer).subarray(byteOffset, byteOffset + byteLength)
: new Uint8Array(arrayBuffer).subarray(byteOffset);
const arrayCopy = new Uint8Array(subArray);
return arrayCopy.buffer;
}

/* Creates a new Uint8Array based on two different ArrayBuffers
* @private
* @param {ArrayBuffers} buffer1 The first buffer.
Expand Down
10 changes: 10 additions & 0 deletions modules/loader-utils/src/lib/parse-json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {getFirstCharacters} from './get-first-characters';

// Minimal JSON parser with a meaningful error message
export function parseJSON(string) {
try {
return JSON.parse(string);
} catch (_) {
throw new Error(`Failed to parse JSON from data starting with "${getFirstCharacters(string)}"`);
}
}

0 comments on commit bb4435e

Please sign in to comment.