2013-11-06 06:05:32 +00:00
/ * *
JSZip - A Javascript class for generating and reading zip files
< http : //stuartk.com/jszip>
( c ) 2009 - 2012 Stuart Knightley < stuart [ at ] stuartk . com >
Dual licenced under the MIT license or GPLv3 . See LICENSE . markdown .
Usage :
zip = new JSZip ( ) ;
zip . file ( "hello.txt" , "Hello, World!" ) . file ( "tempfile" , "nothing" ) ;
zip . folder ( "images" ) . file ( "smile.gif" , base64Data , { base64 : true } ) ;
zip . file ( "Xmas.txt" , "Ho ho ho !" , { date : new Date ( "December 25, 2007 00:00:01" ) } ) ;
zip . remove ( "tempfile" ) ;
base64zip = zip . generate ( ) ;
* * /
// We use strict, but it should not be placed outside of a function because
// the environment is shared inside the browser.
// "use strict";
/ * *
* Representation a of zip file in js
* @ constructor
* @ param { String = | ArrayBuffer = | Uint8Array = | Buffer = } data the data to load , if any ( optional ) .
* @ param { Object = } options the options for creating this objects ( optional ) .
* /
2012-12-04 19:27:20 +00:00
var JSZip = function ( data , options ) {
2013-11-06 06:05:32 +00:00
// object containing the files :
// {
// "folder/" : {...},
// "folder/data.txt" : {...}
// }
this . files = { } ;
// Where we are in the hierarchy
this . root = "" ;
if ( data ) {
this . load ( data , options ) ;
}
2012-12-04 19:27:20 +00:00
} ;
JSZip . signature = {
2013-11-06 06:05:32 +00:00
LOCAL _FILE _HEADER : "\x50\x4b\x03\x04" ,
CENTRAL _FILE _HEADER : "\x50\x4b\x01\x02" ,
CENTRAL _DIRECTORY _END : "\x50\x4b\x05\x06" ,
ZIP64 _CENTRAL _DIRECTORY _LOCATOR : "\x50\x4b\x06\x07" ,
ZIP64 _CENTRAL _DIRECTORY _END : "\x50\x4b\x06\x06" ,
DATA _DESCRIPTOR : "\x50\x4b\x07\x08"
2012-12-04 19:27:20 +00:00
} ;
2013-11-06 06:05:32 +00:00
// Default properties for a new file
2012-12-04 19:27:20 +00:00
JSZip . defaults = {
2013-11-06 06:05:32 +00:00
base64 : false ,
binary : false ,
dir : false ,
date : null ,
compression : null
2012-12-04 19:27:20 +00:00
} ;
2013-11-06 06:05:32 +00:00
/ *
* List features that require a modern browser , and if the current browser support them .
* /
JSZip . support = {
// contains true if JSZip can read/generate ArrayBuffer, false otherwise.
arraybuffer : ( function ( ) {
return typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined" ;
} ) ( ) ,
// contains true if JSZip can read/generate nodejs Buffer, false otherwise.
nodebuffer : ( function ( ) {
return typeof Buffer !== "undefined" ;
} ) ( ) ,
// contains true if JSZip can read/generate Uint8Array, false otherwise.
uint8array : ( function ( ) {
return typeof Uint8Array !== "undefined" ;
} ) ( ) ,
// contains true if JSZip can read/generate Blob, false otherwise.
blob : ( function ( ) {
// the spec started with BlobBuilder then replaced it with a construtor for Blob.
// Result : we have browsers that :
// * know the BlobBuilder (but with prefix)
// * know the Blob constructor
// * know about Blob but not about how to build them
// About the "=== 0" test : if given the wrong type, it may be converted to a string.
// Instead of an empty content, we will get "[object Uint8Array]" for example.
if ( typeof ArrayBuffer === "undefined" ) {
return false ;
}
var buffer = new ArrayBuffer ( 0 ) ;
try {
return new Blob ( [ buffer ] , { type : "application/zip" } ) . size === 0 ;
}
catch ( e ) { }
try {
var BlobBuilder = window . BlobBuilder || window . WebKitBlobBuilder || window . MozBlobBuilder || window . MSBlobBuilder ;
var builder = new BlobBuilder ( ) ;
builder . append ( buffer ) ;
return builder . getBlob ( 'application/zip' ) . size === 0 ;
}
catch ( e ) { }
return false ;
} ) ( )
} ;
JSZip . prototype = ( function ( ) {
var textEncoder , textDecoder ;
if (
JSZip . support . uint8array &&
typeof TextEncoder === "function" &&
typeof TextDecoder === "function"
) {
textEncoder = new TextEncoder ( "utf-8" ) ;
textDecoder = new TextDecoder ( "utf-8" ) ;
}
/ * *
* Returns the raw data of a ZipObject , decompress the content if necessary .
* @ param { ZipObject } file the file to use .
* @ return { String | ArrayBuffer | Uint8Array | Buffer } the data .
* /
var getRawData = function ( file ) {
if ( file . _data instanceof JSZip . CompressedObject ) {
file . _data = file . _data . getContent ( ) ;
file . options . binary = true ;
file . options . base64 = false ;
if ( JSZip . utils . getTypeOf ( file . _data ) === "uint8array" ) {
var copy = file . _data ;
// when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array.
// if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file).
file . _data = new Uint8Array ( copy . length ) ;
// with an empty Uint8Array, Opera fails with a "Offset larger than array size"
if ( copy . length !== 0 ) {
file . _data . set ( copy , 0 ) ;
}
}
}
return file . _data ;
} ;
/ * *
* Returns the data of a ZipObject in a binary form . If the content is an unicode string , encode it .
* @ param { ZipObject } file the file to use .
* @ return { String | ArrayBuffer | Uint8Array | Buffer } the data .
* /
var getBinaryData = function ( file ) {
var result = getRawData ( file ) , type = JSZip . utils . getTypeOf ( result ) ;
if ( type === "string" ) {
if ( ! file . options . binary ) {
// unicode text !
// unicode string => binary string is a painful process, check if we can avoid it.
if ( textEncoder ) {
return textEncoder . encode ( result ) ;
}
if ( JSZip . support . nodebuffer ) {
return new Buffer ( result , "utf-8" ) ;
}
}
return file . asBinary ( ) ;
}
return result ;
} ;
/ * *
* Transform this . _data into a string .
* @ param { function } filter a function String - > String , applied if not null on the result .
* @ return { String } the string representing this . _data .
* /
var dataToString = function ( asUTF8 ) {
var result = getRawData ( this ) ;
if ( result === null || typeof result === "undefined" ) {
return "" ;
}
// if the data is a base64 string, we decode it before checking the encoding !
if ( this . options . base64 ) {
result = JSZip . base64 . decode ( result ) ;
}
if ( asUTF8 && this . options . binary ) {
// JSZip.prototype.utf8decode supports arrays as input
// skip to array => string step, utf8decode will do it.
result = JSZip . prototype . utf8decode ( result ) ;
} else {
// no utf8 transformation, do the array => string step.
result = JSZip . utils . transformTo ( "string" , result ) ;
}
if ( ! asUTF8 && ! this . options . binary ) {
result = JSZip . prototype . utf8encode ( result ) ;
}
return result ;
} ;
/ * *
* A simple object representing a file in the zip file .
* @ constructor
* @ param { string } name the name of the file
* @ param { String | ArrayBuffer | Uint8Array | Buffer } data the data
* @ param { Object } options the options of the file
* /
var ZipObject = function ( name , data , options ) {
this . name = name ;
this . _data = data ;
this . options = options ;
} ;
ZipObject . prototype = {
/ * *
* Return the content as UTF8 string .
* @ return { string } the UTF8 string .
* /
asText : function ( ) {
return dataToString . call ( this , true ) ;
} ,
/ * *
* Returns the binary content .
* @ return { string } the content as binary .
* /
asBinary : function ( ) {
return dataToString . call ( this , false ) ;
} ,
/ * *
* Returns the content as a nodejs Buffer .
* @ return { Buffer } the content as a Buffer .
* /
asNodeBuffer : function ( ) {
var result = getBinaryData ( this ) ;
return JSZip . utils . transformTo ( "nodebuffer" , result ) ;
} ,
/ * *
* Returns the content as an Uint8Array .
* @ return { Uint8Array } the content as an Uint8Array .
* /
asUint8Array : function ( ) {
var result = getBinaryData ( this ) ;
return JSZip . utils . transformTo ( "uint8array" , result ) ;
} ,
/ * *
* Returns the content as an ArrayBuffer .
* @ return { ArrayBuffer } the content as an ArrayBufer .
* /
asArrayBuffer : function ( ) {
return this . asUint8Array ( ) . buffer ;
}
} ;
/ * *
* Transform an integer into a string in hexadecimal .
* @ private
* @ param { number } dec the number to convert .
* @ param { number } bytes the number of bytes to generate .
* @ returns { string } the result .
* /
var decToHex = function ( dec , bytes ) {
var hex = "" , i ;
for ( i = 0 ; i < bytes ; i ++ ) {
hex += String . fromCharCode ( dec & 0xff ) ;
dec = dec >>> 8 ;
}
return hex ;
} ;
/ * *
* Merge the objects passed as parameters into a new one .
* @ private
* @ param { ... Object } var _args All objects to merge .
* @ return { Object } a new object with the data of the others .
* /
var extend = function ( ) {
var result = { } , i , attr ;
for ( i = 0 ; i < arguments . length ; i ++ ) { // arguments is not enumerable in some browsers
for ( attr in arguments [ i ] ) {
if ( arguments [ i ] . hasOwnProperty ( attr ) && typeof result [ attr ] === "undefined" ) {
result [ attr ] = arguments [ i ] [ attr ] ;
}
}
}
return result ;
} ;
/ * *
* Transforms the ( incomplete ) options from the user into the complete
* set of options to create a file .
* @ private
* @ param { Object } o the options from the user .
* @ return { Object } the complete set of options .
* /
var prepareFileAttrs = function ( o ) {
o = o || { } ;
/*jshint -W041 */
if ( o . base64 === true && o . binary == null ) {
o . binary = true ;
}
/*jshint +W041 */
o = extend ( o , JSZip . defaults ) ;
o . date = o . date || new Date ( ) ;
if ( o . compression !== null ) o . compression = o . compression . toUpperCase ( ) ;
return o ;
} ;
/ * *
* Add a file in the current folder .
* @ private
* @ param { string } name the name of the file
* @ param { String | ArrayBuffer | Uint8Array | Buffer } data the data of the file
* @ param { Object } o the options of the file
* @ return { Object } the new file .
* /
var fileAdd = function ( name , data , o ) {
// be sure sub folders exist
var parent = parentFolder ( name ) , dataType = JSZip . utils . getTypeOf ( data ) ;
if ( parent ) {
folderAdd . call ( this , parent ) ;
}
o = prepareFileAttrs ( o ) ;
if ( o . dir || data === null || typeof data === "undefined" ) {
o . base64 = false ;
o . binary = false ;
data = null ;
} else if ( dataType === "string" ) {
if ( o . binary && ! o . base64 ) {
// optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask
if ( o . optimizedBinaryString !== true ) {
// this is a string, not in a base64 format.
// Be sure that this is a correct "binary string"
data = JSZip . utils . string2binary ( data ) ;
}
}
} else { // arraybuffer, uint8array, ...
o . base64 = false ;
o . binary = true ;
if ( ! dataType && ! ( data instanceof JSZip . CompressedObject ) ) {
throw new Error ( "The data of '" + name + "' is in an unsupported format !" ) ;
}
// special case : it's way easier to work with Uint8Array than with ArrayBuffer
if ( dataType === "arraybuffer" ) {
data = JSZip . utils . transformTo ( "uint8array" , data ) ;
}
}
var object = new ZipObject ( name , data , o ) ;
this . files [ name ] = object ;
return object ;
} ;
/ * *
* Find the parent folder of the path .
* @ private
* @ param { string } path the path to use
* @ return { string } the parent folder , or ""
* /
var parentFolder = function ( path ) {
if ( path . slice ( - 1 ) == '/' ) {
path = path . substring ( 0 , path . length - 1 ) ;
}
var lastSlash = path . lastIndexOf ( '/' ) ;
return ( lastSlash > 0 ) ? path . substring ( 0 , lastSlash ) : "" ;
} ;
/ * *
* Add a ( sub ) folder in the current folder .
* @ private
* @ param { string } name the folder ' s name
* @ return { Object } the new folder .
* /
var folderAdd = function ( name ) {
// Check the name ends with a /
if ( name . slice ( - 1 ) != "/" ) {
name += "/" ; // IE doesn't like substr(-1)
}
// Does this folder already exist?
if ( ! this . files [ name ] ) {
fileAdd . call ( this , name , null , { dir : true } ) ;
}
return this . files [ name ] ;
} ;
/ * *
* Generate a JSZip . CompressedObject for a given zipOject .
* @ param { ZipObject } file the object to read .
* @ param { JSZip . compression } compression the compression to use .
* @ return { JSZip . CompressedObject } the compressed result .
* /
var generateCompressedObjectFrom = function ( file , compression ) {
var result = new JSZip . CompressedObject ( ) , content ;
// the data has not been decompressed, we might reuse things !
if ( file . _data instanceof JSZip . CompressedObject ) {
result . uncompressedSize = file . _data . uncompressedSize ;
result . crc32 = file . _data . crc32 ;
if ( result . uncompressedSize === 0 || file . options . dir ) {
compression = JSZip . compressions [ 'STORE' ] ;
result . compressedContent = "" ;
result . crc32 = 0 ;
} else if ( file . _data . compressionMethod === compression . magic ) {
result . compressedContent = file . _data . getCompressedContent ( ) ;
} else {
content = file . _data . getContent ( ) ;
// need to decompress / recompress
result . compressedContent = compression . compress ( JSZip . utils . transformTo ( compression . compressInputType , content ) ) ;
}
} else {
// have uncompressed data
content = getBinaryData ( file ) ;
if ( ! content || content . length === 0 || file . options . dir ) {
compression = JSZip . compressions [ 'STORE' ] ;
content = "" ;
}
result . uncompressedSize = content . length ;
result . crc32 = this . crc32 ( content ) ;
result . compressedContent = compression . compress ( JSZip . utils . transformTo ( compression . compressInputType , content ) ) ;
}
result . compressedSize = result . compressedContent . length ;
result . compressionMethod = compression . magic ;
return result ;
} ;
/ * *
* Generate the various parts used in the construction of the final zip file .
* @ param { string } name the file name .
* @ param { ZipObject } file the file content .
* @ param { JSZip . CompressedObject } compressedObject the compressed object .
* @ param { number } offset the current offset from the start of the zip file .
* @ return { object } the zip parts .
* /
var generateZipParts = function ( name , file , compressedObject , offset ) {
var data = compressedObject . compressedContent ,
utfEncodedFileName = this . utf8encode ( file . name ) ,
useUTF8 = utfEncodedFileName !== file . name ,
o = file . options ,
dosTime ,
dosDate ;
// date
// @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html
// @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html
// @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html
dosTime = o . date . getHours ( ) ;
dosTime = dosTime << 6 ;
dosTime = dosTime | o . date . getMinutes ( ) ;
dosTime = dosTime << 5 ;
dosTime = dosTime | o . date . getSeconds ( ) / 2 ;
dosDate = o . date . getFullYear ( ) - 1980 ;
dosDate = dosDate << 4 ;
dosDate = dosDate | ( o . date . getMonth ( ) + 1 ) ;
dosDate = dosDate << 5 ;
dosDate = dosDate | o . date . getDate ( ) ;
var header = "" ;
// version needed to extract
header += "\x0A\x00" ;
// general purpose bit flag
// set bit 11 if utf8
header += useUTF8 ? "\x00\x08" : "\x00\x00" ;
// compression method
header += compressedObject . compressionMethod ;
// last mod file time
header += decToHex ( dosTime , 2 ) ;
// last mod file date
header += decToHex ( dosDate , 2 ) ;
// crc-32
header += decToHex ( compressedObject . crc32 , 4 ) ;
// compressed size
header += decToHex ( compressedObject . compressedSize , 4 ) ;
// uncompressed size
header += decToHex ( compressedObject . uncompressedSize , 4 ) ;
// file name length
header += decToHex ( utfEncodedFileName . length , 2 ) ;
// extra field length
header += "\x00\x00" ;
var fileRecord = JSZip . signature . LOCAL _FILE _HEADER + header + utfEncodedFileName ;
var dirRecord = JSZip . signature . CENTRAL _FILE _HEADER +
// version made by (00: DOS)
"\x14\x00" +
// file header (common to file and central directory)
header +
// file comment length
"\x00\x00" +
// disk number start
"\x00\x00" +
// internal file attributes TODO
"\x00\x00" +
// external file attributes
( file . options . dir === true ? "\x10\x00\x00\x00" : "\x00\x00\x00\x00" ) +
// relative offset of local header
decToHex ( offset , 4 ) +
// file name
utfEncodedFileName ;
return {
fileRecord : fileRecord ,
dirRecord : dirRecord ,
compressedObject : compressedObject
} ;
} ;
/ * *
* An object to write any content to a string .
* @ constructor
* /
var StringWriter = function ( ) {
this . data = [ ] ;
} ;
StringWriter . prototype = {
/ * *
* Append any content to the current string .
* @ param { Object } input the content to add .
* /
append : function ( input ) {
input = JSZip . utils . transformTo ( "string" , input ) ;
this . data . push ( input ) ;
} ,
/ * *
* Finalize the construction an return the result .
* @ return { string } the generated string .
* /
finalize : function ( ) {
return this . data . join ( "" ) ;
}
} ;
/ * *
* An object to write any content to an Uint8Array .
* @ constructor
* @ param { number } length The length of the array .
* /
var Uint8ArrayWriter = function ( length ) {
this . data = new Uint8Array ( length ) ;
this . index = 0 ;
} ;
Uint8ArrayWriter . prototype = {
/ * *
* Append any content to the current array .
* @ param { Object } input the content to add .
* /
append : function ( input ) {
if ( input . length !== 0 ) {
// with an empty Uint8Array, Opera fails with a "Offset larger than array size"
input = JSZip . utils . transformTo ( "uint8array" , input ) ;
this . data . set ( input , this . index ) ;
this . index += input . length ;
}
} ,
/ * *
* Finalize the construction an return the result .
* @ return { Uint8Array } the generated array .
* /
finalize : function ( ) {
return this . data ;
}
} ;
// return the actual prototype of JSZip
return {
/ * *
* Read an existing zip and merge the data in the current JSZip object .
* The implementation is in jszip - load . js , don ' t forget to include it .
* @ param { String | ArrayBuffer | Uint8Array | Buffer } stream The stream to load
* @ param { Object } options Options for loading the stream .
* options . base64 : is the stream in base64 ? default : false
* @ return { JSZip } the current JSZip object
* /
load : function ( stream , options ) {
throw new Error ( "Load method is not defined. Is the file jszip-load.js included ?" ) ;
} ,
/ * *
* Filter nested files / folders with the specified function .
* @ param { Function } search the predicate to use :
* function ( relativePath , file ) { ... }
* It takes 2 arguments : the relative path and the file .
* @ return { Array } An array of matching elements .
* /
filter : function ( search ) {
var result = [ ] , filename , relativePath , file , fileClone ;
for ( filename in this . files ) {
if ( ! this . files . hasOwnProperty ( filename ) ) { continue ; }
file = this . files [ filename ] ;
// return a new object, don't let the user mess with our internal objects :)
fileClone = new ZipObject ( file . name , file . _data , extend ( file . options ) ) ;
relativePath = filename . slice ( this . root . length , filename . length ) ;
if ( filename . slice ( 0 , this . root . length ) === this . root && // the file is in the current root
search ( relativePath , fileClone ) ) { // and the file matches the function
result . push ( fileClone ) ;
}
}
return result ;
} ,
/ * *
* Add a file to the zip file , or search a file .
* @ param { string | RegExp } name The name of the file to add ( if data is defined ) ,
* the name of the file to find ( if no data ) or a regex to match files .
* @ param { String | ArrayBuffer | Uint8Array | Buffer } data The file data , either raw or base64 encoded
* @ param { Object } o File options
* @ return { JSZip | Object | Array } this JSZip object ( when adding a file ) ,
* a file ( when searching by string ) or an array of files ( when searching by regex ) .
* /
file : function ( name , data , o ) {
if ( arguments . length === 1 ) {
if ( JSZip . utils . isRegExp ( name ) ) {
var regexp = name ;
return this . filter ( function ( relativePath , file ) {
return ! file . options . dir && regexp . test ( relativePath ) ;
} ) ;
} else { // text
return this . filter ( function ( relativePath , file ) {
return ! file . options . dir && relativePath === name ;
} ) [ 0 ] || null ;
}
} else { // more than one argument : we have data !
name = this . root + name ;
fileAdd . call ( this , name , data , o ) ;
}
return this ;
} ,
/ * *
* Add a directory to the zip file , or search .
* @ param { String | RegExp } arg The name of the directory to add , or a regex to search folders .
* @ return { JSZip } an object with the new directory as the root , or an array containing matching folders .
* /
folder : function ( arg ) {
if ( ! arg ) {
2012-12-04 19:27:20 +00:00
return this ;
2013-11-06 06:05:32 +00:00
}
if ( JSZip . utils . isRegExp ( arg ) ) {
return this . filter ( function ( relativePath , file ) {
return file . options . dir && arg . test ( relativePath ) ;
2012-12-04 19:27:20 +00:00
} ) ;
2013-11-06 06:05:32 +00:00
}
2012-12-04 19:27:20 +00:00
2013-11-06 06:05:32 +00:00
// else, name is a new folder
var name = this . root + arg ;
var newFolder = folderAdd . call ( this , name ) ;
2012-12-04 19:27:20 +00:00
2013-11-06 06:05:32 +00:00
// Allow chaining by returning a new object with this folder as the root
var ret = this . clone ( ) ;
ret . root = newFolder . name ;
return ret ;
} ,
/ * *
* Delete a file , or a directory and all sub - files , from the zip
* @ param { string } name the name of the file to delete
* @ return { JSZip } this JSZip object
* /
remove : function ( name ) {
name = this . root + name ;
var file = this . files [ name ] ;
if ( ! file ) {
// Look for any folders
if ( name . slice ( - 1 ) != "/" ) {
name += "/" ;
}
file = this . files [ name ] ;
}
if ( file ) {
if ( ! file . options . dir ) {
// file
delete this . files [ name ] ;
2012-12-04 19:27:20 +00:00
} else {
2013-11-06 06:05:32 +00:00
// folder
var kids = this . filter ( function ( relativePath , file ) {
return file . name . slice ( 0 , name . length ) === name ;
} ) ;
for ( var i = 0 ; i < kids . length ; i ++ ) {
delete this . files [ kids [ i ] . name ] ;
}
}
}
return this ;
} ,
/ * *
* Generate the complete zip file
* @ param { Object } options the options to generate the zip file :
* - base64 , ( deprecated , use type instead ) true to generate base64 .
* - compression , "STORE" by default .
* - type , "base64" by default . Values are : string , base64 , uint8array , arraybuffer , blob .
* @ return { String | Uint8Array | ArrayBuffer | Buffer | Blob } the zip file
* /
generate : function ( options ) {
options = extend ( options || { } , {
base64 : true ,
compression : "STORE" ,
type : "base64"
} ) ;
JSZip . utils . checkSupport ( options . type ) ;
var zipData = [ ] , localDirLength = 0 , centralDirLength = 0 , writer , i ;
// first, generate all the zip parts.
for ( var name in this . files ) {
if ( ! this . files . hasOwnProperty ( name ) ) { continue ; }
var file = this . files [ name ] ;
var compressionName = file . options . compression || options . compression . toUpperCase ( ) ;
var compression = JSZip . compressions [ compressionName ] ;
if ( ! compression ) {
throw new Error ( compressionName + " is not a valid compression method !" ) ;
2012-12-04 19:27:20 +00:00
}
2013-11-06 06:05:32 +00:00
var compressedObject = generateCompressedObjectFrom . call ( this , file , compression ) ;
var zipPart = generateZipParts . call ( this , name , file , compressedObject , localDirLength ) ;
localDirLength += zipPart . fileRecord . length + compressedObject . compressedSize ;
centralDirLength += zipPart . dirRecord . length ;
zipData . push ( zipPart ) ;
}
var dirEnd = "" ;
// end of central dir signature
dirEnd = JSZip . signature . CENTRAL _DIRECTORY _END +
// number of this disk
"\x00\x00" +
// number of the disk with the start of the central directory
"\x00\x00" +
// total number of entries in the central directory on this disk
decToHex ( zipData . length , 2 ) +
// total number of entries in the central directory
decToHex ( zipData . length , 2 ) +
// size of the central directory 4 bytes
decToHex ( centralDirLength , 4 ) +
// offset of start of central directory with respect to the starting disk number
decToHex ( localDirLength , 4 ) +
// .ZIP file comment length
"\x00\x00" ;
// we have all the parts (and the total length)
// time to create a writer !
switch ( options . type . toLowerCase ( ) ) {
case "uint8array" :
case "arraybuffer" :
case "blob" :
case "nodebuffer" :
writer = new Uint8ArrayWriter ( localDirLength + centralDirLength + dirEnd . length ) ;
break ;
// case "base64" :
// case "string" :
default :
writer = new StringWriter ( localDirLength + centralDirLength + dirEnd . length ) ;
break ;
}
for ( i = 0 ; i < zipData . length ; i ++ ) {
writer . append ( zipData [ i ] . fileRecord ) ;
writer . append ( zipData [ i ] . compressedObject . compressedContent ) ;
}
for ( i = 0 ; i < zipData . length ; i ++ ) {
writer . append ( zipData [ i ] . dirRecord ) ;
}
writer . append ( dirEnd ) ;
var zip = writer . finalize ( ) ;
switch ( options . type . toLowerCase ( ) ) {
// case "zip is an Uint8Array"
case "uint8array" :
case "arraybuffer" :
case "nodebuffer" :
return JSZip . utils . transformTo ( options . type . toLowerCase ( ) , zip ) ;
case "blob" :
return JSZip . utils . arrayBuffer2Blob ( JSZip . utils . transformTo ( "arraybuffer" , zip ) ) ;
// case "zip is a string"
case "base64" :
return ( options . base64 ) ? JSZip . base64 . encode ( zip ) : zip ;
default : // case "string" :
return zip ;
}
} ,
/ * *
*
* Javascript crc32
* http : //www.webtoolkit.info/
*
* /
crc32 : function crc32 ( input , crc ) {
if ( typeof input === "undefined" || ! input . length ) {
return 0 ;
}
var isArray = JSZip . utils . getTypeOf ( input ) !== "string" ;
var table = [
0x00000000 , 0x77073096 , 0xEE0E612C , 0x990951BA ,
0x076DC419 , 0x706AF48F , 0xE963A535 , 0x9E6495A3 ,
0x0EDB8832 , 0x79DCB8A4 , 0xE0D5E91E , 0x97D2D988 ,
0x09B64C2B , 0x7EB17CBD , 0xE7B82D07 , 0x90BF1D91 ,
0x1DB71064 , 0x6AB020F2 , 0xF3B97148 , 0x84BE41DE ,
0x1ADAD47D , 0x6DDDE4EB , 0xF4D4B551 , 0x83D385C7 ,
0x136C9856 , 0x646BA8C0 , 0xFD62F97A , 0x8A65C9EC ,
0x14015C4F , 0x63066CD9 , 0xFA0F3D63 , 0x8D080DF5 ,
0x3B6E20C8 , 0x4C69105E , 0xD56041E4 , 0xA2677172 ,
0x3C03E4D1 , 0x4B04D447 , 0xD20D85FD , 0xA50AB56B ,
0x35B5A8FA , 0x42B2986C , 0xDBBBC9D6 , 0xACBCF940 ,
0x32D86CE3 , 0x45DF5C75 , 0xDCD60DCF , 0xABD13D59 ,
0x26D930AC , 0x51DE003A , 0xC8D75180 , 0xBFD06116 ,
0x21B4F4B5 , 0x56B3C423 , 0xCFBA9599 , 0xB8BDA50F ,
0x2802B89E , 0x5F058808 , 0xC60CD9B2 , 0xB10BE924 ,
0x2F6F7C87 , 0x58684C11 , 0xC1611DAB , 0xB6662D3D ,
0x76DC4190 , 0x01DB7106 , 0x98D220BC , 0xEFD5102A ,
0x71B18589 , 0x06B6B51F , 0x9FBFE4A5 , 0xE8B8D433 ,
0x7807C9A2 , 0x0F00F934 , 0x9609A88E , 0xE10E9818 ,
0x7F6A0DBB , 0x086D3D2D , 0x91646C97 , 0xE6635C01 ,
0x6B6B51F4 , 0x1C6C6162 , 0x856530D8 , 0xF262004E ,
0x6C0695ED , 0x1B01A57B , 0x8208F4C1 , 0xF50FC457 ,
0x65B0D9C6 , 0x12B7E950 , 0x8BBEB8EA , 0xFCB9887C ,
0x62DD1DDF , 0x15DA2D49 , 0x8CD37CF3 , 0xFBD44C65 ,
0x4DB26158 , 0x3AB551CE , 0xA3BC0074 , 0xD4BB30E2 ,
0x4ADFA541 , 0x3DD895D7 , 0xA4D1C46D , 0xD3D6F4FB ,
0x4369E96A , 0x346ED9FC , 0xAD678846 , 0xDA60B8D0 ,
0x44042D73 , 0x33031DE5 , 0xAA0A4C5F , 0xDD0D7CC9 ,
0x5005713C , 0x270241AA , 0xBE0B1010 , 0xC90C2086 ,
0x5768B525 , 0x206F85B3 , 0xB966D409 , 0xCE61E49F ,
0x5EDEF90E , 0x29D9C998 , 0xB0D09822 , 0xC7D7A8B4 ,
0x59B33D17 , 0x2EB40D81 , 0xB7BD5C3B , 0xC0BA6CAD ,
0xEDB88320 , 0x9ABFB3B6 , 0x03B6E20C , 0x74B1D29A ,
0xEAD54739 , 0x9DD277AF , 0x04DB2615 , 0x73DC1683 ,
0xE3630B12 , 0x94643B84 , 0x0D6D6A3E , 0x7A6A5AA8 ,
0xE40ECF0B , 0x9309FF9D , 0x0A00AE27 , 0x7D079EB1 ,
0xF00F9344 , 0x8708A3D2 , 0x1E01F268 , 0x6906C2FE ,
0xF762575D , 0x806567CB , 0x196C3671 , 0x6E6B06E7 ,
0xFED41B76 , 0x89D32BE0 , 0x10DA7A5A , 0x67DD4ACC ,
0xF9B9DF6F , 0x8EBEEFF9 , 0x17B7BE43 , 0x60B08ED5 ,
0xD6D6A3E8 , 0xA1D1937E , 0x38D8C2C4 , 0x4FDFF252 ,
0xD1BB67F1 , 0xA6BC5767 , 0x3FB506DD , 0x48B2364B ,
0xD80D2BDA , 0xAF0A1B4C , 0x36034AF6 , 0x41047A60 ,
0xDF60EFC3 , 0xA867DF55 , 0x316E8EEF , 0x4669BE79 ,
0xCB61B38C , 0xBC66831A , 0x256FD2A0 , 0x5268E236 ,
0xCC0C7795 , 0xBB0B4703 , 0x220216B9 , 0x5505262F ,
0xC5BA3BBE , 0xB2BD0B28 , 0x2BB45A92 , 0x5CB36A04 ,
0xC2D7FFA7 , 0xB5D0CF31 , 0x2CD99E8B , 0x5BDEAE1D ,
0x9B64C2B0 , 0xEC63F226 , 0x756AA39C , 0x026D930A ,
0x9C0906A9 , 0xEB0E363F , 0x72076785 , 0x05005713 ,
0x95BF4A82 , 0xE2B87A14 , 0x7BB12BAE , 0x0CB61B38 ,
0x92D28E9B , 0xE5D5BE0D , 0x7CDCEFB7 , 0x0BDBDF21 ,
0x86D3D2D4 , 0xF1D4E242 , 0x68DDB3F8 , 0x1FDA836E ,
0x81BE16CD , 0xF6B9265B , 0x6FB077E1 , 0x18B74777 ,
0x88085AE6 , 0xFF0F6A70 , 0x66063BCA , 0x11010B5C ,
0x8F659EFF , 0xF862AE69 , 0x616BFFD3 , 0x166CCF45 ,
0xA00AE278 , 0xD70DD2EE , 0x4E048354 , 0x3903B3C2 ,
0xA7672661 , 0xD06016F7 , 0x4969474D , 0x3E6E77DB ,
0xAED16A4A , 0xD9D65ADC , 0x40DF0B66 , 0x37D83BF0 ,
0xA9BCAE53 , 0xDEBB9EC5 , 0x47B2CF7F , 0x30B5FFE9 ,
0xBDBDF21C , 0xCABAC28A , 0x53B39330 , 0x24B4A3A6 ,
0xBAD03605 , 0xCDD70693 , 0x54DE5729 , 0x23D967BF ,
0xB3667A2E , 0xC4614AB8 , 0x5D681B02 , 0x2A6F2B94 ,
0xB40BBE37 , 0xC30C8EA1 , 0x5A05DF1B , 0x2D02EF8D
] ;
if ( typeof ( crc ) == "undefined" ) { crc = 0 ; }
var x = 0 ;
var y = 0 ;
var byte = 0 ;
crc = crc ^ ( - 1 ) ;
for ( var i = 0 , iTop = input . length ; i < iTop ; i ++ ) {
byte = isArray ? input [ i ] : input . charCodeAt ( i ) ;
y = ( crc ^ byte ) & 0xFF ;
x = table [ y ] ;
crc = ( crc >>> 8 ) ^ x ;
}
return crc ^ ( - 1 ) ;
} ,
// Inspired by http://my.opera.com/GreyWyvern/blog/show.dml/1725165
clone : function ( ) {
var newObj = new JSZip ( ) ;
for ( var i in this ) {
if ( typeof this [ i ] !== "function" ) {
newObj [ i ] = this [ i ] ;
}
}
return newObj ;
} ,
/ * *
* http : //www.webtoolkit.info/javascript-utf8.html
* /
utf8encode : function ( string ) {
// TextEncoder + Uint8Array to binary string is faster than checking every bytes on long strings.
// http://jsperf.com/utf8encode-vs-textencoder
// On short strings (file names for example), the TextEncoder API is (currently) slower.
if ( textEncoder ) {
var u8 = textEncoder . encode ( string ) ;
return JSZip . utils . transformTo ( "string" , u8 ) ;
}
if ( JSZip . support . nodebuffer ) {
return JSZip . utils . transformTo ( "string" , new Buffer ( string , "utf-8" ) ) ;
}
// array.join may be slower than string concatenation but generates less objects (less time spent garbage collecting).
// See also http://jsperf.com/array-direct-assignment-vs-push/31
var result = [ ] , resIndex = 0 ;
for ( var n = 0 ; n < string . length ; n ++ ) {
var c = string . charCodeAt ( n ) ;
if ( c < 128 ) {
result [ resIndex ++ ] = String . fromCharCode ( c ) ;
} else if ( ( c > 127 ) && ( c < 2048 ) ) {
result [ resIndex ++ ] = String . fromCharCode ( ( c >> 6 ) | 192 ) ;
result [ resIndex ++ ] = String . fromCharCode ( ( c & 63 ) | 128 ) ;
2012-12-04 19:27:20 +00:00
} else {
2013-11-06 06:05:32 +00:00
result [ resIndex ++ ] = String . fromCharCode ( ( c >> 12 ) | 224 ) ;
result [ resIndex ++ ] = String . fromCharCode ( ( ( c >> 6 ) & 63 ) | 128 ) ;
result [ resIndex ++ ] = String . fromCharCode ( ( c & 63 ) | 128 ) ;
2012-12-04 19:27:20 +00:00
}
2013-11-06 06:05:32 +00:00
}
return result . join ( "" ) ;
} ,
/ * *
* http : //www.webtoolkit.info/javascript-utf8.html
* /
utf8decode : function ( input ) {
var result = [ ] , resIndex = 0 ;
var type = JSZip . utils . getTypeOf ( input ) ;
var isArray = type !== "string" ;
var i = 0 ;
var c = 0 , c1 = 0 , c2 = 0 , c3 = 0 ;
// check if we can use the TextDecoder API
// see http://encoding.spec.whatwg.org/#api
if ( textDecoder ) {
return textDecoder . decode (
JSZip . utils . transformTo ( "uint8array" , input )
) ;
}
if ( JSZip . support . nodebuffer ) {
return JSZip . utils . transformTo ( "nodebuffer" , input ) . toString ( "utf-8" ) ;
}
while ( i < input . length ) {
c = isArray ? input [ i ] : input . charCodeAt ( i ) ;
if ( c < 128 ) {
result [ resIndex ++ ] = String . fromCharCode ( c ) ;
i ++ ;
} else if ( ( c > 191 ) && ( c < 224 ) ) {
c2 = isArray ? input [ i + 1 ] : input . charCodeAt ( i + 1 ) ;
result [ resIndex ++ ] = String . fromCharCode ( ( ( c & 31 ) << 6 ) | ( c2 & 63 ) ) ;
i += 2 ;
2012-12-04 19:27:20 +00:00
} else {
2013-11-06 06:05:32 +00:00
c2 = isArray ? input [ i + 1 ] : input . charCodeAt ( i + 1 ) ;
c3 = isArray ? input [ i + 2 ] : input . charCodeAt ( i + 2 ) ;
result [ resIndex ++ ] = String . fromCharCode ( ( ( c & 15 ) << 12 ) | ( ( c2 & 63 ) << 6 ) | ( c3 & 63 ) ) ;
i += 3 ;
2012-12-04 19:27:20 +00:00
}
2013-11-06 06:05:32 +00:00
}
return result . join ( "" ) ;
}
} ;
} ( ) ) ;
/ *
* Compression methods
* This object is filled in as follow :
* name : {
* magic // the 2 bytes indentifying the compression method
* compress // function, take the uncompressed content and return it compressed.
* uncompress // function, take the compressed content and return it uncompressed.
* compressInputType // string, the type accepted by the compress method. null to accept everything.
* uncompressInputType // string, the type accepted by the uncompress method. null to accept everything.
* }
*
* STORE is the default compression method , so it ' s included in this file .
* Other methods should go to separated files : the user wants modularity .
* /
JSZip . compressions = {
"STORE" : {
magic : "\x00\x00" ,
compress : function ( content ) {
return content ; // no compression
} ,
uncompress : function ( content ) {
return content ; // no compression
} ,
compressInputType : null ,
uncompressInputType : null
}
} ;
( function ( ) {
JSZip . utils = {
/ * *
* Convert a string to a "binary string" : a string containing only char codes between 0 and 255.
* @ p aram { string } str the string to transform .
* @ return { String } the binary string .
* /
string2binary : function ( str ) {
var result = "" ;
for ( var i = 0 ; i < str . length ; i ++ ) {
result += String . fromCharCode ( str . charCodeAt ( i ) & 0xff ) ;
}
return result ;
} ,
/ * *
* Create a Uint8Array from the string .
* @ param { string } str the string to transform .
* @ return { Uint8Array } the typed array .
* @ throws { Error } an Error if the browser doesn ' t support the requested feature .
* @ deprecated : use JSZip . utils . transformTo instead .
* /
string2Uint8Array : function ( str ) {
return JSZip . utils . transformTo ( "uint8array" , str ) ;
} ,
/ * *
* Create a string from the Uint8Array .
* @ param { Uint8Array } array the array to transform .
* @ return { string } the string .
* @ throws { Error } an Error if the browser doesn ' t support the requested feature .
* @ deprecated : use JSZip . utils . transformTo instead .
* /
uint8Array2String : function ( array ) {
return JSZip . utils . transformTo ( "string" , array ) ;
} ,
/ * *
* Create a blob from the given ArrayBuffer .
* @ param { ArrayBuffer } buffer the buffer to transform .
* @ return { Blob } the result .
* @ throws { Error } an Error if the browser doesn ' t support the requested feature .
* /
arrayBuffer2Blob : function ( buffer ) {
JSZip . utils . checkSupport ( "blob" ) ;
try {
// Blob constructor
return new Blob ( [ buffer ] , { type : "application/zip" } ) ;
}
catch ( e ) { }
try {
// deprecated, browser only, old way
var BlobBuilder = window . BlobBuilder || window . WebKitBlobBuilder || window . MozBlobBuilder || window . MSBlobBuilder ;
var builder = new BlobBuilder ( ) ;
builder . append ( buffer ) ;
return builder . getBlob ( 'application/zip' ) ;
}
catch ( e ) { }
// well, fuck ?!
throw new Error ( "Bug : can't construct the Blob." ) ;
} ,
/ * *
* Create a blob from the given string .
* @ param { string } str the string to transform .
* @ return { Blob } the result .
* @ throws { Error } an Error if the browser doesn ' t support the requested feature .
* /
string2Blob : function ( str ) {
var buffer = JSZip . utils . transformTo ( "arraybuffer" , str ) ;
return JSZip . utils . arrayBuffer2Blob ( buffer ) ;
}
} ;
/ * *
* The identity function .
* @ param { Object } input the input .
* @ return { Object } the same input .
* /
function identity ( input ) {
return input ;
}
/ * *
* Fill in an array with a string .
* @ param { String } str the string to use .
* @ param { Array | ArrayBuffer | Uint8Array | Buffer } array the array to fill in ( will be mutated ) .
* @ return { Array | ArrayBuffer | Uint8Array | Buffer } the updated array .
* /
function stringToArrayLike ( str , array ) {
for ( var i = 0 ; i < str . length ; ++ i ) {
array [ i ] = str . charCodeAt ( i ) & 0xFF ;
}
return array ;
}
/ * *
* Transform an array - like object to a string .
* @ param { Array | ArrayBuffer | Uint8Array | Buffer } array the array to transform .
* @ return { String } the result .
* /
function arrayLikeToString ( array ) {
// Performances notes :
// --------------------
// String.fromCharCode.apply(null, array) is the fastest, see
// see http://jsperf.com/converting-a-uint8array-to-a-string/2
// but the stack is limited (and we can get huge arrays !).
//
// result += String.fromCharCode(array[i]); generate too many strings !
//
// This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2
var chunk = 65536 ;
var result = [ ] , len = array . length , type = JSZip . utils . getTypeOf ( array ) , k = 0 ;
var canUseApply = true ;
try {
switch ( type ) {
case "uint8array" :
String . fromCharCode . apply ( null , new Uint8Array ( 0 ) ) ;
break ;
case "nodebuffer" :
String . fromCharCode . apply ( null , new Buffer ( 0 ) ) ;
break ;
}
} catch ( e ) {
canUseApply = false ;
}
// no apply : slow and painful algorithm
// default browser on android 4.*
if ( ! canUseApply ) {
var resultStr = "" ;
for ( var i = 0 ; i < array . length ; i ++ ) {
resultStr += String . fromCharCode ( array [ i ] ) ;
}
return resultStr ;
}
while ( k < len && chunk > 1 ) {
try {
if ( type === "array" || type === "nodebuffer" ) {
result . push ( String . fromCharCode . apply ( null , array . slice ( k , Math . min ( k + chunk , len ) ) ) ) ;
2012-12-04 19:27:20 +00:00
} else {
2013-11-06 06:05:32 +00:00
result . push ( String . fromCharCode . apply ( null , array . subarray ( k , Math . min ( k + chunk , len ) ) ) ) ;
}
k += chunk ;
} catch ( e ) {
chunk = Math . floor ( chunk / 2 ) ;
}
}
return result . join ( "" ) ;
}
/ * *
* Copy the data from an array - like to an other array - like .
* @ param { Array | ArrayBuffer | Uint8Array | Buffer } arrayFrom the origin array .
* @ param { Array | ArrayBuffer | Uint8Array | Buffer } arrayTo the destination array which will be mutated .
* @ return { Array | ArrayBuffer | Uint8Array | Buffer } the updated destination array .
* /
function arrayLikeToArrayLike ( arrayFrom , arrayTo ) {
for ( var i = 0 ; i < arrayFrom . length ; i ++ ) {
arrayTo [ i ] = arrayFrom [ i ] ;
}
return arrayTo ;
}
// a matrix containing functions to transform everything into everything.
var transform = { } ;
// string to ?
transform [ "string" ] = {
"string" : identity ,
"array" : function ( input ) {
return stringToArrayLike ( input , new Array ( input . length ) ) ;
} ,
"arraybuffer" : function ( input ) {
return transform [ "string" ] [ "uint8array" ] ( input ) . buffer ;
} ,
"uint8array" : function ( input ) {
return stringToArrayLike ( input , new Uint8Array ( input . length ) ) ;
} ,
"nodebuffer" : function ( input ) {
return stringToArrayLike ( input , new Buffer ( input . length ) ) ;
}
} ;
// array to ?
transform [ "array" ] = {
"string" : arrayLikeToString ,
"array" : identity ,
"arraybuffer" : function ( input ) {
return ( new Uint8Array ( input ) ) . buffer ;
} ,
"uint8array" : function ( input ) {
return new Uint8Array ( input ) ;
} ,
"nodebuffer" : function ( input ) {
return new Buffer ( input ) ;
}
} ;
// arraybuffer to ?
transform [ "arraybuffer" ] = {
"string" : function ( input ) {
return arrayLikeToString ( new Uint8Array ( input ) ) ;
} ,
"array" : function ( input ) {
return arrayLikeToArrayLike ( new Uint8Array ( input ) , new Array ( input . byteLength ) ) ;
} ,
"arraybuffer" : identity ,
"uint8array" : function ( input ) {
return new Uint8Array ( input ) ;
} ,
"nodebuffer" : function ( input ) {
return new Buffer ( new Uint8Array ( input ) ) ;
}
} ;
// uint8array to ?
transform [ "uint8array" ] = {
"string" : arrayLikeToString ,
"array" : function ( input ) {
return arrayLikeToArrayLike ( input , new Array ( input . length ) ) ;
} ,
"arraybuffer" : function ( input ) {
return input . buffer ;
} ,
"uint8array" : identity ,
"nodebuffer" : function ( input ) {
return new Buffer ( input ) ;
}
} ;
// nodebuffer to ?
transform [ "nodebuffer" ] = {
"string" : arrayLikeToString ,
"array" : function ( input ) {
return arrayLikeToArrayLike ( input , new Array ( input . length ) ) ;
} ,
"arraybuffer" : function ( input ) {
return transform [ "nodebuffer" ] [ "uint8array" ] ( input ) . buffer ;
} ,
"uint8array" : function ( input ) {
return arrayLikeToArrayLike ( input , new Uint8Array ( input . length ) ) ;
} ,
"nodebuffer" : identity
} ;
/ * *
* Transform an input into any type .
* The supported output type are : string , array , uint8array , arraybuffer , nodebuffer .
* If no output type is specified , the unmodified input will be returned .
* @ param { String } outputType the output type .
* @ param { String | Array | ArrayBuffer | Uint8Array | Buffer } input the input to convert .
* @ throws { Error } an Error if the browser doesn ' t support the requested output type .
* /
JSZip . utils . transformTo = function ( outputType , input ) {
if ( ! input ) {
// undefined, null, etc
// an empty string won't harm.
input = "" ;
}
if ( ! outputType ) {
return input ;
}
JSZip . utils . checkSupport ( outputType ) ;
var inputType = JSZip . utils . getTypeOf ( input ) ;
var result = transform [ inputType ] [ outputType ] ( input ) ;
return result ;
} ;
/ * *
* Return the type of the input .
* The type will be in a format valid for JSZip . utils . transformTo : string , array , uint8array , arraybuffer .
* @ param { Object } input the input to identify .
* @ return { String } the ( lowercase ) type of the input .
* /
JSZip . utils . getTypeOf = function ( input ) {
if ( typeof input === "string" ) {
return "string" ;
}
if ( Object . prototype . toString . call ( input ) === "[object Array]" ) {
return "array" ;
}
if ( JSZip . support . nodebuffer && Buffer . isBuffer ( input ) ) {
return "nodebuffer" ;
}
if ( JSZip . support . uint8array && input instanceof Uint8Array ) {
return "uint8array" ;
}
if ( JSZip . support . arraybuffer && input instanceof ArrayBuffer ) {
return "arraybuffer" ;
}
} ;
/ * *
* Cross - window , cross - Node - context regular expression detection
* @ param { Object } object Anything
* @ return { Boolean } true if the object is a regular expression ,
* false otherwise
* /
JSZip . utils . isRegExp = function ( object ) {
return Object . prototype . toString . call ( object ) === "[object RegExp]" ;
} ;
/ * *
* Throw an exception if the type is not supported .
* @ param { String } type the type to check .
* @ throws { Error } an Error if the browser doesn ' t support the requested type .
* /
JSZip . utils . checkSupport = function ( type ) {
var supported = true ;
switch ( type . toLowerCase ( ) ) {
case "uint8array" :
supported = JSZip . support . uint8array ;
break ;
case "arraybuffer" :
supported = JSZip . support . arraybuffer ;
break ;
case "nodebuffer" :
supported = JSZip . support . nodebuffer ;
break ;
case "blob" :
supported = JSZip . support . blob ;
break ;
}
if ( ! supported ) {
throw new Error ( type + " is not supported by this browser" ) ;
}
} ;
2012-12-04 19:27:20 +00:00
} ) ( ) ;
2013-11-06 06:05:32 +00:00
( function ( ) {
/ * *
* Represents an entry in the zip .
* The content may or may not be compressed .
* @ constructor
* /
JSZip . CompressedObject = function ( ) {
this . compressedSize = 0 ;
this . uncompressedSize = 0 ;
this . crc32 = 0 ;
this . compressionMethod = null ;
this . compressedContent = null ;
} ;
JSZip . CompressedObject . prototype = {
/ * *
* Return the decompressed content in an unspecified format .
* The format will depend on the decompressor .
* @ return { Object } the decompressed content .
* /
getContent : function ( ) {
return null ; // see implementation
} ,
/ * *
* Return the compressed content in an unspecified format .
* The format will depend on the compressed conten source .
* @ return { Object } the compressed content .
* /
getCompressedContent : function ( ) {
return null ; // see implementation
}
} ;
2012-12-04 19:27:20 +00:00
} ) ( ) ;
2013-11-06 06:05:32 +00:00
/ * *
*
* Base64 encode / decode
* http : //www.webtoolkit.info/
*
* Hacked so that it doesn ' t utf8 en / decode everything
* * /
JSZip . base64 = ( function ( ) {
// private property
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ;
return {
// public method for encoding
encode : function ( input , utf8 ) {
var output = "" ;
var chr1 , chr2 , chr3 , enc1 , enc2 , enc3 , enc4 ;
var i = 0 ;
while ( i < input . length ) {
chr1 = input . charCodeAt ( i ++ ) ;
chr2 = input . charCodeAt ( i ++ ) ;
chr3 = input . charCodeAt ( i ++ ) ;
enc1 = chr1 >> 2 ;
enc2 = ( ( chr1 & 3 ) << 4 ) | ( chr2 >> 4 ) ;
enc3 = ( ( chr2 & 15 ) << 2 ) | ( chr3 >> 6 ) ;
enc4 = chr3 & 63 ;
if ( isNaN ( chr2 ) ) {
enc3 = enc4 = 64 ;
} else if ( isNaN ( chr3 ) ) {
enc4 = 64 ;
2012-12-04 19:27:20 +00:00
}
2013-11-06 06:05:32 +00:00
output = output +
_keyStr . charAt ( enc1 ) + _keyStr . charAt ( enc2 ) +
_keyStr . charAt ( enc3 ) + _keyStr . charAt ( enc4 ) ;
}
return output ;
} ,
// public method for decoding
decode : function ( input , utf8 ) {
var output = "" ;
var chr1 , chr2 , chr3 ;
var enc1 , enc2 , enc3 , enc4 ;
var i = 0 ;
input = input . replace ( /[^A-Za-z0-9\+\/\=]/g , "" ) ;
while ( i < input . length ) {
enc1 = _keyStr . indexOf ( input . charAt ( i ++ ) ) ;
enc2 = _keyStr . indexOf ( input . charAt ( i ++ ) ) ;
enc3 = _keyStr . indexOf ( input . charAt ( i ++ ) ) ;
enc4 = _keyStr . indexOf ( input . charAt ( i ++ ) ) ;
chr1 = ( enc1 << 2 ) | ( enc2 >> 4 ) ;
chr2 = ( ( enc2 & 15 ) << 4 ) | ( enc3 >> 2 ) ;
chr3 = ( ( enc3 & 3 ) << 6 ) | enc4 ;
output = output + String . fromCharCode ( chr1 ) ;
if ( enc3 != 64 ) {
output = output + String . fromCharCode ( chr2 ) ;
2012-12-04 19:27:20 +00:00
}
2013-11-06 06:05:32 +00:00
if ( enc4 != 64 ) {
output = output + String . fromCharCode ( chr3 ) ;
2012-12-04 19:27:20 +00:00
}
2013-11-06 06:05:32 +00:00
}
return output ;
}
} ;
} ( ) ) ;
// enforcing Stuk's coding style
// vim: set shiftwidth=3 softtabstop=3:
( function ( ) {
"use strict" ;
if ( ! JSZip ) {
throw "JSZip not defined" ;
}
/*jshint -W004, -W018, -W030, -W032, -W033, -W034, -W037,-W040, -W055, -W056, -W061, -W064, -W093, -W117 */
var context = { } ;
( function ( ) {
// https://github.com/imaya/zlib.js
// tag 0.1.6
// file bin/deflate.min.js
/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ ( function ( ) { 'use strict' ; var n = void 0 , u = ! 0 , aa = this ; function ba ( e , d ) { var c = e . split ( "." ) , f = aa ; ! ( c [ 0 ] in f ) && f . execScript && f . execScript ( "var " + c [ 0 ] ) ; for ( var a ; c . length && ( a = c . shift ( ) ) ; ) ! c . length && d !== n ? f [ a ] = d : f = f [ a ] ? f [ a ] : f [ a ] = { } } ; var C = "undefined" !== typeof Uint8Array && "undefined" !== typeof Uint16Array && "undefined" !== typeof Uint32Array ; function K ( e , d ) { this . index = "number" === typeof d ? d : 0 ; this . d = 0 ; this . buffer = e instanceof ( C ? Uint8Array : Array ) ? e : new ( C ? Uint8Array : Array ) ( 32768 ) ; if ( 2 * this . buffer . length <= this . index ) throw Error ( "invalid index" ) ; this . buffer . length <= this . index && ca ( this ) } function ca ( e ) { var d = e . buffer , c , f = d . length , a = new ( C ? Uint8Array : Array ) ( f << 1 ) ; if ( C ) a . set ( d ) ; else for ( c = 0 ; c < f ; ++ c ) a [ c ] = d [ c ] ; return e . buffer = a }
K . prototype . a = function ( e , d , c ) { var f = this . buffer , a = this . index , b = this . d , k = f [ a ] , m ; c && 1 < d && ( e = 8 < d ? ( L [ e & 255 ] << 24 | L [ e >>> 8 & 255 ] << 16 | L [ e >>> 16 & 255 ] << 8 | L [ e >>> 24 & 255 ] ) >> 32 - d : L [ e ] >> 8 - d ) ; if ( 8 > d + b ) k = k << d | e , b += d ; else for ( m = 0 ; m < d ; ++ m ) k = k << 1 | e >> d - m - 1 & 1 , 8 === ++ b && ( b = 0 , f [ a ++ ] = L [ k ] , k = 0 , a === f . length && ( f = ca ( this ) ) ) ; f [ a ] = k ; this . buffer = f ; this . d = b ; this . index = a } ; K . prototype . finish = function ( ) { var e = this . buffer , d = this . index , c ; 0 < this . d && ( e [ d ] <<= 8 - this . d , e [ d ] = L [ e [ d ] ] , d ++ ) ; C ? c = e . subarray ( 0 , d ) : ( e . length = d , c = e ) ; return c } ;
var ga = new ( C ? Uint8Array : Array ) ( 256 ) , M ; for ( M = 0 ; 256 > M ; ++ M ) { for ( var R = M , S = R , ha = 7 , R = R >>> 1 ; R ; R >>>= 1 ) S <<= 1 , S |= R & 1 , -- ha ; ga [ M ] = ( S << ha & 255 ) >>> 0 } var L = ga ; function ja ( e ) { this . buffer = new ( C ? Uint16Array : Array ) ( 2 * e ) ; this . length = 0 } ja . prototype . getParent = function ( e ) { return 2 * ( ( e - 2 ) / 4 | 0 ) } ; ja . prototype . push = function ( e , d ) { var c , f , a = this . buffer , b ; c = this . length ; a [ this . length ++ ] = d ; for ( a [ this . length ++ ] = e ; 0 < c ; ) if ( f = this . getParent ( c ) , a [ c ] > a [ f ] ) b = a [ c ] , a [ c ] = a [ f ] , a [ f ] = b , b = a [ c + 1 ] , a [ c + 1 ] = a [ f + 1 ] , a [ f + 1 ] = b , c = f ; else break ; return this . length } ;
ja . prototype . pop = function ( ) { var e , d , c = this . buffer , f , a , b ; d = c [ 0 ] ; e = c [ 1 ] ; this . length -= 2 ; c [ 0 ] = c [ this . length ] ; c [ 1 ] = c [ this . length + 1 ] ; for ( b = 0 ; ; ) { a = 2 * b + 2 ; if ( a >= this . length ) break ; a + 2 < this . length && c [ a + 2 ] > c [ a ] && ( a += 2 ) ; if ( c [ a ] > c [ b ] ) f = c [ b ] , c [ b ] = c [ a ] , c [ a ] = f , f = c [ b + 1 ] , c [ b + 1 ] = c [ a + 1 ] , c [ a + 1 ] = f ; else break ; b = a } return { index : e , value : d , length : this . length } } ; function ka ( e , d ) { this . e = ma ; this . f = 0 ; this . input = C && e instanceof Array ? new Uint8Array ( e ) : e ; this . c = 0 ; d && ( d . lazy && ( this . f = d . lazy ) , "number" === typeof d . compressionType && ( this . e = d . compressionType ) , d . outputBuffer && ( this . b = C && d . outputBuffer instanceof Array ? new Uint8Array ( d . outputBuffer ) : d . outputBuffer ) , "number" === typeof d . outputIndex && ( this . c = d . outputIndex ) ) ; this . b || ( this . b = new ( C ? Uint8Array : Array ) ( 32768 ) ) } var ma = 2 , T = [ ] , U ;
for ( U = 0 ; 288 > U ; U ++ ) switch ( u ) { case 143 >= U : T . push ( [ U + 48 , 8 ] ) ; break ; case 255 >= U : T . push ( [ U - 144 + 400 , 9 ] ) ; break ; case 279 >= U : T . push ( [ U - 256 + 0 , 7 ] ) ; break ; case 287 >= U : T . push ( [ U - 280 + 192 , 8 ] ) ; break ; default : throw "invalid literal: " + U ; }
ka . prototype . h = function ( ) { var e , d , c , f , a = this . input ; switch ( this . e ) { case 0 : c = 0 ; for ( f = a . length ; c < f ; ) { d = C ? a . subarray ( c , c + 65535 ) : a . slice ( c , c + 65535 ) ; c += d . length ; var b = d , k = c === f , m = n , g = n , p = n , v = n , x = n , l = this . b , h = this . c ; if ( C ) { for ( l = new Uint8Array ( this . b . buffer ) ; l . length <= h + b . length + 5 ; ) l = new Uint8Array ( l . length << 1 ) ; l . set ( this . b ) } m = k ? 1 : 0 ; l [ h ++ ] = m | 0 ; g = b . length ; p = ~ g + 65536 & 65535 ; l [ h ++ ] = g & 255 ; l [ h ++ ] = g >>> 8 & 255 ; l [ h ++ ] = p & 255 ; l [ h ++ ] = p >>> 8 & 255 ; if ( C ) l . set ( b , h ) , h += b . length , l = l . subarray ( 0 , h ) ; else { v = 0 ; for ( x = b . length ; v < x ; ++ v ) l [ h ++ ] =
b [ v ] ; l . length = h } this . c = h ; this . b = l } break ; case 1 : var q = new K ( C ? new Uint8Array ( this . b . buffer ) : this . b , this . c ) ; q . a ( 1 , 1 , u ) ; q . a ( 1 , 2 , u ) ; var t = na ( this , a ) , w , da , z ; w = 0 ; for ( da = t . length ; w < da ; w ++ ) if ( z = t [ w ] , K . prototype . a . apply ( q , T [ z ] ) , 256 < z ) q . a ( t [ ++ w ] , t [ ++ w ] , u ) , q . a ( t [ ++ w ] , 5 ) , q . a ( t [ ++ w ] , t [ ++ w ] , u ) ; else if ( 256 === z ) break ; this . b = q . finish ( ) ; this . c = this . b . length ; break ; case ma : var B = new K ( C ? new Uint8Array ( this . b . buffer ) : this . b , this . c ) , ra , J , N , O , P , Ia = [ 16 , 17 , 18 , 0 , 8 , 7 , 9 , 6 , 10 , 5 , 11 , 4 , 12 , 3 , 13 , 2 , 14 , 1 , 15 ] , W , sa , X , ta , ea , ia = Array ( 19 ) ,
ua , Q , fa , y , va ; ra = ma ; B . a ( 1 , 1 , u ) ; B . a ( ra , 2 , u ) ; J = na ( this , a ) ; W = oa ( this . j , 15 ) ; sa = pa ( W ) ; X = oa ( this . i , 7 ) ; ta = pa ( X ) ; for ( N = 286 ; 257 < N && 0 === W [ N - 1 ] ; N -- ) ; for ( O = 30 ; 1 < O && 0 === X [ O - 1 ] ; O -- ) ; var wa = N , xa = O , F = new ( C ? Uint32Array : Array ) ( wa + xa ) , r , G , s , Y , E = new ( C ? Uint32Array : Array ) ( 316 ) , D , A , H = new ( C ? Uint8Array : Array ) ( 19 ) ; for ( r = G = 0 ; r < wa ; r ++ ) F [ G ++ ] = W [ r ] ; for ( r = 0 ; r < xa ; r ++ ) F [ G ++ ] = X [ r ] ; if ( ! C ) { r = 0 ; for ( Y = H . length ; r < Y ; ++ r ) H [ r ] = 0 } r = D = 0 ; for ( Y = F . length ; r < Y ; r += G ) { for ( G = 1 ; r + G < Y && F [ r + G ] === F [ r ] ; ++ G ) ; s = G ; if ( 0 === F [ r ] ) if ( 3 > s ) for ( ; 0 < s -- ; ) E [ D ++ ] = 0 ,
H [ 0 ] ++ ; else for ( ; 0 < s ; ) A = 138 > s ? s : 138 , A > s - 3 && A < s && ( A = s - 3 ) , 10 >= A ? ( E [ D ++ ] = 17 , E [ D ++ ] = A - 3 , H [ 17 ] ++ ) : ( E [ D ++ ] = 18 , E [ D ++ ] = A - 11 , H [ 18 ] ++ ) , s -= A ; else if ( E [ D ++ ] = F [ r ] , H [ F [ r ] ] ++ , s -- , 3 > s ) for ( ; 0 < s -- ; ) E [ D ++ ] = F [ r ] , H [ F [ r ] ] ++ ; else for ( ; 0 < s ; ) A = 6 > s ? s : 6 , A > s - 3 && A < s && ( A = s - 3 ) , E [ D ++ ] = 16 , E [ D ++ ] = A - 3 , H [ 16 ] ++ , s -= A } e = C ? E . subarray ( 0 , D ) : E . slice ( 0 , D ) ; ea = oa ( H , 7 ) ; for ( y = 0 ; 19 > y ; y ++ ) ia [ y ] = ea [ Ia [ y ] ] ; for ( P = 19 ; 4 < P && 0 === ia [ P - 1 ] ; P -- ) ; ua = pa ( ea ) ; B . a ( N - 257 , 5 , u ) ; B . a ( O - 1 , 5 , u ) ; B . a ( P - 4 , 4 , u ) ; for ( y = 0 ; y < P ; y ++ ) B . a ( ia [ y ] , 3 , u ) ; y = 0 ; for ( va = e . length ; y < va ; y ++ ) if ( Q =
e [ y ] , B . a ( ua [ Q ] , ea [ Q ] , u ) , 16 <= Q ) { y ++ ; switch ( Q ) { case 16 : fa = 2 ; break ; case 17 : fa = 3 ; break ; case 18 : fa = 7 ; break ; default : throw "invalid code: " + Q ; } B . a ( e [ y ] , fa , u ) } var ya = [ sa , W ] , za = [ ta , X ] , I , Aa , Z , la , Ba , Ca , Da , Ea ; Ba = ya [ 0 ] ; Ca = ya [ 1 ] ; Da = za [ 0 ] ; Ea = za [ 1 ] ; I = 0 ; for ( Aa = J . length ; I < Aa ; ++ I ) if ( Z = J [ I ] , B . a ( Ba [ Z ] , Ca [ Z ] , u ) , 256 < Z ) B . a ( J [ ++ I ] , J [ ++ I ] , u ) , la = J [ ++ I ] , B . a ( Da [ la ] , Ea [ la ] , u ) , B . a ( J [ ++ I ] , J [ ++ I ] , u ) ; else if ( 256 === Z ) break ; this . b = B . finish ( ) ; this . c = this . b . length ; break ; default : throw "invalid compression type" ; } return this . b } ;
function qa ( e , d ) { this . length = e ; this . g = d }
var Fa = function ( ) { function e ( a ) { switch ( u ) { case 3 === a : return [ 257 , a - 3 , 0 ] ; case 4 === a : return [ 258 , a - 4 , 0 ] ; case 5 === a : return [ 259 , a - 5 , 0 ] ; case 6 === a : return [ 260 , a - 6 , 0 ] ; case 7 === a : return [ 261 , a - 7 , 0 ] ; case 8 === a : return [ 262 , a - 8 , 0 ] ; case 9 === a : return [ 263 , a - 9 , 0 ] ; case 10 === a : return [ 264 , a - 10 , 0 ] ; case 12 >= a : return [ 265 , a - 11 , 1 ] ; case 14 >= a : return [ 266 , a - 13 , 1 ] ; case 16 >= a : return [ 267 , a - 15 , 1 ] ; case 18 >= a : return [ 268 , a - 17 , 1 ] ; case 22 >= a : return [ 269 , a - 19 , 2 ] ; case 26 >= a : return [ 270 , a - 23 , 2 ] ; case 30 >= a : return [ 271 , a - 27 , 2 ] ; case 34 >= a : return [ 272 ,
a - 31 , 2 ] ; case 42 >= a : return [ 273 , a - 35 , 3 ] ; case 50 >= a : return [ 274 , a - 43 , 3 ] ; case 58 >= a : return [ 275 , a - 51 , 3 ] ; case 66 >= a : return [ 276 , a - 59 , 3 ] ; case 82 >= a : return [ 277 , a - 67 , 4 ] ; case 98 >= a : return [ 278 , a - 83 , 4 ] ; case 114 >= a : return [ 279 , a - 99 , 4 ] ; case 130 >= a : return [ 280 , a - 115 , 4 ] ; case 162 >= a : return [ 281 , a - 131 , 5 ] ; case 194 >= a : return [ 282 , a - 163 , 5 ] ; case 226 >= a : return [ 283 , a - 195 , 5 ] ; case 257 >= a : return [ 284 , a - 227 , 5 ] ; case 258 === a : return [ 285 , a - 258 , 0 ] ; default : throw "invalid length: " + a ; } } var d = [ ] , c , f ; for ( c = 3 ; 258 >= c ; c ++ ) f = e ( c ) , d [ c ] = f [ 2 ] << 24 |
f [ 1 ] << 16 | f [ 0 ] ; return d } ( ) , Ga = C ? new Uint32Array ( Fa ) : Fa ;
function na ( e , d ) { function c ( a , c ) { var b = a . g , d = [ ] , f = 0 , e ; e = Ga [ a . length ] ; d [ f ++ ] = e & 65535 ; d [ f ++ ] = e >> 16 & 255 ; d [ f ++ ] = e >> 24 ; var g ; switch ( u ) { case 1 === b : g = [ 0 , b - 1 , 0 ] ; break ; case 2 === b : g = [ 1 , b - 2 , 0 ] ; break ; case 3 === b : g = [ 2 , b - 3 , 0 ] ; break ; case 4 === b : g = [ 3 , b - 4 , 0 ] ; break ; case 6 >= b : g = [ 4 , b - 5 , 1 ] ; break ; case 8 >= b : g = [ 5 , b - 7 , 1 ] ; break ; case 12 >= b : g = [ 6 , b - 9 , 2 ] ; break ; case 16 >= b : g = [ 7 , b - 13 , 2 ] ; break ; case 24 >= b : g = [ 8 , b - 17 , 3 ] ; break ; case 32 >= b : g = [ 9 , b - 25 , 3 ] ; break ; case 48 >= b : g = [ 10 , b - 33 , 4 ] ; break ; case 64 >= b : g = [ 11 , b - 49 , 4 ] ; break ; case 96 >= b : g = [ 12 , b -
65 , 5 ] ; break ; case 128 >= b : g = [ 13 , b - 97 , 5 ] ; break ; case 192 >= b : g = [ 14 , b - 129 , 6 ] ; break ; case 256 >= b : g = [ 15 , b - 193 , 6 ] ; break ; case 384 >= b : g = [ 16 , b - 257 , 7 ] ; break ; case 512 >= b : g = [ 17 , b - 385 , 7 ] ; break ; case 768 >= b : g = [ 18 , b - 513 , 8 ] ; break ; case 1024 >= b : g = [ 19 , b - 769 , 8 ] ; break ; case 1536 >= b : g = [ 20 , b - 1025 , 9 ] ; break ; case 2048 >= b : g = [ 21 , b - 1537 , 9 ] ; break ; case 3072 >= b : g = [ 22 , b - 2049 , 10 ] ; break ; case 4096 >= b : g = [ 23 , b - 3073 , 10 ] ; break ; case 6144 >= b : g = [ 24 , b - 4097 , 11 ] ; break ; case 8192 >= b : g = [ 25 , b - 6145 , 11 ] ; break ; case 12288 >= b : g = [ 26 , b - 8193 , 12 ] ; break ; case 16384 >=
b : g = [ 27 , b - 12289 , 12 ] ; break ; case 24576 >= b : g = [ 28 , b - 16385 , 13 ] ; break ; case 32768 >= b : g = [ 29 , b - 24577 , 13 ] ; break ; default : throw "invalid distance" ; } e = g ; d [ f ++ ] = e [ 0 ] ; d [ f ++ ] = e [ 1 ] ; d [ f ++ ] = e [ 2 ] ; var k , m ; k = 0 ; for ( m = d . length ; k < m ; ++ k ) l [ h ++ ] = d [ k ] ; t [ d [ 0 ] ] ++ ; w [ d [ 3 ] ] ++ ; q = a . length + c - 1 ; x = null } var f , a , b , k , m , g = { } , p , v , x , l = C ? new Uint16Array ( 2 * d . length ) : [ ] , h = 0 , q = 0 , t = new ( C ? Uint32Array : Array ) ( 286 ) , w = new ( C ? Uint32Array : Array ) ( 30 ) , da = e . f , z ; if ( ! C ) { for ( b = 0 ; 285 >= b ; ) t [ b ++ ] = 0 ; for ( b = 0 ; 29 >= b ; ) w [ b ++ ] = 0 } t [ 256 ] = 1 ; f = 0 ; for ( a = d . length ; f < a ; ++ f ) { b =
m = 0 ; for ( k = 3 ; b < k && f + b !== a ; ++ b ) m = m << 8 | d [ f + b ] ; g [ m ] === n && ( g [ m ] = [ ] ) ; p = g [ m ] ; if ( ! ( 0 < q -- ) ) { for ( ; 0 < p . length && 32768 < f - p [ 0 ] ; ) p . shift ( ) ; if ( f + 3 >= a ) { x && c ( x , - 1 ) ; b = 0 ; for ( k = a - f ; b < k ; ++ b ) z = d [ f + b ] , l [ h ++ ] = z , ++ t [ z ] ; break } 0 < p . length ? ( v = Ha ( d , f , p ) , x ? x . length < v . length ? ( z = d [ f - 1 ] , l [ h ++ ] = z , ++ t [ z ] , c ( v , 0 ) ) : c ( x , - 1 ) : v . length < da ? x = v : c ( v , 0 ) ) : x ? c ( x , - 1 ) : ( z = d [ f ] , l [ h ++ ] = z , ++ t [ z ] ) } p . push ( f ) } l [ h ++ ] = 256 ; t [ 256 ] ++ ; e . j = t ; e . i = w ; return C ? l . subarray ( 0 , h ) : l }
function Ha ( e , d , c ) { var f , a , b = 0 , k , m , g , p , v = e . length ; m = 0 ; p = c . length ; a : for ( ; m < p ; m ++ ) { f = c [ p - m - 1 ] ; k = 3 ; if ( 3 < b ) { for ( g = b ; 3 < g ; g -- ) if ( e [ f + g - 1 ] !== e [ d + g - 1 ] ) continue a ; k = b } for ( ; 258 > k && d + k < v && e [ f + k ] === e [ d + k ] ; ) ++ k ; k > b && ( a = f , b = k ) ; if ( 258 === k ) break } return new qa ( b , d - a ) }
function oa ( e , d ) { var c = e . length , f = new ja ( 572 ) , a = new ( C ? Uint8Array : Array ) ( c ) , b , k , m , g , p ; if ( ! C ) for ( g = 0 ; g < c ; g ++ ) a [ g ] = 0 ; for ( g = 0 ; g < c ; ++ g ) 0 < e [ g ] && f . push ( g , e [ g ] ) ; b = Array ( f . length / 2 ) ; k = new ( C ? Uint32Array : Array ) ( f . length / 2 ) ; if ( 1 === b . length ) return a [ f . pop ( ) . index ] = 1 , a ; g = 0 ; for ( p = f . length / 2 ; g < p ; ++ g ) b [ g ] = f . pop ( ) , k [ g ] = b [ g ] . value ; m = Ja ( k , k . length , d ) ; g = 0 ; for ( p = b . length ; g < p ; ++ g ) a [ b [ g ] . index ] = m [ g ] ; return a }
function Ja ( e , d , c ) { function f ( a ) { var b = g [ a ] [ p [ a ] ] ; b === d ? ( f ( a + 1 ) , f ( a + 1 ) ) : -- k [ b ] ; ++ p [ a ] } var a = new ( C ? Uint16Array : Array ) ( c ) , b = new ( C ? Uint8Array : Array ) ( c ) , k = new ( C ? Uint8Array : Array ) ( d ) , m = Array ( c ) , g = Array ( c ) , p = Array ( c ) , v = ( 1 << c ) - d , x = 1 << c - 1 , l , h , q , t , w ; a [ c - 1 ] = d ; for ( h = 0 ; h < c ; ++ h ) v < x ? b [ h ] = 0 : ( b [ h ] = 1 , v -= x ) , v <<= 1 , a [ c - 2 - h ] = ( a [ c - 1 - h ] / 2 | 0 ) + d ; a [ 0 ] = b [ 0 ] ; m [ 0 ] = Array ( a [ 0 ] ) ; g [ 0 ] = Array ( a [ 0 ] ) ; for ( h = 1 ; h < c ; ++ h ) a [ h ] > 2 * a [ h - 1 ] + b [ h ] && ( a [ h ] = 2 * a [ h - 1 ] + b [ h ] ) , m [ h ] = Array ( a [ h ] ) , g [ h ] = Array ( a [ h ] ) ; for ( l = 0 ; l < d ; ++ l ) k [ l ] = c ; for ( q = 0 ; q < a [ c - 1 ] ; ++ q ) m [ c -
1 ] [ q ] = e [ q ] , g [ c - 1 ] [ q ] = q ; for ( l = 0 ; l < c ; ++ l ) p [ l ] = 0 ; 1 === b [ c - 1 ] && ( -- k [ 0 ] , ++ p [ c - 1 ] ) ; for ( h = c - 2 ; 0 <= h ; -- h ) { t = l = 0 ; w = p [ h + 1 ] ; for ( q = 0 ; q < a [ h ] ; q ++ ) t = m [ h + 1 ] [ w ] + m [ h + 1 ] [ w + 1 ] , t > e [ l ] ? ( m [ h ] [ q ] = t , g [ h ] [ q ] = d , w += 2 ) : ( m [ h ] [ q ] = e [ l ] , g [ h ] [ q ] = l , ++ l ) ; p [ h ] = 0 ; 1 === b [ h ] && f ( h ) } return k }
function pa ( e ) { var d = new ( C ? Uint16Array : Array ) ( e . length ) , c = [ ] , f = [ ] , a = 0 , b , k , m , g ; b = 0 ; for ( k = e . length ; b < k ; b ++ ) c [ e [ b ] ] = ( c [ e [ b ] ] | 0 ) + 1 ; b = 1 ; for ( k = 16 ; b <= k ; b ++ ) f [ b ] = a , a += c [ b ] | 0 , a <<= 1 ; b = 0 ; for ( k = e . length ; b < k ; b ++ ) { a = f [ e [ b ] ] ; f [ e [ b ] ] += 1 ; m = d [ b ] = 0 ; for ( g = e [ b ] ; m < g ; m ++ ) d [ b ] = d [ b ] << 1 | a & 1 , a >>>= 1 } return d } ; ba ( "Zlib.RawDeflate" , ka ) ; ba ( "Zlib.RawDeflate.prototype.compress" , ka . prototype . h ) ; var Ka = { NONE : 0 , FIXED : 1 , DYNAMIC : ma } , V , La , $ , Ma ; if ( Object . keys ) V = Object . keys ( Ka ) ; else for ( La in V = [ ] , $ = 0 , Ka ) V [ $ ++ ] = La ; $ = 0 ; for ( Ma = V . length ; $ < Ma ; ++ $ ) La = V [ $ ] , ba ( "Zlib.RawDeflate.CompressionType." + La , Ka [ La ] ) ; } ) . call ( this ) ; //@ sourceMappingURL=rawdeflate.min.js.map
} ) . call ( context ) ;
/*jshint +W004, +W018, +W030, +W032, +W033, +W034, +W037,+W040, +W055, +W056, +W061, +W064, +W093, +W117 */
var compress = function ( input ) {
var deflate = new context . Zlib . RawDeflate ( input ) ;
return deflate . compress ( ) ;
} ;
var USE _TYPEDARRAY =
( typeof Uint8Array !== 'undefined' ) &&
( typeof Uint16Array !== 'undefined' ) &&
( typeof Uint32Array !== 'undefined' ) ;
// we add the compression method for JSZip
if ( ! JSZip . compressions [ "DEFLATE" ] ) {
JSZip . compressions [ "DEFLATE" ] = {
magic : "\x08\x00" ,
compress : compress ,
compressInputType : USE _TYPEDARRAY ? "uint8array" : "array"
} ;
} else {
JSZip . compressions [ "DEFLATE" ] . compress = compress ;
JSZip . compressions [ "DEFLATE" ] . compressInputType = USE _TYPEDARRAY ? "uint8array" : "array" ;
}
} ) ( ) ;
// enforcing Stuk's coding style
// vim: set shiftwidth=3 softtabstop=3:
( function ( ) {
"use strict" ;
if ( ! JSZip ) {
throw "JSZip not defined" ;
}
/*jshint -W004, -W030, -W032, -W033, -W034, -W040, -W056, -W061, -W064, -W093 */
var context = { } ;
( function ( ) {
// https://github.com/imaya/zlib.js
// tag 0.1.6
// file bin/deflate.min.js
/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ ( function ( ) { 'use strict' ; var l = void 0 , p = this ; function q ( c , d ) { var a = c . split ( "." ) , b = p ; ! ( a [ 0 ] in b ) && b . execScript && b . execScript ( "var " + a [ 0 ] ) ; for ( var e ; a . length && ( e = a . shift ( ) ) ; ) ! a . length && d !== l ? b [ e ] = d : b = b [ e ] ? b [ e ] : b [ e ] = { } } ; var r = "undefined" !== typeof Uint8Array && "undefined" !== typeof Uint16Array && "undefined" !== typeof Uint32Array ; function u ( c ) { var d = c . length , a = 0 , b = Number . POSITIVE _INFINITY , e , f , g , h , k , m , s , n , t ; for ( n = 0 ; n < d ; ++ n ) c [ n ] > a && ( a = c [ n ] ) , c [ n ] < b && ( b = c [ n ] ) ; e = 1 << a ; f = new ( r ? Uint32Array : Array ) ( e ) ; g = 1 ; h = 0 ; for ( k = 2 ; g <= a ; ) { for ( n = 0 ; n < d ; ++ n ) if ( c [ n ] === g ) { m = 0 ; s = h ; for ( t = 0 ; t < g ; ++ t ) m = m << 1 | s & 1 , s >>= 1 ; for ( t = m ; t < e ; t += k ) f [ t ] = g << 16 | n ; ++ h } ++ g ; h <<= 1 ; k <<= 1 } return [ f , a , b ] } ; function v ( c , d ) { this . g = [ ] ; this . h = 32768 ; this . c = this . f = this . d = this . k = 0 ; this . input = r ? new Uint8Array ( c ) : c ; this . l = ! 1 ; this . i = w ; this . p = ! 1 ; if ( d || ! ( d = { } ) ) d . index && ( this . d = d . index ) , d . bufferSize && ( this . h = d . bufferSize ) , d . bufferType && ( this . i = d . bufferType ) , d . resize && ( this . p = d . resize ) ; switch ( this . i ) { case x : this . a = 32768 ; this . b = new ( r ? Uint8Array : Array ) ( 32768 + this . h + 258 ) ; break ; case w : this . a = 0 ; this . b = new ( r ? Uint8Array : Array ) ( this . h ) ; this . e = this . u ; this . m = this . r ; this . j = this . s ; break ; default : throw Error ( "invalid inflate mode" ) ;
} } var x = 0 , w = 1 ;
v . prototype . t = function ( ) { for ( ; ! this . l ; ) { var c = y ( this , 3 ) ; c & 1 && ( this . l = ! 0 ) ; c >>>= 1 ; switch ( c ) { case 0 : var d = this . input , a = this . d , b = this . b , e = this . a , f = l , g = l , h = l , k = b . length , m = l ; this . c = this . f = 0 ; f = d [ a ++ ] ; if ( f === l ) throw Error ( "invalid uncompressed block header: LEN (first byte)" ) ; g = f ; f = d [ a ++ ] ; if ( f === l ) throw Error ( "invalid uncompressed block header: LEN (second byte)" ) ; g |= f << 8 ; f = d [ a ++ ] ; if ( f === l ) throw Error ( "invalid uncompressed block header: NLEN (first byte)" ) ; h = f ; f = d [ a ++ ] ; if ( f === l ) throw Error ( "invalid uncompressed block header: NLEN (second byte)" ) ; h |=
f << 8 ; if ( g === ~ h ) throw Error ( "invalid uncompressed block header: length verify" ) ; if ( a + g > d . length ) throw Error ( "input buffer is broken" ) ; switch ( this . i ) { case x : for ( ; e + g > b . length ; ) { m = k - e ; g -= m ; if ( r ) b . set ( d . subarray ( a , a + m ) , e ) , e += m , a += m ; else for ( ; m -- ; ) b [ e ++ ] = d [ a ++ ] ; this . a = e ; b = this . e ( ) ; e = this . a } break ; case w : for ( ; e + g > b . length ; ) b = this . e ( { o : 2 } ) ; break ; default : throw Error ( "invalid inflate mode" ) ; } if ( r ) b . set ( d . subarray ( a , a + g ) , e ) , e += g , a += g ; else for ( ; g -- ; ) b [ e ++ ] = d [ a ++ ] ; this . d = a ; this . a = e ; this . b = b ; break ; case 1 : this . j ( z ,
A ) ; break ; case 2 : B ( this ) ; break ; default : throw Error ( "unknown BTYPE: " + c ) ; } } return this . m ( ) } ;
var C = [ 16 , 17 , 18 , 0 , 8 , 7 , 9 , 6 , 10 , 5 , 11 , 4 , 12 , 3 , 13 , 2 , 14 , 1 , 15 ] , D = r ? new Uint16Array ( C ) : C , E = [ 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 13 , 15 , 17 , 19 , 23 , 27 , 31 , 35 , 43 , 51 , 59 , 67 , 83 , 99 , 115 , 131 , 163 , 195 , 227 , 258 , 258 , 258 ] , F = r ? new Uint16Array ( E ) : E , G = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 3 , 3 , 3 , 3 , 4 , 4 , 4 , 4 , 5 , 5 , 5 , 5 , 0 , 0 , 0 ] , H = r ? new Uint8Array ( G ) : G , I = [ 1 , 2 , 3 , 4 , 5 , 7 , 9 , 13 , 17 , 25 , 33 , 49 , 65 , 97 , 129 , 193 , 257 , 385 , 513 , 769 , 1025 , 1537 , 2049 , 3073 , 4097 , 6145 , 8193 , 12289 , 16385 , 24577 ] , J = r ? new Uint16Array ( I ) : I , K = [ 0 , 0 , 0 , 0 , 1 , 1 , 2 , 2 , 3 , 3 , 4 , 4 , 5 , 5 , 6 , 6 , 7 , 7 , 8 , 8 , 9 , 9 , 10 , 10 , 11 , 11 , 12 , 12 , 13 ,
13 ] , L = r ? new Uint8Array ( K ) : K , M = new ( r ? Uint8Array : Array ) ( 288 ) , N , O ; N = 0 ; for ( O = M . length ; N < O ; ++ N ) M [ N ] = 143 >= N ? 8 : 255 >= N ? 9 : 279 >= N ? 7 : 8 ; var z = u ( M ) , P = new ( r ? Uint8Array : Array ) ( 30 ) , Q , R ; Q = 0 ; for ( R = P . length ; Q < R ; ++ Q ) P [ Q ] = 5 ; var A = u ( P ) ; function y ( c , d ) { for ( var a = c . f , b = c . c , e = c . input , f = c . d , g ; b < d ; ) { g = e [ f ++ ] ; if ( g === l ) throw Error ( "input buffer is broken" ) ; a |= g << b ; b += 8 } g = a & ( 1 << d ) - 1 ; c . f = a >>> d ; c . c = b - d ; c . d = f ; return g }
function S ( c , d ) { for ( var a = c . f , b = c . c , e = c . input , f = c . d , g = d [ 0 ] , h = d [ 1 ] , k , m , s ; b < h ; ) { k = e [ f ++ ] ; if ( k === l ) break ; a |= k << b ; b += 8 } m = g [ a & ( 1 << h ) - 1 ] ; s = m >>> 16 ; c . f = a >> s ; c . c = b - s ; c . d = f ; return m & 65535 }
function B ( c ) { function d ( a , c , b ) { var d , f , e , g ; for ( g = 0 ; g < a ; ) switch ( d = S ( this , c ) , d ) { case 16 : for ( e = 3 + y ( this , 2 ) ; e -- ; ) b [ g ++ ] = f ; break ; case 17 : for ( e = 3 + y ( this , 3 ) ; e -- ; ) b [ g ++ ] = 0 ; f = 0 ; break ; case 18 : for ( e = 11 + y ( this , 7 ) ; e -- ; ) b [ g ++ ] = 0 ; f = 0 ; break ; default : f = b [ g ++ ] = d } return b } var a = y ( c , 5 ) + 257 , b = y ( c , 5 ) + 1 , e = y ( c , 4 ) + 4 , f = new ( r ? Uint8Array : Array ) ( D . length ) , g , h , k , m ; for ( m = 0 ; m < e ; ++ m ) f [ D [ m ] ] = y ( c , 3 ) ; g = u ( f ) ; h = new ( r ? Uint8Array : Array ) ( a ) ; k = new ( r ? Uint8Array : Array ) ( b ) ; c . j ( u ( d . call ( c , a , g , h ) ) , u ( d . call ( c , b , g , k ) ) ) }
v . prototype . j = function ( c , d ) { var a = this . b , b = this . a ; this . n = c ; for ( var e = a . length - 258 , f , g , h , k ; 256 !== ( f = S ( this , c ) ) ; ) if ( 256 > f ) b >= e && ( this . a = b , a = this . e ( ) , b = this . a ) , a [ b ++ ] = f ; else { g = f - 257 ; k = F [ g ] ; 0 < H [ g ] && ( k += y ( this , H [ g ] ) ) ; f = S ( this , d ) ; h = J [ f ] ; 0 < L [ f ] && ( h += y ( this , L [ f ] ) ) ; b >= e && ( this . a = b , a = this . e ( ) , b = this . a ) ; for ( ; k -- ; ) a [ b ] = a [ b ++ - h ] } for ( ; 8 <= this . c ; ) this . c -= 8 , this . d -- ; this . a = b } ;
v . prototype . s = function ( c , d ) { var a = this . b , b = this . a ; this . n = c ; for ( var e = a . length , f , g , h , k ; 256 !== ( f = S ( this , c ) ) ; ) if ( 256 > f ) b >= e && ( a = this . e ( ) , e = a . length ) , a [ b ++ ] = f ; else { g = f - 257 ; k = F [ g ] ; 0 < H [ g ] && ( k += y ( this , H [ g ] ) ) ; f = S ( this , d ) ; h = J [ f ] ; 0 < L [ f ] && ( h += y ( this , L [ f ] ) ) ; b + k > e && ( a = this . e ( ) , e = a . length ) ; for ( ; k -- ; ) a [ b ] = a [ b ++ - h ] } for ( ; 8 <= this . c ; ) this . c -= 8 , this . d -- ; this . a = b } ;
v . prototype . e = function ( ) { var c = new ( r ? Uint8Array : Array ) ( this . a - 32768 ) , d = this . a - 32768 , a , b , e = this . b ; if ( r ) c . set ( e . subarray ( 32768 , c . length ) ) ; else { a = 0 ; for ( b = c . length ; a < b ; ++ a ) c [ a ] = e [ a + 32768 ] } this . g . push ( c ) ; this . k += c . length ; if ( r ) e . set ( e . subarray ( d , d + 32768 ) ) ; else for ( a = 0 ; 32768 > a ; ++ a ) e [ a ] = e [ d + a ] ; this . a = 32768 ; return e } ;
v . prototype . u = function ( c ) { var d , a = this . input . length / this . d + 1 | 0 , b , e , f , g = this . input , h = this . b ; c && ( "number" === typeof c . o && ( a = c . o ) , "number" === typeof c . q && ( a += c . q ) ) ; 2 > a ? ( b = ( g . length - this . d ) / this . n [ 2 ] , f = 258 * ( b / 2 ) | 0 , e = f < h . length ? h . length + f : h . length << 1 ) : e = h . length * a ; r ? ( d = new Uint8Array ( e ) , d . set ( h ) ) : d = h ; return this . b = d } ;
v . prototype . m = function ( ) { var c = 0 , d = this . b , a = this . g , b , e = new ( r ? Uint8Array : Array ) ( this . k + ( this . a - 32768 ) ) , f , g , h , k ; if ( 0 === a . length ) return r ? this . b . subarray ( 32768 , this . a ) : this . b . slice ( 32768 , this . a ) ; f = 0 ; for ( g = a . length ; f < g ; ++ f ) { b = a [ f ] ; h = 0 ; for ( k = b . length ; h < k ; ++ h ) e [ c ++ ] = b [ h ] } f = 32768 ; for ( g = this . a ; f < g ; ++ f ) e [ c ++ ] = d [ f ] ; this . g = [ ] ; return this . buffer = e } ;
v . prototype . r = function ( ) { var c , d = this . a ; r ? this . p ? ( c = new Uint8Array ( d ) , c . set ( this . b . subarray ( 0 , d ) ) ) : c = this . b . subarray ( 0 , d ) : ( this . b . length > d && ( this . b . length = d ) , c = this . b ) ; return this . buffer = c } ; q ( "Zlib.RawInflate" , v ) ; q ( "Zlib.RawInflate.prototype.decompress" , v . prototype . t ) ; var T = { ADAPTIVE : w , BLOCK : x } , U , V , W , X ; if ( Object . keys ) U = Object . keys ( T ) ; else for ( V in U = [ ] , W = 0 , T ) U [ W ++ ] = V ; W = 0 ; for ( X = U . length ; W < X ; ++ W ) V = U [ W ] , q ( "Zlib.RawInflate.BufferType." + V , T [ V ] ) ; } ) . call ( this ) ; //@ sourceMappingURL=rawinflate.min.js.map
} ) . call ( context ) ;
/*jshint +W004, +W030, +W032, +W033, +W034, +W040, +W056, +W061, +W064, +W093 */
var uncompress = function ( input ) {
var inflate = new context . Zlib . RawInflate ( input ) ;
return inflate . decompress ( ) ;
} ;
var USE _TYPEDARRAY =
( typeof Uint8Array !== 'undefined' ) &&
( typeof Uint16Array !== 'undefined' ) &&
( typeof Uint32Array !== 'undefined' ) ;
// we add the compression method for JSZip
if ( ! JSZip . compressions [ "DEFLATE" ] ) {
JSZip . compressions [ "DEFLATE" ] = {
magic : "\x08\x00" ,
uncompress : uncompress ,
uncompressInputType : USE _TYPEDARRAY ? "uint8array" : "array"
} ;
} else {
JSZip . compressions [ "DEFLATE" ] . uncompress = uncompress ;
JSZip . compressions [ "DEFLATE" ] . uncompressInputType = USE _TYPEDARRAY ? "uint8array" : "array" ;
}
} ) ( ) ;
// enforcing Stuk's coding style
// vim: set shiftwidth=3 softtabstop=3:
/ * *
JSZip - A Javascript class for generating and reading zip files
< http : //stuartk.com/jszip>
( c ) 2011 David Duponchel < d . duponchel @ gmail . com >
Dual licenced under the MIT license or GPLv3 . See LICENSE . markdown .
* * /
/*global JSZip */
( function ( root ) {
"use strict" ;
var MAX _VALUE _16BITS = 65535 ;
var MAX _VALUE _32BITS = - 1 ; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1
/ * *
* Prettify a string read as binary .
* @ param { string } str the string to prettify .
* @ return { string } a pretty string .
* /
var pretty = function ( str ) {
var res = '' , code , i ;
for ( i = 0 ; i < ( str || "" ) . length ; i ++ ) {
code = str . charCodeAt ( i ) ;
res += '\\x' + ( code < 16 ? "0" : "" ) + code . toString ( 16 ) . toUpperCase ( ) ;
}
return res ;
} ;
/ * *
* Find a compression registered in JSZip .
* @ param { string } compressionMethod the method magic to find .
* @ return { Object | null } the JSZip compression object , null if none found .
* /
var findCompression = function ( compressionMethod ) {
for ( var method in JSZip . compressions ) {
if ( ! JSZip . compressions . hasOwnProperty ( method ) ) { continue ; }
if ( JSZip . compressions [ method ] . magic === compressionMethod ) {
return JSZip . compressions [ method ] ;
}
}
return null ;
} ;
// class DataReader {{{
/ * *
* Read bytes from a source .
* Developer tip : when debugging , a watch on pretty ( this . reader . data . slice ( this . reader . index ) )
* is very useful : )
* @ constructor
* @ param { String | ArrayBuffer | Uint8Array | Buffer } data the data to read .
* /
function DataReader ( data ) {
this . data = null ; // type : see implementation
this . length = 0 ;
this . index = 0 ;
}
DataReader . prototype = {
/ * *
* Check that the offset will not go too far .
* @ param { string } offset the additional offset to check .
* @ throws { Error } an Error if the offset is out of bounds .
* /
checkOffset : function ( offset ) {
this . checkIndex ( this . index + offset ) ;
} ,
/ * *
* Check that the specifed index will not be too far .
* @ param { string } newIndex the index to check .
* @ throws { Error } an Error if the index is out of bounds .
* /
checkIndex : function ( newIndex ) {
if ( this . length < newIndex || newIndex < 0 ) {
throw new Error ( "End of data reached (data length = " +
this . length + ", asked index = " +
( newIndex ) + "). Corrupted zip ?" ) ;
}
} ,
/ * *
* Change the index .
* @ param { number } newIndex The new index .
* @ throws { Error } if the new index is out of the data .
* /
setIndex : function ( newIndex ) {
this . checkIndex ( newIndex ) ;
this . index = newIndex ;
} ,
/ * *
* Skip the next n bytes .
* @ param { number } n the number of bytes to skip .
* @ throws { Error } if the new index is out of the data .
* /
skip : function ( n ) {
this . setIndex ( this . index + n ) ;
} ,
/ * *
* Get the byte at the specified index .
* @ param { number } i the index to use .
* @ return { number } a byte .
* /
byteAt : function ( i ) {
// see implementations
} ,
/ * *
* Get the next number with a given byte size .
* @ param { number } size the number of bytes to read .
* @ return { number } the corresponding number .
* /
readInt : function ( size ) {
var result = 0 , i ;
this . checkOffset ( size ) ;
for ( i = this . index + size - 1 ; i >= this . index ; i -- ) {
result = ( result << 8 ) + this . byteAt ( i ) ;
}
this . index += size ;
return result ;
} ,
/ * *
* Get the next string with a given byte size .
* @ param { number } size the number of bytes to read .
* @ return { string } the corresponding string .
* /
readString : function ( size ) {
return JSZip . utils . transformTo ( "string" , this . readData ( size ) ) ;
} ,
/ * *
* Get raw data without conversion , < size > bytes .
* @ param { number } size the number of bytes to read .
* @ return { Object } the raw data , implementation specific .
* /
readData : function ( size ) {
// see implementations
} ,
/ * *
* Find the last occurence of a zip signature ( 4 bytes ) .
* @ param { string } sig the signature to find .
* @ return { number } the index of the last occurence , - 1 if not found .
* /
lastIndexOfSignature : function ( sig ) {
// see implementations
} ,
/ * *
* Get the next date .
* @ return { Date } the date .
* /
readDate : function ( ) {
var dostime = this . readInt ( 4 ) ;
return new Date (
( ( dostime >> 25 ) & 0x7f ) + 1980 , // year
( ( dostime >> 21 ) & 0x0f ) - 1 , // month
( dostime >> 16 ) & 0x1f , // day
( dostime >> 11 ) & 0x1f , // hour
( dostime >> 5 ) & 0x3f , // minute
( dostime & 0x1f ) << 1 ) ; // second
}
} ;
/ * *
* Read bytes from a string .
* @ constructor
* @ param { String } data the data to read .
* /
function StringReader ( data , optimizedBinaryString ) {
this . data = data ;
if ( ! optimizedBinaryString ) {
this . data = JSZip . utils . string2binary ( this . data ) ;
}
this . length = this . data . length ;
this . index = 0 ;
}
StringReader . prototype = new DataReader ( ) ;
/ * *
* @ see DataReader . byteAt
* /
StringReader . prototype . byteAt = function ( i ) {
return this . data . charCodeAt ( i ) ;
} ;
/ * *
* @ see DataReader . lastIndexOfSignature
* /
StringReader . prototype . lastIndexOfSignature = function ( sig ) {
return this . data . lastIndexOf ( sig ) ;
} ;
/ * *
* @ see DataReader . readData
* /
StringReader . prototype . readData = function ( size ) {
this . checkOffset ( size ) ;
// this will work because the constructor applied the "& 0xff" mask.
var result = this . data . slice ( this . index , this . index + size ) ;
this . index += size ;
return result ;
} ;
/ * *
* Read bytes from an Uin8Array .
* @ constructor
* @ param { Uint8Array } data the data to read .
* /
function Uint8ArrayReader ( data ) {
if ( data ) {
this . data = data ;
this . length = this . data . length ;
this . index = 0 ;
}
}
Uint8ArrayReader . prototype = new DataReader ( ) ;
/ * *
* @ see DataReader . byteAt
* /
Uint8ArrayReader . prototype . byteAt = function ( i ) {
return this . data [ i ] ;
} ;
/ * *
* @ see DataReader . lastIndexOfSignature
* /
Uint8ArrayReader . prototype . lastIndexOfSignature = function ( sig ) {
var sig0 = sig . charCodeAt ( 0 ) ,
sig1 = sig . charCodeAt ( 1 ) ,
sig2 = sig . charCodeAt ( 2 ) ,
sig3 = sig . charCodeAt ( 3 ) ;
for ( var i = this . length - 4 ; i >= 0 ; -- i ) {
if ( this . data [ i ] === sig0 && this . data [ i + 1 ] === sig1 && this . data [ i + 2 ] === sig2 && this . data [ i + 3 ] === sig3 ) {
return i ;
}
}
return - 1 ;
} ;
/ * *
* @ see DataReader . readData
* /
Uint8ArrayReader . prototype . readData = function ( size ) {
this . checkOffset ( size ) ;
var result = this . data . subarray ( this . index , this . index + size ) ;
this . index += size ;
return result ;
} ;
/ * *
* Read bytes from a Buffer .
* @ constructor
* @ param { Buffer } data the data to read .
* /
function NodeBufferReader ( data ) {
this . data = data ;
this . length = this . data . length ;
this . index = 0 ;
}
NodeBufferReader . prototype = new Uint8ArrayReader ( ) ;
/ * *
* @ see DataReader . readData
* /
NodeBufferReader . prototype . readData = function ( size ) {
this . checkOffset ( size ) ;
var result = this . data . slice ( this . index , this . index + size ) ;
this . index += size ;
return result ;
} ;
// }}} end of DataReader
// class ZipEntry {{{
/ * *
* An entry in the zip file .
* @ constructor
* @ param { Object } options Options of the current file .
* @ param { Object } loadOptions Options for loading the data .
* /
function ZipEntry ( options , loadOptions ) {
this . options = options ;
this . loadOptions = loadOptions ;
}
ZipEntry . prototype = {
/ * *
* say if the file is encrypted .
* @ return { boolean } true if the file is encrypted , false otherwise .
* /
isEncrypted : function ( ) {
// bit 1 is set
return ( this . bitFlag & 0x0001 ) === 0x0001 ;
} ,
/ * *
* say if the file has utf - 8 filename / comment .
* @ return { boolean } true if the filename / comment is in utf - 8 , false otherwise .
* /
useUTF8 : function ( ) {
// bit 11 is set
return ( this . bitFlag & 0x0800 ) === 0x0800 ;
} ,
/ * *
* Prepare the function used to generate the compressed content from this ZipFile .
* @ param { DataReader } reader the reader to use .
* @ param { number } from the offset from where we should read the data .
* @ param { number } length the length of the data to read .
* @ return { Function } the callback to get the compressed content ( the type depends of the DataReader class ) .
* /
prepareCompressedContent : function ( reader , from , length ) {
return function ( ) {
var previousIndex = reader . index ;
reader . setIndex ( from ) ;
var compressedFileData = reader . readData ( length ) ;
reader . setIndex ( previousIndex ) ;
return compressedFileData ;
} ;
} ,
/ * *
* Prepare the function used to generate the uncompressed content from this ZipFile .
* @ param { DataReader } reader the reader to use .
* @ param { number } from the offset from where we should read the data .
* @ param { number } length the length of the data to read .
* @ param { JSZip . compression } compression the compression used on this file .
* @ param { number } uncompressedSize the uncompressed size to expect .
* @ return { Function } the callback to get the uncompressed content ( the type depends of the DataReader class ) .
* /
prepareContent : function ( reader , from , length , compression , uncompressedSize ) {
return function ( ) {
var compressedFileData = JSZip . utils . transformTo ( compression . uncompressInputType , this . getCompressedContent ( ) ) ;
var uncompressedFileData = compression . uncompress ( compressedFileData ) ;
if ( uncompressedFileData . length !== uncompressedSize ) {
throw new Error ( "Bug : uncompressed data size mismatch" ) ;
2012-12-04 19:27:20 +00:00
}
2013-11-06 06:05:32 +00:00
return uncompressedFileData ;
} ;
} ,
/ * *
* Read the local part of a zip file and add the info in this object .
* @ param { DataReader } reader the reader to use .
* /
readLocalPart : function ( reader ) {
var compression , localExtraFieldsLength ;
// we already know everything from the central dir !
// If the central dir data are false, we are doomed.
// On the bright side, the local part is scary : zip64, data descriptors, both, etc.
// The less data we get here, the more reliable this should be.
// Let's skip the whole header and dash to the data !
reader . skip ( 22 ) ;
// in some zip created on windows, the filename stored in the central dir contains \ instead of /.
// Strangely, the filename here is OK.
// I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes
// or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators...
// Search "unzip mismatching "local" filename continuing with "central" filename version" on
// the internet.
//
// I think I see the logic here : the central directory is used to display
// content and the local directory is used to extract the files. Mixing / and \
// may be used to display \ to windows users and use / when extracting the files.
// Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394
this . fileNameLength = reader . readInt ( 2 ) ;
localExtraFieldsLength = reader . readInt ( 2 ) ; // can't be sure this will be the same as the central dir
this . fileName = reader . readString ( this . fileNameLength ) ;
reader . skip ( localExtraFieldsLength ) ;
if ( this . compressedSize == - 1 || this . uncompressedSize == - 1 ) {
throw new Error ( "Bug or corrupted zip : didn't get enough informations from the central directory " +
"(compressedSize == -1 || uncompressedSize == -1)" ) ;
}
compression = findCompression ( this . compressionMethod ) ;
if ( compression === null ) { // no compression found
throw new Error ( "Corrupted zip : compression " + pretty ( this . compressionMethod ) +
" unknown (inner file : " + this . fileName + ")" ) ;
}
this . decompressed = new JSZip . CompressedObject ( ) ;
this . decompressed . compressedSize = this . compressedSize ;
this . decompressed . uncompressedSize = this . uncompressedSize ;
this . decompressed . crc32 = this . crc32 ;
this . decompressed . compressionMethod = this . compressionMethod ;
this . decompressed . getCompressedContent = this . prepareCompressedContent ( reader , reader . index , this . compressedSize , compression ) ;
this . decompressed . getContent = this . prepareContent ( reader , reader . index , this . compressedSize , compression , this . uncompressedSize ) ;
// we need to compute the crc32...
if ( this . loadOptions . checkCRC32 ) {
this . decompressed = JSZip . utils . transformTo ( "string" , this . decompressed . getContent ( ) ) ;
if ( JSZip . prototype . crc32 ( this . decompressed ) !== this . crc32 ) {
throw new Error ( "Corrupted zip : CRC32 mismatch" ) ;
}
}
} ,
/ * *
* Read the central part of a zip file and add the info in this object .
* @ param { DataReader } reader the reader to use .
* /
readCentralPart : function ( reader ) {
this . versionMadeBy = reader . readString ( 2 ) ;
this . versionNeeded = reader . readInt ( 2 ) ;
this . bitFlag = reader . readInt ( 2 ) ;
this . compressionMethod = reader . readString ( 2 ) ;
this . date = reader . readDate ( ) ;
this . crc32 = reader . readInt ( 4 ) ;
this . compressedSize = reader . readInt ( 4 ) ;
this . uncompressedSize = reader . readInt ( 4 ) ;
this . fileNameLength = reader . readInt ( 2 ) ;
this . extraFieldsLength = reader . readInt ( 2 ) ;
this . fileCommentLength = reader . readInt ( 2 ) ;
this . diskNumberStart = reader . readInt ( 2 ) ;
this . internalFileAttributes = reader . readInt ( 2 ) ;
this . externalFileAttributes = reader . readInt ( 4 ) ;
this . localHeaderOffset = reader . readInt ( 4 ) ;
if ( this . isEncrypted ( ) ) {
throw new Error ( "Encrypted zip are not supported" ) ;
}
this . fileName = reader . readString ( this . fileNameLength ) ;
this . readExtraFields ( reader ) ;
this . parseZIP64ExtraField ( reader ) ;
this . fileComment = reader . readString ( this . fileCommentLength ) ;
// warning, this is true only for zip with madeBy == DOS (plateform dependent feature)
this . dir = this . externalFileAttributes & 0x00000010 ? true : false ;
} ,
/ * *
* Parse the ZIP64 extra field and merge the info in the current ZipEntry .
* @ param { DataReader } reader the reader to use .
* /
parseZIP64ExtraField : function ( reader ) {
if ( ! this . extraFields [ 0x0001 ] ) {
return ;
}
// should be something, preparing the extra reader
var extraReader = new StringReader ( this . extraFields [ 0x0001 ] . value ) ;
// I really hope that these 64bits integer can fit in 32 bits integer, because js
// won't let us have more.
if ( this . uncompressedSize === MAX _VALUE _32BITS ) {
this . uncompressedSize = extraReader . readInt ( 8 ) ;
}
if ( this . compressedSize === MAX _VALUE _32BITS ) {
this . compressedSize = extraReader . readInt ( 8 ) ;
}
if ( this . localHeaderOffset === MAX _VALUE _32BITS ) {
this . localHeaderOffset = extraReader . readInt ( 8 ) ;
}
if ( this . diskNumberStart === MAX _VALUE _32BITS ) {
this . diskNumberStart = extraReader . readInt ( 4 ) ;
}
} ,
/ * *
* Read the central part of a zip file and add the info in this object .
* @ param { DataReader } reader the reader to use .
* /
readExtraFields : function ( reader ) {
var start = reader . index ,
extraFieldId ,
extraFieldLength ,
extraFieldValue ;
this . extraFields = this . extraFields || { } ;
while ( reader . index < start + this . extraFieldsLength ) {
extraFieldId = reader . readInt ( 2 ) ;
extraFieldLength = reader . readInt ( 2 ) ;
extraFieldValue = reader . readString ( extraFieldLength ) ;
this . extraFields [ extraFieldId ] = {
id : extraFieldId ,
length : extraFieldLength ,
value : extraFieldValue
} ;
}
} ,
/ * *
* Apply an UTF8 transformation if needed .
* /
handleUTF8 : function ( ) {
if ( this . useUTF8 ( ) ) {
this . fileName = JSZip . prototype . utf8decode ( this . fileName ) ;
this . fileComment = JSZip . prototype . utf8decode ( this . fileComment ) ;
}
}
} ;
// }}} end of ZipEntry
// class ZipEntries {{{
/ * *
* All the entries in the zip file .
* @ constructor
* @ param { String | ArrayBuffer | Uint8Array | Buffer } data the binary data to load .
* @ param { Object } loadOptions Options for loading the data .
* /
function ZipEntries ( data , loadOptions ) {
this . files = [ ] ;
this . loadOptions = loadOptions ;
if ( data ) {
this . load ( data ) ;
}
}
ZipEntries . prototype = {
/ * *
* Check that the reader is on the speficied signature .
* @ param { string } expectedSignature the expected signature .
* @ throws { Error } if it is an other signature .
* /
checkSignature : function ( expectedSignature ) {
var signature = this . reader . readString ( 4 ) ;
if ( signature !== expectedSignature ) {
throw new Error ( "Corrupted zip or bug : unexpected signature " +
"(" + pretty ( signature ) + ", expected " + pretty ( expectedSignature ) + ")" ) ;
}
} ,
/ * *
* Read the end of the central directory .
* /
readBlockEndOfCentral : function ( ) {
this . diskNumber = this . reader . readInt ( 2 ) ;
this . diskWithCentralDirStart = this . reader . readInt ( 2 ) ;
this . centralDirRecordsOnThisDisk = this . reader . readInt ( 2 ) ;
this . centralDirRecords = this . reader . readInt ( 2 ) ;
this . centralDirSize = this . reader . readInt ( 4 ) ;
this . centralDirOffset = this . reader . readInt ( 4 ) ;
this . zipCommentLength = this . reader . readInt ( 2 ) ;
this . zipComment = this . reader . readString ( this . zipCommentLength ) ;
} ,
/ * *
* Read the end of the Zip 64 central directory .
* Not merged with the method readEndOfCentral :
* The end of central can coexist with its Zip64 brother ,
* I don ' t want to read the wrong number of bytes !
* /
readBlockZip64EndOfCentral : function ( ) {
this . zip64EndOfCentralSize = this . reader . readInt ( 8 ) ;
this . versionMadeBy = this . reader . readString ( 2 ) ;
this . versionNeeded = this . reader . readInt ( 2 ) ;
this . diskNumber = this . reader . readInt ( 4 ) ;
this . diskWithCentralDirStart = this . reader . readInt ( 4 ) ;
this . centralDirRecordsOnThisDisk = this . reader . readInt ( 8 ) ;
this . centralDirRecords = this . reader . readInt ( 8 ) ;
this . centralDirSize = this . reader . readInt ( 8 ) ;
this . centralDirOffset = this . reader . readInt ( 8 ) ;
this . zip64ExtensibleData = { } ;
var extraDataSize = this . zip64EndOfCentralSize - 44 ,
index = 0 ,
extraFieldId ,
extraFieldLength ,
extraFieldValue ;
while ( index < extraDataSize ) {
extraFieldId = this . reader . readInt ( 2 ) ;
extraFieldLength = this . reader . readInt ( 4 ) ;
extraFieldValue = this . reader . readString ( extraFieldLength ) ;
this . zip64ExtensibleData [ extraFieldId ] = {
id : extraFieldId ,
length : extraFieldLength ,
value : extraFieldValue
} ;
}
} ,
/ * *
* Read the end of the Zip 64 central directory locator .
* /
readBlockZip64EndOfCentralLocator : function ( ) {
this . diskWithZip64CentralDirStart = this . reader . readInt ( 4 ) ;
this . relativeOffsetEndOfZip64CentralDir = this . reader . readInt ( 8 ) ;
this . disksCount = this . reader . readInt ( 4 ) ;
if ( this . disksCount > 1 ) {
throw new Error ( "Multi-volumes zip are not supported" ) ;
}
} ,
/ * *
* Read the local files , based on the offset read in the central part .
* /
readLocalFiles : function ( ) {
var i , file ;
for ( i = 0 ; i < this . files . length ; i ++ ) {
file = this . files [ i ] ;
this . reader . setIndex ( file . localHeaderOffset ) ;
this . checkSignature ( JSZip . signature . LOCAL _FILE _HEADER ) ;
file . readLocalPart ( this . reader ) ;
file . handleUTF8 ( ) ;
}
} ,
/ * *
* Read the central directory .
* /
readCentralDir : function ( ) {
var file ;
this . reader . setIndex ( this . centralDirOffset ) ;
while ( this . reader . readString ( 4 ) === JSZip . signature . CENTRAL _FILE _HEADER ) {
file = new ZipEntry ( {
zip64 : this . zip64
} , this . loadOptions ) ;
file . readCentralPart ( this . reader ) ;
this . files . push ( file ) ;
}
} ,
/ * *
* Read the end of central directory .
* /
readEndOfCentral : function ( ) {
var offset = this . reader . lastIndexOfSignature ( JSZip . signature . CENTRAL _DIRECTORY _END ) ;
if ( offset === - 1 ) {
throw new Error ( "Corrupted zip : can't find end of central directory" ) ;
}
this . reader . setIndex ( offset ) ;
this . checkSignature ( JSZip . signature . CENTRAL _DIRECTORY _END ) ;
this . readBlockEndOfCentral ( ) ;
/ * e x t r a c t f r o m t h e z i p s p e c :
4 ) If one of the fields in the end of central directory
record is too small to hold required data , the field
should be set to - 1 ( 0xFFFF or 0xFFFFFFFF ) and the
ZIP64 format record should be created .
5 ) The end of central directory record and the
Zip64 end of central directory locator record must
reside on the same disk when splitting or spanning
an archive .
* /
if ( this . diskNumber === MAX _VALUE _16BITS ||
this . diskWithCentralDirStart === MAX _VALUE _16BITS ||
this . centralDirRecordsOnThisDisk === MAX _VALUE _16BITS ||
this . centralDirRecords === MAX _VALUE _16BITS ||
this . centralDirSize === MAX _VALUE _32BITS ||
this . centralDirOffset === MAX _VALUE _32BITS
) {
this . zip64 = true ;
/ *
Warning : the zip64 extension is supported , but ONLY if the 64 bits integer read from
the zip file can fit into a 32 bits integer . This cannot be solved : Javascript represents
all numbers as 64 - bit double precision IEEE 754 floating point numbers .
So , we have 53 bits for integers and bitwise operations treat everything as 32 bits .
see https : //developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators
and http : //www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5
* /
// should look for a zip64 EOCD locator
offset = this . reader . lastIndexOfSignature ( JSZip . signature . ZIP64 _CENTRAL _DIRECTORY _LOCATOR ) ;
2012-12-04 19:27:20 +00:00
if ( offset === - 1 ) {
2013-11-06 06:05:32 +00:00
throw new Error ( "Corrupted zip : can't find the ZIP64 end of central directory locator" ) ;
2012-12-04 19:27:20 +00:00
}
2013-11-06 06:05:32 +00:00
this . reader . setIndex ( offset ) ;
this . checkSignature ( JSZip . signature . ZIP64 _CENTRAL _DIRECTORY _LOCATOR ) ;
this . readBlockZip64EndOfCentralLocator ( ) ;
// now the zip64 EOCD record
this . reader . setIndex ( this . relativeOffsetEndOfZip64CentralDir ) ;
this . checkSignature ( JSZip . signature . ZIP64 _CENTRAL _DIRECTORY _END ) ;
this . readBlockZip64EndOfCentral ( ) ;
}
} ,
prepareReader : function ( data ) {
var type = JSZip . utils . getTypeOf ( data ) ;
if ( type === "string" && ! JSZip . support . uint8array ) {
this . reader = new StringReader ( data , this . loadOptions . optimizedBinaryString ) ;
} else if ( type === "nodebuffer" ) {
this . reader = new NodeBufferReader ( data ) ;
} else {
this . reader = new Uint8ArrayReader ( JSZip . utils . transformTo ( "uint8array" , data ) ) ;
}
} ,
/ * *
* Read a zip file and create ZipEntries .
* @ param { String | ArrayBuffer | Uint8Array | Buffer } data the binary string representing a zip file .
* /
load : function ( data ) {
this . prepareReader ( data ) ;
this . readEndOfCentral ( ) ;
this . readCentralDir ( ) ;
this . readLocalFiles ( ) ;
}
} ;
// }}} end of ZipEntries
/ * *
* Implementation of the load method of JSZip .
* It uses the above classes to decode a zip file , and load every files .
* @ param { String | ArrayBuffer | Uint8Array | Buffer } data the data to load .
* @ param { Object } options Options for loading the data .
* options . base64 : is the data in base64 ? default : false
* /
JSZip . prototype . load = function ( data , options ) {
var files , zipEntries , i , input ;
options = options || { } ;
if ( options . base64 ) {
data = JSZip . base64 . decode ( data ) ;
}
zipEntries = new ZipEntries ( data , options ) ;
files = zipEntries . files ;
for ( i = 0 ; i < files . length ; i ++ ) {
input = files [ i ] ;
this . file ( input . fileName , input . decompressed , {
binary : true ,
optimizedBinaryString : true ,
date : input . date ,
dir : input . dir
} ) ;
}
return this ;
} ;
} ( this ) ) ;
2012-12-04 19:27:20 +00:00
if ( typeof exports !== 'undefined' ) exports . JSZip = JSZip ;
2013-11-06 06:05:32 +00:00
// enforcing Stuk's coding style
// vim: set shiftwidth=3 softtabstop=3 foldmethod=marker: