// An Entry consisting of: // // "%d %s=%s\n", , , // // The length is a decimal number, and includes itself and the \n // \0 does not terminate anything. Only the length terminates the string. // Numeric values are decimal strings. module.exports = ExtendedHeader var Entry = require("./entry.js") , inherits = require("inherits") , tar = require("../tar.js") , numeric = tar.numeric , keyTrans = { "SCHILY.dev": "dev" , "SCHILY.ino": "ino" , "SCHILY.nlink": "nlink" } function ExtendedHeader () { Entry.apply(this, arguments) this.on("data", this._parse) this.fields = {} this._position = 0 this._fieldPos = 0 this._state = SIZE this._sizeBuf = [] this._keyBuf = [] this._valBuf = [] this._size = -1 this._key = "" } inherits(ExtendedHeader, Entry) ExtendedHeader.prototype._parse = parse var s = 0 , states = ExtendedHeader.states = {} , SIZE = states.SIZE = s++ , KEY = states.KEY = s++ , VAL = states.VAL = s++ , ERR = states.ERR = s++ Object.keys(states).forEach(function (s) { states[states[s]] = states[s] }) states[s] = null // char code values for comparison var _0 = "0".charCodeAt(0) , _9 = "9".charCodeAt(0) , point = ".".charCodeAt(0) , a = "a".charCodeAt(0) , Z = "Z".charCodeAt(0) , a = "a".charCodeAt(0) , z = "z".charCodeAt(0) , space = " ".charCodeAt(0) , eq = "=".charCodeAt(0) , cr = "\n".charCodeAt(0) function parse (c) { if (this._state === ERR) return for ( var i = 0, l = c.length ; i < l ; this._position++, this._fieldPos++, i++) { // console.error("top of loop, size="+this._size) var b = c[i] if (this._size >= 0 && this._fieldPos > this._size) { error(this, "field exceeds length="+this._size) return } switch (this._state) { case ERR: return case SIZE: // console.error("parsing size, b=%d, rest=%j", b, c.slice(i).toString()) if (b === space) { this._state = KEY // this._fieldPos = this._sizeBuf.length this._size = parseInt(new Buffer(this._sizeBuf).toString(), 10) this._sizeBuf.length = 0 continue } if (b < _0 || b > _9) { error(this, "expected [" + _0 + ".." + _9 + "], got " + b) return } this._sizeBuf.push(b) continue case KEY: // can be any char except =, not > size. if (b === eq) { this._state = VAL this._key = new Buffer(this._keyBuf).toString() if (keyTrans[this._key]) this._key = keyTrans[this._key] this._keyBuf.length = 0 continue } this._keyBuf.push(b) continue case VAL: // field must end with cr if (this._fieldPos === this._size - 1) { // console.error("finished with "+this._key) if (b !== cr) { error(this, "expected \\n at end of field") return } var val = new Buffer(this._valBuf).toString() if (numeric[this._key]) { val = parseFloat(val) } this.fields[this._key] = val this._valBuf.length = 0 this._state = SIZE this._size = -1 this._fieldPos = -1 continue } this._valBuf.push(b) continue } } } function error (me, msg) { msg = "invalid header: " + msg + "\nposition=" + me._position + "\nfield position=" + me._fieldPos me.error(msg) me.state = ERR }