Skip to content

Commit

Permalink
Merge pull request #20 from dertseha/flac-ignoredLastBlock
Browse files Browse the repository at this point in the history
Flac ignored last block
  • Loading branch information
leetreveil committed Apr 6, 2013
2 parents e32a5c9 + 2891017 commit ad31175
Showing 1 changed file with 115 additions and 59 deletions.
174 changes: 115 additions & 59 deletions lib/flac.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,123 @@
/* jshint node:true, sub:true, globalstrict:true */
"use strict";

var util = require('util');
var events = require('events');
var strtok = require('strtok');
var fs = require('fs');
var common = require('./common');

var DataDecoder = function(data) {
this.data = data;
this.offset = 0;
};

DataDecoder.prototype.readInt32 = function() {
var value = strtok.UINT32_LE.get(this.data, this.offset);

this.offset += 4;

return value;
};

DataDecoder.prototype.readStringUtf8 = function() {
var len = this.readInt32();
var value = this.data.toString('utf8', this.offset, this.offset + len);

this.offset += len;

return value;
};

var finishedState = {
parse: function(context) {
return this;
},
getExpectedType: function() {
return strtok.DONE;
}
};

var BlockDataState = function(type, length, nextStateFactory) {
this.type = type;
this.length = length;
this.nextStateFactory = nextStateFactory;
};

BlockDataState.prototype.parse = function(context, data) {
if (this.type === 4) {
var decoder = new DataDecoder(data);
var vendorString = decoder.readStringUtf8();
var commentListLength = decoder.readInt32();
var comment;
var split;
var i;

for (i = 0; i < commentListLength; i++) {
comment = decoder.readStringUtf8();
split = comment.split('=');
context.emit(split[0].toUpperCase(), split[1]);
}
} else if (this.type === 6) {
var picture = common.readVorbisPicture(data);
context.emit('METADATA_BLOCK_PICTURE', picture);
}

return this.nextStateFactory();
};

BlockDataState.prototype.getExpectedType = function() {
return new strtok.BufferType(this.length);
};

var blockHeaderState = {
parse: function(context, data) {
var header = {
lastBlock: (data[0] & 0x80) == 0x80,
type: data[0] & 0x7f,
length: strtok.UINT24_BE.get(data, 1)
};
var followingStateFactory = header.lastBlock ? function() {
context.emit('done');
return finishedState;
} : function() {
return blockHeaderState;
};

return new BlockDataState(header.type, header.length, followingStateFactory);
},
getExpectedType: function() {
return new strtok.BufferType(4);
}
};

var idState = {
parse: function(context, data) {
if (data !== 'fLaC') {
throw new Error('expected flac header but was not found');
}

return blockHeaderState;
},
getExpectedType: function() {
return new strtok.StringType(4);
}
};

var startState = {
parse: function(context) {
return idState;
},
getExpectedType: function() {
return strtok.DONE;
}
};

var Flac = module.exports = function(stream) {
events.EventEmitter.call(this);
this.stream = stream;

this.currentState = startState;

this.parse();
};

Expand All @@ -17,66 +128,11 @@ Flac.prototype.parse = function() {

strtok.parse(self.stream, function(v, cb) {
try {
if (!v) {
cb.position = 'ID';
return new strtok.StringType(4);
}

if (cb.position === 'ID') {
if (v !== 'fLaC') {
throw new Error('expected flac header but was not found');
}

cb.position = 'METADATA_BLOCK_HEADER';
return new strtok.BufferType(4);
}

if (cb.position === 'METADATA_BLOCK_HEADER') {
cb.blockHeader = {
last_metadata_block: (v[0] & 0x80) == 0x80,
block_type: v[0] & 0x7f,
length: strtok.UINT24_BE.get(v, 1)
}

if (cb.blockHeader.last_metadata_block) {
self.emit('done');
return strtok.DONE;
}

cb.position = 'METADATA_BLOCK_DATA';
return new strtok.BufferType(cb.blockHeader.length);
}

if (cb.position === 'METADATA_BLOCK_DATA') {
if (cb.blockHeader.block_type === 4) {
var offset = 0;
var vendorLen = strtok.UINT32_LE.get(v, offset);
offset += 4;
var vendorString = v.toString('utf8', offset, offset += vendorLen);
var commentListLength = strtok.UINT32_LE.get(v, offset);
offset += 4;

for (var i = 0; i < commentListLength; i++) {
var len = strtok.UINT32_LE.get(v, offset);
offset += 4;
var comment = v.toString('utf8', offset, offset += len);
var split = comment.split('=');
self.emit(split[0].toUpperCase(), split[1]);
}
}
if (cb.blockHeader.block_type === 6) {
var picture = common.readVorbisPicture(v);
self.emit('METADATA_BLOCK_PICTURE', picture);
}

cb.position = 'METADATA_BLOCK_HEADER';
return new strtok.BufferType(4);
}


self.currentState = self.currentState.parse(self, v);
} catch (exception) {
self.currentState = finishedState;
self.emit('done', exception);
return strtok.DONE;
}
return self.currentState.getExpectedType();
});
};

0 comments on commit ad31175

Please sign in to comment.