diff --git a/LICENSE b/LICENSE index c0b38dc..71fbdc1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2017 Rafael da Silva Rocha. +Copyright (c) 2017-2018 Rafael da Silva Rocha. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 85a90f5..c4b80fb 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # riff-chunks Read and write the chunks of RIFF and RIFX files. -Copyright (c) 2017 Rafael da Silva Rocha. +Copyright (c) 2017-2018 Rafael da Silva Rocha. https://github.com/rochars/riff-chunks -[![NPM version](https://img.shields.io/npm/v/riff-chunks.svg?style=for-the-badge)](https://www.npmjs.com/package/riff-chunks) [![Docs](https://img.shields.io/badge/docs-online-blue.svg?style=for-the-badge)](https://rochars.github.io/riff-chunks/index.html) [![JSPerf](https://img.shields.io/badge/jsperf-run-blue.svg?style=for-the-badge)](https://jsperf.com/riff-chunks) +[![NPM version](https://img.shields.io/npm/v/riff-chunks.svg?style=for-the-badge)](https://www.npmjs.com/package/riff-chunks) [![Docs](https://img.shields.io/badge/docs-online-blue.svg?style=for-the-badge)](https://rochars.github.io/riff-chunks/index.html) +[![Codecov](https://img.shields.io/codecov/c/github/rochars/riff-chunks.svg?style=flat-square)](https://codecov.io/gh/rochars/riff-chunks) [![Unix Build](https://img.shields.io/travis/rochars/riff-chunks.svg?style=flat-square)](https://travis-ci.org/rochars/riff-chunks) [![Windows Build](https://img.shields.io/appveyor/ci/rochars/riff-chunks.svg?style=flat-square&logo=appveyor)](https://ci.appveyor.com/project/rochars/riff-chunks) [![Scrutinizer](https://img.shields.io/scrutinizer/g/rochars/riff-chunks.svg?style=flat-square&logo=scrutinizer)](https://scrutinizer-ci.com/g/rochars/riff-chunks/) ## Install ``` @@ -58,7 +59,7 @@ function write(chunks) {} ``` ## LICENSE -Copyright (c) 2017 Rafael da Silva Rocha. +Copyright (c) 2017-2018 Rafael da Silva Rocha. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/dist/riff-chunks-min.js b/dist/riff-chunks-min.js index 58688b7..eceb353 100644 --- a/dist/riff-chunks-min.js +++ b/dist/riff-chunks-min.js @@ -5,8 +5,8 @@ https://github.com/rochars/riff-chunks byte-data - Readable data to and from byte buffers. - Copyright (c) 2017 Rafael da Silva Rocha. + Read and write data to and from byte buffers. + Copyright (c) 2017-2018 Rafael da Silva Rocha. https://github.com/rochars/byte-data endianness @@ -15,22 +15,26 @@ https://github.com/rochars/endianness */ -for(var q="function"==typeof Object.defineProperties?Object.defineProperty:function(a,n,l){a!=Array.prototype&&a!=Object.prototype&&(a[n]=l.value)},r="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this,t=["Object","assign"],u=0;uc[b].length&&(c[b]=Array(5-c[b].length).join("0")+c[b])}function p(c,d,b){(2==d||16==d)&&2>c[b].length&&(c[b]="0"+c[b])}function b(c,d){for(;c.lengththis.max&&(a-=2*this.max+2);return a};h.prototype.overflow=function(a){a> -this.max?a=this.max:athis.b?1:this.b/8;this.v();this.A();this.c||this.s()};h.prototype.v=function(){this.F=this.char?f.l.readChar:f.l["read"+(8>this.b?8:this.b)+"Bit"+(this.c?"Float":"")]};h.prototype.A=function(){this.J=this.char?f.m.writeString:f.m["write"+this.b+"Bit"+(this.c?"Float":"")]};h.prototype.s=function(){var a=Math.pow(2,this.b);this.B?(this.max=a/2-1,this.min=a/2*-1):(this.max=a-1,this.min=0)};a.a=h},function(a, -n,l){function h(d,c){(void 0===c?0:c)||(k.be="RIFX"==d.chunkId);c=b.j(d.chunkId,m).concat(b.D(d.chunkSize,k),b.j(d.format,m),f(d.subChunks,k.o));if("RIFF"==d.chunkId||"RIFX"==d.chunkId)c=new Uint8Array(c);return c}function f(d,c){for(var a=[],f=0;fa[e].b?1:a[e].b/8;c=c.concat(f(b.slice(k,k+m),a[e],d));k+=m;e++}return c};a.a.xa=function(b,a,d){d=void 0===d?10:d;if(b.length>>0},read32BitFloat:function(a,c){p[0]=k.read32Bit(a,c);return b[0]},read40Bit:function(a,c){return h(a,c,5)},read48Bit:function(a, -c){return h(a,c,6)},read64BitFloat:function(a,c){return g.N(a.slice(c,c+8))},readChar:function(a,c,b){var d="",e=0;for(b=b.b/8;e>>24&255;return e},write24Bit:function(a,b,e){e=m.write16Bit(a,b,e);a[e++]=b>>>16&255;return e},write16Bit:function(a,b,e){a[e++]=b&255;a[e++]=b>>>8&255;return e},write16BitFloat:function(a,b,e){b=g.T(b);a[e]=b&255;a[e+1]=b>>>8&255;return e+2},write8Bit:function(a,b,e){a[e++]=b&255;return e},write4Bit:function(a,b,e){a[e++]=b&15;return e},write2Bit:function(a,b,e){a[e++]=0>b?b+4:b;return e},write1Bit:function(a,b,e){a[e++]=b?1:0;return e}, -writeString:function(a,b,e){a[e++]=b.charCodeAt(0);return e}};a.a.m=m;a.a.l=k},function(a,n,l){function h(a,k){k=void 0===k?!1:k;for(var b="",d=0,c=a.length;d>10,f=a&1023;return(b?Math.pow(2,b-15)*(1+f/1024):f/1024*.00006103515625)*(a>>15?-1:1)};a.a.N=function(a){if("0,0,0,0,0,0,0,0"==a.toString())return 0;a=h(a);for(var b= -"1"+a.substr(12,52),f=1,d=0,c=0;c=a&&(b=2147483648,a=-a);var f=Math.floor(Math.log(a)/Math.log(2)),d=Math.floor(a/Math.pow(2,f)*Math.pow(2,52));a=d&4294967295;d/=Math.pow(2,32);return[b|f+1023<<20|d&1048575,a]};a.a.T=function(a){g[0]=a;var b=p[0];a=b>>16&32768;var f=b>>12&2047;b=b>>23&255;return 103>b?a:(a|b-112<<10|f>>1)+(f& -1)}}]); +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.objectCreate=$jscomp.ASSUME_ES5||"function"==typeof Object.create?Object.create:function(a){var b=function(){};b.prototype=a;return new b};$jscomp.underscoreProtoCanBeSet=function(){var a={a:!0},b={};try{return b.__proto__=a,b.a}catch(c){}return!1}; +$jscomp.setPrototypeOf="function"==typeof Object.setPrototypeOf?Object.setPrototypeOf:$jscomp.underscoreProtoCanBeSet()?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null; +$jscomp.inherits=function(a,b){a.prototype=$jscomp.objectCreate(b.prototype);a.prototype.constructor=a;if($jscomp.setPrototypeOf){var c=$jscomp.setPrototypeOf;c(a,b)}else for(c in b)if("prototype"!=c)if(Object.defineProperties){var f=Object.getOwnPropertyDescriptor(b,c);f&&Object.defineProperty(a,c,f)}else a[c]=b[c];a.superClass_=b.prototype};$jscomp.owns=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)}; +$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)};$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this); +$jscomp.polyfill=function(a,b,c,f){if(b){c=$jscomp.global;a=a.split(".");for(f=0;f>10;var h=a&1023;return(c?Math.pow(2,c-15)*(1+h/1024):h/1024*.00006103515625)*(a>>15?-1:1)};b.prototype.read32F_=function(a,c){g[0]=this.read_(a,c,{bits:32,offset:4});return f[0]};b.prototype.read64F_=function(a, +c){d[0]=this.read_(a,c,{bits:32,offset:4});d[1]=this.read_(a,c+4,{bits:32,offset:4});return e[0]};b.prototype.readChar_=function(a,c){for(var h="",d=0;d>16&32768; +var h=b>>12&2047;b=b>>23&255;103<=b&&(c=(c|b-112<<10|h>>1)+(h&1));a[d++]=c&255;a[d++]=c>>>8&255;return d};b.prototype.writeChar_=function(a,c,d){a[d++]=c.charCodeAt(0);return d};b.prototype.buildType_=function(){this.setReader_();this.setWriter_();this.float&&(this.min=-Infinity,this.max=Infinity)};b.prototype.setReader_=function(){this.float?16==this.bits?this.reader=this.read16F_:32==this.bits?this.reader=this.read32F_:64==this.bits&&(this.reader=this.read64F_):this.char?this.reader=this.readChar_: +32c.bits?c.bits:c.realBits/8),e.getType(c,b));return a=c.char?a.slice(0,c.bits/8):a[0]}var e=c(3),d=c(0);a.exports.pack=f;a.exports.unpack=g;a.exports.packArray=function(a,c,b){return e.toBytes(a,e.getType(c,void 0===b?10:b))};a.exports.unpackArray=function(a,c,b){return e.fromBytes(a,e.getType(c,void 0===b?10:b))};a.exports.unpackStruct=function(a,c,b){b=void 0===b?10:b;for(var d=a.length,e=0,h=0;hc[e].bits?1:c[e].realBits/8;d=d.concat(g(a.slice(h,h+k),c[e],b));h+=k;e++}return d};a.exports.packStruct=function(a,c,b){b=void 0===b?10:b;if(a.lengththis.max&&(a-=2*this.max+2);return a};b.prototype.overflow=function(a){a>this.max?a=this.max:a>>0;return this.overflow(this.sign(c))};b.prototype.readBits_=function(a,b,g){g=void 0===g?this:g;for(var c="",d=0;dthis.bits?1:Math.ceil(this.realBits/8)};b.prototype.setMinMax_=function(){var a=Math.pow(2,this.bits);this.signed?(this.max=a/2-1,this.min=-a/2):(this.max=a-1,this.min=0)};b.prototype.validateWordSize_=function(){if(1>this.bits||64=this.bits?16:24>=this.bits?24:32>=this.bits?32:40>=this.bits?40:48>=this.bits?48:56>=this.bits?56:64:this.bits};b.prototype.setLastByteMask_=function(){var a=8-(this.realBits-this.bits);this.lastByteMask=Math.pow(2,0e.bits?a[g++]=0>b?b+Math.pow(2,e.bits):b:a[g++]=b&255;return g};a.exports=b},function(a,b){a.exports=function(a,b){for(var c=a.length,e=0;e} bytes The bytes as binary strings. - * @param {number} base The base. - * @param {number} index The byte to pad. - */ -function padding(bytes, base, index) { - bytes[index] = bytePadding(bytes[index], base); -} - -/** - * Padding with 0s for byte strings. - * @param {string} theByte The byte as a binary or hex string. - * @param {number} base The base. - * @returns {string} The padded byte. - */ -function bytePadding(theByte, base) { - let offset = theByte.length + 1; - if (base == 2) { - offset = 8; - } else if (base == 16) { - offset = 2; - } - return lPadZeros(theByte, offset); -} - -/** - * Fix the size of nibbles. - * @param {!Array} nibbles The nibble as a binary or hex string. - * @param {number} base The base. - * @param {number} index The nibble offset. - */ -function paddingNibble(nibbles, base, index) { - if (base == 2 && nibbles[index].length < 4) { - nibbles[index] = - new Array((5 - nibbles[index].length)).join("0") + nibbles[index]; - } -} - -/** - * Fix the size of crumbs. - * @param {!Array} crumbs The nibble as a binary or hex string. - * @param {number} base The base. - * @param {number} index The nibble offset. - */ -function paddingCrumb(crumbs, base, index) { - if ((base == 2 || base == 16) && crumbs[index].length < 2) { - crumbs[index] = '0' + crumbs[index]; - } -} - -/** - * Pad a string with zeros to the left. - * TODO: This should support both arrays and strings. - * @param {string} value The string (representing a binary or hex value). - * @param {number} numZeros the max number of zeros. - * For 1 binary byte string it should be 8. - */ -function lPadZeros(value, numZeros) { - while (value.length < numZeros) { - value = '0' + value; - } - return value; -} - -/** - * Swap the endianness to big endian. - * @param {!Array} bytes The values. - * @param {Object} type The type. - */ -function makeBigEndian(bytes, type) { - if (type.be) { - endianness(bytes, type.offset); - } -} - -/** - * Turn bytes to base 2, 10 or 16. - * @param {!Array|!Array} bytes The bytes. - * @param {number} base The base. - * @param {Function} padFunction The function to use for padding. - */ -function bytesToBase(bytes, base, padFunction=padding) { - if (base != 10) { - let i = 0; - let len = bytes.length; - while (i < len) { - bytes[i] = bytes[i].toString(base); - padFunction(bytes, base, i); - i++; - } - } -} - -/** - * Turn the output to the correct base. - * @param {!Array} bytes The bytes. - * @param {number} bitDepth The bit depth of the data. - * @param {number} base The desired base for the output data. - */ -function outputToBase(bytes, bitDepth, base) { - if (bitDepth == 4) { - bytesToBase(bytes, base, paddingNibble); - } else if (bitDepth == 2) { - bytesToBase(bytes, base, paddingCrumb); - } else if(bitDepth == 1) { - bytesToBase(bytes, base, function(){}); - }else { - bytesToBase(bytes, base); - } -} - -/** - * Get the full type spec for the reading/writing. - * @param {Object} atype One of the available types. - * @param {number} base The base of the input. - * @param {boolean} single True if its a single value, false for array. - * @return {Object} - */ -function getType(atype, base, single) { - let theType = Object.assign(new Type({}), atype); - theType.base = base; - theType.single = single; - return theType; -} - -/** - * Make a single value an array in case it is not. - * If the value is a string it stays a string. - * @param {!Array|number|string} values The value or values. - * @return {!Array|string} - */ -function turnToArray(values) { - if (!Array.isArray(values) && typeof values != "string") { - values = [values]; - } - return values; -} - -module.exports.makeBigEndian = makeBigEndian; -module.exports.outputToBase = outputToBase; -module.exports.padding = padding; -module.exports.paddingNibble = paddingNibble; -module.exports.paddingCrumb = paddingCrumb; -module.exports.bytePadding = bytePadding; -module.exports.lPadZeros = lPadZeros; -module.exports.getType = getType; -module.exports.turnToArray = turnToArray; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/** +/* * type: The Type class. * Copyright (c) 2017 Rafael da Silva Rocha. * https://github.com/rochars/byte-data */ /** @private */ -const bitParser = __webpack_require__(6); +let f32 = new Float32Array(1); +/** @private */ +let i32 = new Int32Array(f32.buffer); +/** @private */ +let f64 = new Float64Array(1); +/** @private */ +let ui32 = new Uint32Array(f64.buffer); +/** @private */ +const GInt = __webpack_require__(4); /** * A class to represent byte-data types. */ -class Type { +class Type extends GInt { + /** + * @param {Object} options The type definition. + * @param {number} options.bits Number of bits used by data of this type. + * @param {boolean} options.char True for string/char types. + * @param {boolean} options.float True for float types. + * Available only for 16, 32 and 64-bit data. + * @param {boolean} options.be True for big-endian. + * @param {boolean} options.signed True for signed types. + */ constructor(options) { + super(options); /** - * The max number of bits used by data of this type. - * @type {number} - */ - this.bits = options["bits"]; - /** - * If this type represent floating-point values or not. + * If this type is a char or not. * @type {boolean} */ this.char = options["char"]; /** - * If this type it is signed or not. + * If this type is a floating-point number or not. * @type {boolean} */ this.float = options["float"]; - /** - * If this type is big-endian or not. - * @type {boolean} - */ - this.be = options["be"]; - /** - * If this type it is signed or not. - * @type {boolean} - */ - this.signed = this.float ? true : options["signed"]; - /** - * If this type represent a single value or an array. - * @type {boolean} - */ - this.single = true; - /** - * The function to read values of this type from buffers. - * @type {Function} - */ - this.reader = null; - /** - * The function to write values of this type to buffers. - * @type {Function} - */ - this.writer = null; - /** - * The number of bytes used by data of this type. - * @type {number} - */ - this.offset = 0; - /** - * The base used to represent data of this type. - * @type {number} - */ - this.base = 10; - /** - * Min value for numbers of this type. - * @type {number} - */ - this.min = -Infinity; - /** - * Max value for numbers of this type. - * @type {number} - */ - this.max = Infinity; - this.build_(); + this.buildType_(); } /** - * Sign a number according to the type. - * @param {number} num The number. + * Read 1 16-bit float from from bytes. + * Thanks https://stackoverflow.com/a/8796597 + * @param {!Array|Uint8Array} bytes An array of bytes. + * @param {number} i The index to read. + * @return {number} + * @private */ - sign(num) { - if (num > this.max) { - num -= (this.max * 2) + 2; + read16F_(bytes, i) { + let int = this.read_(bytes, i, {"bits": 16, "offset": 2}); + let exponent = (int & 0x7C00) >> 10; + let fraction = int & 0x03FF; + let floatValue; + if (exponent) { + floatValue = Math.pow(2, exponent - 15) * (1 + fraction / 0x400); + } else { + floatValue = 6.103515625e-5 * (fraction / 0x400); } - return num; + return floatValue * (int >> 15 ? -1 : 1); } /** - * Limit the value according to the bit depth in case of - * overflow or underflow. - * @param {!Array|number|string} value The data. + * Read 1 32-bit float from bytes. + * @param {!Array|Uint8Array} bytes An array of bytes. + * @param {number} i The index to read. + * @return {number} + * @private */ - overflow(value) { - if (value > this.max) { - value = this.max; - } else if (value < this.min) { - value = this.min; + read32F_(bytes, i) { + i32[0] = this.read_(bytes, i, {"bits": 32, "offset": 4}); + return f32[0]; + } + + /** + * Read 1 64-bit double from bytes. + * Thanks https://gist.github.com/kg/2192799 + * @param {!Array|Uint8Array} bytes An array of bytes. + * @param {number} i The index to read. + * @return {number} + * @private + */ + read64F_(bytes, i) { + ui32[0] = this.read_(bytes, i, {"bits": 32, "offset": 4}); + ui32[1] = this.read_(bytes, i + 4, {"bits": 32, "offset": 4}); + return f64[0]; + } + + /** + * Read 1 char from bytes. + * @param {!Array|Uint8Array} bytes An array of bytes. + * @param {number} i The index to read. + * @return {string} + * @private + */ + readChar_(bytes, i) { + let chrs = ""; + let j = 0; + while(j < this.offset) { + chrs += String.fromCharCode(bytes[i+j]); + j++; } - return value; + return chrs; + } + + /** + * Write one 64-bit float as a binary value. + * @param {!Array} bytes An array of bytes. + * @param {number} number The number to write as bytes. + * @param {number} j The index being written in the byte buffer. + * @return {number} The next index to write on the byte buffer. + * @private + */ + write64F_(bytes, number, j) { + f64[0] = number; + let type = {bits: 32, offset: 4, lastByteMask:255}; + j = this.write_(bytes, ui32[0], j, type); + return this.write_(bytes, ui32[1], j, type); + } + + /** + * Write one 32-bit float as a binary value. + * @param {!Array} bytes An array of bytes. + * @param {number} number The number to write as bytes. + * @param {number} j The index being written in the byte buffer. + * @param {Object} type The type. + * @return {number} The next index to write on the byte buffer. + * @private + */ + write32F_(bytes, number, j, type) { + f32[0] = number; + j = this.write_(bytes, i32[0], j, type); + return j; + } + + /** + * Write one 16-bit float as a binary value. + * @param {!Array} bytes An array of bytes. + * @param {number} number The number to write as bytes. + * @param {number} j The index being written in the byte buffer. + * @return {number} The next index to write on the byte buffer. + * @private + */ + write16F_(bytes, number, j) { + f32[0] = number; + let x = i32[0]; + let bits = (x >> 16) & 0x8000; + let m = (x >> 12) & 0x07ff; + let e = (x >> 23) & 0xff; + if (e >= 103) { + bits |= ((e - 112) << 10) | (m >> 1); + bits += m & 1; + } + bytes[j++] = bits & 0xFF; + bytes[j++] = bits >>> 8 & 0xFF; + return j; + } + + /** + * Write one char as a byte. + * @param {!Array} bytes An array of bytes. + * @param {string} string The string to write as bytes. + * @param {number} j The index being written in the byte buffer. + * @return {number} The next index to write on the byte buffer. + * @private + */ + writeChar_(bytes, string, j) { + bytes[j++] = string.charCodeAt(0); + return j; } /** * Build the type. * @private */ - build_() { - this.offset = this.bits < 8 ? 1 : this.bits / 8; + buildType_() { this.setReader_(); this.setWriter_(); - if (!this.float) { - this.setMinMax_(); + if (this.float) { + this.min = -Infinity; + this.max = Infinity; } } @@ -351,10 +261,20 @@ class Type { * @private */ setReader_() { - this.reader = this.char ? - bitParser.BitReader["readChar"] : bitParser.BitReader[ - 'read' + (this.bits < 8 ? 8 : this.bits) + - 'Bit' + (this.float ? "Float" : "")]; + if (this.float) { + if (this.bits == 16) { + this.reader = this.read16F_; + } else if(this.bits == 32) { + this.reader = this.read32F_; + } else if(this.bits == 64) { + this.reader = this.read64F_; + } + } else if (this.char) { + this.reader = this.readChar_; + } else if (this.bits > 32) { + //this.reader = this.read_; + this.reader = this.readBits_; + } } /** @@ -362,26 +282,16 @@ class Type { * @private */ setWriter_() { - if (this.char) { - this.writer = bitParser.BitWriter["writeString"]; - } else { - this.writer = bitParser.BitWriter[ - 'write' + this.bits + 'Bit' + (this.float ? "Float" : "")]; - } - } - - /** - * Set the minimum and maximum values for the type. - * @private - */ - setMinMax_() { - let max = Math.pow(2, this.bits); - if (this.signed) { - this.max = (max / 2) - 1; - this.min = (max / 2) * -1; - } else { - this.max = max - 1; - this.min = 0; + if (this.float) { + if (this.bits == 16) { + this.writer = this.write16F_; + } else if(this.bits == 32) { + this.writer = this.write32F_; + } else if(this.bits == 64) { + this.writer = this.write64F_; + } + } else if (this.char) { + this.writer = this.writeChar_; } } } @@ -390,7 +300,7 @@ module.exports = Type; /***/ }), -/* 2 */ +/* 1 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -401,7 +311,7 @@ module.exports = Type; * */ -const byteData = __webpack_require__(3); +const byteData = __webpack_require__(2); const uInt32 = byteData.uInt32; const chr = byteData.chr; @@ -532,65 +442,83 @@ window['riffChunks']['write'] = write; /***/ }), -/* 3 */ +/* 2 */ /***/ (function(module, exports, __webpack_require__) { /*! * byte-data - * Readable data to and from byte buffers. - * Copyright (c) 2017 Rafael da Silva Rocha. + * Read and write data to and from byte buffers. + * Copyright (c) 2017-2018 Rafael da Silva Rocha. * https://github.com/rochars/byte-data * */ -const rw = __webpack_require__(4); -const helpers = __webpack_require__(0); -let Type = __webpack_require__(1); +/** @private */ +const rw = __webpack_require__(3); +const Type = __webpack_require__(0); /** - * Turn a number or string into a byte buffer. + * Turn a number or fixed-length string into a byte buffer. * @param {number|string} value The value. * @param {Object} type One of the available types. * @param {number} base The base of the output. Optional. Default is 10. + * Possible values are 2, 10 or 16. * @return {!Array|!Array} */ -function packValue(value, type, base=10) { - let theType = helpers.getType(type, base, true); - value = theType.char ? value.slice(0, type.bits / 8) : value; - return rw.toBytes(helpers.turnToArray(value), theType); +function pack(value, type, base=10) { + let values = []; + if (type.char) { + values = type.char ? value.slice(0, type.realBits / 8) : value; + } else if (!Array.isArray(value)) { + values = [value]; + } + return rw.toBytes(values, rw.getType(type, base)); } /** - * Turn a byte buffer into a readable value. + * Turn a byte buffer into a number or a fixed-length string. * @param {!Array|!Array|Uint8Array} buffer An array of bytes. * @param {Object} type One of the available types. * @param {number} base The base of the input. Optional. Default is 10. + * Possible values are 2, 10 or 16. * @return {number|string} */ -function unpackValue(buffer, type, base=10) { - return rw.fromBytes(buffer, helpers.getType(type, base, true)); +function unpack(buffer, type, base=10) { + let offset = type.bits < 8 ? type.bits : type.realBits / 8; + let values = rw.fromBytes( + buffer.slice(0, offset), + rw.getType(type, base) + ); + if (type.char) { + values = values.slice(0, type.bits / 8); + } else { + values = values[0]; + } + return values; } /** - * Turn a array of numbers into a byte buffer. + * Turn a array of numbers or a string into a byte buffer. * @param {!Array|string} values The values. * @param {Object} type One of the available types. * @param {number} base The base of the output. Optional. Default is 10. + * Possible values are 2, 10 or 16. * @return {!Array|!Array} */ function packArray(values, type, base=10) { - return rw.toBytes(values, helpers.getType(type, base, false)); + return rw.toBytes(values, rw.getType(type, base)); } /** - * Turn a byte array into a sequence of readable values. + * Turn a byte buffer into a array of numbers or a string. * @param {!Array|!Array|Uint8Array} buffer The byte array. * @param {Object} type One of the available types. * @param {number} base The base of the input. Optional. Default is 10. + * Possible values are 2, 10 or 16. * @return {!Array|string} */ function unpackArray(buffer, type, base=10) { - return rw.fromBytes(buffer, helpers.getType(type, base, false)); + return rw.fromBytes(buffer, rw.getType(type, base)); } /** @@ -603,7 +531,7 @@ function unpackArray(buffer, type, base=10) { function findString(buffer, text) { let found = ""; for (let i = 0; i < buffer.length; i++) { - found = unpackValue( + found = unpack( buffer.slice(i, i + text.length + 1), new Type({"bits": text.length * 8, "char": true}) ); @@ -617,9 +545,10 @@ function findString(buffer, text) { /** * Turn a struct into a byte buffer. * A struct is an array of values of not necessarily the same type. - * @param {Array} struct The struct values. + * @param {Array} struct The struct values. * @param {!Array} def The struct type definition. * @param {number} base The base of the output. Optional. Default is 10. + * Possible values are 2, 10 or 16. * @return {!Array|!Array} */ function packStruct(struct, def, base=10) { @@ -628,30 +557,31 @@ function packStruct(struct, def, base=10) { } let bytes = []; for (let i = 0; i < def.length; i++) { - bytes = bytes.concat(packValue(struct[i], def[i], base)); + bytes = bytes.concat(pack(struct[i], def[i], base)); } return bytes; } /** - * Turn a byte buffer into a structure. + * Turn a byte buffer into a struct. * A struct is an array of values of not necessarily the same type. * @param {!Array|!Array|Uint8Array} buffer The byte buffer. * @param {!Array} def The struct type definition. * @param {number} base The base of the input. Optional. Default is 10. - * @return {Array} + * Possible values are 2, 10 or 16. + * @return {Array} */ function unpackStruct(buffer, def, base=10) { - if (buffer.length < getStructBits(def)) { + if (buffer.length < getStructDefSize(def)) { return []; } let struct = []; let i = 0; let j = 0; while (i < def.length) { - let bits = def[i].bits < 8 ? 1 : def[i].bits / 8; + let bits = def[i].bits < 8 ? 1 : def[i].realBits / 8; struct = struct.concat( - unpackValue(buffer.slice(j, j + bits), def[i], base) + unpack(buffer.slice(j, j + bits), def[i], base) ); j += bits; i++; @@ -659,75 +589,219 @@ function unpackStruct(buffer, def, base=10) { return struct; } -function getStructBits(def) { +/** + * Get the length in bytes of a struct definition. + * @param {!Array} def The struct type definition. + * @return {number} The length of the structure in bytes. + * @private + */ +function getStructDefSize(def) { let bits = 0; for (let i = 0; i < def.length; i++) { - bits += def[i].bits / 8; + bits += def[i].realBits / 8; } return bits; } // interface -module.exports.pack = packValue; -module.exports.unpack = unpackValue; +module.exports.pack = pack; +module.exports.unpack = unpack; module.exports.packArray = packArray; module.exports.unpackArray = unpackArray; module.exports.unpackStruct = unpackStruct; module.exports.packStruct = packStruct; module.exports.findString = findString; module.exports.Type = Type; - -// types +/** + * A char. + * @type {Object} + */ module.exports.chr = new Type({"bits": 8, "char": true}); +/** + * A 4-char string + * @type {Object} + */ module.exports.fourCC = new Type({"bits": 32, "char": true}); +/** + * Booleans + * @type {Object} + */ module.exports.bool = new Type({"bits": 1}); +/** + * Signed 2-bit integers + * @type {Object} + */ module.exports.int2 = new Type({"bits": 2, "signed": true}); +/** + * Unsigned 2-bit integers + * @type {Object} + */ module.exports.uInt2 = new Type({"bits": 2}); +/** + * Signed 4-bit integers + * @type {Object} + */ module.exports.int4 = new Type({"bits": 4, "signed": true}); +/** + * Unsigned 4-bit integers + * @type {Object} + */ module.exports.uInt4 = new Type({"bits": 4}); +/** + * Signed 8-bit integers + * @type {Object} + */ module.exports.int8 = new Type({"bits": 8, "signed": true}); +/** + * Unsigned 4-bit integers + * @type {Object} + */ module.exports.uInt8 = new Type({"bits": 8}); // LE +/** + * Signed 16-bit integers little-endian + * @type {Object} + */ module.exports.int16 = new Type({"bits": 16, "signed": true}); -module.exports.uInt16 = new Type({"bits": 16}); +/** + * Unsigned 16-bit integers little-endian + * @type {Object} + */ +module.exports.uInt16 = new Type({"bits": 16}); +/** + * Half-precision floating-point numbers little-endian + * @type {Object} + */ module.exports.float16 = new Type({"bits": 16, "float": true}); +/** + * Signed 24-bit integers little-endian + * @type {Object} + */ module.exports.int24 = new Type({"bits": 24, "signed": true}); +/** + * Unsigned 24-bit integers little-endian + * @type {Object} + */ module.exports.uInt24 = new Type({"bits": 24}); +/** + * Signed 32-bit integers little-endian + * @type {Object} + */ module.exports.int32 = new Type({"bits": 32, "signed": true}); +/** + * Unsigned 32-bit integers little-endian + * @type {Object} + */ module.exports.uInt32 = new Type({"bits": 32}); +/** + * Single-precision floating-point numbers little-endian + * @type {Object} + */ module.exports.float32 = new Type({"bits": 32, "float": true}); +/** + * Signed 40-bit integers little-endian + * @type {Object} + */ module.exports.int40 = new Type({"bits": 40, "signed": true}); +/** + * Unsigned 40-bit integers little-endian + * @type {Object} + */ module.exports.uInt40 = new Type({"bits": 40}); +/** + * Signed 48-bit integers little-endian + * @type {Object} + */ module.exports.int48 = new Type({"bits": 48, "signed": true}); +/** + * Unsigned 48-bit integers little-endian + * @type {Object} + */ module.exports.uInt48 = new Type({"bits": 48}); +/** + * Double-precision floating-point numbers little-endian + * @type {Object} + */ module.exports.float64 = new Type({"bits": 64, "float": true}); // BE +/** + * Signed 16-bit integers big-endian + * @type {Object} + */ module.exports.int16BE = new Type({"bits": 16, "signed": true, "be": true}); +/** + * Unsigned 16-bit integers big-endian + * @type {Object} + */ module.exports.uInt16BE = new Type({"bits": 16, "be": true}); +/** + * Half-precision floating-point numbers big-endian + * @type {Object} + */ module.exports.float16BE = new Type({"bits": 16, "float": true, "be": true}); +/** + * Signed 24-bit integers big-endian + * @type {Object} + */ module.exports.int24BE = new Type({"bits": 24, "signed": true, "be": true}); +/** + * Unsigned 24-bit integers big-endian + * @type {Object} + */ module.exports.uInt24BE = new Type({"bits": 24, "be": true}); +/** + * Signed 32-bit integers big-endian + * @type {Object} + */ module.exports.int32BE = new Type({"bits": 32, "signed": true, "be": true}); +/** + * Unsigned 32-bit integers big-endian + * @type {Object} + */ module.exports.uInt32BE = new Type({"bits": 32, "be": true}); +/** + * Single-precision floating-point numbers big-endian + * @type {Object} + */ module.exports.float32BE = new Type({"bits": 32, "float": true, "be": true}); +/** + * Signed 40-bit integers big-endian + * @type {Object} + */ module.exports.int40BE = new Type({"bits": 40, "signed": true, "be": true}); +/** + * Unsigned 40-bit integers big-endian + * @type {Object} + */ module.exports.uInt40BE = new Type({"bits": 40, "be": true}); +/** + * Signed 48-bit integers big-endian + * @type {Object} + */ module.exports.int48BE = new Type({"bits": 48, "signed": true, "be": true}); +/** + * Unsigned 48-bit integers big-endian + * @type {Object} + */ module.exports.uInt48BE = new Type({"bits": 48, "be": true}); +/** + * Double-precision floating-point numbers big-endian + * @type {Object} + */ module.exports.float64BE = new Type({"bits": 64, "float": true, "be": true}); /***/ }), -/* 4 */ +/* 3 */ /***/ (function(module, exports, __webpack_require__) { -/** - * from-bytes: Numbers and strings from bytes. +/* * Copyright (c) 2017 Rafael da Silva Rocha. * https://github.com/rochars/byte-data */ -const helpers = __webpack_require__(0); +const Type = __webpack_require__(0); +const endianness = __webpack_require__(5); /** * Turn a byte buffer into what the bytes represent. @@ -736,31 +810,31 @@ const helpers = __webpack_require__(0); * @return {!Array|number|string} */ function fromBytes(buffer, type) { - helpers.makeBigEndian(buffer, type); - bytesFromBase(buffer, type.base); - let values = readBytes( - buffer, - type - ); - if (type.single) { - values = getSingleValue(values, type); + if (type.be) { + endianness(buffer, type.offset); } - return values; + if (type.base != 10) { + bytesFromBase(buffer, type.base); + } + return readBytes(buffer, type); } /** - * Return the first value from the result value array. - * @param {!Array|string} values The values. + * Turn numbers and strings to bytes. + * @param {!Array|number|string} values The data. * @param {Object} type One of the available types. - * @return {number|string} + * @return {!Array|!Array} the data as a byte buffer. */ -function getSingleValue(values, type) { - if (type.char) { - values = values.slice(0, type.bits / 8); - } else { - values = values[0]; +function toBytes(values, type) { + let bytes = writeBytes(values, type); + if (type.be) { + endianness(bytes, type.offset); } - return values; + if (type.base != 10) { + bytesToBase(bytes, type.base); + formatOutput(bytes, type); + } + return bytes; } /** @@ -774,9 +848,7 @@ function readBytes(bytes, type) { let i = 0; let len = bytes.length - (type.offset - 1); while (i < len) { - values.push( - type.sign(type.reader(bytes, i, type)) - ); + values.push(type.reader(bytes, i)); i += type.offset; } if (type.char) { @@ -785,35 +857,6 @@ function readBytes(bytes, type) { return values; } -/** - * Turn bytes to base 10. - * @param {!Array|Uint8Array} bytes The bytes as binary or hex strings. - * @param {number} base The base. - */ -function bytesFromBase(bytes, base) { - if (base != 10) { - let i = 0; - let len = bytes.length; - while(i < len) { - bytes[i] = parseInt(bytes[i], base); - i++; - } - } -} - -/** - * Turn numbers and strings to bytes. - * @param {!Array|number|string} values The data. - * @param {Object} type One of the available types. - * @return {!Array|!Array|Uint8Array} the data as a byte buffer. - */ -function toBytes(values, type) { - let bytes = writeBytes(values, type); - helpers.makeBigEndian(bytes, type); - helpers.outputToBase(bytes, type.bits, type.base); - return bytes; -} - /** * Write values as bytes. * @param {!Array|number|string} values The data. @@ -826,427 +869,394 @@ function writeBytes(values, type) { let len = values.length; let bytes = []; while (i < len) { - j = type.writer(bytes, type.overflow(values[i]), j); - i++; + j = type.writer(bytes, values[i++], j); } return bytes; } -module.exports.toBytes = toBytes; -module.exports.fromBytes = fromBytes; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports) { - -/*! - * endianness - * Swap endianness in byte arrays. - * Copyright (c) 2017 Rafael da Silva Rocha. - * https://github.com/rochars/endianness - * +/** + * Get the full type spec for the reading/writing. + * @param {Object} type One of the available types. + * @param {number} base The base of the input. + * @return {Object} */ +function getType(type, base) { + let theType = Object.assign(new Type({}), type); + theType.base = base; + return theType; +} /** - * Swap the endianness of units of information in a byte array. - * The original array is modified in-place. - * @param {!Array|!Array|Uint8Array} bytes The bytes. - * @param {number} offset The number of bytes of each unit of information. + * Turn bytes to base 10 from base 2 or 16. + * @param {!Array|Uint8Array} bytes The bytes as binary or hex strings. + * @param {number} base The base. */ -function endianness(bytes, offset) { +function bytesFromBase(bytes, base) { + let i = 0; let len = bytes.length; + while(i < len) { + bytes[i] = parseInt(bytes[i], base); + i++; + } +} + +/** + * Turn the output to the correct base. + * @param {Array} bytes The bytes. + * @param {Object} type The type. + */ +function formatOutput(bytes, type) { let i = 0; - while (i < len) { - swap(bytes, offset, i); - i += offset; + let len = bytes.length; + let offset = (type.base == 2 ? 8 : 2) + 1; + while(i < len) { + bytes[i] = Array(offset - bytes[i].length).join("0") + bytes[i]; + i++; } } /** - * Swap the endianness of a unit of information in a byte array. - * The original array is modified in-place. - * @param {!Array|!Array|Uint8Array} bytes The bytes. - * @param {number} offset The number of bytes of the unit of information. - * @param {number} index The start index of the unit of information. + * Turn bytes from base 10 to base 2 or 16. + * @param {!Array|Array} bytes The bytes. + * @param {number} base The base. */ -function swap(bytes, offset, index) { - let x = 0; - let y = offset - 1; - let limit = parseInt(offset / 2, 10); - while(x < limit) { - let theByte = bytes[index + x]; - bytes[index + x] = bytes[index + y]; - bytes[index + y] = theByte; - x++; - y--; +function bytesToBase(bytes, base) { + let i = 0; + let len = bytes.length; + while (i < len) { + bytes[i] = bytes[i].toString(base); + i++; } } -module.exports = endianness; +module.exports.getType = getType; +module.exports.toBytes = toBytes; +module.exports.fromBytes = fromBytes; /***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { +/* 4 */ +/***/ (function(module, exports) { -/** - * bit-parser: Functions to read and write bytes. +/* + * gint: Generic integer. + * A class to represent any integer from 1 to 53-Bit. * Copyright (c) 2017 Rafael da Silva Rocha. * https://github.com/rochars/byte-data - * Float32 based on int-bits: https://github.com/Jam3/int-bits */ -const helpers = __webpack_require__(0); -const floats = __webpack_require__(7); -let i8 = new Int8Array(4); -let i32 = new Int32Array(i8.buffer, 0, 1); -let f32 = new Float32Array(i8.buffer, 0, 1); - /** - * Read a group of bytes by turning it to bits. - * Useful for 40 & 48-bit, but underperform. - * @param {!Array|Uint8Array} bytes An array of bytes. - * @param {number} i The index to read. - * @param {number} numBytes The number of bytes - * (1 for 8-bit, 2 for 16-bit, etc). - * @return {number} - */ -function readBytesAsBits(bytes, i, numBytes) { - let j = numBytes-1; - let bits = ""; - while (j >= 0) { - bits += helpers.bytePadding(bytes[j + i].toString(2), 2); - j--; - } - return parseInt(bits, 2); -} - -let BitReader = { + * A class to represent any integer from 1 to 53-Bit. + */ +class GInt { /** - * Read 1 8-bit int from from bytes. - * @param {!Array|Uint8Array} bytes An array of bytes. - * @param {number} i The index to read. - * @return {number} + * @param {Object} options The type definition. + * @param {number} options.bits Number of bits used by data of this type. + * @param {boolean} options.be True for big-endian. + * @param {boolean} options.signed True for signed types. */ - "read8Bit": function (bytes, i) { - return bytes[i]; - }, + constructor(options) { + /** + * The max number of bits used by data of this type. + * @type {number} + */ + this.bits = options["bits"]; + /** + * If this type is big-endian or not. + * @type {boolean} + */ + this.be = options["be"]; + /** + * If this type it is signed or not. + * @type {boolean} + */ + this.signed = options["signed"]; + /** + * The base used to represent data of this type. + * Default is 10. + * @type {number} + */ + this.base = options["base"] ? options["base"] : 10; + /** + * The function to read values of this type from buffers. + * @type {Function} + * @ignore + */ + this.reader = this.read_; + /** + * The function to write values of this type to buffers. + * @type {Function} + * @ignore + */ + this.writer = this.write_; + /** + * The number of bytes used by data of this type. + * @type {number} + * @ignore + */ + this.offset = 0; + /** + * Min value for numbers of this type. + * @type {number} + * @ignore + */ + this.min = -Infinity; + /** + * Max value for numbers of this type. + * @type {number} + * @ignore + */ + this.max = Infinity; + /** + * The word size. + * @type {number} + * @ignore + */ + this.realBits = this.bits; + /** + * The mask to be used in the last byte of this type. + * @type {number} + * @ignore + */ + this.lastByteMask = 255; + this.build_(); + } /** - * Read 1 16-bit int from from bytes. - * @param {!Array|Uint8Array} bytes An array of bytes. - * @param {number} i The index to read. + * Sign a number according to the type. + * @param {number} num The number. * @return {number} + * @ignore */ - "read16Bit": function (bytes, i) { - return bytes[1 + i] << 8 | bytes[i]; - }, + sign(num) { + if (num > this.max) { + num -= (this.max * 2) + 2; + } + return num; + } /** - * Read 1 16-bit float from from bytes. - * @param {!Array|Uint8Array} bytes An array of bytes. - * @param {number} i The index to read. + * Limit the value according to the bit depth in case of + * overflow or underflow. + * @param {number} value The data. * @return {number} + * @ignore */ - "read16BitFloat": function (bytes, i) { - return floats.decodeFloat16([bytes[i+1], bytes[i]]); - }, + overflow(value) { + if (value > this.max) { + value = this.max; + } else if (value < this.min) { + value = this.min; + } + return value; + } /** - * Read 1 24-bit int from from bytes. + * Read a integer number from a byte buffer. * @param {!Array|Uint8Array} bytes An array of bytes. * @param {number} i The index to read. + * @param {Object} type The type if other than this. * @return {number} + * @private */ - "read24Bit": function (bytes, i) { - return bytes[2 + i] << 16 | BitReader["read16Bit"](bytes, i); - }, + read_(bytes, i, type=this) { + let num = 0; + let x = type.offset - 1; + while (x > 0) { + num = (bytes[x + i] << x * 8) | num; + x--; + } + num = (bytes[i] | num) >>> 0; + return this.overflow(this.sign(num)); + } /** - * Read 1 32-bit int from from bytes. + * Read a integer number from a byte buffer by turning the bytes + * to a string of bits. * @param {!Array|Uint8Array} bytes An array of bytes. * @param {number} i The index to read. + * @param {Object} type The type if other than this. * @return {number} + * @private */ - "read32Bit": function (bytes, i) { - return (bytes[3 + i] << 24 | - BitReader["read24Bit"](bytes, i)) >>> 0; - }, + readBits_(bytes, i, type=this) { + let binary = ""; + let j = 0; + while(j < type.offset) { + let bits = bytes[i + j].toString(2); + binary = Array(9 - bits.length).join("0") + bits + binary; + j++; + } + return this.overflow(this.sign(parseInt(binary, 2))); + } /** - * Read 1 32-bit float from from bytes. - * @param {!Array|Uint8Array} bytes An array of bytes. - * @param {number} i The index to read. - * @return {number} + * Write one integer number to a byte buffer. + * @param {!Array} bytes An array of bytes. + * @param {number} number The number. + * @param {number} j The index being written in the byte buffer. + * @param {Object} type The type. + * @return {number} The next index to write on the byte buffer. + * @private */ - "read32BitFloat": function (bytes, i) { - i32[0] = BitReader["read32Bit"](bytes, i); - return f32[0]; - }, + write_(bytes, number, j, type=this) { + number = this.overflow(number); + let mask = 255; + let len = type.offset; + j = this.writeFirstByte_(bytes, number, j, type); + for (let i = 2; i <= len; i++) { + if (i == len) { + mask = type.lastByteMask; + } + bytes[j++] = Math.floor(number / Math.pow(2, ((i - 1) * 8))) & mask; + } + return j; + } /** - * Read 1 40-bit int from from bytes. - * @param {!Array|Uint8Array} bytes An array of bytes. - * @param {number} i The index to read. - * @return {number} + * Build the type. + * @private */ - "read40Bit": function (bytes, i) { - return readBytesAsBits(bytes, i, 5); - }, + build_() { + this.validateWordSize_(); + this.setRealBits_(); + this.setLastByteMask_(); + this.setMinMax_(); + this.offset = this.bits < 8 ? 1 : Math.ceil(this.realBits / 8); + } /** - * Read 1 48-bit int from bytes. - * @param {!Array|Uint8Array} bytes An array of bytes. - * @param {number} i The index to read. - * @return {number} + * Set the minimum and maximum values for the type. + * @private */ - "read48Bit": function (bytes, i) { - return readBytesAsBits(bytes, i, 6); - }, + setMinMax_() { + let max = Math.pow(2, this.bits); + if (this.signed) { + this.max = max / 2 -1; + this.min = -max / 2; + } else { + this.max = max - 1; + this.min = 0; + } + } - /** - * Read 1 64-bit double from bytes. - * @param {!Array|Uint8Array} bytes An array of bytes. - * @param {number} i The index to read. - * @return {number} - */ - "read64BitFloat": function (bytes, i) { - return floats.decodeFloat64(bytes.slice(i,i+8)); - }, + validateWordSize_() { + if (this.bits < 1 || this.bits > 64) { + throw Error("Not a supported type."); + } + } /** - * Read 1 char from bytes. - * @param {!Array|Uint8Array} bytes An array of bytes. - * @param {number} i The index to read. - * @return {string} + * Set the real bit depth for data with bit count different from the + * standard types (1, 2, 4, 8, 16, 32, 40, 48, 64): the closest bigger + * standard number of bits. The data is then treated as data of the + * standard type on all aspects except for the min and max values. + * Ex: a 11-bit uInt is treated as 16-bit uInt with a max value of 2048. + * @private */ - "readChar": function (bytes, i, type) { - let chrs = ""; - let j = 0; - let len = type.bits / 8; - while(j < len) { - chrs += String.fromCharCode(bytes[i+j]); - j++; + setRealBits_() { + if (this.bits > 8) { + if (this.bits <= 16) { + this.realBits = 16; + } else if (this.bits <= 24) { + this.realBits = 24; + } else if (this.bits <= 32) { + this.realBits = 32; + } else if (this.bits <= 40) { + this.realBits = 40; + } else if (this.bits <= 48) { + this.realBits = 48; + } else if (this.bits <= 56) { + this.realBits = 56; + } else { + this.realBits = 64; + } + } else { + this.realBits = this.bits; } - return chrs; } -}; - -let BitWriter = { - - "write64BitFloat": function(bytes, number, j) { - let bits = floats.toFloat64(number); - j = BitWriter["write32Bit"](bytes, bits[1], j); - return BitWriter["write32Bit"](bytes, bits[0], j); - }, - - // Thanks https://github.com/majimboo/c-struct - "write48Bit": function (bytes, number, j) { - j = BitWriter["write40Bit"](bytes, number, j); - bytes[j++] = number / 0x10000000000 & 0xFF; - return j; - }, - - // Thanks https://github.com/majimboo/c-struct - "write40Bit": function (bytes, number, j) { - j = BitWriter["write32Bit"](bytes, number, j); - bytes[j++] = number / 0x100000000 & 0xFF; - return j; - }, - - "write32BitFloat": function (bytes, number, j) { - f32[0] = number; - j = BitWriter["write32Bit"](bytes, i32[0], j); - return j; - }, - - "write32Bit": function (bytes, number, j) { - j = BitWriter["write24Bit"](bytes, number, j); - bytes[j++] = number >>> 24 & 0xFF; - return j; - }, - - "write24Bit": function (bytes, number, j) { - j = BitWriter["write16Bit"](bytes, number, j); - bytes[j++] = number >>> 16 & 0xFF; - return j; - }, - - "write16Bit": function (bytes, number, j) { - bytes[j++] = number & 0xFF; - bytes[j++] = number >>> 8 & 0xFF; - return j; - }, - - "write16BitFloat": function (bytes, number, j) { - let bits = floats.toHalf(number); - bytes[j] = bits & 0xFF; - bytes[j+1] = bits >>> 8 & 0xFF; - return j+2; - }, - - "write8Bit": function (bytes, number, j) { - bytes[j++] = number & 0xFF; - return j; - }, - - "write4Bit": function (bytes, number, j) { - bytes[j++] = number & 0xF; - return j; - }, - - "write2Bit": function (bytes, number, j) { - bytes[j++] = number < 0 ? number + 4 : number; - return j; - }, - "write1Bit": function (bytes, number, j) { - bytes[j++] = number ? 1 : 0; - return j; - }, + /** + * Set the mask that should be used when writing the last byte of + * data of the type. + * @private + */ + setLastByteMask_() { + let r = 8 - (this.realBits - this.bits); + this.lastByteMask = Math.pow(2, r > 0 ? r : 8) -1; + } - "writeString": function (bytes, string, j) { - bytes[j++] = string.charCodeAt(0); + /** + * Write the first byte of a integer number. + * @param {!Array} bytes An array of bytes. + * @param {number} number The number. + * @param {number} j The index being written in the byte buffer. + * @param {Object} type The type. + * @return {number} The next index to write on the byte buffer. + * @private + */ + writeFirstByte_(bytes, number, j, type=this) { + if (type.bits < 8) { + bytes[j++] = number < 0 ? number + Math.pow(2, type.bits) : number; + } else { + bytes[j++] = number & 255; + } return j; } -}; +} -module.exports.BitWriter = BitWriter; -module.exports.BitReader = BitReader; +module.exports = GInt; /***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { +/* 5 */ +/***/ (function(module, exports) { -/** - * float: Functions to work with 16, 32 & 64 bit floats. +/*! + * endianness + * Swap endianness in byte arrays. * Copyright (c) 2017 Rafael da Silva Rocha. - * https://github.com/rochars/byte-data - */ - -const helpers = __webpack_require__(0); - -/** - * Get a binary string representation of a value described as bytes. - * @param {Array|number} bytes The bytes. - * @param {boolean} rev If the bytes should be reversed or not. + * https://github.com/rochars/endianness + * */ -function getBinary(bytes, rev=false) { - let binary = ""; - let i = 0; - let bytesLength = bytes.length; - while(i < bytesLength) { - let bits = helpers.lPadZeros(bytes[i].toString(2), 8); - if (rev) { - binary = binary + bits; - } else { - binary = bits + binary; - } - i++; - } - return binary; -} - -/** - * Turn bytes to a float 16.. - * Thanks https://stackoverflow.com/a/8796597 - * @param {number} bytes 2 bytes representing a float 16. - */ -function decodeFloat16(bytes) { - let binary = parseInt(getBinary(bytes, true), 2); - let exponent = (binary & 0x7C00) >> 10; - let fraction = binary & 0x03FF; - let floatValue; - if (exponent) { - floatValue = Math.pow(2, exponent - 15) * (1 + fraction / 0x400); - } else { - floatValue = 6.103515625e-5 * (fraction / 0x400); - } - return floatValue * (binary >> 15 ? -1 : 1); -} /** - * Turn an array of bytes into a float 64. - * Thanks https://gist.github.com/kg/2192799 - * @param {!Array} bytes 8 bytes representing a float 64. + * Swap the endianness of units of information in a byte array. + * The original array is modified in-place. + * @param {!Array|!Array|Uint8Array} bytes The bytes. + * @param {number} offset The number of bytes of each unit of information. */ -function decodeFloat64(bytes) { - if (bytes.toString() == "0,0,0,0,0,0,0,0") { - return 0; - } - let binary = getBinary(bytes); - let significandBin = "1" + binary.substr(1 + 11, 52); - let val = 1; - let significand = 0; +function endianness(bytes, offset) { + let len = bytes.length; let i = 0; - while (i < significandBin.length) { - significand += val * parseInt(significandBin.charAt(i), 10); - val = val / 2; - i++; - } - let sign = (binary.charAt(0) == "1") ? -1 : 1; - let doubleValue = sign * significand * - Math.pow(2, parseInt(binary.substr(1, 11), 2) - 1023); - return doubleValue; -} - -/** - * Unpack a 64 bit float into two words. - * Thanks https://stackoverflow.com/a/16043259 - * @param {number} value A float64 number. - */ -function toFloat64(value) { - if (value == 0) { - return [0, 0]; - } - let hiWord = 0; - let loWord = 0; - if (value <= 0.0) { - hiWord = 0x80000000; - value = -value; + while (i < len) { + swap(bytes, offset, i); + i += offset; } - let exponent = Math.floor( - Math.log(value) / Math.log(2)); - let significand = Math.floor( - (value / Math.pow(2, exponent)) * Math.pow(2, 52)); - loWord = significand & 0xFFFFFFFF; - significand /= Math.pow(2, 32); - exponent += 1023; - hiWord = hiWord | (exponent << 20); - hiWord = hiWord | (significand & ~(-1 << 20)); - return [hiWord, loWord]; } -let floatView = new Float32Array(1); -let int32View = new Int32Array(floatView.buffer); - /** - * to-half: int bits of half-precision floating point values - * Based on: - * https://mail.mozilla.org/pipermail/es-discuss/2017-April/047994.html - * https://github.com/rochars/byte-data + * Swap the endianness of a unit of information in a byte array. + * The original array is modified in-place. + * @param {!Array|!Array|Uint8Array} bytes The bytes. + * @param {number} offset The number of bytes of the unit of information. + * @param {number} index The start index of the unit of information. */ -function toHalf(val) { - floatView[0] = val; - let x = int32View[0]; - let bits = (x >> 16) & 0x8000; - let m = (x >> 12) & 0x07ff; - let e = (x >> 23) & 0xff; - if (e < 103) { - return bits; +function swap(bytes, offset, index) { + let x = 0; + let y = offset - 1; + let limit = parseInt(offset / 2, 10); + while(x < limit) { + let theByte = bytes[index + x]; + bytes[index + x] = bytes[index + y]; + bytes[index + y] = theByte; + x++; + y--; } - bits |= ((e - 112) << 10) | (m >> 1); - bits += m & 1; - return bits; } -module.exports.decodeFloat16 = decodeFloat16; -module.exports.decodeFloat64 = decodeFloat64; -module.exports.toFloat64 = toFloat64; -module.exports.toHalf = toHalf; +module.exports = endianness; /***/ }) diff --git a/docs/global.html b/docs/global.html index 43c5c82..3d1634c 100644 --- a/docs/global.html +++ b/docs/global.html @@ -1358,7 +1358,7 @@
Returns:

