Li-Fan Chen says to OwO
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Types * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ var typeFields = ['name' , 'structure', 'format' , 'size']; var types = exports.types = [ ['end' , null , null , null ], ['byte' , 'word' , 'Int8' , 1 ], ['short' , 'word' , 'Int16BE' , 2 ], ['int' , 'word' , 'Int32BE' , 4 ], ['long' , 'list' , 'int' , 2 ], ['float' , 'word' , 'FloatBE' , 4 ], ['double' , 'word' , 'DoubleBE', 8 ], ['byteArray', 'list' , 'byte' , null ], ['string' , null , null , null ], ['list' , 'list' , null , null ], ['compound' , null , null , null ], ['intArray' , 'list' , 'int' , null ] ]; types.forEach(function(typeData, typeIndex) { var type = { value: typeIndex }; typeFields.forEach(function(propertyName, propertyIndex) { type[propertyName] = typeData[propertyIndex]; }); types[type.value] = types[type.name] = type; }); types.fromSchema = function(schema) { return typeof schema === 'string' ? types[schema] : (Array.isArray(schema) ? types.list : types.compound); }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Reader * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ var Reader = exports.Reader = function(buffer) { this.buffer = buffer; this.offset = 0; }; function read(reader, object) { var type = types[reader.byte().payload]; if (type !== types.end) { var name = reader.string().payload; var result = reader[type.name](); object.schema[name] = result.schema; object.payload[name] = result.payload; } return type; } types.forEach(function(type) { switch(type.structure) { case 'word': Reader.prototype[type.name] = function() { var word = this.buffer['read' + type.format](this.offset); this.offset += type.size; return { schema: type.name, payload: word }; }; break; case 'list': var isList = type === types.list; Reader.prototype[type.name] = function() { var typeName = type.format || types[this.byte().payload].name; var result = { schema: isList ? [ typeName ] : type.name, payload: [] }; var length = type.size || this.int().payload; for (var i = 0; i < length; i++) { var element = this[typeName](); if (isList) { result.schema = [ element.schema ]; } result.payload.push(element.payload); } return result; }; break; } }); Reader.prototype[types.string.name] = function() { var length = this.short().payload; return new Object ({ schema: types.string.name, payload: this.buffer.toString('utf8', this.offset, this.offset += length) }); }; Reader.prototype[types.compound.name] = function() { var result = { schema: {}, payload: {} }; while (read(this, result) !== types.end); return result; }; exports.read = function(buffer) { var result = { schema: {}, payload: {} }; read(new Reader(buffer), result); return result; };