'use strict';

var syncInflate = require('../../../../../../_virtual/sync-inflate.js');
var require$$5 = require('assert');
var zlib = require('zlib');
var require$$0$1 = require('util');
var require$$0 = require('buffer');

(function (module, exports) {

	let assert = require$$5.ok;
	let zlib$1 = zlib;
	let util = require$$0$1;

	let kMaxLength = require$$0.kMaxLength;

	function Inflate(opts) {
	  if (!(this instanceof Inflate)) {
	    return new Inflate(opts);
	  }

	  if (opts && opts.chunkSize < zlib$1.Z_MIN_CHUNK) {
	    opts.chunkSize = zlib$1.Z_MIN_CHUNK;
	  }

	  zlib$1.Inflate.call(this, opts);

	  // Node 8 --> 9 compatibility check
	  this._offset = this._offset === undefined ? this._outOffset : this._offset;
	  this._buffer = this._buffer || this._outBuffer;

	  if (opts && opts.maxLength != null) {
	    this._maxLength = opts.maxLength;
	  }
	}

	function createInflate(opts) {
	  return new Inflate(opts);
	}

	function _close(engine, callback) {

	  // Caller may invoke .close after a zlib error (which will null _handle).
	  if (!engine._handle) {
	    return;
	  }

	  engine._handle.close();
	  engine._handle = null;
	}

	Inflate.prototype._processChunk = function (chunk, flushFlag, asyncCb) {
	  if (typeof asyncCb === "function") {
	    return zlib$1.Inflate._processChunk.call(this, chunk, flushFlag, asyncCb);
	  }

	  let self = this;

	  let availInBefore = chunk && chunk.length;
	  let availOutBefore = this._chunkSize - this._offset;
	  let leftToInflate = this._maxLength;
	  let inOff = 0;

	  let buffers = [];
	  let nread = 0;

	  let error;
	  this.on("error", function (err) {
	    error = err;
	  });

	  function handleChunk(availInAfter, availOutAfter) {
	    if (self._hadError) {
	      return;
	    }

	    let have = availOutBefore - availOutAfter;
	    assert(have >= 0, "have should not go down");

	    if (have > 0) {
	      let out = self._buffer.slice(self._offset, self._offset + have);
	      self._offset += have;

	      if (out.length > leftToInflate) {
	        out = out.slice(0, leftToInflate);
	      }

	      buffers.push(out);
	      nread += out.length;
	      leftToInflate -= out.length;

	      if (leftToInflate === 0) {
	        return false;
	      }
	    }

	    if (availOutAfter === 0 || self._offset >= self._chunkSize) {
	      availOutBefore = self._chunkSize;
	      self._offset = 0;
	      self._buffer = Buffer.allocUnsafe(self._chunkSize);
	    }

	    if (availOutAfter === 0) {
	      inOff += availInBefore - availInAfter;
	      availInBefore = availInAfter;

	      return true;
	    }

	    return false;
	  }

	  assert(this._handle, "zlib binding closed");
	  let res;
	  do {
	    res = this._handle.writeSync(
	      flushFlag,
	      chunk, // in
	      inOff, // in_off
	      availInBefore, // in_len
	      this._buffer, // out
	      this._offset, //out_off
	      availOutBefore
	    ); // out_len
	    // Node 8 --> 9 compatibility check
	    res = res || this._writeState;
	  } while (!this._hadError && handleChunk(res[0], res[1]));

	  if (this._hadError) {
	    throw error;
	  }

	  if (nread >= kMaxLength) {
	    _close(this);
	    throw new RangeError(
	      "Cannot create final Buffer. It would be larger than 0x" +
	        kMaxLength.toString(16) +
	        " bytes"
	    );
	  }

	  let buf = Buffer.concat(buffers, nread);
	  _close(this);

	  return buf;
	};

	util.inherits(Inflate, zlib$1.Inflate);

	function zlibBufferSync(engine, buffer) {
	  if (typeof buffer === "string") {
	    buffer = Buffer.from(buffer);
	  }
	  if (!(buffer instanceof Buffer)) {
	    throw new TypeError("Not a string or buffer");
	  }

	  let flushFlag = engine._finishFlushFlag;
	  if (flushFlag == null) {
	    flushFlag = zlib$1.Z_FINISH;
	  }

	  return engine._processChunk(buffer, flushFlag);
	}

	function inflateSync(buffer, opts) {
	  return zlibBufferSync(new Inflate(opts), buffer);
	}

	module.exports = exports = inflateSync;
	exports.Inflate = Inflate;
	exports.createInflate = createInflate;
	exports.inflateSync = inflateSync; 
} (syncInflate.__module, syncInflate.__module.exports));

var syncInflateExports = syncInflate.__module.exports;

exports.syncInflateExports = syncInflateExports;
