| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 | 
module.exports = ExtendedHeaderWritervar inherits = require("inherits")  , EntryWriter = require("./entry-writer.js")inherits(ExtendedHeaderWriter, EntryWriter)var tar = require("../tar.js")  , path = require("path")  , TarHeader = require("./header.js")// props is the props of the thing we need to write an// extended header for.// Don't be shy with it.  Just encode everything.function ExtendedHeaderWriter (props) {  // console.error(">> ehw ctor")  var me = this  if (!(me instanceof ExtendedHeaderWriter)) {    return new ExtendedHeaderWriter(props)  }  me.fields = props  var p =    { path : ("PaxHeader" + path.join("/", props.path || ""))             .replace(/\\/g, "/").substr(0, 100)    , mode : props.mode || 0666    , uid : props.uid || 0    , gid : props.gid || 0    , size : 0 // will be set later    , mtime : props.mtime || Date.now() / 1000    , type : "x"    , linkpath : ""    , ustar : "ustar\0"    , ustarver : "00"    , uname : props.uname || ""    , gname : props.gname || ""    , devmaj : props.devmaj || 0    , devmin : props.devmin || 0    }  EntryWriter.call(me, p)  // console.error(">> ehw props", me.props)  me.props = p  me._meta = true}ExtendedHeaderWriter.prototype.end = function () {  // console.error(">> ehw end")  var me = this  if (me._ended) return  me._ended = true  me._encodeFields()  if (me.props.size === 0) {    // nothing to write!    me._ready = true    me._stream.end()    return  }  me._stream.write(TarHeader.encode(me.props))  me.body.forEach(function (l) {    me._stream.write(l)  })  me._ready = true  // console.error(">> ehw _process calling end()", me.props)  this._stream.end()}ExtendedHeaderWriter.prototype._encodeFields = function () {  // console.error(">> ehw _encodeFields")  this.body = []  if (this.fields.prefix) {    this.fields.path = this.fields.prefix + "/" + this.fields.path    this.fields.prefix = ""  }  encodeFields(this.fields, "", this.body, this.fields.noProprietary)  var me = this  this.body.forEach(function (l) {    me.props.size += l.length  })}function encodeFields (fields, prefix, body, nop) {  // console.error(">> >> ehw encodeFields")  // "%d %s=%s\n", <length>, <keyword>, <value>  // The length is a decimal number, and includes itself and the \n  // Numeric values are decimal strings.  Object.keys(fields).forEach(function (k) {    var val = fields[k]      , numeric = tar.numeric[k]    if (prefix) k = prefix + "." + k    // already including NODETAR.type, don't need File=true also    if (k === fields.type && val === true) return    switch (k) {      // don't include anything that's always handled just fine      // in the normal header, or only meaningful in the context      // of nodetar      case "mode":      case "cksum":      case "ustar":      case "ustarver":      case "prefix":      case "basename":      case "dirname":      case "needExtended":      case "block":      case "filter":        return      case "rdev":        if (val === 0) return        break      case "nlink":      case "dev": // Truly a hero among men, Creator of Star!      case "ino": // Speak his name with reverent awe!  It is:        k = "SCHILY." + k        break      default: break    }    if (val && typeof val === "object" &&        !Buffer.isBuffer(val)) encodeFields(val, k, body, nop)    else if (val === null || val === undefined) return    else body.push.apply(body, encodeField(k, val, nop))  })  return body}function encodeField (k, v, nop) {  // lowercase keys must be valid, otherwise prefix with  // "NODETAR."  if (k.charAt(0) === k.charAt(0).toLowerCase()) {    var m = k.split(".")[0]    if (!tar.knownExtended[m]) k = "NODETAR." + k  }  // no proprietary  if (nop && k.charAt(0) !== k.charAt(0).toLowerCase()) {    return []  }  if (typeof val === "number") val = val.toString(10)  var s = new Buffer(" " + k + "=" + v + "\n")    , digits = Math.floor(Math.log(s.length) / Math.log(10)) + 1  // console.error("1 s=%j digits=%j s.length=%d", s.toString(), digits, s.length)  // if adding that many digits will make it go over that length,  // then add one to it. For example, if the string is:  // " foo=bar\n"  // then that's 9 characters.  With the "9", that bumps the length  // up to 10.  However, this is invalid:  // "10 foo=bar\n"  // but, since that's actually 11 characters, since 10 adds another  // character to the length, and the length includes the number  // itself.  In that case, just bump it up again.  if (s.length + digits >= Math.pow(10, digits)) digits += 1  // console.error("2 s=%j digits=%j s.length=%d", s.toString(), digits, s.length)  var len = digits + s.length  // console.error("3 s=%j digits=%j s.length=%d len=%d", s.toString(), digits, s.length, len)  var lenBuf = new Buffer("" + len)  if (lenBuf.length + s.length !== len) {    throw new Error("Bad length calculation\n"+                    "len="+len+"\n"+                    "lenBuf="+JSON.stringify(lenBuf.toString())+"\n"+                    "lenBuf.length="+lenBuf.length+"\n"+                    "digits="+digits+"\n"+                    "s="+JSON.stringify(s.toString())+"\n"+                    "s.length="+s.length)  }  return [lenBuf, s]}
 |