You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
3.5 KiB
140 lines
3.5 KiB
// An Entry consisting of: |
|
// |
|
// "%d %s=%s\n", <length>, <keyword>, <value> |
|
// |
|
// 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 |
|
}
|
|
|