'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.readFromBufferP = exports.readFromBuffer = undefined;

var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); /**
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          * Simple module for reading SWF properties
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          *
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          * (c) 2014 Rafael Leal Dias <rafaeldias.c at gmail dot com>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          * MIT LICENCE
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          *
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          */


var _tagReaders = require('./tag-readers');

Object.keys(_tagReaders).forEach(function (key) {
  if (key === "default" || key === "__esModule") return;
  Object.defineProperty(exports, key, {
    enumerable: true,
    get: function get() {
      return _tagReaders[key];
    }
  });
});

var _swfTags = require('./swf-tags');

Object.keys(_swfTags).forEach(function (key) {
  if (key === "default" || key === "__esModule") return;
  Object.defineProperty(exports, key, {
    enumerable: true,
    get: function get() {
      return _swfTags[key];
    }
  });
});

var _extractImages = require('./extract-images');

Object.keys(_extractImages).forEach(function (key) {
  if (key === "default" || key === "__esModule") return;
  Object.defineProperty(exports, key, {
    enumerable: true,
    get: function get() {
      return _extractImages[key];
    }
  });
});

var _extractSounds = require('./extract-sounds');

Object.keys(_extractSounds).forEach(function (key) {
  if (key === "default" || key === "__esModule") return;
  Object.defineProperty(exports, key, {
    enumerable: true,
    get: function get() {
      return _extractSounds[key];
    }
  });
});

var _zlib = require('zlib');

var _zlib2 = _interopRequireDefault(_zlib);

var _lzmaPurejs = require('lzma-purejs');

var _lzmaPurejs2 = _interopRequireDefault(_lzmaPurejs);

var _stream = require('stream');

var _stream2 = _interopRequireDefault(_stream);

var _swfBuffer = require('./swf-buffer');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var readSWFTags = function readSWFTags(buff, callbacks) {
  var _loop = function _loop() {
    var _buff$readTagCodeAndL = buff.readTagCodeAndLength(),
        code = _buff$readTagCodeAndL.code,
        length = _buff$readTagCodeAndL.length;

    var pos = buff.pointer;
    setTimeout(function () {
      return callbacks.tag(code, length, buff.buffer, pos);
    });
    buff.incr(length);
  };

  while (buff.pointer < buff.buffer.length) {
    _loop();
  }
  setTimeout(function () {
    return callbacks.done();
  });
};

/**
 * Reads tags and their contents, passing a SWF object to callback
 *
 * @param {SWFBuffer} buff
 * @param {Buffer} compressed_buff
 * @api private
 *
 */
var readSWFBuff = function readSWFBuff(buff, compressedBuff, callbacks) {
  // skipping magic numbers
  buff.seek(3);

  var swf = {
    version: buff.readUInt8(),
    fileLength: {
      compressed: compressedBuff.length,
      uncompressed: buff.readUIntLE(32)
    },
    // Returns a RECT object. i.e : { x : 0, y : 0, width : 200, height: 300 }
    frameSize: buff.readRect(),
    frameRate: buff.readUIntLE(16) / 256,
    frameCount: buff.readUIntLE(16)
  };
  setTimeout(function () {
    return callbacks.header(swf);
  });
  readSWFTags(buff, callbacks);
};

/**
 * Uncompress SWF and start reading it
 *
 * @param {Buffer} swf
 *
 */
