extended-header.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // An Entry consisting of:
  2. //
  3. // "%d %s=%s\n", <length>, <keyword>, <value>
  4. //
  5. // The length is a decimal number, and includes itself and the \n
  6. // \0 does not terminate anything. Only the length terminates the string.
  7. // Numeric values are decimal strings.
  8. module.exports = ExtendedHeader
  9. var Entry = require("./entry.js")
  10. , inherits = require("inherits")
  11. , tar = require("../tar.js")
  12. , numeric = tar.numeric
  13. , keyTrans = { "SCHILY.dev": "dev"
  14. , "SCHILY.ino": "ino"
  15. , "SCHILY.nlink": "nlink" }
  16. function ExtendedHeader () {
  17. Entry.apply(this, arguments)
  18. this.on("data", this._parse)
  19. this.fields = {}
  20. this._position = 0
  21. this._fieldPos = 0
  22. this._state = SIZE
  23. this._sizeBuf = []
  24. this._keyBuf = []
  25. this._valBuf = []
  26. this._size = -1
  27. this._key = ""
  28. }
  29. inherits(ExtendedHeader, Entry)
  30. ExtendedHeader.prototype._parse = parse
  31. var s = 0
  32. , states = ExtendedHeader.states = {}
  33. , SIZE = states.SIZE = s++
  34. , KEY = states.KEY = s++
  35. , VAL = states.VAL = s++
  36. , ERR = states.ERR = s++
  37. Object.keys(states).forEach(function (s) {
  38. states[states[s]] = states[s]
  39. })
  40. states[s] = null
  41. // char code values for comparison
  42. var _0 = "0".charCodeAt(0)
  43. , _9 = "9".charCodeAt(0)
  44. , point = ".".charCodeAt(0)
  45. , a = "a".charCodeAt(0)
  46. , Z = "Z".charCodeAt(0)
  47. , a = "a".charCodeAt(0)
  48. , z = "z".charCodeAt(0)
  49. , space = " ".charCodeAt(0)
  50. , eq = "=".charCodeAt(0)
  51. , cr = "\n".charCodeAt(0)
  52. function parse (c) {
  53. if (this._state === ERR) return
  54. for ( var i = 0, l = c.length
  55. ; i < l
  56. ; this._position++, this._fieldPos++, i++) {
  57. // console.error("top of loop, size="+this._size)
  58. var b = c[i]
  59. if (this._size >= 0 && this._fieldPos > this._size) {
  60. error(this, "field exceeds length="+this._size)
  61. return
  62. }
  63. switch (this._state) {
  64. case ERR: return
  65. case SIZE:
  66. // console.error("parsing size, b=%d, rest=%j", b, c.slice(i).toString())
  67. if (b === space) {
  68. this._state = KEY
  69. // this._fieldPos = this._sizeBuf.length
  70. this._size = parseInt(new Buffer(this._sizeBuf).toString(), 10)
  71. this._sizeBuf.length = 0
  72. continue
  73. }
  74. if (b < _0 || b > _9) {
  75. error(this, "expected [" + _0 + ".." + _9 + "], got " + b)
  76. return
  77. }
  78. this._sizeBuf.push(b)
  79. continue
  80. case KEY:
  81. // can be any char except =, not > size.
  82. if (b === eq) {
  83. this._state = VAL
  84. this._key = new Buffer(this._keyBuf).toString()
  85. if (keyTrans[this._key]) this._key = keyTrans[this._key]
  86. this._keyBuf.length = 0
  87. continue
  88. }
  89. this._keyBuf.push(b)
  90. continue
  91. case VAL:
  92. // field must end with cr
  93. if (this._fieldPos === this._size - 1) {
  94. // console.error("finished with "+this._key)
  95. if (b !== cr) {
  96. error(this, "expected \\n at end of field")
  97. return
  98. }
  99. var val = new Buffer(this._valBuf).toString()
  100. if (numeric[this._key]) {
  101. val = parseFloat(val)
  102. }
  103. this.fields[this._key] = val
  104. this._valBuf.length = 0
  105. this._state = SIZE
  106. this._size = -1
  107. this._fieldPos = -1
  108. continue
  109. }
  110. this._valBuf.push(b)
  111. continue
  112. }
  113. }
  114. }
  115. function error (me, msg) {
  116. msg = "invalid header: " + msg
  117. + "\nposition=" + me._position
  118. + "\nfield position=" + me._fieldPos
  119. me.error(msg)
  120. me.state = ERR
  121. }