mirror of
				https://github.com/crazy-max/ghaction-upx.git
				synced 2025-11-04 04:58:11 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			259 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var util = require('util')
 | 
						|
var bl = require('bl')
 | 
						|
var xtend = require('xtend')
 | 
						|
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)
 | 
						|
}
 | 
						|
 | 
						|
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 = xtend(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)
 | 
						|
    } 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
 |