var uncompress = function uncompress(swf, callbacks) {
  var _swf = _slicedToArray(swf, 1),
      swfType = _swf[0];
  // uncompressed


  if (swfType === 0x46) {
    return readSWFBuff(new _swfBuffer.SWFBuffer(swf), swf, callbacks);
  }
  // zlib compressed
  if (swfType === 0x43) {
    var compressedBuff = swf.slice(8);
    var uncompressedBuff = Buffer.concat([swf.slice(0, 8), _zlib2.default.unzipSync(compressedBuff,
    /*
        suppress default error handling in case the file is truncated
        ref: https://nodejs.org/api/zlib.html as of Jan 03, 2018
      */
    { finishFlush: _zlib2.default.constants.Z_SYNC_FLUSH })]);
    return readSWFBuff(new _swfBuffer.SWFBuffer(uncompressedBuff), swf, callbacks);
  }

  // lzma compressed
  if (swfType === 0x5a) {
    /*
       reference: https://helpx.adobe.com/flash-player/kb/exception-thrown-you-decompress-lzma-compressed.html
        - 0~3: ZWS + version
       - 4~7: Uncompressed length
       - 8~11: Compressed length bytes
       - 12~16: LZMA properties
       - 17~: Compressed data
     */

    var _compressedBuff = swf.slice(17);
    var lzmaProperties = swf.slice(12, 16 + 1);
    var uncompressedLenBuff = swf.slice(4, 7 + 1);
    /* eslint-disable no-bitwise */
    var uncompressedLength = uncompressedLenBuff[0] + (uncompressedLenBuff[1] << 8) + (uncompressedLenBuff[2] << 16) + (uncompressedLenBuff[3] << 24) - 8;
    /* eslint-enable no-bitwise */

    /*
    // this part works with
    // but it's just too slow to be useful
    const lzma2 = require('lzma')
      const recompressLenBuff = Buffer.alloc(8,0)
    recompressLenBuff[0] = uncompressedLength & 0xFF
    recompressLenBuff[1] = (uncompressedLength >> 8) & 0xFF
    recompressLenBuff[2] = (uncompressedLength >> 16) & 0xFF
    recompressLenBuff[3] = (uncompressedLength >> 24) & 0xFF
    const lzmaData = Buffer.concat([lzmaProperties,recompressLenBuff,compressedBuff])
      if (true) {
      const uncompressedBuff = Buffer.from(lzma2.decompress(lzmaData))
      return readSWFBuff(new SWFBuffer(uncompressedBuff), swf, callbacks)
    }
     */

    var inputStream = new _stream2.default();

    {
      var _pos = 0;
      inputStream.readByte = function () {
        if (_pos < _compressedBuff.length) {
          var v = _compressedBuff[_pos];
          ++_pos;
          return v;
        } else {
          return -1;
        }
      };
    }

    var outputStream = new _stream2.default();

    {
      var buffer = new Buffer(uncompressedLength);
      var _pos2 = 0;

      outputStream.writeByte = function (_byte) {
        buffer[_pos2] = _byte;
        ++_pos2;
      };

      outputStream.getBuffer = function () {
        return _pos2 !== buffer.length ? buffer.slice(0, _pos2) : buffer;
      };
    }

    _lzmaPurejs2.default.decompress(lzmaProperties, inputStream, outputStream, -1);
    var _uncompressedBuff = Buffer.concat([swf.slice(0, 8), outputStream.getBuffer()]);
    return readSWFBuff(new _swfBuffer.SWFBuffer(_uncompressedBuff), swf, callbacks);
  }

  setTimeout(function () {
    return callbacks.error(new Error('Unknown SWF compression type: ' + swfType));
  });
};

/*
   callbacks:

   error(e)

   header(swf)
   tag(code,length,buffer,pos)
   done()

 */
var readFromBuffer = function readFromBuffer(buffer, callbacks) {
  if (!Buffer.isBuffer(buffer)) throw new Error('expecting a buffer');

  return uncompress(buffer, callbacks);
};

var readFromBufferP = function readFromBufferP(buffer) {
  return new Promise(function (resolve, reject) {
    var data = { tags: [] };
    readFromBuffer(buffer, {
      error: function error(e) {
        return reject(e);
      },
      header: function header(swf) {
        return Object.assign(data, swf);
      },
      tag: function tag(code, length, swfBuf, pos) {
        var tag = {
          code: code, length: length,
          rawData: Buffer.from(swfBuf.buffer, pos, length)
        };
        data.tags.push(tag);
      },
      done: function done() {
        return resolve(data);
      }
    });
  });
};

exports.readFromBuffer = readFromBuffer;
exports.readFromBufferP = readFromBufferP;