itdcole

VF JSZip #1

Sep 4th, 2016
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  
  3. JSZip - A Javascript class for generating and reading zip files
  4. <http://stuartk.com/jszip>
  5.  
  6. (c) 2009-2012 Stuart Knightley <stuart [at] stuartk.com>
  7. Dual licenced under the MIT license or GPLv3. See LICENSE.markdown.
  8.  
  9. Usage:
  10.    zip = new JSZip();
  11.    zip.file("hello.txt", "Hello, World!").file("tempfile", "nothing");
  12.    zip.folder("images").file("smile.gif", base64Data, {base64: true});
  13.    zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")});
  14.    zip.remove("tempfile");
  15.  
  16.    base64zip = zip.generate();
  17.  
  18. **/
  19. // We use strict, but it should not be placed outside of a function because
  20. // the environment is shared inside the browser.
  21. // "use strict";
  22.  
  23. /**
  24.  * Representation a of zip file in js
  25.  * @constructor
  26.  * @param {String=|ArrayBuffer=|Uint8Array=|Buffer=} data the data to load, if any (optional).
  27.  * @param {Object=} options the options for creating this objects (optional).
  28.  */
  29. var JSZip = function(data, options) {
  30.    // object containing the files :
  31.    // {
  32.    //   "folder/" : {...},
  33.    //   "folder/data.txt" : {...}
  34.    // }
  35.    this.files = {};
  36.  
  37.    // Where we are in the hierarchy
  38.    this.root = "";
  39.  
  40.    if (data) {
  41.       this.load(data, options);
  42.    }
  43. };
  44.  
  45. JSZip.signature = {
  46.    LOCAL_FILE_HEADER : "\x50\x4b\x03\x04",
  47.    CENTRAL_FILE_HEADER : "\x50\x4b\x01\x02",
  48.    CENTRAL_DIRECTORY_END : "\x50\x4b\x05\x06",
  49.    ZIP64_CENTRAL_DIRECTORY_LOCATOR : "\x50\x4b\x06\x07",
  50.    ZIP64_CENTRAL_DIRECTORY_END : "\x50\x4b\x06\x06",
  51.    DATA_DESCRIPTOR : "\x50\x4b\x07\x08"
  52. };
  53.  
  54. // Default properties for a new file
  55. JSZip.defaults = {
  56.    base64: false,
  57.    binary: false,
  58.    dir: false,
  59.    date: null,
  60.    compression: null
  61. };
  62.  
  63. /*
  64.  * List features that require a modern browser, and if the current browser support them.
  65.  */
  66. JSZip.support = {
  67.    // contains true if JSZip can read/generate ArrayBuffer, false otherwise.
  68.    arraybuffer : (function(){
  69.       return typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined";
  70.    })(),
  71.    // contains true if JSZip can read/generate nodejs Buffer, false otherwise.
  72.    nodebuffer : (function(){
  73.       return typeof Buffer !== "undefined";
  74.    })(),
  75.    // contains true if JSZip can read/generate Uint8Array, false otherwise.
  76.    uint8array : (function(){
  77.       return typeof Uint8Array !== "undefined";
  78.    })(),
  79.    // contains true if JSZip can read/generate Blob, false otherwise.
  80.    blob : (function(){
  81.       // the spec started with BlobBuilder then replaced it with a construtor for Blob.
  82.       // Result : we have browsers that :
  83.       // * know the BlobBuilder (but with prefix)
  84.       // * know the Blob constructor
  85.       // * know about Blob but not about how to build them
  86.       // About the "=== 0" test : if given the wrong type, it may be converted to a string.
  87.       // Instead of an empty content, we will get "[object Uint8Array]" for example.
  88.       if (typeof ArrayBuffer === "undefined") {
  89.          return false;
  90.       }
  91.       var buffer = new ArrayBuffer(0);
  92.       try {
  93.          return new Blob([buffer], { type: "application/zip" }).size === 0;
  94.       }
  95.       catch(e) {}
  96.  
  97.       try {
  98.          var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
  99.          var builder = new BlobBuilder();
  100.          builder.append(buffer);
  101.          return builder.getBlob('application/zip').size === 0;
  102.       }
  103.       catch(e) {}
  104.  
  105.       return false;
  106.    })()
  107. };
  108.  
  109. JSZip.prototype = (function () {
  110.    var textEncoder, textDecoder;
  111.    if (
  112.       JSZip.support.uint8array &&
  113.       typeof TextEncoder === "function" &&
  114.       typeof TextDecoder === "function"
  115.    ) {
  116.       textEncoder = new TextEncoder("utf-8");
  117.       textDecoder = new TextDecoder("utf-8");
  118.    }
  119.  
  120.    /**
  121.     * Returns the raw data of a ZipObject, decompress the content if necessary.
  122.     * @param {ZipObject} file the file to use.
  123.     * @return {String|ArrayBuffer|Uint8Array|Buffer} the data.
  124.     */
  125.    var getRawData = function (file) {
  126.       if (file._data instanceof JSZip.CompressedObject) {
  127.          file._data = file._data.getContent();
  128.          file.options.binary = true;
  129.          file.options.base64 = false;
  130.  
  131.          if (JSZip.utils.getTypeOf(file._data) === "uint8array") {
  132.             var copy = file._data;
  133.             // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array.
  134.             // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file).
  135.             file._data = new Uint8Array(copy.length);
  136.             // with an empty Uint8Array, Opera fails with a "Offset larger than array size"
  137.             if (copy.length !== 0) {
  138.                file._data.set(copy, 0);
  139.             }
  140.          }
  141.       }
  142.       return file._data;
  143.    };
  144.  
  145.    /**
  146.     * Returns the data of a ZipObject in a binary form. If the content is an unicode string, encode it.
  147.     * @param {ZipObject} file the file to use.
  148.     * @return {String|ArrayBuffer|Uint8Array|Buffer} the data.
  149.     */
  150.    var getBinaryData = function (file) {
  151.       var result = getRawData(file), type = JSZip.utils.getTypeOf(result);
  152.       if (type === "string") {
  153.          if (!file.options.binary) {
  154.             // unicode text !
  155.             // unicode string => binary string is a painful process, check if we can avoid it.
  156.             if (textEncoder) {
  157.                return textEncoder.encode(result);
  158.             }
  159.             if (JSZip.support.nodebuffer) {
  160.                return new Buffer(result, "utf-8");
  161.             }
  162.          }
  163.          return file.asBinary();
  164.       }
  165.       return result;
  166.    };
  167.  
  168.    /**
  169.     * Transform this._data into a string.
  170.     * @param {function} filter a function String -> String, applied if not null on the result.
  171.     * @return {String} the string representing this._data.
  172.     */
  173.    var dataToString = function (asUTF8) {
  174.       var result = getRawData(this);
  175.       if (result === null || typeof result === "undefined") {
  176.          return "";
  177.       }
  178.       // if the data is a base64 string, we decode it before checking the encoding !
  179.       if (this.options.base64) {
  180.          result = JSZip.base64.decode(result);
  181.       }
  182.       if (asUTF8 && this.options.binary) {
  183.          // JSZip.prototype.utf8decode supports arrays as input
  184.          // skip to array => string step, utf8decode will do it.
  185.          result = JSZip.prototype.utf8decode(result);
  186.       } else {
  187.          // no utf8 transformation, do the array => string step.
  188.          result = JSZip.utils.transformTo("string", result);
  189.       }
  190.  
  191.       if (!asUTF8 && !this.options.binary) {
  192.          result = JSZip.prototype.utf8encode(result);
  193.       }
  194.       return result;
  195.    };
  196.    /**
  197.     * A simple object representing a file in the zip file.
  198.     * @constructor
  199.     * @param {string} name the name of the file
  200.     * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data
  201.     * @param {Object} options the options of the file
  202.     */
  203.    var ZipObject = function (name, data, options) {
  204.       this.name = name;
  205.       this._data = data;
  206.       this.options = options;
  207.    };
  208.  
  209.    ZipObject.prototype = {
  210.       /**
  211.        * Return the content as UTF8 string.
  212.        * @return {string} the UTF8 string.
  213.        */
  214.       asText : function () {
  215.          return dataToString.call(this, true);
  216.       },
  217.       /**
  218.        * Returns the binary content.
  219.        * @return {string} the content as binary.
  220.        */
  221.       asBinary : function () {
  222.          return dataToString.call(this, false);
  223.       },
  224.       /**
  225.        * Returns the content as a nodejs Buffer.
  226.        * @return {Buffer} the content as a Buffer.
  227.        */
  228.       asNodeBuffer : function () {
  229.          var result = getBinaryData(this);
  230.          return JSZip.utils.transformTo("nodebuffer", result);
  231.       },
  232.       /**
  233.        * Returns the content as an Uint8Array.
  234.        * @return {Uint8Array} the content as an Uint8Array.
  235.        */
  236.       asUint8Array : function () {
  237.          var result = getBinaryData(this);
  238.          return JSZip.utils.transformTo("uint8array", result);
  239.       },
  240.       /**
  241.        * Returns the content as an ArrayBuffer.
  242.        * @return {ArrayBuffer} the content as an ArrayBufer.
  243.        */
  244.       asArrayBuffer : function () {
  245.          return this.asUint8Array().buffer;
  246.       }
  247.    };
  248.  
  249.    /**
  250.     * Transform an integer into a string in hexadecimal.
  251.     * @private
  252.     * @param {number} dec the number to convert.
  253.     * @param {number} bytes the number of bytes to generate.
  254.     * @returns {string} the result.
  255.     */
  256.    var decToHex = function(dec, bytes) {
  257.       var hex = "", i;
  258.       for(i = 0; i < bytes; i++) {
  259.          hex += String.fromCharCode(dec&0xff);
  260.          dec=dec>>>8;
  261.       }
  262.       return hex;
  263.    };
  264.  
  265.    /**
  266.     * Merge the objects passed as parameters into a new one.
  267.     * @private
  268.     * @param {...Object} var_args All objects to merge.
  269.     * @return {Object} a new object with the data of the others.
  270.     */
  271.    var extend = function () {
  272.       var result = {}, i, attr;
  273.       for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers
  274.          for (attr in arguments[i]) {
  275.             if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === "undefined") {
  276.                result[attr] = arguments[i][attr];
  277.             }
  278.          }
  279.       }
  280.       return result;
  281.    };
  282.  
  283.    /**
  284.     * Transforms the (incomplete) options from the user into the complete
  285.     * set of options to create a file.
  286.     * @private
  287.     * @param {Object} o the options from the user.
  288.     * @return {Object} the complete set of options.
  289.     */
  290.    var prepareFileAttrs = function (o) {
  291.       o = o || {};
  292.       /*jshint -W041 */
  293.       if (o.base64 === true && o.binary == null) {
  294.          o.binary = true;
  295.       }
  296.       /*jshint +W041 */
  297.       o = extend(o, JSZip.defaults);
  298.       o.date = o.date || new Date();
  299.       if (o.compression !== null) o.compression = o.compression.toUpperCase();
  300.  
  301.       return o;
  302.    };
  303.  
  304.    /**
  305.     * Add a file in the current folder.
  306.     * @private
  307.     * @param {string} name the name of the file
  308.     * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file
  309.     * @param {Object} o the options of the file
  310.     * @return {Object} the new file.
  311.     */
  312.    var fileAdd = function (name, data, o) {
  313.       // be sure sub folders exist
  314.       var parent = parentFolder(name), dataType = JSZip.utils.getTypeOf(data);
  315.       if (parent) {
  316.          folderAdd.call(this, parent);
  317.       }
  318.  
  319.       o = prepareFileAttrs(o);
  320.  
  321.       if (o.dir || data === null || typeof data === "undefined") {
  322.          o.base64 = false;
  323.          o.binary = false;
  324.          data = null;
  325.       } else if (dataType === "string") {
  326.          if (o.binary && !o.base64) {
  327.             // optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask
  328.             if (o.optimizedBinaryString !== true) {
  329.                // this is a string, not in a base64 format.
  330.                // Be sure that this is a correct "binary string"
  331.                data = JSZip.utils.string2binary(data);
  332.             }
  333.          }
  334.       } else { // arraybuffer, uint8array, ...
  335.          o.base64 = false;
  336.          o.binary = true;
  337.  
  338.          if (!dataType && !(data instanceof JSZip.CompressedObject)) {
  339.             throw new Error("The data of '" + name + "' is in an unsupported format !");
  340.          }
  341.  
  342.          // special case : it's way easier to work with Uint8Array than with ArrayBuffer
  343.          if (dataType === "arraybuffer") {
  344.             data = JSZip.utils.transformTo("uint8array", data);
  345.          }
  346.       }
  347.  
  348.       var object = new ZipObject(name, data, o);
  349.       this.files[name] = object;
  350.       return object;
  351.    };
  352.  
  353.  
  354.    /**
  355.     * Find the parent folder of the path.
  356.     * @private
  357.     * @param {string} path the path to use
  358.     * @return {string} the parent folder, or ""
  359.     */
  360.    var parentFolder = function (path) {
  361.       if (path.slice(-1) == '/') {
  362.          path = path.substring(0, path.length - 1);
  363.       }
  364.       var lastSlash = path.lastIndexOf('/');
  365.       return (lastSlash > 0) ? path.substring(0, lastSlash) : "";
  366.    };
  367.  
  368.    /**
  369.     * Add a (sub) folder in the current folder.
  370.     * @private
  371.     * @param {string} name the folder's name
  372.     * @return {Object} the new folder.
  373.     */
  374.    var folderAdd = function (name) {
  375.       // Check the name ends with a /
  376.       if (name.slice(-1) != "/") {
  377.          name += "/"; // IE doesn't like substr(-1)
  378.       }
  379.  
  380.       // Does this folder already exist?
  381.       if (!this.files[name]) {
  382.          fileAdd.call(this, name, null, {dir:true});
  383.       }
  384.       return this.files[name];
  385.    };
  386.  
  387.    /**
  388.     * Generate a JSZip.CompressedObject for a given zipOject.
  389.     * @param {ZipObject} file the object to read.
  390.     * @param {JSZip.compression} compression the compression to use.
  391.     * @return {JSZip.CompressedObject} the compressed result.
  392.     */
  393.    var generateCompressedObjectFrom = function (file, compression) {
  394.       var result = new JSZip.CompressedObject(), content;
  395.  
  396.       // the data has not been decompressed, we might reuse things !
  397.       if (file._data instanceof JSZip.CompressedObject) {
  398.          result.uncompressedSize = file._data.uncompressedSize;
  399.          result.crc32 = file._data.crc32;
  400.  
  401.          if (result.uncompressedSize === 0 || file.options.dir) {
  402.             compression = JSZip.compressions['STORE'];
  403.             result.compressedContent = "";
  404.             result.crc32 = 0;
  405.          } else if (file._data.compressionMethod === compression.magic) {
  406.             result.compressedContent = file._data.getCompressedContent();
  407.          } else {
  408.             content = file._data.getContent();
  409.             // need to decompress / recompress
  410.             result.compressedContent = compression.compress(JSZip.utils.transformTo(compression.compressInputType, content));
  411.          }
  412.       } else {
  413.          // have uncompressed data
  414.          content = getBinaryData(file);
  415.          if (!content || content.length === 0 || file.options.dir) {
  416.             compression = JSZip.compressions['STORE'];
  417.             content = "";
  418.          }
  419.          result.uncompressedSize = content.length;
  420.          result.crc32 = this.crc32(content);
  421.          result.compressedContent = compression.compress(JSZip.utils.transformTo(compression.compressInputType, content));
  422.       }
  423.  
  424.       result.compressedSize = result.compressedContent.length;
  425.       result.compressionMethod = compression.magic;
  426.  
  427.       return result;
  428.    };
  429.  
  430.    /**
  431.     * Generate the various parts used in the construction of the final zip file.
  432.     * @param {string} name the file name.
  433.     * @param {ZipObject} file the file content.
  434.     * @param {JSZip.CompressedObject} compressedObject the compressed object.
  435.     * @param {number} offset the current offset from the start of the zip file.
  436.     * @return {object} the zip parts.
  437.     */
  438.    var generateZipParts = function(name, file, compressedObject, offset) {
  439.       var data = compressedObject.compressedContent,
  440.           utfEncodedFileName = this.utf8encode(file.name),
  441.           useUTF8 = utfEncodedFileName !== file.name,
  442.           o       = file.options,
  443.           dosTime,
  444.           dosDate;
  445.  
  446.       // date
  447.       // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html
  448.       // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html
  449.       // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html
  450.  
  451.       dosTime = o.date.getHours();
  452.       dosTime = dosTime << 6;
  453.       dosTime = dosTime | o.date.getMinutes();
  454.       dosTime = dosTime << 5;
  455.       dosTime = dosTime | o.date.getSeconds() / 2;
  456.  
  457.       dosDate = o.date.getFullYear() - 1980;
  458.       dosDate = dosDate << 4;
  459.       dosDate = dosDate | (o.date.getMonth() + 1);
  460.       dosDate = dosDate << 5;
  461.       dosDate = dosDate | o.date.getDate();
  462.  
  463.  
  464.       var header = "";
  465.  
  466.       // version needed to extract
  467.       header += "\x0A\x00";
  468.       // general purpose bit flag
  469.       // set bit 11 if utf8
  470.       header += useUTF8 ? "\x00\x08" : "\x00\x00";
  471.       // compression method
  472.       header += compressedObject.compressionMethod;
  473.       // last mod file time
  474.       header += decToHex(dosTime, 2);
  475.       // last mod file date
  476.       header += decToHex(dosDate, 2);
  477.       // crc-32
  478.       header += decToHex(compressedObject.crc32, 4);
  479.       // compressed size
  480.       header += decToHex(compressedObject.compressedSize, 4);
  481.       // uncompressed size
  482.       header += decToHex(compressedObject.uncompressedSize, 4);
  483.       // file name length
  484.       header += decToHex(utfEncodedFileName.length, 2);
  485.       // extra field length
  486.       header += "\x00\x00";
  487.  
  488.  
  489.       var fileRecord = JSZip.signature.LOCAL_FILE_HEADER + header + utfEncodedFileName;
  490.  
  491.       var dirRecord = JSZip.signature.CENTRAL_FILE_HEADER +
  492.       // version made by (00: DOS)
  493.       "\x14\x00" +
  494.       // file header (common to file and central directory)
  495.       header +
  496.       // file comment length
  497.       "\x00\x00" +
  498.       // disk number start
  499.       "\x00\x00" +
  500.       // internal file attributes TODO
  501.       "\x00\x00" +
  502.       // external file attributes
  503.       (file.options.dir===true?"\x10\x00\x00\x00":"\x00\x00\x00\x00")+
  504.       // relative offset of local header
  505.       decToHex(offset, 4) +
  506.       // file name
  507.       utfEncodedFileName;
  508.  
  509.  
  510.       return {
  511.          fileRecord : fileRecord,
  512.          dirRecord : dirRecord,
  513.          compressedObject : compressedObject
  514.       };
  515.    };
  516.  
  517.    /**
  518.     * An object to write any content to a string.
  519.     * @constructor
  520.     */
  521.    var StringWriter = function () {
  522.       this.data = [];
  523.    };
  524.    StringWriter.prototype = {
  525.       /**
  526.        * Append any content to the current string.
  527.        * @param {Object} input the content to add.
  528.        */
  529.       append : function (input) {
  530.          input = JSZip.utils.transformTo("string", input);
  531.          this.data.push(input);
  532.       },
  533.       /**
  534.        * Finalize the construction an return the result.
  535.        * @return {string} the generated string.
  536.        */
  537.       finalize : function () {
  538.          return this.data.join("");
  539.       }
  540.    };
  541.    /**
  542.     * An object to write any content to an Uint8Array.
  543.     * @constructor
  544.     * @param {number} length The length of the array.
  545.     */
  546.    var Uint8ArrayWriter = function (length) {
  547.       this.data = new Uint8Array(length);
  548.       this.index = 0;
  549.    };
  550.    Uint8ArrayWriter.prototype = {
  551.       /**
  552.        * Append any content to the current array.
  553.        * @param {Object} input the content to add.
  554.        */
  555.       append : function (input) {
  556.          if (input.length !== 0) {
  557.             // with an empty Uint8Array, Opera fails with a "Offset larger than array size"
  558.             input = JSZip.utils.transformTo("uint8array", input);
  559.             this.data.set(input, this.index);
  560.             this.index += input.length;
  561.          }
  562.       },
  563.       /**
  564.        * Finalize the construction an return the result.
  565.        * @return {Uint8Array} the generated array.
  566.        */
  567.       finalize : function () {
  568.          return this.data;
  569.       }
  570.    };
  571.  
  572.    // return the actual prototype of JSZip
  573.    return {
  574.       /**
  575.        * Read an existing zip and merge the data in the current JSZip object.
  576.        * The implementation is in jszip-load.js, don't forget to include it.
  577.        * @param {String|ArrayBuffer|Uint8Array|Buffer} stream  The stream to load
  578.        * @param {Object} options Options for loading the stream.
  579.        *  options.base64 : is the stream in base64 ? default : false
  580.        * @return {JSZip} the current JSZip object
  581.        */
  582.       load : function (stream, options) {
  583.          throw new Error("Load method is not defined. Is the file jszip-load.js included ?");
  584.       },
  585.  
  586.       /**
  587.        * Filter nested files/folders with the specified function.
  588.        * @param {Function} search the predicate to use :
  589.        * function (relativePath, file) {...}
  590.        * It takes 2 arguments : the relative path and the file.
  591.        * @return {Array} An array of matching elements.
  592.        */
  593.       filter : function (search) {
  594.          var result = [], filename, relativePath, file, fileClone;
  595.          for (filename in this.files) {
  596.             if ( !this.files.hasOwnProperty(filename) ) { continue; }
  597.             file = this.files[filename];
  598.             // return a new object, don't let the user mess with our internal objects :)
  599.             fileClone = new ZipObject(file.name, file._data, extend(file.options));
  600.             relativePath = filename.slice(this.root.length, filename.length);
  601.             if (filename.slice(0, this.root.length) === this.root && // the file is in the current root
  602.                 search(relativePath, fileClone)) { // and the file matches the function
  603.                result.push(fileClone);
  604.             }
  605.          }
  606.          return result;
  607.       },
  608.  
  609.       /**
  610.        * Add a file to the zip file, or search a file.
  611.        * @param   {string|RegExp} name The name of the file to add (if data is defined),
  612.        * the name of the file to find (if no data) or a regex to match files.
  613.        * @param   {String|ArrayBuffer|Uint8Array|Buffer} data  The file data, either raw or base64 encoded
  614.        * @param   {Object} o     File options
  615.        * @return  {JSZip|Object|Array} this JSZip object (when adding a file),
  616.        * a file (when searching by string) or an array of files (when searching by regex).
  617.        */
  618.       file : function(name, data, o) {
  619.          if (arguments.length === 1) {
  620.             if (JSZip.utils.isRegExp(name)) {
  621.                var regexp = name;
  622.                return this.filter(function(relativePath, file) {
  623.                   return !file.options.dir && regexp.test(relativePath);
  624.                });
  625.             } else { // text
  626.                return this.filter(function (relativePath, file) {
  627.                   return !file.options.dir && relativePath === name;
  628.                })[0]||null;
  629.             }
  630.          } else { // more than one argument : we have data !
  631.             name = this.root+name;
  632.             fileAdd.call(this, name, data, o);
  633.          }
  634.          return this;
  635.       },
  636.  
  637.       /**
  638.        * Add a directory to the zip file, or search.
  639.        * @param   {String|RegExp} arg The name of the directory to add, or a regex to search folders.
  640.        * @return  {JSZip} an object with the new directory as the root, or an array containing matching folders.
  641.        */
  642.       folder : function(arg) {
  643.          if (!arg) {
  644.             return this;
  645.          }
  646.  
  647.          if (JSZip.utils.isRegExp(arg)) {
  648.             return this.filter(function(relativePath, file) {
  649.                return file.options.dir && arg.test(relativePath);
  650.             });
  651.          }
  652.  
  653.          // else, name is a new folder
  654.          var name = this.root + arg;
  655.          var newFolder = folderAdd.call(this, name);
  656.  
  657.          // Allow chaining by returning a new object with this folder as the root
  658.          var ret = this.clone();
  659.          ret.root = newFolder.name;
  660.          return ret;
  661.       },
  662.  
  663.       /**
  664.        * Delete a file, or a directory and all sub-files, from the zip
  665.        * @param {string} name the name of the file to delete
  666.        * @return {JSZip} this JSZip object
  667.        */
  668.       remove : function(name) {
  669.          name = this.root + name;
  670.          var file = this.files[name];
  671.          if (!file) {
  672.             // Look for any folders
  673.             if (name.slice(-1) != "/") {
  674.                name += "/";
  675.             }
  676.             file = this.files[name];
  677.          }
  678.  
  679.          if (file) {
  680.             if (!file.options.dir) {
  681.                // file
  682.                delete this.files[name];
  683.             } else {
  684.                // folder
  685.                var kids = this.filter(function (relativePath, file) {
  686.                   return file.name.slice(0, name.length) === name;
  687.                });
  688.                for (var i = 0; i < kids.length; i++) {
  689.                   delete this.files[kids[i].name];
  690.                }
  691.             }
  692.          }
  693.  
  694.          return this;
  695.       },
  696.  
  697.       /**
  698.        * Generate the complete zip file
  699.        * @param {Object} options the options to generate the zip file :
  700.        * - base64, (deprecated, use type instead) true to generate base64.
  701.        * - compression, "STORE" by default.
  702.        * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob.
  703.        * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file
  704.        */
  705.       generate : function(options) {
  706.          options = extend(options || {}, {
  707.             base64 : true,
  708.             compression : "STORE",
  709.             type : "base64"
  710.          });
  711.  
  712.          JSZip.utils.checkSupport(options.type);
  713.  
  714.          var zipData = [], localDirLength = 0, centralDirLength = 0, writer, i;
  715.  
  716.  
  717.          // first, generate all the zip parts.
  718.          for (var name in this.files) {
  719.             if ( !this.files.hasOwnProperty(name) ) { continue; }
  720.             var file = this.files[name];
  721.  
  722.             var compressionName = file.options.compression || options.compression.toUpperCase();
  723.             var compression = JSZip.compressions[compressionName];
  724.             if (!compression) {
  725.                throw new Error(compressionName + " is not a valid compression method !");
  726.             }
  727.  
  728.             var compressedObject = generateCompressedObjectFrom.call(this, file, compression);
  729.  
  730.             var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength);
  731.             localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize;
  732.             centralDirLength += zipPart.dirRecord.length;
  733.             zipData.push(zipPart);
  734.          }
  735.  
  736.          var dirEnd = "";
  737.  
  738.          // end of central dir signature
  739.          dirEnd = JSZip.signature.CENTRAL_DIRECTORY_END +
  740.          // number of this disk
  741.          "\x00\x00" +
  742.          // number of the disk with the start of the central directory
  743.          "\x00\x00" +
  744.          // total number of entries in the central directory on this disk
  745.          decToHex(zipData.length, 2) +
  746.          // total number of entries in the central directory
  747.          decToHex(zipData.length, 2) +
  748.          // size of the central directory   4 bytes
  749.          decToHex(centralDirLength, 4) +
  750.          // offset of start of central directory with respect to the starting disk number
  751.          decToHex(localDirLength, 4) +
  752.          // .ZIP file comment length
  753.          "\x00\x00";
  754.  
  755.  
  756.          // we have all the parts (and the total length)
  757.          // time to create a writer !
  758.          switch(options.type.toLowerCase()) {
  759.             case "uint8array" :
  760.             case "arraybuffer" :
  761.             case "blob" :
  762.             case "nodebuffer" :
  763.                writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length);
  764.                break;
  765.             // case "base64" :
  766.             // case "string" :
  767.             default :
  768.                writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length);
  769.                break;
  770.          }
  771.  
  772.          for (i = 0; i < zipData.length; i++) {
  773.             writer.append(zipData[i].fileRecord);
  774.             writer.append(zipData[i].compressedObject.compressedContent);
  775.          }
  776.          for (i = 0; i < zipData.length; i++) {
  777.             writer.append(zipData[i].dirRecord);
  778.          }
  779.  
  780.          writer.append(dirEnd);
  781.  
  782.          var zip = writer.finalize();
  783.  
  784.  
  785.  
  786.          switch(options.type.toLowerCase()) {
  787.             // case "zip is an Uint8Array"
  788.             case "uint8array" :
  789.             case "arraybuffer" :
  790.             case "nodebuffer" :
  791.                return JSZip.utils.transformTo(options.type.toLowerCase(), zip);
  792.             case "blob" :
  793.                return JSZip.utils.arrayBuffer2Blob(JSZip.utils.transformTo("arraybuffer", zip));
  794.  
  795.             // case "zip is a string"
  796.             case "base64" :
  797.                return (options.base64) ? JSZip.base64.encode(zip) : zip;
  798.             default : // case "string" :
  799.                return zip;
  800.          }
  801.       },
  802.  
  803.       /**
  804.        *
  805.        *  Javascript crc32
  806.        *  http://www.webtoolkit.info/
  807.        *
  808.        */
  809.       crc32 : function crc32(input, crc) {
  810.          if (typeof input === "undefined" || !input.length) {
  811.             return 0;
  812.          }
  813.  
  814.          var isArray = JSZip.utils.getTypeOf(input) !== "string";
  815.  
  816.          var table = [
  817.             0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
  818.             0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
  819.             0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
  820.             0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
  821.             0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
  822.             0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
  823.             0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
  824.             0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
  825.             0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
  826.             0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
  827.             0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
  828.             0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
  829.             0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
  830.             0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
  831.             0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
  832.             0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
  833.             0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
  834.             0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
  835.             0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
  836.             0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
  837.             0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
  838.             0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
  839.             0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
  840.             0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
  841.             0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
  842.             0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
  843.             0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
  844.             0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
  845.             0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
  846.             0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
  847.             0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
  848.             0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
  849.             0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
  850.             0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
  851.             0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
  852.             0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
  853.             0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
  854.             0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
  855.             0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
  856.             0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
  857.             0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
  858.             0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
  859.             0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
  860.             0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
  861.             0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
  862.             0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
  863.             0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
  864.             0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
  865.             0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
  866.             0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
  867.             0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
  868.             0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
  869.             0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
  870.             0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
  871.             0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
  872.             0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
  873.             0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
  874.             0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
  875.             0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
  876.             0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
  877.             0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
  878.             0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
  879.             0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
  880.             0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
  881.          ];
  882.  
  883.          if (typeof(crc) == "undefined") { crc = 0; }
  884.          var x = 0;
  885.          var y = 0;
  886.          var byte = 0;
  887.  
  888.          crc = crc ^ (-1);
  889.          for( var i = 0, iTop = input.length; i < iTop; i++ ) {
  890.             byte = isArray ? input[i] : input.charCodeAt(i);
  891.             y = ( crc ^ byte ) & 0xFF;
  892.             x = table[y];
  893.             crc = ( crc >>> 8 ) ^ x;
  894.          }
  895.  
  896.          return crc ^ (-1);
  897.       },
  898.  
  899.       // Inspired by http://my.opera.com/GreyWyvern/blog/show.dml/1725165
  900.       clone : function() {
  901.          var newObj = new JSZip();
  902.          for (var i in this) {
  903.             if (typeof this[i] !== "function") {
  904.                newObj[i] = this[i];
  905.             }
  906.          }
  907.          return newObj;
  908.       },
  909.  
  910.  
  911.       /**
  912.        * http://www.webtoolkit.info/javascript-utf8.html
  913.        */
  914.       utf8encode : function (string) {
  915.          // TextEncoder + Uint8Array to binary string is faster than checking every bytes on long strings.
  916.          // http://jsperf.com/utf8encode-vs-textencoder
  917.          // On short strings (file names for example), the TextEncoder API is (currently) slower.
  918.          if (textEncoder) {
  919.             var u8 = textEncoder.encode(string);
  920.             return JSZip.utils.transformTo("string", u8);
  921.          }
  922.          if (JSZip.support.nodebuffer) {
  923.             return JSZip.utils.transformTo("string", new Buffer(string, "utf-8"));
  924.          }
  925.  
  926.          // array.join may be slower than string concatenation but generates less objects (less time spent garbage collecting).
  927.          // See also http://jsperf.com/array-direct-assignment-vs-push/31
  928.          var result = [], resIndex = 0;
  929.  
  930.          for (var n = 0; n < string.length; n++) {
  931.  
  932.             var c = string.charCodeAt(n);
  933.  
  934.             if (c < 128) {
  935.                result[resIndex++] = String.fromCharCode(c);
  936.             } else if ((c > 127) && (c < 2048)) {
  937.                result[resIndex++] = String.fromCharCode((c >> 6) | 192);
  938.                result[resIndex++] = String.fromCharCode((c & 63) | 128);
  939.             } else {
  940.                result[resIndex++] = String.fromCharCode((c >> 12) | 224);
  941.                result[resIndex++] = String.fromCharCode(((c >> 6) & 63) | 128);
  942.                result[resIndex++] = String.fromCharCode((c & 63) | 128);
  943.             }
  944.  
  945.          }
  946.  
  947.          return result.join("");
  948.       },
  949.  
  950.       /**
  951.        * http://www.webtoolkit.info/javascript-utf8.html
  952.        */
  953.       utf8decode : function (input) {
  954.          var result = [], resIndex = 0;
  955.          var type = JSZip.utils.getTypeOf(input);
  956.          var isArray = type !== "string";
  957.          var i = 0;
  958.          var c = 0, c1 = 0, c2 = 0, c3 = 0;
  959.  
  960.          // check if we can use the TextDecoder API
  961.          // see http://encoding.spec.whatwg.org/#api
  962.          if (textDecoder) {
  963.             return textDecoder.decode(
  964.                JSZip.utils.transformTo("uint8array", input)
  965.             );
  966.          }
  967.          if (JSZip.support.nodebuffer) {
  968.             return JSZip.utils.transformTo("nodebuffer", input).toString("utf-8");
  969.          }
  970.  
  971.          while ( i < input.length ) {
  972.  
  973.             c = isArray ? input[i] : input.charCodeAt(i);
  974.  
  975.             if (c < 128) {
  976.                result[resIndex++] = String.fromCharCode(c);
  977.                i++;
  978.             } else if ((c > 191) && (c < 224)) {
  979.                c2 = isArray ? input[i+1] : input.charCodeAt(i+1);
  980.                result[resIndex++] = String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  981.                i += 2;
  982.             } else {
  983.                c2 = isArray ? input[i+1] : input.charCodeAt(i+1);
  984.                c3 = isArray ? input[i+2] : input.charCodeAt(i+2);
  985.                result[resIndex++] = String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  986.                i += 3;
  987.             }
  988.  
  989.          }
  990.  
  991.          return result.join("");
  992.       }
  993.    };
  994. }());
  995.  
  996. /*
  997.  * Compression methods
  998.  * This object is filled in as follow :
  999.  * name : {
  1000.  *    magic // the 2 bytes indentifying the compression method
  1001.  *    compress // function, take the uncompressed content and return it compressed.
  1002.  *    uncompress // function, take the compressed content and return it uncompressed.
  1003.  *    compressInputType // string, the type accepted by the compress method. null to accept everything.
  1004.  *    uncompressInputType // string, the type accepted by the uncompress method. null to accept everything.
  1005.  * }
  1006.  *
  1007.  * STORE is the default compression method, so it's included in this file.
  1008.  * Other methods should go to separated files : the user wants modularity.
  1009.  */
  1010. JSZip.compressions = {
  1011.    "STORE" : {
  1012.       magic : "\x00\x00",
  1013.       compress : function (content) {
  1014.          return content; // no compression
  1015.       },
  1016.       uncompress : function (content) {
  1017.          return content; // no compression
  1018.       },
  1019.       compressInputType : null,
  1020.       uncompressInputType : null
  1021.    }
  1022. };
  1023.  
  1024. (function () {
  1025.    JSZip.utils = {
  1026.       /**
  1027.        * Convert a string to a "binary string" : a string containing only char codes between 0 and 255.
  1028.        * @param {string} str the string to transform.
  1029.        * @return {String} the binary string.
  1030.        */
  1031.       string2binary : function (str) {
  1032.          var result = "";
  1033.          for (var i = 0; i < str.length; i++) {
  1034.             result += String.fromCharCode(str.charCodeAt(i) & 0xff);
  1035.          }
  1036.          return result;
  1037.       },
  1038.       /**
  1039.        * Create a Uint8Array from the string.
  1040.        * @param {string} str the string to transform.
  1041.        * @return {Uint8Array} the typed array.
  1042.        * @throws {Error} an Error if the browser doesn't support the requested feature.
  1043.        * @deprecated : use JSZip.utils.transformTo instead.
  1044.        */
  1045.       string2Uint8Array : function (str) {
  1046.          return JSZip.utils.transformTo("uint8array", str);
  1047.       },
  1048.  
  1049.       /**
  1050.        * Create a string from the Uint8Array.
  1051.        * @param {Uint8Array} array the array to transform.
  1052.        * @return {string} the string.
  1053.        * @throws {Error} an Error if the browser doesn't support the requested feature.
  1054.        * @deprecated : use JSZip.utils.transformTo instead.
  1055.        */
  1056.       uint8Array2String : function (array) {
  1057.          return JSZip.utils.transformTo("string", array);
  1058.       },
  1059.       /**
  1060.        * Create a blob from the given ArrayBuffer.
  1061.        * @param {ArrayBuffer} buffer the buffer to transform.
  1062.        * @return {Blob} the result.
  1063.        * @throws {Error} an Error if the browser doesn't support the requested feature.
  1064.        */
  1065.       arrayBuffer2Blob : function (buffer) {
  1066.          JSZip.utils.checkSupport("blob");
  1067.  
  1068.          try {
  1069.             // Blob constructor
  1070.             return new Blob([buffer], { type: "application/zip" });
  1071.          }
  1072.          catch(e) {}
  1073.  
  1074.          try {
  1075.             // deprecated, browser only, old way
  1076.             var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
  1077.             var builder = new BlobBuilder();
  1078.             builder.append(buffer);
  1079.             return builder.getBlob('application/zip');
  1080.          }
  1081.          catch(e) {}
  1082.  
  1083.          // well, fuck ?!
  1084.          throw new Error("Bug : can't construct the Blob.");
  1085.       },
  1086.       /**
  1087.        * Create a blob from the given string.
  1088.        * @param {string} str the string to transform.
  1089.        * @return {Blob} the result.
  1090.        * @throws {Error} an Error if the browser doesn't support the requested feature.
  1091.        */
  1092.       string2Blob : function (str) {
  1093.          var buffer = JSZip.utils.transformTo("arraybuffer", str);
  1094.          return JSZip.utils.arrayBuffer2Blob(buffer);
  1095.       }
  1096.    };
  1097.  
  1098.    /**
  1099.     * The identity function.
  1100.     * @param {Object} input the input.
  1101.     * @return {Object} the same input.
  1102.     */
  1103.    function identity(input) {
  1104.       return input;
  1105.    }
  1106.  
  1107.    /**
  1108.     * Fill in an array with a string.
  1109.     * @param {String} str the string to use.
  1110.     * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated).
  1111.     * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array.
  1112.     */
  1113.    function stringToArrayLike(str, array) {
  1114.       for (var i = 0; i < str.length; ++i) {
  1115.          array[i] = str.charCodeAt(i) & 0xFF;
  1116.       }
  1117.       return array;
  1118.    }
  1119.  
  1120.    /**
  1121.     * Transform an array-like object to a string.
  1122.     * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform.
  1123.     * @return {String} the result.
  1124.     */
  1125.    function arrayLikeToString(array) {
  1126.       // Performances notes :
  1127.       // --------------------
  1128.       // String.fromCharCode.apply(null, array) is the fastest, see
  1129.       // see http://jsperf.com/converting-a-uint8array-to-a-string/2
  1130.       // but the stack is limited (and we can get huge arrays !).
  1131.       //
  1132.       // result += String.fromCharCode(array[i]); generate too many strings !
  1133.       //
  1134.       // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2
  1135.       var chunk = 65536;
  1136.       var result = [], len = array.length, type = JSZip.utils.getTypeOf(array), k = 0;
  1137.  
  1138.       var canUseApply = true;
  1139.       try {
  1140.          switch(type) {
  1141.             case "uint8array":
  1142.                String.fromCharCode.apply(null, new Uint8Array(0));
  1143.                break;
  1144.             case "nodebuffer":
  1145.                String.fromCharCode.apply(null, new Buffer(0));
  1146.                break;
  1147.          }
  1148.       } catch(e) {
  1149.          canUseApply = false;
  1150.       }
  1151.  
  1152.       // no apply : slow and painful algorithm
  1153.       // default browser on android 4.*
  1154.       if (!canUseApply) {
  1155.          var resultStr = "";
  1156.          for(var i = 0; i < array.length;i++) {
  1157.             resultStr += String.fromCharCode(array[i]);
  1158.          }
  1159.          return resultStr;
  1160.       }
  1161.  
  1162.       while (k < len && chunk > 1) {
  1163.          try {
  1164.             if (type === "array" || type === "nodebuffer") {
  1165.                result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len))));
  1166.             } else {
  1167.                result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len))));
  1168.             }
  1169.             k += chunk;
  1170.          } catch (e) {
  1171.             chunk = Math.floor(chunk / 2);
  1172.          }
  1173.       }
  1174.       return result.join("");
  1175.    }
  1176.  
  1177.    /**
  1178.     * Copy the data from an array-like to an other array-like.
  1179.     * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array.
  1180.     * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated.
  1181.     * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array.
  1182.     */
  1183.    function arrayLikeToArrayLike(arrayFrom, arrayTo) {
  1184.       for(var i = 0; i < arrayFrom.length; i++) {
  1185.          arrayTo[i] = arrayFrom[i];
  1186.       }
  1187.       return arrayTo;
  1188.    }
  1189.  
  1190.    // a matrix containing functions to transform everything into everything.
  1191.    var transform = {};
  1192.  
  1193.    // string to ?
  1194.    transform["string"] = {
  1195.       "string" : identity,
  1196.       "array" : function (input) {
  1197.          return stringToArrayLike(input, new Array(input.length));
  1198.       },
  1199.       "arraybuffer" : function (input) {
  1200.          return transform["string"]["uint8array"](input).buffer;
  1201.       },
  1202.       "uint8array" : function (input) {
  1203.          return stringToArrayLike(input, new Uint8Array(input.length));
  1204.       },
  1205.       "nodebuffer" : function (input) {
  1206.          return stringToArrayLike(input, new Buffer(input.length));
  1207.       }
  1208.    };
  1209.  
  1210.    // array to ?
  1211.    transform["array"] = {
  1212.       "string" : arrayLikeToString,
  1213.       "array" : identity,
  1214.       "arraybuffer" : function (input) {
  1215.          return (new Uint8Array(input)).buffer;
  1216.       },
  1217.       "uint8array" : function (input) {
  1218.          return new Uint8Array(input);
  1219.       },
  1220.       "nodebuffer" : function (input) {
  1221.          return new Buffer(input);
  1222.       }
  1223.    };
  1224.  
  1225.    // arraybuffer to ?
  1226.    transform["arraybuffer"] = {
  1227.       "string" : function (input) {
  1228.          return arrayLikeToString(new Uint8Array(input));
  1229.       },
  1230.       "array" : function (input) {
  1231.          return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength));
  1232.       },
  1233.       "arraybuffer" : identity,
  1234.       "uint8array" : function (input) {
  1235.          return new Uint8Array(input);
  1236.       },
  1237.       "nodebuffer" : function (input) {
  1238.          return new Buffer(new Uint8Array(input));
  1239.       }
  1240.    };
  1241.  
  1242.    // uint8array to ?
  1243.    transform["uint8array"] = {
  1244.       "string" : arrayLikeToString,
  1245.       "array" : function (input) {
  1246.          return arrayLikeToArrayLike(input, new Array(input.length));
  1247.       },
  1248.       "arraybuffer" : function (input) {
  1249.          return input.buffer;
  1250.       },
  1251.       "uint8array" : identity,
  1252.       "nodebuffer" : function(input) {
  1253.          return new Buffer(input);
  1254.       }
  1255.    };
  1256.  
  1257.    // nodebuffer to ?
  1258.    transform["nodebuffer"] = {
  1259.       "string" : arrayLikeToString,
  1260.       "array" : function (input) {
  1261.          return arrayLikeToArrayLike(input, new Array(input.length));
  1262.       },
  1263.       "arraybuffer" : function (input) {
  1264.          return transform["nodebuffer"]["uint8array"](input).buffer;
  1265.       },
  1266.       "uint8array" : function (input) {
  1267.          return arrayLikeToArrayLike(input, new Uint8Array(input.length));
  1268.       },
  1269.       "nodebuffer" : identity
  1270.    };
  1271.  
  1272.    /**
  1273.     * Transform an input into any type.
  1274.     * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer.
  1275.     * If no output type is specified, the unmodified input will be returned.
  1276.     * @param {String} outputType the output type.
  1277.     * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert.
  1278.     * @throws {Error} an Error if the browser doesn't support the requested output type.
  1279.     */
  1280.    JSZip.utils.transformTo = function (outputType, input) {
  1281.       if (!input) {
  1282.          // undefined, null, etc
  1283.          // an empty string won't harm.
  1284.          input = "";
  1285.       }
  1286.       if (!outputType) {
  1287.          return input;
  1288.       }
  1289.       JSZip.utils.checkSupport(outputType);
  1290.       var inputType = JSZip.utils.getTypeOf(input);
  1291.       var result = transform[inputType][outputType](input);
  1292.       return result;
  1293.    };
  1294.  
  1295.    /**
  1296.     * Return the type of the input.
  1297.     * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer.
  1298.     * @param {Object} input the input to identify.
  1299.     * @return {String} the (lowercase) type of the input.
  1300.     */
  1301.    JSZip.utils.getTypeOf = function (input) {
  1302.       if (typeof input === "string") {
  1303.          return "string";
  1304.       }
  1305.       if (Object.prototype.toString.call(input) === "[object Array]") {
  1306.          return "array";
  1307.       }
  1308.       if (JSZip.support.nodebuffer && Buffer.isBuffer(input)) {
  1309.          return "nodebuffer";
  1310.       }
  1311.       if (JSZip.support.uint8array && input instanceof Uint8Array) {
  1312.          return "uint8array";
  1313.       }
  1314.       if (JSZip.support.arraybuffer && input instanceof ArrayBuffer) {
  1315.          return "arraybuffer";
  1316.       }
  1317.    };
  1318.  
  1319.    /**
  1320.     * Cross-window, cross-Node-context regular expression detection
  1321.     * @param  {Object}  object Anything
  1322.     * @return {Boolean}        true if the object is a regular expression,
  1323.     * false otherwise
  1324.     */
  1325.    JSZip.utils.isRegExp = function (object) {
  1326.       return Object.prototype.toString.call(object) === "[object RegExp]";
  1327.    };
  1328.  
  1329.    /**
  1330.     * Throw an exception if the type is not supported.
  1331.     * @param {String} type the type to check.
  1332.     * @throws {Error} an Error if the browser doesn't support the requested type.
  1333.     */
  1334.    JSZip.utils.checkSupport = function (type) {
  1335.       var supported = true;
  1336.       switch (type.toLowerCase()) {
  1337.          case "uint8array":
  1338.             supported = JSZip.support.uint8array;
  1339.          break;
  1340.          case "arraybuffer":
  1341.             supported = JSZip.support.arraybuffer;
  1342.          break;
  1343.          case "nodebuffer":
  1344.             supported = JSZip.support.nodebuffer;
  1345.          break;
  1346.          case "blob":
  1347.             supported = JSZip.support.blob;
  1348.          break;
  1349.       }
  1350.       if (!supported) {
  1351.          throw new Error(type + " is not supported by this browser");
  1352.       }
  1353.    };
  1354.  
  1355.  
  1356. })();
  1357.  
  1358. (function (){
  1359.    /**
  1360.     * Represents an entry in the zip.
  1361.     * The content may or may not be compressed.
  1362.     * @constructor
  1363.     */
  1364.    JSZip.CompressedObject = function () {
  1365.          this.compressedSize = 0;
  1366.          this.uncompressedSize = 0;
  1367.          this.crc32 = 0;
  1368.          this.compressionMethod = null;
  1369.          this.compressedContent = null;
  1370.    };
  1371.  
  1372.    JSZip.CompressedObject.prototype = {
  1373.       /**
  1374.        * Return the decompressed content in an unspecified format.
  1375.        * The format will depend on the decompressor.
  1376.        * @return {Object} the decompressed content.
  1377.        */
  1378.       getContent : function () {
  1379.          return null; // see implementation
  1380.       },
  1381.       /**
  1382.        * Return the compressed content in an unspecified format.
  1383.        * The format will depend on the compressed conten source.
  1384.        * @return {Object} the compressed content.
  1385.        */
  1386.       getCompressedContent : function () {
  1387.          return null; // see implementation
  1388.       }
  1389.    };
  1390. })();
  1391.  
  1392. /**
  1393.  *
  1394.  *  Base64 encode / decode
  1395.  *  http://www.webtoolkit.info/
  1396.  *
  1397.  *  Hacked so that it doesn't utf8 en/decode everything
  1398.  **/
  1399. JSZip.base64 = (function() {
  1400.    // private property
  1401.    var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  1402.  
  1403.    return {
  1404.       // public method for encoding
  1405.       encode : function(input, utf8) {
  1406.          var output = "";
  1407.          var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
  1408.          var i = 0;
  1409.  
  1410.          while (i < input.length) {
  1411.  
  1412.             chr1 = input.charCodeAt(i++);
  1413.             chr2 = input.charCodeAt(i++);
  1414.             chr3 = input.charCodeAt(i++);
  1415.  
  1416.             enc1 = chr1 >> 2;
  1417.             enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  1418.             enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  1419.             enc4 = chr3 & 63;
  1420.  
  1421.             if (isNaN(chr2)) {
  1422.                enc3 = enc4 = 64;
  1423.             } else if (isNaN(chr3)) {
  1424.                enc4 = 64;
  1425.             }
  1426.  
  1427.             output = output +
  1428.                _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
  1429.                _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
  1430.  
  1431.          }
  1432.  
  1433.          return output;
  1434.       },
  1435.  
  1436.       // public method for decoding
  1437.       decode : function(input, utf8) {
  1438.          var output = "";
  1439.          var chr1, chr2, chr3;
  1440.          var enc1, enc2, enc3, enc4;
  1441.          var i = 0;
  1442.  
  1443.          input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  1444.  
  1445.          while (i < input.length) {
  1446.  
  1447.             enc1 = _keyStr.indexOf(input.charAt(i++));
  1448.             enc2 = _keyStr.indexOf(input.charAt(i++));
  1449.             enc3 = _keyStr.indexOf(input.charAt(i++));
  1450.             enc4 = _keyStr.indexOf(input.charAt(i++));
  1451.  
  1452.             chr1 = (enc1 << 2) | (enc2 >> 4);
  1453.             chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  1454.             chr3 = ((enc3 & 3) << 6) | enc4;
  1455.  
  1456.             output = output + String.fromCharCode(chr1);
  1457.  
  1458.             if (enc3 != 64) {
  1459.                output = output + String.fromCharCode(chr2);
  1460.             }
  1461.             if (enc4 != 64) {
  1462.                output = output + String.fromCharCode(chr3);
  1463.             }
  1464.  
  1465.          }
  1466.  
  1467.          return output;
  1468.  
  1469.       }
  1470.    };
  1471. }());
  1472.  
  1473. // enforcing Stuk's coding style
  1474. // vim: set shiftwidth=3 softtabstop=3:
Add Comment
Please, Sign In to add comment