- Documentation generated by JSDoc 3.5.5 on Wed Dec 06 2017 05:29:20 GMT-0200 (Horário brasileiro de verão) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Wed Apr 25 2018 01:05:40 GMT-0300 (Hora oficial do Brasil) using the docdash theme.
diff --git a/docs/index.html b/docs/index.html index e8a9c4b..e38a3c9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -46,8 +46,8 @@

Home

Global

  • -

    riff-chunks

    Read and write the chunks of RIFF and RIFX files.
    Copyright (c) 2017 Rafael da Silva Rocha.
    https://github.com/rochars/riff-chunks

    -

    NPM version Docs JSPerf

    +

    riff-chunks

    Read and write the chunks of RIFF and RIFX files.
    Copyright (c) 2017-2018 Rafael da Silva Rocha.
    https://github.com/rochars/riff-chunks

    +

    NPM version Docs
    Codecov Unix Build Windows Build Scrutinizer

    Install

    npm install riff-chunks

    Use

    const riffChunks = require("riff-chunks");
     const fs = require("fs");
     
    @@ -75,7 +75,7 @@ 

    riffChunks.write()

    LICENSE

    Copyright (c) 2017 Rafael da Silva Rocha.

    +function write(chunks) {}

    LICENSE

    Copyright (c) 2017-2018 Rafael da Silva Rocha.

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including @@ -104,7 +104,7 @@

    riffChunks.write()

    
     
     
    - Documentation generated by JSDoc 3.5.5 on Wed Dec 06 2017 05:29:20 GMT-0200 (Horário brasileiro de verão) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Wed Apr 25 2018 01:05:40 GMT-0300 (Hora oficial do Brasil) using the docdash theme.
    diff --git a/docs/index.js.html b/docs/index.js.html index 13bd99b..d5d1d98 100644 --- a/docs/index.js.html +++ b/docs/index.js.html @@ -185,7 +185,7 @@

    index.js


    - Documentation generated by JSDoc 3.5.5 on Wed Dec 06 2017 05:29:20 GMT-0200 (Horário brasileiro de verão) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Wed Apr 25 2018 01:05:40 GMT-0300 (Hora oficial do Brasil) using the docdash theme.
    diff --git a/package.json b/package.json index 1179a27..f57b534 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "riff-chunks", - "version": "3.0.5", - "description": "Get and set the chunks of RIFF and RIFX files.", + "version": "3.1.0", + "description": "Read and write the chunks of RIFF and RIFX files.", "homepage": "https://github.com/rochars/riff-chunks", "author": "Rafael da Silva Rocha ", "license": "MIT", @@ -12,7 +12,9 @@ "server", "browser", "chunk", - "parser" + "parser", + "read", + "write" ], "repository": { "type": "git", @@ -20,16 +22,18 @@ }, "scripts": { "lint": "jshint index.js && jshint test", - "test": "nyc ./node_modules/mocha/bin/_mocha test --recursive", + "test": "nyc ./node_modules/mocha/bin/_mocha test --src --recursive", + "test-dist": "nyc ./node_modules/mocha/bin/_mocha test --dist --recursive", "coverage": "nyc report --reporter=lcov > coverage.lcov && codecov", "bundle": "webpack", - "compile": "google-closure-compiler-js dist/riff-chunks.js > dist/riff-chunks-min.js --compilationLevel=ADVANCED", + "compile": "google-closure-compiler-js dist/riff-chunks.js > dist/riff-chunks-min.js", "doc": "./node_modules/.bin/jsdoc index.js -d docs -r README.md -t node_modules/docdash", "qa": "npm run lint && npm test", "pack": "npm run bundle && npm run compile && npm run doc", - "build": "npm run qa && npm run pack" + "build": "npm run qa && npm run pack && npm run test-dist" }, "devDependencies": { + "browser-env": "^3.2.4", "codecov": "^3.0.0", "docdash": "^0.4.0", "google-closure-compiler-js": "^20170910.0.1", @@ -43,6 +47,6 @@ }, "main": "index.js", "dependencies": { - "byte-data": "^3.0.1" + "byte-data": "^4.0.2" } } diff --git a/test/RIFF.js b/test/RIFF.js index 7d68194..f49fe2a 100644 --- a/test/RIFF.js +++ b/test/RIFF.js @@ -9,7 +9,8 @@ var assert = require("assert"); describe("riffChunks vs RIFF WAVE: Read file", function() { - const riffChunks = require("../index.js"); + const riffChunks = require("../test/loader.js"); + //const path = require("../test/loader.js").path; const fs = require("fs"); let chunks = riffChunks.read( diff --git a/test/RIFX.js b/test/RIFX.js index 2471a5d..a1cc496 100644 --- a/test/RIFX.js +++ b/test/RIFX.js @@ -9,7 +9,7 @@ var assert = require("assert"); describe("riffChunks vs RIFX WAVE: Read", function() { - const riffChunks = require("../index.js"); + const riffChunks = require("../test/loader.js"); const fs = require("fs"); let chunks = riffChunks.read(fs.readFileSync('./test/files/RIFX-16bit-mono.wav')); diff --git a/test/interface.js b/test/interface.js index 6fca158..6bdc0b8 100644 --- a/test/interface.js +++ b/test/interface.js @@ -8,18 +8,18 @@ var assert = require("assert"); describe("interface", function() { - const riffChunks = require("../index.js"); - + const riffChunks = require("../test/loader.js"); + it("Should have the read() function available", function() { assert.ok(riffChunks.read([])); }); it("Should have the write() function available", function() { assert.ok(riffChunks.write({ - "chunkId": "RIFF", - "chunkSize": 0, - "format": "WAVE", - "subChunks": [] - }) - ); + "chunkId": "RIFF", + "chunkSize": 0, + "format": "WAVE", + "subChunks": [] + }) + ); }); }); diff --git a/test/loader.js b/test/loader.js new file mode 100644 index 0000000..55d7381 --- /dev/null +++ b/test/loader.js @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2017 Rafael da Silva Rocha. + * https://github.com/rochars/byte-data + * + */ + +let riffChunks = require('../index.js'); + +if (process.argv[3] == '--dist') { + require('browser-env')();let assert = require('assert'); + require('../dist/riff-chunks-min.js'); + riffChunks = window.riffChunks; +} + +module.exports = riffChunks;