| var util = require('util') | |
| var bl = require('bl') | |
| var headers = require('./headers') | |
| var Writable = require('readable-stream').Writable | |
| var PassThrough = require('readable-stream').PassThrough | |
| var noop = function () {} | |
| var overflow = function (size) { | |
| size &= 511 | |
| return size && 512 - size | |
| } | |
| var emptyStream = function (self, offset) { | |
| var s = new Source(self, offset) | |
| s.end() | |
| return s | |
| } | |
| var mixinPax = function (header, pax) { | |
| if (pax.path) header.name = pax.path | |
| if (pax.linkpath) header.linkname = pax.linkpath | |
| if (pax.size) header.size = parseInt(pax.size, 10) | |
| header.pax = pax | |
| return header | |
| } | |
| var Source = function (self, offset) { | |
| this._parent = self | |
| this.offset = offset | |
| PassThrough.call(this, { autoDestroy: false }) | |
| } | |
| util.inherits(Source, PassThrough) | |
| Source.prototype.destroy = function (err) { | |
| this._parent.destroy(err) | |
| } | |
| var Extract = function (opts) { | |
| if (!(this instanceof Extract)) return new Extract(opts) | |
| Writable.call(this, opts) | |
| opts = opts || {} | |
| this._offset = 0 | |
| this._buffer = bl() | |
| this._missing = 0 | |
| this._partial = false | |
| this._onparse = noop | |
| this._header = null | |
| this._stream = null | |
| this._overflow = null | |
| this._cb = null | |
| this._locked = false | |
| this._destroyed = false | |
| this._pax = null | |
| this._paxGlobal = null | |
| this._gnuLongPath = null | |
| this._gnuLongLinkPath = null | |
| var self = this | |
| var b = self._buffer | |
| var oncontinue = function () { | |
| self._continue() | |
| } | |
| var onunlock = function (err) { | |
| self._locked = false | |
| if (err) return self.destroy(err) | |
| if (!self._stream) oncontinue() | |
| } | |
| var onstreamend = function () { | |
| self._stream = null | |
| var drain = overflow(self._header.size) | |
| if (drain) self._parse(drain, ondrain) | |
| else self._parse(512, onheader) | |
| if (!self._locked) oncontinue() | |
| } | |
| var ondrain = function () { | |
| self._buffer.consume(overflow(self._header.size)) | |
| self._parse(512, onheader) | |
| oncontinue() | |
| } | |
| var onpaxglobalheader = function () { | |
| var size = self._header.size | |
| self._paxGlobal = headers.decodePax(b.slice(0, size)) | |
| b.consume(size) | |
| onstreamend() | |
| } | |
| var onpaxheader = function () { | |
| var size = self._header.size | |
| self._pax = headers.decodePax(b.slice(0, size)) | |
| if (self._paxGlobal) self._pax = Object.assign({}, self._paxGlobal, self._pax) | |
| b.consume(size) | |
| onstreamend() | |
| } | |
| var ongnulongpath = function () { | |
| var size = self._header.size | |
| this._gnuLongPath = headers.decodeLongPath(b.slice(0, size), opts.filenameEncoding) | |
| b.consume(size) | |
| onstreamend() | |
| } | |
| var ongnulonglinkpath = function () { | |
| var size = self._header.size | |
| this._gnuLongLinkPath = headers.decodeLongPath(b.slice(0, size), opts.filenameEncoding) | |
| b.consume(size) | |
| onstreamend() | |
| } | |
| var onheader = function () { | |
| var offset = self._offset | |
| var header | |
| try { | |
| header = self._header = headers.decode(b.slice(0, 512), opts.filenameEncoding, opts.allowUnknownFormat) | |
| } catch (err) { | |
| self.emit('error', err) | |
| } | |
| b.consume(512) | |
| if (!header) { | |
| self._parse(512, onheader) | |
| oncontinue() | |
| return | |
| } | |
| if (header.type === 'gnu-long-path') { | |
| self._parse(header.size, ongnulongpath) | |
| oncontinue() | |
| return | |
| } | |
| if (header.type === 'gnu-long-link-path') { | |
| self._parse(header.size, ongnulonglinkpath) | |
| oncontinue() | |
| return | |
| } | |
| if (header.type === 'pax-global-header') { | |
| self._parse(header.size, onpaxglobalheader) | |
| oncontinue() | |
| return | |
| } | |
| if (header.type === 'pax-header') { | |
| self._parse(header.size, onpaxheader) | |
| oncontinue() | |
| return | |
| } | |
| if (self._gnuLongPath) { | |
| header.name = self._gnuLongPath | |
| self._gnuLongPath = null | |
| } | |
| if (self._gnuLongLinkPath) { | |
| header.linkname = self._gnuLongLinkPath | |
| self._gnuLongLinkPath = null | |
| } | |
| if (self._pax) { | |
| self._header = header = mixinPax(header, self._pax) | |
| self._pax = null | |
| } | |
| self._locked = true | |
| if (!header.size || header.type === 'directory') { | |
| self._parse(512, onheader) | |
| self.emit('entry', header, emptyStream(self, offset), onunlock) | |
| return | |
| } | |
| self._stream = new Source(self, offset) | |
| self.emit('entry', header, self._stream, onunlock) | |
| self._parse(header.size, onstreamend) | |
| oncontinue() | |
| } | |
| this._onheader = onheader | |
| this._parse(512, onheader) | |
| } | |
| util.inherits(Extract, Writable) | |
| Extract.prototype.destroy = function (err) { | |
| if (this._destroyed) return | |
| this._destroyed = true | |
| if (err) this.emit('error', err) | |
| this.emit('close') | |
| if (this._stream) this._stream.emit('close') | |
| } | |
| Extract.prototype._parse = function (size, onparse) { | |
| if (this._destroyed) return | |
| this._offset += size | |
| this._missing = size | |
| if (onparse === this._onheader) this._partial = false | |
| this._onparse = onparse | |
| } | |
| Extract.prototype._continue = function () { | |
| if (this._destroyed) return | |
| var cb = this._cb | |
| this._cb = noop | |
| if (this._overflow) this._write(this._overflow, undefined, cb) | |
| else cb() | |
| } | |
| Extract.prototype._write = function (data, enc, cb) { | |
| if (this._destroyed) return | |
| var s = this._stream | |
| var b = this._buffer | |
| var missing = this._missing | |
| if (data.length) this._partial = true | |
| // we do not reach end-of-chunk now. just forward it | |
| if (data.length < missing) { | |
| this._missing -= data.length | |
| this._overflow = null | |
| if (s) return s.write(data, cb) | |
| b.append(data) | |
| return cb() | |
| } | |
| // end-of-chunk. the parser should call cb. | |
| this._cb = cb | |
| this._missing = 0 | |
| var overflow = null | |
| if (data.length > missing) { | |
| overflow = data.slice(missing) | |
| data = data.slice(0, missing) | |
| } | |
| if (s) s.end(data) | |
| else b.append(data) | |
| this._overflow = overflow | |
| this._onparse() | |
| } | |
| Extract.prototype._final = function (cb) { | |
| if (this._partial) return this.destroy(new Error('Unexpected end of data')) | |
| cb() | |
| } | |
| module.exports = Extract | |
Xet Storage Details
- Size:
- 5.96 kB
- Xet hash:
- ceb0df6798055db45219f5e5daffd399fe8e251325de1ca0743f6b6cafe2a2d3
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.