riff-reader
Version:
RIFF (Resource Interchange File Format) file reader.
106 lines (88 loc) • 2.93 kB
JavaScript
(function() {
// RIFF reader
// @ref https://msdn.microsoft.com/en-us/library/windows/desktop/dd798636(v=vs.85).aspx
var RIFFReader, _, assert, fs,
indexOf = [].indexOf;
assert = require('assert');
fs = require('fs');
_ = require('underscore');
// function(file, formType)
// - file String filepath or content buffer
// - formtype 4 characters id
module.exports = function(file, formType) {
return new RIFFReader(file, formType);
};
RIFFReader = class RIFFReader {
// new RIFFReader(file, formType)
// - file String filepath or content buffer
// - formType 4 characters id
constructor(file, formType) {
var fileSize, header, magic, stat;
fileSize = _.isString(file) ? (this.filepath = file, stat = fs.statSync(file), stat.size) : (this.buf = file, this.buf.length);
this.pos = 0;
header = this._read(12);
magic = header.toString('utf8', 0, 4);
assert.ok(magic === 'RIFF', `Invalid file. magic:${magic}`);
this.fileSize = Math.min((header.readUInt32LE(4)) + 8, fileSize);
this.formType = header.toString('ascii', 8, 12);
assert.ok(this.formType === formType, `Invalid file. form type:${this.formType}`);
}
// readSync(callback, [subscribeIds])
// - callback function(chunkId, data)
// - subscribeIds array of chunk id. *optional
readSync(callback, subscribeIds) {
var remainSize;
// RIFF size of some files has wrong (+1) value
remainSize = this.fileSize - this.pos;
while (remainSize >= 4) {
this._readChunk(callback, subscribeIds);
remainSize = this.fileSize - this.pos;
}
return this;
}
_readChunk(callback, subscribeIds) {
var data, header, id, size;
header = this._read(8);
id = header.toString('ascii', 0, 4);
size = header.readUInt32LE(4);
if (subscribeIds && !(indexOf.call(subscribeIds, id) >= 0)) {
this._skip(size);
} else {
data = this._read(size);
callback.call(this, id, data);
}
if (size & 0x01) {
// skip padding byte for 16bit boundary
this._skip(1);
}
return this;
}
_skip(len) {
this.pos += len;
return this;
}
_read(len) {
if (this.filepath) {
return this._readFile(len);
} else {
return this._readBuffer(len);
}
}
_readFile(len) {
var bytesRead, fd, ret;
ret = Buffer.alloc(len);
fd = fs.openSync(this.filepath, 'r');
bytesRead = fs.readSync(fd, ret, 0, len, this.pos);
fs.closeSync(fd);
assert.ok(bytesRead === len, `File read error. bytesRead:${bytesRead} expected bytes:${len}`);
this.pos += len;
return ret;
}
_readBuffer(len) {
var ret;
ret = this.buf.slice(this.pos, this.pos + len);
this.pos += len;
return ret;
}
};
}).call(this);