@amazon-dax-sdk/client-dax
Version:
Amazon DAX Client for JavaScript
268 lines (230 loc) • 6.14 kB
JavaScript
/*
* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
* use this file except in compliance with the License. A copy of the License
* is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
'use strict';
const CborTypes = require('./CborTypes');
const SHIFT32 = Math.pow(2, 32);
const {NeedMoreData} = require('./CborDecoder');
/** Skip over CBOR while validating structure.
*
* This will check if the CBOR in a buffer is correct and complete by reading each CBOR token
* and advancing the appropriate number of bytes.
*
* @returns the number of complete items skipped over, or `null` if the end of the skipped
* region occurs in the middle of a CBOR value
*/
exports.skipCbor = function skipCbor(data, start, end) {
try {
return SKIPPER.reset(data, start, end).skip();
} catch(e) {
if(e instanceof NeedMoreData) {
return null;
} else {
throw e;
}
}
};
class CborSkipper {
reset(data, start, end) {
this.buffer = data;
this.offset = start || 0;
this.end = end === undefined ? data.length : end;
return this;
}
/**
* Skips over as many CBOR values as possible, until the end is reached.
*
* @returns the number of complete items skipped over
* @throws NeedMoreData if the end of the skipped region occurs in the middle of a CBOR value
*/
skip() {
let count = 0;
while(this.offset < this.end) {
let t = this.nextType();
this.skipItem(t);
++count;
}
this._ensureAvailable(0);
return count;
}
nextType() {
this._ensureAvailable(1);
return this.buffer[this.offset++];
}
skipItem(t) {
let mt = CborTypes.majorType(t);
switch(mt) {
case CborTypes.TYPE_POSINT:
case CborTypes.TYPE_NEGINT:
this.skipInt(t);
break;
case CborTypes.TYPE_BYTES:
case CborTypes.TYPE_UTF:
this.skipByteString(t);
break;
case CborTypes.TYPE_ARRAY:
this.skipArray(t);
break;
case CborTypes.TYPE_MAP:
this.skipMap(t);
break;
case CborTypes.TYPE_TAG:
this.skipTag(t);
this.skipItem(this.nextType()); // skip the tagged item as well
break;
case CborTypes.TYPE_SIMPLE:
this.skipSimple(t);
break;
default:
throw new Error('Unexpected major type ' + mt);
}
}
skipInt(t) {
let size = CborTypes.minorType(t);
switch(size) {
case CborTypes.SIZE_8:
this.offset += 1;
break;
case CborTypes.SIZE_16:
this.offset += 2;
break;
case CborTypes.SIZE_32:
this.offset += 4;
break;
case CborTypes.SIZE_64:
this.offset += 8;
break;
default:
if(size < CborTypes.SIZE_8) {
// no need to advance
return;
} else {
throw new Error('Unexpected size for integer');
}
}
}
skipByteString(t) {
let size = this.readLength(t);
if(size != -1) {
this.offset += size;
} else {
while(t != CborTypes.TYPE_BREAK) {
t = this.nextType();
this.skipItem(t);
}
}
}
skipArray(t) {
let size = this.readLength(t);
if(size != -1) {
for(let i = 0; i < size; i++) {
this.skipItem(this.nextType());
}
} else {
while(t != CborTypes.TYPE_BREAK) {
t = this.nextType();
this.skipItem(t);
}
}
}
skipMap(t) {
let size = this.readLength(t);
if(size != -1) {
for(let i = 0; i < size; i++) {
this.skipItem(this.nextType()); // key
this.skipItem(this.nextType()); // value
}
} else {
while(true) {
t = this.nextType();
if(t == CborTypes.TYPE_BREAK) {
break;
}
this.skipItem(t); // key
this.skipItem(this.nextType()); // value
}
}
}
skipTag(t) {
this.skipInt(t);
}
skipSimple(t) {
switch(t) {
case CborTypes.TYPE_BREAK:
case CborTypes.TYPE_NULL:
case CborTypes.TYPE_UNDEFINED:
case CborTypes.TYPE_TRUE:
case CborTypes.TYPE_FALSE:
// nothing to advance
break;
case CborTypes.TYPE_FLOAT_16:
this.offset += 2;
break;
case CborTypes.TYPE_FLOAT_32:
this.offset += 4;
break;
case CborTypes.TYPE_FLOAT_64:
this.offset += 8;
break;
case CborTypes.TYPE_SIMPLE_8:
this.offset += 1;
break;
default:
throw new Error('Unexpected simple type ' + t);
}
}
readLength(t) {
let size = CborTypes.minorType(t);
let result;
switch(size) {
case CborTypes.SIZE_8:
this._ensureAvailable(1);
result = this.buffer[this.offset++];
break;
case CborTypes.SIZE_16:
this._ensureAvailable(2);
result = this.buffer.readUInt16BE(this.offset);
this.offset += 2;
break;
case CborTypes.SIZE_32:
this._ensureAvailable(4);
result = this.buffer.readUInt32BE(this.offset);
this.offset += 4;
break;
case CborTypes.SIZE_64:
this._ensureAvailable(8);
let f = buf.readUInt32BE(this.offset);
let g = buf.readUInt32BE(this.offset);
result = (f * SHIFT32) + g;
this.offset += 8;
break;
case CborTypes.SIZE_STREAM:
result = -1;
break;
default:
if(size < CborTypes.SIZE_8) {
result = size;
} else {
throw new Error('Unexpected size for integer: ' + size);
}
}
return result;
}
_ensureAvailable(n) {
if(this.offset + n > this.end) {
throw new NeedMoreData();
}
}
}
const SKIPPER = new CborSkipper();