From de5529905778866362f2e58c10cdb12e7b0fcab1 Mon Sep 17 00:00:00 2001 From: Karl Fogel Date: Tue, 4 Aug 2015 21:21:26 -0500 Subject: [PATCH] Export a CSV file inside a zipfile + folder (#14). * public/js/index.js: Export HMIS_Data.zip expanding to subfolder and file `HMIS_Data/Clients.csv`, the latter now finally in CSV format. Remove the experimental enrollments export code, as it's not that useful for completing the export of Universal Data Elements (UDE). * public/js/lib/jszip/: Add this third-party library from commit e3485a652 of https://github.com/Stuk/jszip, except replace upstream `dist/jszip.min.js` with our own made by yui-compressor. * app/views/index.jade: Require `jszip`. --- app/views/index.jade | 1 + public/js/index.js | 119 +- public/js/lib/jszip/.gitignore | 4 + public/js/lib/jszip/.jshintignore | 2 + public/js/lib/jszip/.jshintrc | 12 + public/js/lib/jszip/.npmignore | 8 + public/js/lib/jszip/.travis.yml | 11 + public/js/lib/jszip/CHANGES.md | 69 + public/js/lib/jszip/Gruntfile.js | 130 + public/js/lib/jszip/LICENSE.markdown | 651 ++ public/js/lib/jszip/README.markdown | 41 + public/js/lib/jszip/_config.yml | 25 + public/js/lib/jszip/bower.json | 22 + public/js/lib/jszip/component.json | 16 + public/js/lib/jszip/dist/jszip.js | 9155 +++++++++++++++++ public/js/lib/jszip/dist/jszip.min.js | 12 + public/js/lib/jszip/docs/APPNOTE.TXT | 3217 ++++++ public/js/lib/jszip/docs/ZIP spec.txt | 66 + public/js/lib/jszip/docs/references.txt | 18 + .../jszip/documentation/_layouts/default.html | 158 + .../js/lib/jszip/documentation/api_jszip.md | 15 + .../documentation/api_jszip/constructor.md | 23 + .../api_jszip/constructor_load.md | 22 + .../documentation/api_jszip/file_data.md | 90 + .../documentation/api_jszip/file_name.md | 46 + .../documentation/api_jszip/file_regex.md | 49 + .../jszip/documentation/api_jszip/filter.md | 43 + .../documentation/api_jszip/folder_data.md | 34 + .../documentation/api_jszip/folder_regex.md | 40 + .../jszip/documentation/api_jszip/generate.md | 139 + .../lib/jszip/documentation/api_jszip/load.md | 81 + .../jszip/documentation/api_jszip/remove.md | 37 + .../jszip/documentation/api_jszip/support.md | 16 + .../lib/jszip/documentation/api_zipobject.md | 37 + .../lib/jszip/documentation/contributing.md | 62 + .../js/lib/jszip/documentation/css/main.css | 24 + .../lib/jszip/documentation/css/pygments.css | 64 + public/js/lib/jszip/documentation/examples.md | 115 + .../examples/download-zip-file.html | 59 + .../documentation/examples/downloader.html | 58 + .../documentation/examples/downloader.js | 89 + .../examples/get-binary-files-ajax.html | 43 + .../examples/read-local-file-api.html | 87 + public/js/lib/jszip/documentation/faq.md | 19 + .../lib/jszip/documentation/howto/read_zip.md | 152 + .../jszip/documentation/howto/write_zip.md | 106 + .../js/lib/jszip/documentation/limitations.md | 73 + .../lib/jszip/documentation/upgrade_guide.md | 57 + public/js/lib/jszip/index.html | 169 + public/js/lib/jszip/lib/base64.js | 70 + public/js/lib/jszip/lib/compressedObject.js | 28 + public/js/lib/jszip/lib/compressions.js | 13 + public/js/lib/jszip/lib/crc32.js | 102 + public/js/lib/jszip/lib/dataReader.js | 107 + public/js/lib/jszip/lib/defaults.js | 11 + .../js/lib/jszip/lib/deprecatedPublicUtils.js | 105 + public/js/lib/jszip/lib/flate.js | 16 + public/js/lib/jszip/lib/index.js | 79 + public/js/lib/jszip/lib/license_header.js | 11 + public/js/lib/jszip/lib/load.js | 31 + public/js/lib/jszip/lib/nodeBuffer.js | 7 + public/js/lib/jszip/lib/nodeBufferReader.js | 20 + public/js/lib/jszip/lib/object.js | 883 ++ public/js/lib/jszip/lib/signature.js | 7 + public/js/lib/jszip/lib/stringReader.js | 36 + public/js/lib/jszip/lib/stringWriter.js | 30 + public/js/lib/jszip/lib/support.js | 34 + public/js/lib/jszip/lib/uint8ArrayReader.js | 47 + public/js/lib/jszip/lib/uint8ArrayWriter.js | 36 + public/js/lib/jszip/lib/utf8.js | 207 + public/js/lib/jszip/lib/utils.js | 326 + public/js/lib/jszip/lib/zipEntries.js | 221 + public/js/lib/jszip/lib/zipEntry.js | 310 + public/js/lib/jszip/package.json | 53 + .../js/lib/jszip/test/browser-test-utils.js | 5 + public/js/lib/jszip/test/index.html | 75 + public/js/lib/jszip/test/jquery-1.8.3.min.js | 2 + public/js/lib/jszip/test/node.js | 9 + public/js/lib/jszip/test/qunit-1.11.0.css | 244 + public/js/lib/jszip/test/qunit-1.11.0.js | 2152 ++++ public/js/lib/jszip/test/ref/all.7zip.zip | Bin 0 -> 367 bytes public/js/lib/jszip/test/ref/all.windows.zip | Bin 0 -> 273 bytes public/js/lib/jszip/test/ref/all.zip | Bin 0 -> 367 bytes .../js/lib/jszip/test/ref/archive_comment.zip | Bin 0 -> 153 bytes public/js/lib/jszip/test/ref/backslash.zip | Bin 0 -> 130 bytes .../ref/complex_files/AntarcticaTemps.ods | Bin 0 -> 40538 bytes .../ref/complex_files/AntarcticaTemps.xlsx | Bin 0 -> 31683 bytes .../Franz Kafka - The Metamorphosis.epub | Bin 0 -> 278014 bytes .../complex_files/Outlook2007_Calendar.xps | Bin 0 -> 188822 bytes .../js/lib/jszip/test/ref/data_descriptor.zip | Bin 0 -> 196 bytes public/js/lib/jszip/test/ref/deflate.zip | Bin 0 -> 189 bytes public/js/lib/jszip/test/ref/encrypted.zip | Bin 0 -> 156 bytes .../lib/jszip/test/ref/extra_attributes.zip | Bin 0 -> 180 bytes public/js/lib/jszip/test/ref/folder.zip | Bin 0 -> 112 bytes public/js/lib/jszip/test/ref/image.zip | Bin 0 -> 157 bytes .../lib/jszip/test/ref/invalid/bad_offset.zip | Bin 0 -> 128 bytes .../jszip/test/ref/invalid/compression.zip | Bin 0 -> 189 bytes .../js/lib/jszip/test/ref/invalid/crc32.zip | Bin 0 -> 128 bytes public/js/lib/jszip/test/ref/nested.zip | Bin 0 -> 368 bytes .../jszip/test/ref/nested_data_descriptor.zip | Bin 0 -> 400 bytes public/js/lib/jszip/test/ref/nested_zip64.zip | Bin 0 -> 564 bytes .../jszip/test/ref/permissions/linux_7z.zip | Bin 0 -> 666 bytes .../jszip/test/ref/permissions/linux_ark.zip | Bin 0 -> 1030 bytes .../permissions/linux_file_roller-ubuntu.zip | Bin 0 -> 666 bytes .../permissions/linux_file_roller-xubuntu.zip | Bin 0 -> 1030 bytes .../jszip/test/ref/permissions/linux_zip.zip | Bin 0 -> 1030 bytes .../jszip/test/ref/permissions/mac_finder.zip | Bin 0 -> 862 bytes .../jszip/test/ref/permissions/windows_7z.zip | Bin 0 -> 1082 bytes .../windows_compressed_folders.zip | Bin 0 -> 612 bytes .../test/ref/permissions/windows_izarc.zip | Bin 0 -> 612 bytes .../test/ref/permissions/windows_winrar.zip | Bin 0 -> 1082 bytes public/js/lib/jszip/test/ref/pile_of_poo.zip | Bin 0 -> 209 bytes .../lib/jszip/test/ref/slashes_and_izarc.zip | Bin 0 -> 139 bytes public/js/lib/jszip/test/ref/store.zip | Bin 0 -> 210 bytes public/js/lib/jszip/test/ref/subfolder.zip | Bin 0 -> 222 bytes public/js/lib/jszip/test/ref/text.zip | Bin 0 -> 128 bytes public/js/lib/jszip/test/ref/utf8.zip | Bin 0 -> 124 bytes public/js/lib/jszip/test/ref/utf8_in_name.zip | Bin 0 -> 122 bytes .../jszip/test/ref/winrar_utf8_in_name.zip | Bin 0 -> 154 bytes public/js/lib/jszip/test/ref/zip64.zip | Bin 0 -> 288 bytes public/js/lib/jszip/test/smile.gif | Bin 0 -> 41 bytes public/js/lib/jszip/test/test.js | 1529 +++ public/js/lib/jszip/vendor/FileSaver.js | 247 + 123 files changed, 22589 insertions(+), 50 deletions(-) create mode 100644 public/js/lib/jszip/.gitignore create mode 100644 public/js/lib/jszip/.jshintignore create mode 100644 public/js/lib/jszip/.jshintrc create mode 100644 public/js/lib/jszip/.npmignore create mode 100644 public/js/lib/jszip/.travis.yml create mode 100644 public/js/lib/jszip/CHANGES.md create mode 100644 public/js/lib/jszip/Gruntfile.js create mode 100644 public/js/lib/jszip/LICENSE.markdown create mode 100644 public/js/lib/jszip/README.markdown create mode 100644 public/js/lib/jszip/_config.yml create mode 100644 public/js/lib/jszip/bower.json create mode 100644 public/js/lib/jszip/component.json create mode 100644 public/js/lib/jszip/dist/jszip.js create mode 100644 public/js/lib/jszip/dist/jszip.min.js create mode 100644 public/js/lib/jszip/docs/APPNOTE.TXT create mode 100644 public/js/lib/jszip/docs/ZIP spec.txt create mode 100644 public/js/lib/jszip/docs/references.txt create mode 100644 public/js/lib/jszip/documentation/_layouts/default.html create mode 100644 public/js/lib/jszip/documentation/api_jszip.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/constructor.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/constructor_load.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/file_data.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/file_name.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/file_regex.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/filter.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/folder_data.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/folder_regex.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/generate.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/load.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/remove.md create mode 100644 public/js/lib/jszip/documentation/api_jszip/support.md create mode 100644 public/js/lib/jszip/documentation/api_zipobject.md create mode 100644 public/js/lib/jszip/documentation/contributing.md create mode 100644 public/js/lib/jszip/documentation/css/main.css create mode 100644 public/js/lib/jszip/documentation/css/pygments.css create mode 100644 public/js/lib/jszip/documentation/examples.md create mode 100644 public/js/lib/jszip/documentation/examples/download-zip-file.html create mode 100644 public/js/lib/jszip/documentation/examples/downloader.html create mode 100644 public/js/lib/jszip/documentation/examples/downloader.js create mode 100644 public/js/lib/jszip/documentation/examples/get-binary-files-ajax.html create mode 100644 public/js/lib/jszip/documentation/examples/read-local-file-api.html create mode 100644 public/js/lib/jszip/documentation/faq.md create mode 100644 public/js/lib/jszip/documentation/howto/read_zip.md create mode 100644 public/js/lib/jszip/documentation/howto/write_zip.md create mode 100644 public/js/lib/jszip/documentation/limitations.md create mode 100644 public/js/lib/jszip/documentation/upgrade_guide.md create mode 100644 public/js/lib/jszip/index.html create mode 100644 public/js/lib/jszip/lib/base64.js create mode 100644 public/js/lib/jszip/lib/compressedObject.js create mode 100644 public/js/lib/jszip/lib/compressions.js create mode 100644 public/js/lib/jszip/lib/crc32.js create mode 100644 public/js/lib/jszip/lib/dataReader.js create mode 100644 public/js/lib/jszip/lib/defaults.js create mode 100644 public/js/lib/jszip/lib/deprecatedPublicUtils.js create mode 100644 public/js/lib/jszip/lib/flate.js create mode 100644 public/js/lib/jszip/lib/index.js create mode 100644 public/js/lib/jszip/lib/license_header.js create mode 100644 public/js/lib/jszip/lib/load.js create mode 100644 public/js/lib/jszip/lib/nodeBuffer.js create mode 100644 public/js/lib/jszip/lib/nodeBufferReader.js create mode 100644 public/js/lib/jszip/lib/object.js create mode 100644 public/js/lib/jszip/lib/signature.js create mode 100644 public/js/lib/jszip/lib/stringReader.js create mode 100644 public/js/lib/jszip/lib/stringWriter.js create mode 100644 public/js/lib/jszip/lib/support.js create mode 100644 public/js/lib/jszip/lib/uint8ArrayReader.js create mode 100644 public/js/lib/jszip/lib/uint8ArrayWriter.js create mode 100644 public/js/lib/jszip/lib/utf8.js create mode 100644 public/js/lib/jszip/lib/utils.js create mode 100644 public/js/lib/jszip/lib/zipEntries.js create mode 100644 public/js/lib/jszip/lib/zipEntry.js create mode 100644 public/js/lib/jszip/package.json create mode 100644 public/js/lib/jszip/test/browser-test-utils.js create mode 100644 public/js/lib/jszip/test/index.html create mode 100644 public/js/lib/jszip/test/jquery-1.8.3.min.js create mode 100644 public/js/lib/jszip/test/node.js create mode 100644 public/js/lib/jszip/test/qunit-1.11.0.css create mode 100644 public/js/lib/jszip/test/qunit-1.11.0.js create mode 100644 public/js/lib/jszip/test/ref/all.7zip.zip create mode 100644 public/js/lib/jszip/test/ref/all.windows.zip create mode 100644 public/js/lib/jszip/test/ref/all.zip create mode 100644 public/js/lib/jszip/test/ref/archive_comment.zip create mode 100644 public/js/lib/jszip/test/ref/backslash.zip create mode 100644 public/js/lib/jszip/test/ref/complex_files/AntarcticaTemps.ods create mode 100644 public/js/lib/jszip/test/ref/complex_files/AntarcticaTemps.xlsx create mode 100644 public/js/lib/jszip/test/ref/complex_files/Franz Kafka - The Metamorphosis.epub create mode 100644 public/js/lib/jszip/test/ref/complex_files/Outlook2007_Calendar.xps create mode 100644 public/js/lib/jszip/test/ref/data_descriptor.zip create mode 100644 public/js/lib/jszip/test/ref/deflate.zip create mode 100644 public/js/lib/jszip/test/ref/encrypted.zip create mode 100644 public/js/lib/jszip/test/ref/extra_attributes.zip create mode 100644 public/js/lib/jszip/test/ref/folder.zip create mode 100644 public/js/lib/jszip/test/ref/image.zip create mode 100644 public/js/lib/jszip/test/ref/invalid/bad_offset.zip create mode 100644 public/js/lib/jszip/test/ref/invalid/compression.zip create mode 100644 public/js/lib/jszip/test/ref/invalid/crc32.zip create mode 100644 public/js/lib/jszip/test/ref/nested.zip create mode 100644 public/js/lib/jszip/test/ref/nested_data_descriptor.zip create mode 100644 public/js/lib/jszip/test/ref/nested_zip64.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/linux_7z.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/linux_ark.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/linux_file_roller-ubuntu.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/linux_file_roller-xubuntu.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/linux_zip.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/mac_finder.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/windows_7z.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/windows_compressed_folders.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/windows_izarc.zip create mode 100644 public/js/lib/jszip/test/ref/permissions/windows_winrar.zip create mode 100644 public/js/lib/jszip/test/ref/pile_of_poo.zip create mode 100644 public/js/lib/jszip/test/ref/slashes_and_izarc.zip create mode 100644 public/js/lib/jszip/test/ref/store.zip create mode 100644 public/js/lib/jszip/test/ref/subfolder.zip create mode 100644 public/js/lib/jszip/test/ref/text.zip create mode 100644 public/js/lib/jszip/test/ref/utf8.zip create mode 100644 public/js/lib/jszip/test/ref/utf8_in_name.zip create mode 100644 public/js/lib/jszip/test/ref/winrar_utf8_in_name.zip create mode 100644 public/js/lib/jszip/test/ref/zip64.zip create mode 100644 public/js/lib/jszip/test/smile.gif create mode 100644 public/js/lib/jszip/test/test.js create mode 100644 public/js/lib/jszip/vendor/FileSaver.js diff --git a/app/views/index.jade b/app/views/index.jade index 168e003..b7235bc 100644 --- a/app/views/index.jade +++ b/app/views/index.jade @@ -16,6 +16,7 @@ html(lang="en") script(type='text/javascript', src='js/lib/pikaday.js') script(type='text/javascript', src='js/lib/FileSaver.js/FileSaver.min.js') script(type='text/javascript', src='js/lib/Blob.js/Blob.min.js') + script(type='text/javascript', src='js/lib/jszip/dist/jszip.min.js') script(type='text/javascript', src='js/lib/sampleData.js') script(type='text/javascript', src='js/papaparse.js') script(type='text/javascript', src='js/index.js') diff --git a/public/js/index.js b/public/js/index.js index f00dcfb..4dc75b8 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -322,8 +322,6 @@ $(function() { } function exportAll() { - console.log("DEBUG: calling exportAll()"); - /* For now we implement the downloadable-file functionality * entirely on the browser side, even though in the long-term * doing it in the intermediary node server is probably right. @@ -435,22 +433,11 @@ $(function() { */ // Export all clients. - console.log("DEBUG: exporting clients"); $.ajax("/clients", { method: "GET", dataType: "json" }).done(function(clients) { console.log("DEBUG: fetched clients for export: " + JSON.stringify(clients)); - var num_clients = clients.length; - console.log(" num clients: " + num_clients); - for (var i = 0; i < num_clients; i++) { - console.log(" client: " + JSON.stringify(clients[i])); - }; - // Create a downloadable for clients. Note it's still - // JSON, not CSV, and the JSON is still pretty opaque -- - // it's just "[object Object]" over and over. We'll - // unpack it when we're really creating CSV, of course. - // UDE columns to export to CSV (in progress): // // 3.13 PersonalID (3.13.1) @@ -477,47 +464,79 @@ $(function() { // no Veteran Status data. // 4.41 Veteran Information - var clients_downloadable = new Blob(clients, {type: "text/plain;charset=utf-8"}); - // We use the HUD 2014 standard name for this file, - // http://www.hudhdx.info/Resources/Vendors/4_0/HMISCSVSpecifications4_0FINAL.pdf - // Pages 17(bottom)-19 - // - // NOTE: For some reason, this saveAs() can blank your - // console log in the Firefox Inspect Element window. If - // you comment out the saveAs(), you'll see all the - // preceding console.log() output again. - saveAs(clients_downloadable, "Client.csv"); - }); - console.log("DEBUG: done exporting clients"); - - // Export all enrollments. - console.log("DEBUG: exporting enrollments"); - $.ajax("/enrollments", { - method: "GET", - dataType: "json" - }).done(function(enrollments) { - console.log("DEBUG: fetched enrollments for export: " + JSON.stringify(enrollments)); - var num_enrollments = enrollments.length; - console.log(" num enrollments: " + num_enrollments); - for (var i = 0; i < num_enrollments; i++) { - console.log(" enrollment: " + JSON.stringify(enrollments[i])); + // Initialize the CSV with a header row. + var clients_csv = + '"OrganizationID",' + + '"PersonalIdentificationNumber",' + + '"LegalFirstName",' + + '"LegalMiddleName",' + + '"LegalLastName",' + + '"LegalSuffix",' + + '"SocialSecurityNumber",' + + '"SocialSecNumberQualityCode",' + + '"DateOfBirth",' + + '"DateOfBirthQualityCode",' + + '"PrimaryRace",' + + '"SecondaryRace",' + + '"Ethnicity",' + + '"Gender",' + + '"DateAdded",' + + '"DateUpdated",' + + '"UpdateOrDelete",' + + '"IdentityVerification",' + + '"ReleaseOfInformation",' + + '"ExportIDStr"\n'; + for (var i = 0; i < clients.length; i++) { + c = clients[i]; + // Assemble the row. Note our dates come out as + // YYYY-MM-DD, which is correct according to + // http://www.hudhdx.info/Resources/Vendors/4_0/HMISCSVSpecifications4_0FINAL.pdf + // page 9 top, even though some existing HMIS software + // exports (and presumably imports) M/D/YYYY. + var this_row = "" + + "99" + ',' // OrganizationID + + (c.personalId ? c.personalId : "") + ',' // PersonalIdentificationNumber + + '"' + (c.firstName ? c.firstName : "") + '",' // LegalFirstName + + '"' + (c.middleName ? c.middleName : "") + '",' // LegalMiddleName + + '"' + (c.lastName ? c.lastName : "") + '",' // LegalLastName + + '"' + (c.nameSuffix ? c.nameSuffix : "") + '",' // LegalSuffix + + '"' + (c.ssn ? c.ssn : "") + '",' // SocialSecurityNumber + + '"' + (c.ssnDataQuality ? c.ssnDataQuality : "") + '",' // SocialSecNumberQualityCode + + '"' + (c.dob ? c.dob : "") + '",' // DateOfBirth + + '"' + (c.dobDataQuality ? c.dobDataQuality : "") + '",' // DateOfBirthQualityCode + + '"' + "" + '",' // PrimaryRace + + '"' + "" + '",' // SecondaryRace + + '"' + (c.ethnicity ? c.ethnicity : "") + '",' // Ethnicity + + '"' + (c.gender ? c.gender : "") + '",' // Gender + + '"' + (c.dateCreated ? c.dateCreated : "") + '",' // DateAdded + + '"' + (c.dateUpdated ? c.dateUpdated : "") + '",' // DateUpdated + + '"' + "" + '",' // UpdateOrDelete + + "" + ',' // IdentityVerification + + "" + ',' // ReleaseOfInformation + + "1729" + ''; // ExportIDStr + clients_csv += this_row + "\n"; + // Some other fields, from a JSON represntation of a + // client, that we may need to properly construct the + // PrimaryRace and SecondaryRace CSV fields. + // + // "amIndAKNative":0, + // "asian":0, + // "blackAfAmerican":0, + // "nativeHIOtherPacific":0, + // "white":1, + // "raceNone":8 }; - // Create a downloadable for enrollments. Note it's still - // JSON, not CSV, and the JSON is still pretty opaque -- - // it's just "[object Object]" over and over. We'll - // unpack it when we're really creating CSV, of course. - var enrollments_downloadable = new Blob(enrollments, {type: "text/plain;charset=utf-8"}); + + // Build and export the zipfile. + var zipper = new JSZip(); + var folder = zipper.folder("HMIS_Data"); // We use the HUD 2014 standard name for this file, // http://www.hudhdx.info/Resources/Vendors/4_0/HMISCSVSpecifications4_0FINAL.pdf - // Pages 19(bottom)-23(top) - // - // NOTE: For some reason, this saveAs() can blank your - // console log in the Firefox Inspect Element window. If - // you comment out the saveAs(), you'll see all the - // preceding console.log() output again. - saveAs(enrollments_downloadable, "Enrollment.csv"); + // Pages 17(bottom)-19 + folder.file("Client.csv", clients_csv); + var zipfile = zipper.generate({type:"blob"}); + saveAs(zipfile, "HMIS_Data.zip"); }); - console.log("DEBUG: done exporting enrollments"); } function importAll() { diff --git a/public/js/lib/jszip/.gitignore b/public/js/lib/jszip/.gitignore new file mode 100644 index 0000000..972cdc6 --- /dev/null +++ b/public/js/lib/jszip/.gitignore @@ -0,0 +1,4 @@ +*~ +node_modules +sauce_connect.log +.c9revisions \ No newline at end of file diff --git a/public/js/lib/jszip/.jshintignore b/public/js/lib/jszip/.jshintignore new file mode 100644 index 0000000..f05b1f2 --- /dev/null +++ b/public/js/lib/jszip/.jshintignore @@ -0,0 +1,2 @@ +node_modules +test diff --git a/public/js/lib/jszip/.jshintrc b/public/js/lib/jszip/.jshintrc new file mode 100644 index 0000000..0f34a5f --- /dev/null +++ b/public/js/lib/jszip/.jshintrc @@ -0,0 +1,12 @@ +{ + "undef": true, + "strict": true, + "sub": true, + + "globals": { + "TextEncoder": false, + "TextDecoder": false + }, + "browser": true, + "node": true +} diff --git a/public/js/lib/jszip/.npmignore b/public/js/lib/jszip/.npmignore new file mode 100644 index 0000000..e70a6ae --- /dev/null +++ b/public/js/lib/jszip/.npmignore @@ -0,0 +1,8 @@ +_config.yml +bower.json +component.json +docs +documentation +Gruntfile.js +index.html +test diff --git a/public/js/lib/jszip/.travis.yml b/public/js/lib/jszip/.travis.yml new file mode 100644 index 0000000..07c0624 --- /dev/null +++ b/public/js/lib/jszip/.travis.yml @@ -0,0 +1,11 @@ +language: node_js +node_js: +- '0.10' +script: npm run $COMMAND +env: + matrix: + - COMMAND=test-node + - COMMAND=test-browser + global: + - secure: MhA8GHU42X3GWTUMaqdZVvarx4BMjhQCUGNi3kvuD/iCmKVb7gMwj4jbds7AcJdsCRsRk8bBGzZs/E7HidBJMPDa5DhgLKy9EV1s42JlHq8lVzbJeWIGgrtyJvhVUkGRy2OJjnDSgh3U6elkQmvDn74jreSQc6m/yGoPFF1nqq8= + - secure: qREw6aUu2DnB+2reMuHgygSkumRiJvt7Z5Fz4uEVoraqbe65e4PGhtzypr9uIgCN43vxS2D5tAIeDbfid5VQrWFUQnrC9O5Z5qgVPsKN94zZ1tvYurXI4wRlAg58nNjkfGXWhLI3VUjjDTp5gYcMqgfe5hpEFYUPnUQkKGnaqAk= diff --git a/public/js/lib/jszip/CHANGES.md b/public/js/lib/jszip/CHANGES.md new file mode 100644 index 0000000..1b13776 --- /dev/null +++ b/public/js/lib/jszip/CHANGES.md @@ -0,0 +1,69 @@ +--- +title: Changelog +layout: default +section: main +--- + +### v2.5.0 2015-03-10 +- add support for custom mime-types (see [#199](https://github.com/Stuk/jszip/issues/199)). +- add an option to set the DEFLATE level (see [#201](https://github.com/Stuk/jszip/issues/201)). +- improve the error message with corrupted zip (see [#202](https://github.com/Stuk/jszip/issues/202)). +- add support for UNIX / DOS permissions (see [#200](https://github.com/Stuk/jszip/issues/200) and [#205](https://github.com/Stuk/jszip/issues/205)). + +### v2.4.0 2014-07-24 +- update pako to 0.2.5 (see [#156](https://github.com/Stuk/jszip/issues/156)). +- make JSZip work in a Firefox addon context (see [#151](https://github.com/Stuk/jszip/issues/151)). +- add an option (`createFolders`) to control the subfolder generation (see [#154](https://github.com/Stuk/jszip/issues/154)). +- allow `Buffer` polyfill in the browser (see [#139](https://github.com/Stuk/jszip/issues/139)). + +### v2.3.0 2014-06-18 +- don't generate subfolders (see [#130](https://github.com/Stuk/jszip/issues/130)). +- add comment support (see [#134](https://github.com/Stuk/jszip/issues/134)). +- on `ZipObject#options`, the attributes `date` and `dir` have been deprecated and are now on `ZipObject` (see [the upgrade guide](http://stuk.github.io/jszip/documentation/upgrade_guide.html)). +- on `ZipObject#options`, the attributes `base64` and `binary` have been deprecated (see [the upgrade guide](http://stuk.github.io/jszip/documentation/upgrade_guide.html)). +- deprecate internal functions exposed in the public API (see [#123](https://github.com/Stuk/jszip/issues/123)). +- improve UTF-8 support (see [#142](https://github.com/Stuk/jszip/issues/142)). + +### v2.2.2, 2014-05-01 + - update pako to v0.2.1, fix an error when decompressing some files (see [#126](https://github.com/Stuk/jszip/issues/126)). + +### v2.2.1, 2014-04-23 + - fix unreadable generated file on Windows 8 (see [#112](https://github.com/Stuk/jszip/issues/112)). + - replace zlibjs with pako. + +### v2.2.0, 2014-02-25 + - make the `new` operator optional before the `JSZip` constructor (see [#93](https://github.com/Stuk/jszip/pull/93)). + - update zlibjs to v0.2.0. + +### v2.1.1, 2014-02-13 + - use the npm package for zlib.js instead of the github url. + +### v2.1.0, 2014-02-06 + - split the files and use Browserify to generate the final file (see [#74](https://github.com/Stuk/jszip/pull/74)) + - packaging change : instead of 4 files (jszip.js, jszip-load.js, jszip-inflate.js, jszip-deflate.js) we now have 2 files : dist/jszip.js and dist/jszip.min.js + - add component/bower support + - rename variable: 'byte' is a reserved word (see [#76](https://github.com/Stuk/jszip/pull/76)) + - add support for the unicode path extra field (see [#82](https://github.com/Stuk/jszip/pull/82)) + - ensure that the generated files have a header with the licenses (see [#80](https://github.com/Stuk/jszip/pull/80)) + +# v2.0.0, 2013-10-20 + + - `JSZipBase64` has been renamed to `JSZip.base64`. + - The `data` attribute on the object returned by `zip.file(name)` has been removed. Use `asText()`, `asBinary()`, `asUint8Array()`, `asArrayBuffer()` or `asNodeBuffer()`. + + - [Fix issue with Android browser](https://github.com/Stuk/jszip/pull/60) + + - The compression/decompression methods now give their input type with the `compressInputType` and `uncompressInputType` attributes. + - Lazily decompress data when needed and [improve performance in general](https://github.com/Stuk/jszip/pull/56) + - [Add support for `Buffer` in Node.js](https://github.com/Stuk/jszip/pull/57). + - Package for CommonJS/npm. + +### v1.0.1, 2013-03-04 + + - Fixed an issue when generating a compressed zip file with empty files or folders, see #33. + - With bad data (null or undefined), asText/asBinary/asUint8Array/asArrayBuffer methods now return an empty string, see #36. + +# v1.0.0, 2013-02-14 + +- First release after a long period without version. + diff --git a/public/js/lib/jszip/Gruntfile.js b/public/js/lib/jszip/Gruntfile.js new file mode 100644 index 0000000..b52d7c8 --- /dev/null +++ b/public/js/lib/jszip/Gruntfile.js @@ -0,0 +1,130 @@ +/*jshint node: true */ +module.exports = function(grunt) { + var browsers = [{ + browserName: "iphone", + platform: "OS X 10.8", + version: "6" + }, { + browserName: "android", + platform: "Linux", + version: "4.0" + }, { + browserName: "firefox", + platform: "XP" + }, { + browserName: "chrome", + platform: "XP" + }, { + browserName: "internet explorer", + platform: "WIN8", + version: "10" + }, { + browserName: "internet explorer", + platform: "VISTA", + version: "9" + }, { + browserName: "internet explorer", + platform: "Windows 7", + version: "8" + }, { + browserName: "internet explorer", + platform: "XP", + version: "7" + }, { + browserName: "opera", + platform: "Windows 2008", + version: "12" + }, { + browserName: "safari", + platform: "OS X 10.8", + version: "6" + }]; + + var tags = []; + if (process.env.TRAVIS_PULL_REQUEST && process.env.TRAVIS_PULL_REQUEST != "false") { + tags.push("pr" + process.env.TRAVIS_PULL_REQUEST); + } else if (process.env.TRAVIS_BRANCH) { + tags.push(process.env.TRAVIS_BRANCH); + } + + grunt.initConfig({ + connect: { + server: { + options: { + base: "", + port: 9999 + } + } + }, + 'saucelabs-qunit': { + all: { + options: { + urls: ["http://127.0.0.1:9999/test/index.html"], + tunnelTimeout: 5, + build: process.env.TRAVIS_JOB_ID, + concurrency: 3, + browsers: browsers, + testname: "qunit tests", + tags: tags + } + } + }, + jshint: { + options: { + jshintrc: "./.jshintrc" + }, + all: ['./lib/*.js'] + }, + browserify: { + all: { + files: { + 'dist/jszip.js': ['lib/index.js'] + }, + options: { + bundleOptions: { + standalone: 'JSZip', + insertGlobalVars : { + Buffer: function () { + // instead of the full polyfill, we just use the raw value + // (or undefined). + return '(typeof Buffer !== "undefined" ? Buffer : undefined)'; + } + } + }, + postBundleCB: function(err, src, done) { + // add the license + var license = require('fs').readFileSync('lib/license_header.js'); + // remove the source mapping of zlib.js, see #75 + var srcWithoutSourceMapping = src.replace(/\/\/@ sourceMappingURL=raw..flate.min.js.map/g, ''); + done(err, license + srcWithoutSourceMapping); + } + } + } + }, + uglify: { + options: { + report: 'gzip', + mangle: true, + preserveComments: 'some' + }, + all: { + src: 'dist/jszip.js', + dest: 'dist/jszip.min.js' + } + } + }); + + grunt.loadNpmTasks("grunt-saucelabs"); + grunt.loadNpmTasks("grunt-contrib-connect"); + grunt.loadNpmTasks('grunt-browserify'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + + if (process.env.SAUCE_USERNAME && process.env.SAUCE_ACCESS_KEY) { + grunt.registerTask("test", ["connect", "saucelabs-qunit"]); + } else { + grunt.registerTask("test", []); + } + grunt.registerTask("build", ["browserify", "uglify"]); + grunt.registerTask("default", ["jshint", "build"]); +}; diff --git a/public/js/lib/jszip/LICENSE.markdown b/public/js/lib/jszip/LICENSE.markdown new file mode 100644 index 0000000..c0b10c0 --- /dev/null +++ b/public/js/lib/jszip/LICENSE.markdown @@ -0,0 +1,651 @@ +JSZip is dual licensed. You may use it under the MIT license *or* the GPLv3 +license. + +The MIT License +=============== + +Copyright (c) 2009-2014 Stuart Knightley, David Duponchel, Franz Buchinger, António Afonso + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +GPL version 3 +============= + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/public/js/lib/jszip/README.markdown b/public/js/lib/jszip/README.markdown new file mode 100644 index 0000000..5cfa5dd --- /dev/null +++ b/public/js/lib/jszip/README.markdown @@ -0,0 +1,41 @@ +JSZip +===== + +A library for creating, reading and editing .zip files with Javascript, with a +lovely and simple API. + +See http://stuartk.com/jszip for all the documentation. + +```javascript +var zip = new JSZip(); + +zip.file("Hello.txt", "Hello World\n"); + +var img = zip.folder("images"); +img.file("smile.gif", imgData, {base64: true}); + +var content = zip.generate({type:"blob"}); + +// see FileSaver.js +saveAs(content, "example.zip"); + +/* +Results in a zip containing +Hello.txt +images/ + smile.gif +*/ +``` + +Test status +----------- + +[![Build Status](https://api.travis-ci.org/Stuk/jszip.svg?branch=master)](http://travis-ci.org/Stuk/jszip) + +[![Selenium Test Status](https://saucelabs.com/browser-matrix/jszip.svg)](https://saucelabs.com/u/jszip) + +License +------- + +JSZip is dual-licensed. You may use it under the MIT license *or* the GPLv3 +license. See [LICENSE.markdown](LICENSE.markdown). diff --git a/public/js/lib/jszip/_config.yml b/public/js/lib/jszip/_config.yml new file mode 100644 index 0000000..b1959a1 --- /dev/null +++ b/public/js/lib/jszip/_config.yml @@ -0,0 +1,25 @@ +# will be overwritten by github, see https://help.github.com/articles/using-jekyll-with-pages +safe: true +lsi: false +pygments: true +source: ./ +# /overwritten + +baseurl: /jszip + +layouts: ./documentation/_layouts +permalink: none +exclude: ['bin', 'README.md', 'node_modules'] + +markdown: redcarpet +redcarpet: + extensions: [ + 'no_intra_emphasis', + 'fenced_code_blocks', + 'autolink', + 'strikethrough', + 'superscript', + 'with_toc_data', + 'tables', + 'hardwrap' + ] diff --git a/public/js/lib/jszip/bower.json b/public/js/lib/jszip/bower.json new file mode 100644 index 0000000..e7b5f07 --- /dev/null +++ b/public/js/lib/jszip/bower.json @@ -0,0 +1,22 @@ +{ + "name": "jszip", + "homepage": "http://stuartk.com/jszip", + "authors": [ + "Stuart Knightley " + ], + "description": "Create, read and edit .zip files with Javascript http://stuartk.com/jszip", + "main": "dist/jszip.js", + "keywords": [ + "zip", + "deflate", + "inflate" + ], + "license": "MIT or GPLv3", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} diff --git a/public/js/lib/jszip/component.json b/public/js/lib/jszip/component.json new file mode 100644 index 0000000..5d877b0 --- /dev/null +++ b/public/js/lib/jszip/component.json @@ -0,0 +1,16 @@ +{ + "name": "jszip", + "repo": "Stuk/jszip", + "description": "Create, read and edit .zip files with Javascript http://stuartk.com/jszip", + "version": "2.5.0", + "keywords": [ + "zip", + "deflate", + "inflate" + ], + "main": "dist/jszip.js", + "license": "MIT or GPLv3", + "scripts": [ + "dist/jszip.js" + ] +} diff --git a/public/js/lib/jszip/dist/jszip.js b/public/js/lib/jszip/dist/jszip.js new file mode 100644 index 0000000..1546d7f --- /dev/null +++ b/public/js/lib/jszip/dist/jszip.js @@ -0,0 +1,9155 @@ +/*! + +JSZip - A Javascript class for generating and reading zip files + + +(c) 2009-2014 Stuart Knightley +Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. + +JSZip uses the library pako released under the MIT license : +https://github.com/nodeca/pako/blob/master/LICENSE +*/ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.JSZip=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o> 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; + } + + output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); + + } + + return output; +}; + +// public method for decoding +exports.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); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + + } + + return output; + +}; + +},{}],2:[function(_dereq_,module,exports){ +'use strict'; +function CompressedObject() { + this.compressedSize = 0; + this.uncompressedSize = 0; + this.crc32 = 0; + this.compressionMethod = null; + this.compressedContent = null; +} + +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 + } +}; +module.exports = CompressedObject; + +},{}],3:[function(_dereq_,module,exports){ +'use strict'; +exports.STORE = { + magic: "\x00\x00", + compress: function(content, compressionOptions) { + return content; // no compression + }, + uncompress: function(content) { + return content; // no compression + }, + compressInputType: null, + uncompressInputType: null +}; +exports.DEFLATE = _dereq_('./flate'); + +},{"./flate":8}],4:[function(_dereq_,module,exports){ +'use strict'; + +var utils = _dereq_('./utils'); + +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 +]; + +/** + * + * Javascript crc32 + * http://www.webtoolkit.info/ + * + */ +module.exports = function crc32(input, crc) { + if (typeof input === "undefined" || !input.length) { + return 0; + } + + var isArray = utils.getTypeOf(input) !== "string"; + + if (typeof(crc) == "undefined") { + crc = 0; + } + var x = 0; + var y = 0; + var b = 0; + + crc = crc ^ (-1); + for (var i = 0, iTop = input.length; i < iTop; i++) { + b = isArray ? input[i] : input.charCodeAt(i); + y = (crc ^ b) & 0xFF; + x = table[y]; + crc = (crc >>> 8) ^ x; + } + + return crc ^ (-1); +}; +// vim: set shiftwidth=4 softtabstop=4: + +},{"./utils":21}],5:[function(_dereq_,module,exports){ +'use strict'; +var utils = _dereq_('./utils'); + +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 utils.transformTo("string", this.readData(size)); + }, + /** + * Get raw data without conversion, 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 + } +}; +module.exports = DataReader; + +},{"./utils":21}],6:[function(_dereq_,module,exports){ +'use strict'; +exports.base64 = false; +exports.binary = false; +exports.dir = false; +exports.createFolders = false; +exports.date = null; +exports.compression = null; +exports.compressionOptions = null; +exports.comment = null; +exports.unixPermissions = null; +exports.dosPermissions = null; + +},{}],7:[function(_dereq_,module,exports){ +'use strict'; +var utils = _dereq_('./utils'); + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.string2binary = function(str) { + return utils.string2binary(str); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.string2Uint8Array = function(str) { + return utils.transformTo("uint8array", str); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.uint8Array2String = function(array) { + return utils.transformTo("string", array); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.string2Blob = function(str) { + var buffer = utils.transformTo("arraybuffer", str); + return utils.arrayBuffer2Blob(buffer); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.arrayBuffer2Blob = function(buffer) { + return utils.arrayBuffer2Blob(buffer); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.transformTo = function(outputType, input) { + return utils.transformTo(outputType, input); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.getTypeOf = function(input) { + return utils.getTypeOf(input); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.checkSupport = function(type) { + return utils.checkSupport(type); +}; + +/** + * @deprecated + * This value will be removed in a future version without replacement. + */ +exports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS; + +/** + * @deprecated + * This value will be removed in a future version without replacement. + */ +exports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS; + + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.pretty = function(str) { + return utils.pretty(str); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.findCompression = function(compressionMethod) { + return utils.findCompression(compressionMethod); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.isRegExp = function (object) { + return utils.isRegExp(object); +}; + + +},{"./utils":21}],8:[function(_dereq_,module,exports){ +'use strict'; +var USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined'); + +var pako = _dereq_("pako"); +exports.uncompressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; +exports.compressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; + +exports.magic = "\x08\x00"; +exports.compress = function(input, compressionOptions) { + return pako.deflateRaw(input, { + level : compressionOptions.level || -1 // default compression + }); +}; +exports.uncompress = function(input) { + return pako.inflateRaw(input); +}; + +},{"pako":24}],9:[function(_dereq_,module,exports){ +'use strict'; + +var base64 = _dereq_('./base64'); + +/** +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(); + +**/ + +/** + * Representation a of zip file in js + * @constructor + * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional). + * @param {Object=} options the options for creating this objects (optional). + */ +function JSZip(data, options) { + // if this constructor is used without `new`, it adds `new` before itself: + if(!(this instanceof JSZip)) return new JSZip(data, options); + + // object containing the files : + // { + // "folder/" : {...}, + // "folder/data.txt" : {...} + // } + this.files = {}; + + this.comment = null; + + // Where we are in the hierarchy + this.root = ""; + if (data) { + this.load(data, options); + } + this.clone = function() { + var newObj = new JSZip(); + for (var i in this) { + if (typeof this[i] !== "function") { + newObj[i] = this[i]; + } + } + return newObj; + }; +} +JSZip.prototype = _dereq_('./object'); +JSZip.prototype.load = _dereq_('./load'); +JSZip.support = _dereq_('./support'); +JSZip.defaults = _dereq_('./defaults'); + +/** + * @deprecated + * This namespace will be removed in a future version without replacement. + */ +JSZip.utils = _dereq_('./deprecatedPublicUtils'); + +JSZip.base64 = { + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + encode : function(input) { + return base64.encode(input); + }, + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + decode : function(input) { + return base64.decode(input); + } +}; +JSZip.compressions = _dereq_('./compressions'); +module.exports = JSZip; + +},{"./base64":1,"./compressions":3,"./defaults":6,"./deprecatedPublicUtils":7,"./load":10,"./object":13,"./support":17}],10:[function(_dereq_,module,exports){ +'use strict'; +var base64 = _dereq_('./base64'); +var ZipEntries = _dereq_('./zipEntries'); +module.exports = function(data, options) { + var files, zipEntries, i, input; + options = options || {}; + if (options.base64) { + data = 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, + comment : input.fileComment.length ? input.fileComment : null, + unixPermissions : input.unixPermissions, + dosPermissions : input.dosPermissions, + createFolders: options.createFolders + }); + } + if (zipEntries.zipComment.length) { + this.comment = zipEntries.zipComment; + } + + return this; +}; + +},{"./base64":1,"./zipEntries":22}],11:[function(_dereq_,module,exports){ +(function (Buffer){ +'use strict'; +module.exports = function(data, encoding){ + return new Buffer(data, encoding); +}; +module.exports.test = function(b){ + return Buffer.isBuffer(b); +}; + +}).call(this,(typeof Buffer !== "undefined" ? Buffer : undefined)) +},{}],12:[function(_dereq_,module,exports){ +'use strict'; +var Uint8ArrayReader = _dereq_('./uint8ArrayReader'); + +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; +}; +module.exports = NodeBufferReader; + +},{"./uint8ArrayReader":18}],13:[function(_dereq_,module,exports){ +'use strict'; +var support = _dereq_('./support'); +var utils = _dereq_('./utils'); +var crc32 = _dereq_('./crc32'); +var signature = _dereq_('./signature'); +var defaults = _dereq_('./defaults'); +var base64 = _dereq_('./base64'); +var compressions = _dereq_('./compressions'); +var CompressedObject = _dereq_('./compressedObject'); +var nodeBuffer = _dereq_('./nodeBuffer'); +var utf8 = _dereq_('./utf8'); +var StringWriter = _dereq_('./stringWriter'); +var Uint8ArrayWriter = _dereq_('./uint8ArrayWriter'); + +/** + * 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 CompressedObject) { + file._data = file._data.getContent(); + file.options.binary = true; + file.options.base64 = false; + + if (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 = 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 (support.nodebuffer) { + return nodeBuffer(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 = 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 = out.utf8decode(result); + } + else { + // no utf8 transformation, do the array => string step. + result = utils.transformTo("string", result); + } + + if (!asUTF8 && !this.options.binary) { + result = utils.transformTo("string", out.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.dir = options.dir; + this.date = options.date; + this.comment = options.comment; + this.unixPermissions = options.unixPermissions; + this.dosPermissions = options.dosPermissions; + + this._data = data; + this.options = options; + + /* + * This object contains initial values for dir and date. + * With them, we can check if the user changed the deprecated metadata in + * `ZipObject#options` or not. + */ + this._initialMetadata = { + dir : options.dir, + date : options.date + }; +}; + +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 utils.transformTo("nodebuffer", result); + }, + /** + * Returns the content as an Uint8Array. + * @return {Uint8Array} the content as an Uint8Array. + */ + asUint8Array: function() { + var result = getBinaryData(this); + return 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 || {}; + if (o.base64 === true && (o.binary === null || o.binary === undefined)) { + o.binary = true; + } + o = extend(o, 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 dataType = utils.getTypeOf(data), + parent; + + o = prepareFileAttrs(o); + + if (typeof o.unixPermissions === "string") { + o.unixPermissions = parseInt(o.unixPermissions, 8); + } + + // UNX_IFDIR 0040000 see zipinfo.c + if (o.unixPermissions && (o.unixPermissions & 0x4000)) { + o.dir = true; + } + // Bit 4 Directory + if (o.dosPermissions && (o.dosPermissions & 0x0010)) { + o.dir = true; + } + + if (o.dir) { + name = forceTrailingSlash(name); + } + + if (o.createFolders && (parent = parentFolder(name))) { + folderAdd.call(this, parent, true); + } + + if (o.dir || data === null || typeof data === "undefined") { + o.base64 = false; + o.binary = false; + data = null; + dataType = 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 = utils.string2binary(data); + } + } + } + else { // arraybuffer, uint8array, ... + o.base64 = false; + o.binary = true; + + if (!dataType && !(data instanceof 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 = 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) : ""; +}; + + +/** + * Returns the path with a slash at the end. + * @private + * @param {String} path the path to check. + * @return {String} the path with a trailing slash. + */ +var forceTrailingSlash = function(path) { + // Check the name ends with a / + if (path.slice(-1) != "/") { + path += "/"; // IE doesn't like substr(-1) + } + return path; +}; +/** + * Add a (sub) folder in the current folder. + * @private + * @param {string} name the folder's name + * @param {boolean=} [createFolders] If true, automatically create sub + * folders. Defaults to false. + * @return {Object} the new folder. + */ +var folderAdd = function(name, createFolders) { + createFolders = (typeof createFolders !== 'undefined') ? createFolders : false; + + name = forceTrailingSlash(name); + + // Does this folder already exist? + if (!this.files[name]) { + fileAdd.call(this, name, null, { + dir: true, + createFolders: createFolders + }); + } + 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. + * @param {Object} compressionOptions the options to use when compressing. + * @return {JSZip.CompressedObject} the compressed result. + */ +var generateCompressedObjectFrom = function(file, compression, compressionOptions) { + var result = new CompressedObject(), + content; + + // the data has not been decompressed, we might reuse things ! + if (file._data instanceof CompressedObject) { + result.uncompressedSize = file._data.uncompressedSize; + result.crc32 = file._data.crc32; + + if (result.uncompressedSize === 0 || file.dir) { + compression = 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(utils.transformTo(compression.compressInputType, content), compressionOptions); + } + } + else { + // have uncompressed data + content = getBinaryData(file); + if (!content || content.length === 0 || file.dir) { + compression = compressions['STORE']; + content = ""; + } + result.uncompressedSize = content.length; + result.crc32 = crc32(content); + result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions); + } + + result.compressedSize = result.compressedContent.length; + result.compressionMethod = compression.magic; + + return result; +}; + + + + +/** + * Generate the UNIX part of the external file attributes. + * @param {Object} unixPermissions the unix permissions or null. + * @param {Boolean} isDir true if the entry is a directory, false otherwise. + * @return {Number} a 32 bit integer. + * + * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute : + * + * TTTTsstrwxrwxrwx0000000000ADVSHR + * ^^^^____________________________ file type, see zipinfo.c (UNX_*) + * ^^^_________________________ setuid, setgid, sticky + * ^^^^^^^^^________________ permissions + * ^^^^^^^^^^______ not used ? + * ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only + */ +var generateUnixExternalFileAttr = function (unixPermissions, isDir) { + + var result = unixPermissions; + if (!unixPermissions) { + // I can't use octal values in strict mode, hence the hexa. + // 040775 => 0x41fd + // 0100664 => 0x81b4 + result = isDir ? 0x41fd : 0x81b4; + } + + return (result & 0xFFFF) << 16; +}; + +/** + * Generate the DOS part of the external file attributes. + * @param {Object} dosPermissions the dos permissions or null. + * @param {Boolean} isDir true if the entry is a directory, false otherwise. + * @return {Number} a 32 bit integer. + * + * Bit 0 Read-Only + * Bit 1 Hidden + * Bit 2 System + * Bit 3 Volume Label + * Bit 4 Directory + * Bit 5 Archive + */ +var generateDosExternalFileAttr = function (dosPermissions, isDir) { + + // the dir flag is already set for compatibility + + return (dosPermissions || 0) & 0x3F; +}; + +/** + * 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. + * @param {String} platform let's pretend we are this platform (change platform dependents fields) + * @return {object} the zip parts. + */ +var generateZipParts = function(name, file, compressedObject, offset, platform) { + var data = compressedObject.compressedContent, + utfEncodedFileName = utils.transformTo("string", utf8.utf8encode(file.name)), + comment = file.comment || "", + utfEncodedComment = utils.transformTo("string", utf8.utf8encode(comment)), + useUTF8ForFileName = utfEncodedFileName.length !== file.name.length, + useUTF8ForComment = utfEncodedComment.length !== comment.length, + o = file.options, + dosTime, + dosDate, + extraFields = "", + unicodePathExtraField = "", + unicodeCommentExtraField = "", + dir, date; + + + // handle the deprecated options.dir + if (file._initialMetadata.dir !== file.dir) { + dir = file.dir; + } else { + dir = o.dir; + } + + // handle the deprecated options.date + if(file._initialMetadata.date !== file.date) { + date = file.date; + } else { + date = o.date; + } + + var extFileAttr = 0; + var versionMadeBy = 0; + if (dir) { + // dos or unix, we set the dos dir flag + extFileAttr |= 0x00010; + } + if(platform === "UNIX") { + versionMadeBy = 0x031E; // UNIX, version 3.0 + extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir); + } else { // DOS or other, fallback to DOS + versionMadeBy = 0x0014; // DOS, version 2.0 + extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir); + } + + // 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 = date.getHours(); + dosTime = dosTime << 6; + dosTime = dosTime | date.getMinutes(); + dosTime = dosTime << 5; + dosTime = dosTime | date.getSeconds() / 2; + + dosDate = date.getFullYear() - 1980; + dosDate = dosDate << 4; + dosDate = dosDate | (date.getMonth() + 1); + dosDate = dosDate << 5; + dosDate = dosDate | date.getDate(); + + if (useUTF8ForFileName) { + // set the unicode path extra field. unzip needs at least one extra + // field to correctly handle unicode path, so using the path is as good + // as any other information. This could improve the situation with + // other archive managers too. + // This field is usually used without the utf8 flag, with a non + // unicode path in the header (winrar, winzip). This helps (a bit) + // with the messy Windows' default compressed folders feature but + // breaks on p7zip which doesn't seek the unicode path extra field. + // So for now, UTF-8 everywhere ! + unicodePathExtraField = + // Version + decToHex(1, 1) + + // NameCRC32 + decToHex(crc32(utfEncodedFileName), 4) + + // UnicodeName + utfEncodedFileName; + + extraFields += + // Info-ZIP Unicode Path Extra Field + "\x75\x70" + + // size + decToHex(unicodePathExtraField.length, 2) + + // content + unicodePathExtraField; + } + + if(useUTF8ForComment) { + + unicodeCommentExtraField = + // Version + decToHex(1, 1) + + // CommentCRC32 + decToHex(this.crc32(utfEncodedComment), 4) + + // UnicodeName + utfEncodedComment; + + extraFields += + // Info-ZIP Unicode Path Extra Field + "\x75\x63" + + // size + decToHex(unicodeCommentExtraField.length, 2) + + // content + unicodeCommentExtraField; + } + + var header = ""; + + // version needed to extract + header += "\x0A\x00"; + // general purpose bit flag + // set bit 11 if utf8 + header += (useUTF8ForFileName || useUTF8ForComment) ? "\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 += decToHex(extraFields.length, 2); + + + var fileRecord = signature.LOCAL_FILE_HEADER + header + utfEncodedFileName + extraFields; + + var dirRecord = signature.CENTRAL_FILE_HEADER + + // version made by (00: DOS) + decToHex(versionMadeBy, 2) + + // file header (common to file and central directory) + header + + // file comment length + decToHex(utfEncodedComment.length, 2) + + // disk number start + "\x00\x00" + + // internal file attributes TODO + "\x00\x00" + + // external file attributes + decToHex(extFileAttr, 4) + + // relative offset of local header + decToHex(offset, 4) + + // file name + utfEncodedFileName + + // extra field + extraFields + + // file comment + utfEncodedComment; + + return { + fileRecord: fileRecord, + dirRecord: dirRecord, + compressedObject: compressedObject + }; +}; + + +// return the actual prototype of JSZip +var out = { + /** + * 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 (utils.isRegExp(name)) { + var regexp = name; + return this.filter(function(relativePath, file) { + return !file.dir && regexp.test(relativePath); + }); + } + else { // text + return this.filter(function(relativePath, file) { + return !file.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) { + return this; + } + + if (utils.isRegExp(arg)) { + return this.filter(function(relativePath, file) { + return file.dir && arg.test(relativePath); + }); + } + + // else, name is a new folder + var name = this.root + arg; + var newFolder = folderAdd.call(this, name); + + // 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 && !file.dir) { + // file + delete this.files[name]; + } else { + // maybe a folder, delete recursively + 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", + compressionOptions : null, + type: "base64", + platform: "DOS", + comment: null, + mimeType: 'application/zip' + }); + + utils.checkSupport(options.type); + + // accept nodejs `process.platform` + if( + options.platform === 'darwin' || + options.platform === 'freebsd' || + options.platform === 'linux' || + options.platform === 'sunos' + ) { + options.platform = "UNIX"; + } + if (options.platform === 'win32') { + options.platform = "DOS"; + } + + var zipData = [], + localDirLength = 0, + centralDirLength = 0, + writer, i, + utfEncodedComment = utils.transformTo("string", this.utf8encode(options.comment || this.comment || "")); + + // 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 = compressions[compressionName]; + if (!compression) { + throw new Error(compressionName + " is not a valid compression method !"); + } + var compressionOptions = file.options.compressionOptions || options.compressionOptions || {}; + + var compressedObject = generateCompressedObjectFrom.call(this, file, compression, compressionOptions); + + var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength, options.platform); + localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize; + centralDirLength += zipPart.dirRecord.length; + zipData.push(zipPart); + } + + var dirEnd = ""; + + // end of central dir signature + dirEnd = 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 + decToHex(utfEncodedComment.length, 2) + + // .ZIP file comment + utfEncodedComment; + + + // we have all the parts (and the total length) + // time to create a writer ! + var typeName = options.type.toLowerCase(); + if(typeName==="uint8array"||typeName==="arraybuffer"||typeName==="blob"||typeName==="nodebuffer") { + writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length); + }else{ + writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length); + } + + 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 utils.transformTo(options.type.toLowerCase(), zip); + case "blob" : + return utils.arrayBuffer2Blob(utils.transformTo("arraybuffer", zip), options.mimeType); + // case "zip is a string" + case "base64" : + return (options.base64) ? base64.encode(zip) : zip; + default : // case "string" : + return zip; + } + + }, + + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + crc32: function (input, crc) { + return crc32(input, crc); + }, + + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + utf8encode: function (string) { + return utils.transformTo("string", utf8.utf8encode(string)); + }, + + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + utf8decode: function (input) { + return utf8.utf8decode(input); + } +}; +module.exports = out; + +},{"./base64":1,"./compressedObject":2,"./compressions":3,"./crc32":4,"./defaults":6,"./nodeBuffer":11,"./signature":14,"./stringWriter":16,"./support":17,"./uint8ArrayWriter":19,"./utf8":20,"./utils":21}],14:[function(_dereq_,module,exports){ +'use strict'; +exports.LOCAL_FILE_HEADER = "PK\x03\x04"; +exports.CENTRAL_FILE_HEADER = "PK\x01\x02"; +exports.CENTRAL_DIRECTORY_END = "PK\x05\x06"; +exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07"; +exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06"; +exports.DATA_DESCRIPTOR = "PK\x07\x08"; + +},{}],15:[function(_dereq_,module,exports){ +'use strict'; +var DataReader = _dereq_('./dataReader'); +var utils = _dereq_('./utils'); + +function StringReader(data, optimizedBinaryString) { + this.data = data; + if (!optimizedBinaryString) { + this.data = 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; +}; +module.exports = StringReader; + +},{"./dataReader":5,"./utils":21}],16:[function(_dereq_,module,exports){ +'use strict'; + +var utils = _dereq_('./utils'); + +/** + * 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 = 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(""); + } +}; + +module.exports = StringWriter; + +},{"./utils":21}],17:[function(_dereq_,module,exports){ +(function (Buffer){ +'use strict'; +exports.base64 = true; +exports.array = true; +exports.string = true; +exports.arraybuffer = typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined"; +// contains true if JSZip can read/generate nodejs Buffer, false otherwise. +// Browserify will provide a Buffer implementation for browsers, which is +// an augmented Uint8Array (i.e., can be used as either Buffer or U8). +exports.nodebuffer = typeof Buffer !== "undefined"; +// contains true if JSZip can read/generate Uint8Array, false otherwise. +exports.uint8array = typeof Uint8Array !== "undefined"; + +if (typeof ArrayBuffer === "undefined") { + exports.blob = false; +} +else { + var buffer = new ArrayBuffer(0); + try { + exports.blob = new Blob([buffer], { + type: "application/zip" + }).size === 0; + } + catch (e) { + try { + var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + var builder = new Builder(); + builder.append(buffer); + exports.blob = builder.getBlob('application/zip').size === 0; + } + catch (e) { + exports.blob = false; + } + } +} + +}).call(this,(typeof Buffer !== "undefined" ? Buffer : undefined)) +},{}],18:[function(_dereq_,module,exports){ +'use strict'; +var DataReader = _dereq_('./dataReader'); + +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); + if(size === 0) { + // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of []. + return new Uint8Array(0); + } + var result = this.data.subarray(this.index, this.index + size); + this.index += size; + return result; +}; +module.exports = Uint8ArrayReader; + +},{"./dataReader":5}],19:[function(_dereq_,module,exports){ +'use strict'; + +var utils = _dereq_('./utils'); + +/** + * 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 = 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; + } +}; + +module.exports = Uint8ArrayWriter; + +},{"./utils":21}],20:[function(_dereq_,module,exports){ +'use strict'; + +var utils = _dereq_('./utils'); +var support = _dereq_('./support'); +var nodeBuffer = _dereq_('./nodeBuffer'); + +/** + * The following functions come from pako, from pako/lib/utils/strings + * released under the MIT license, see pako https://github.com/nodeca/pako/ + */ + +// Table with utf8 lengths (calculated by first byte of sequence) +// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, +// because max possible codepoint is 0x10ffff +var _utf8len = new Array(256); +for (var i=0; i<256; i++) { + _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1); +} +_utf8len[254]=_utf8len[254]=1; // Invalid sequence start + +// convert string to array (typed, when possible) +var string2buf = function (str) { + var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; + + // count binary size + for (m_pos = 0; m_pos < str_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { + c2 = str.charCodeAt(m_pos+1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; + } + + // allocate buffer + if (support.uint8array) { + buf = new Uint8Array(buf_len); + } else { + buf = new Array(buf_len); + } + + // convert + for (i=0, m_pos = 0; i < buf_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { + c2 = str.charCodeAt(m_pos+1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + if (c < 0x80) { + /* one byte */ + buf[i++] = c; + } else if (c < 0x800) { + /* two bytes */ + buf[i++] = 0xC0 | (c >>> 6); + buf[i++] = 0x80 | (c & 0x3f); + } else if (c < 0x10000) { + /* three bytes */ + buf[i++] = 0xE0 | (c >>> 12); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } else { + /* four bytes */ + buf[i++] = 0xf0 | (c >>> 18); + buf[i++] = 0x80 | (c >>> 12 & 0x3f); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } + } + + return buf; +}; + +// Calculate max possible position in utf8 buffer, +// that will not break sequence. If that's not possible +// - (very small limits) return max size as is. +// +// buf[] - utf8 bytes array +// max - length limit (mandatory); +var utf8border = function(buf, max) { + var pos; + + max = max || buf.length; + if (max > buf.length) { max = buf.length; } + + // go back from last position, until start of sequence found + pos = max-1; + while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } + + // Fuckup - very small and broken sequence, + // return max, because we should return something anyway. + if (pos < 0) { return max; } + + // If we came to start of buffer - that means vuffer is too small, + // return max too. + if (pos === 0) { return max; } + + return (pos + _utf8len[buf[pos]] > max) ? pos : max; +}; + +// convert array to string +var buf2string = function (buf) { + var str, i, out, c, c_len; + var len = buf.length; + + // Reserve max possible length (2 words per char) + // NB: by unknown reasons, Array is significantly faster for + // String.fromCharCode.apply than Uint16Array. + var utf16buf = new Array(len*2); + + for (out=0, i=0; i 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; } + + // apply mask on first byte + c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; + // join the rest + while (c_len > 1 && i < len) { + c = (c << 6) | (buf[i++] & 0x3f); + c_len--; + } + + // terminated by end of string? + if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } + + if (c < 0x10000) { + utf16buf[out++] = c; + } else { + c -= 0x10000; + utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); + utf16buf[out++] = 0xdc00 | (c & 0x3ff); + } + } + + // shrinkBuf(utf16buf, out) + if (utf16buf.length !== out) { + if(utf16buf.subarray) { + utf16buf = utf16buf.subarray(0, out); + } else { + utf16buf.length = out; + } + } + + // return String.fromCharCode.apply(null, utf16buf); + return utils.applyFromCharCode(utf16buf); +}; + + +// That's all for the pako functions. + + +/** + * Transform a javascript string into an array (typed if possible) of bytes, + * UTF-8 encoded. + * @param {String} str the string to encode + * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string. + */ +exports.utf8encode = function utf8encode(str) { + if (support.nodebuffer) { + return nodeBuffer(str, "utf-8"); + } + + return string2buf(str); +}; + + +/** + * Transform a bytes array (or a representation) representing an UTF-8 encoded + * string into a javascript string. + * @param {Array|Uint8Array|Buffer} buf the data de decode + * @return {String} the decoded string. + */ +exports.utf8decode = function utf8decode(buf) { + if (support.nodebuffer) { + return utils.transformTo("nodebuffer", buf).toString("utf-8"); + } + + buf = utils.transformTo(support.uint8array ? "uint8array" : "array", buf); + + // return buf2string(buf); + // Chrome prefers to work with "small" chunks of data + // for the method buf2string. + // Firefox and Chrome has their own shortcut, IE doesn't seem to really care. + var result = [], k = 0, len = buf.length, chunk = 65536; + while (k < len) { + var nextBoundary = utf8border(buf, Math.min(k + chunk, len)); + if (support.uint8array) { + result.push(buf2string(buf.subarray(k, nextBoundary))); + } else { + result.push(buf2string(buf.slice(k, nextBoundary))); + } + k = nextBoundary; + } + return result.join(""); + +}; +// vim: set shiftwidth=4 softtabstop=4: + +},{"./nodeBuffer":11,"./support":17,"./utils":21}],21:[function(_dereq_,module,exports){ +'use strict'; +var support = _dereq_('./support'); +var compressions = _dereq_('./compressions'); +var nodeBuffer = _dereq_('./nodeBuffer'); +/** + * Convert a string to a "binary string" : a string containing only char codes between 0 and 255. + * @param {string} str the string to transform. + * @return {String} the binary string. + */ +exports.string2binary = function(str) { + var result = ""; + for (var i = 0; i < str.length; i++) { + result += String.fromCharCode(str.charCodeAt(i) & 0xff); + } + return result; +}; +exports.arrayBuffer2Blob = function(buffer, mimeType) { + exports.checkSupport("blob"); + mimeType = mimeType || 'application/zip'; + + try { + // Blob constructor + return new Blob([buffer], { + type: mimeType + }); + } + catch (e) { + + try { + // deprecated, browser only, old way + var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + var builder = new Builder(); + builder.append(buffer); + return builder.getBlob(mimeType); + } + catch (e) { + + // well, fuck ?! + throw new Error("Bug : can't construct the Blob."); + } + } + + +}; +/** + * 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 = exports.getTypeOf(array), + k = 0, + canUseApply = true; + try { + switch(type) { + case "uint8array": + String.fromCharCode.apply(null, new Uint8Array(0)); + break; + case "nodebuffer": + String.fromCharCode.apply(null, nodeBuffer(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)))); + } + else { + 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(""); +} + +exports.applyFromCharCode = arrayLikeToString; + + +/** + * 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, nodeBuffer(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 nodeBuffer(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 nodeBuffer(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 nodeBuffer(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. + */ +exports.transformTo = function(outputType, input) { + if (!input) { + // undefined, null, etc + // an empty string won't harm. + input = ""; + } + if (!outputType) { + return input; + } + exports.checkSupport(outputType); + var inputType = exports.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. + */ +exports.getTypeOf = function(input) { + if (typeof input === "string") { + return "string"; + } + if (Object.prototype.toString.call(input) === "[object Array]") { + return "array"; + } + if (support.nodebuffer && nodeBuffer.test(input)) { + return "nodebuffer"; + } + if (support.uint8array && input instanceof Uint8Array) { + return "uint8array"; + } + if (support.arraybuffer && input instanceof ArrayBuffer) { + return "arraybuffer"; + } +}; + +/** + * 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. + */ +exports.checkSupport = function(type) { + var supported = support[type.toLowerCase()]; + if (!supported) { + throw new Error(type + " is not supported by this browser"); + } +}; +exports.MAX_VALUE_16BITS = 65535; +exports.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. + */ +exports.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. + */ +exports.findCompression = function(compressionMethod) { + for (var method in compressions) { + if (!compressions.hasOwnProperty(method)) { + continue; + } + if (compressions[method].magic === compressionMethod) { + return compressions[method]; + } + } + return null; +}; +/** +* Cross-window, cross-Node-context regular expression detection +* @param {Object} object Anything +* @return {Boolean} true if the object is a regular expression, +* false otherwise +*/ +exports.isRegExp = function (object) { + return Object.prototype.toString.call(object) === "[object RegExp]"; +}; + + +},{"./compressions":3,"./nodeBuffer":11,"./support":17}],22:[function(_dereq_,module,exports){ +'use strict'; +var StringReader = _dereq_('./stringReader'); +var NodeBufferReader = _dereq_('./nodeBufferReader'); +var Uint8ArrayReader = _dereq_('./uint8ArrayReader'); +var utils = _dereq_('./utils'); +var sig = _dereq_('./signature'); +var ZipEntry = _dereq_('./zipEntry'); +var support = _dereq_('./support'); +var jszipProto = _dereq_('./object'); +// class ZipEntries {{{ +/** + * All the entries in the zip file. + * @constructor + * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load. + * @param {Object} loadOptions Options for loading the stream. + */ +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 " + "(" + utils.pretty(signature) + ", expected " + utils.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); + // warning : the encoding depends of the system locale + // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded. + // On a windows machine, this field is encoded with the localized windows code page. + this.zipComment = this.reader.readString(this.zipCommentLength); + // To get consistent behavior with the generation part, we will assume that + // this is utf8 encoded. + this.zipComment = jszipProto.utf8decode(this.zipComment); + }, + /** + * 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(sig.LOCAL_FILE_HEADER); + file.readLocalPart(this.reader); + file.handleUTF8(); + file.processAttributes(); + } + }, + /** + * Read the central directory. + */ + readCentralDir: function() { + var file; + + this.reader.setIndex(this.centralDirOffset); + while (this.reader.readString(4) === sig.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(sig.CENTRAL_DIRECTORY_END); + if (offset === -1) { + // Check if the content is a truncated zip or complete garbage. + // A "LOCAL_FILE_HEADER" is not required at the beginning (auto + // extractible zip for example) but it can give a good hint. + // If an ajax request was used without responseType, we will also + // get unreadable data. + var isGarbage = true; + try { + this.reader.setIndex(0); + this.checkSignature(sig.LOCAL_FILE_HEADER); + isGarbage = false; + } catch (e) {} + + if (isGarbage) { + throw new Error("Can't find end of central directory : is this a zip file ? " + + "If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html"); + } else { + throw new Error("Corrupted zip : can't find end of central directory"); + } + } + this.reader.setIndex(offset); + this.checkSignature(sig.CENTRAL_DIRECTORY_END); + this.readBlockEndOfCentral(); + + + /* extract from the zip spec : + 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 === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) { + this.zip64 = true; + + /* + Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from + the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents + all numbers as 64-bit double precision IEEE 754 floating point numbers. + So, we have 53bits for integers and bitwise operations treat everything as 32bits. + 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(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); + if (offset === -1) { + throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator"); + } + this.reader.setIndex(offset); + this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); + this.readBlockZip64EndOfCentralLocator(); + + // now the zip64 EOCD record + this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir); + this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END); + this.readBlockZip64EndOfCentral(); + } + }, + prepareReader: function(data) { + var type = utils.getTypeOf(data); + if (type === "string" && !support.uint8array) { + this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString); + } + else if (type === "nodebuffer") { + this.reader = new NodeBufferReader(data); + } + else { + this.reader = new Uint8ArrayReader(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 +module.exports = ZipEntries; + +},{"./nodeBufferReader":12,"./object":13,"./signature":14,"./stringReader":15,"./support":17,"./uint8ArrayReader":18,"./utils":21,"./zipEntry":23}],23:[function(_dereq_,module,exports){ +'use strict'; +var StringReader = _dereq_('./stringReader'); +var utils = _dereq_('./utils'); +var CompressedObject = _dereq_('./compressedObject'); +var jszipProto = _dereq_('./object'); + +var MADE_BY_DOS = 0x00; +var MADE_BY_UNIX = 0x03; + +// class ZipEntry {{{ +/** + * An entry in the zip file. + * @constructor + * @param {Object} options Options of the current file. + * @param {Object} loadOptions Options for loading the stream. + */ +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 = utils.transformTo(compression.uncompressInputType, this.getCompressedContent()); + var uncompressedFileData = compression.uncompress(compressedFileData); + + if (uncompressedFileData.length !== uncompressedSize) { + throw new Error("Bug : uncompressed data size mismatch"); + } + + 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 = utils.findCompression(this.compressionMethod); + if (compression === null) { // no compression found + throw new Error("Corrupted zip : compression " + utils.pretty(this.compressionMethod) + " unknown (inner file : " + this.fileName + ")"); + } + this.decompressed = new 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 = utils.transformTo("string", this.decompressed.getContent()); + if (jszipProto.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.readInt(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); + }, + + /** + * Parse the external file attributes and get the unix/dos permissions. + */ + processAttributes: function () { + this.unixPermissions = null; + this.dosPermissions = null; + var madeBy = this.versionMadeBy >> 8; + + // Check if we have the DOS directory flag set. + // We look for it in the DOS and UNIX permissions + // but some unknown platform could set it as a compatibility flag. + this.dir = this.externalFileAttributes & 0x0010 ? true : false; + + if(madeBy === MADE_BY_DOS) { + // first 6 bits (0 to 5) + this.dosPermissions = this.externalFileAttributes & 0x3F; + } + + if(madeBy === MADE_BY_UNIX) { + this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF; + // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8); + } + + // fail safe : if the name ends with a / it probably means a folder + if (!this.dir && this.fileName.slice(-1) === '/') { + this.dir = true; + } + }, + + /** + * 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 === utils.MAX_VALUE_32BITS) { + this.uncompressedSize = extraReader.readInt(8); + } + if (this.compressedSize === utils.MAX_VALUE_32BITS) { + this.compressedSize = extraReader.readInt(8); + } + if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) { + this.localHeaderOffset = extraReader.readInt(8); + } + if (this.diskNumberStart === utils.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 = jszipProto.utf8decode(this.fileName); + this.fileComment = jszipProto.utf8decode(this.fileComment); + } else { + var upath = this.findExtraFieldUnicodePath(); + if (upath !== null) { + this.fileName = upath; + } + var ucomment = this.findExtraFieldUnicodeComment(); + if (ucomment !== null) { + this.fileComment = ucomment; + } + } + }, + + /** + * Find the unicode path declared in the extra field, if any. + * @return {String} the unicode path, null otherwise. + */ + findExtraFieldUnicodePath: function() { + var upathField = this.extraFields[0x7075]; + if (upathField) { + var extraReader = new StringReader(upathField.value); + + // wrong version + if (extraReader.readInt(1) !== 1) { + return null; + } + + // the crc of the filename changed, this field is out of date. + if (jszipProto.crc32(this.fileName) !== extraReader.readInt(4)) { + return null; + } + + return jszipProto.utf8decode(extraReader.readString(upathField.length - 5)); + } + return null; + }, + + /** + * Find the unicode comment declared in the extra field, if any. + * @return {String} the unicode comment, null otherwise. + */ + findExtraFieldUnicodeComment: function() { + var ucommentField = this.extraFields[0x6375]; + if (ucommentField) { + var extraReader = new StringReader(ucommentField.value); + + // wrong version + if (extraReader.readInt(1) !== 1) { + return null; + } + + // the crc of the comment changed, this field is out of date. + if (jszipProto.crc32(this.fileComment) !== extraReader.readInt(4)) { + return null; + } + + return jszipProto.utf8decode(extraReader.readString(ucommentField.length - 5)); + } + return null; + } +}; +module.exports = ZipEntry; + +},{"./compressedObject":2,"./object":13,"./stringReader":15,"./utils":21}],24:[function(_dereq_,module,exports){ +// Top level file is just a mixin of submodules & constants +'use strict'; + +var assign = _dereq_('./lib/utils/common').assign; + +var deflate = _dereq_('./lib/deflate'); +var inflate = _dereq_('./lib/inflate'); +var constants = _dereq_('./lib/zlib/constants'); + +var pako = {}; + +assign(pako, deflate, inflate, constants); + +module.exports = pako; +},{"./lib/deflate":25,"./lib/inflate":26,"./lib/utils/common":27,"./lib/zlib/constants":30}],25:[function(_dereq_,module,exports){ +'use strict'; + + +var zlib_deflate = _dereq_('./zlib/deflate.js'); +var utils = _dereq_('./utils/common'); +var strings = _dereq_('./utils/strings'); +var msg = _dereq_('./zlib/messages'); +var zstream = _dereq_('./zlib/zstream'); + + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + +var Z_NO_FLUSH = 0; +var Z_FINISH = 4; + +var Z_OK = 0; +var Z_STREAM_END = 1; + +var Z_DEFAULT_COMPRESSION = -1; + +var Z_DEFAULT_STRATEGY = 0; + +var Z_DEFLATED = 8; + +/* ===========================================================================*/ + + +/** + * class Deflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[deflate]], + * [[deflateRaw]] and [[gzip]]. + **/ + +/* internal + * Deflate.chunks -> Array + * + * Chunks of output data, if [[Deflate#onData]] not overriden. + **/ + +/** + * Deflate.result -> Uint8Array|Array + * + * Compressed result, generated by default [[Deflate#onData]] + * and [[Deflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Deflate#push]] with `Z_FINISH` / `true` param). + **/ + +/** + * Deflate.err -> Number + * + * Error code after deflate finished. 0 (Z_OK) on success. + * You will not need it in real life, because deflate errors + * are possible only on wrong options or bad `onData` / `onEnd` + * custom handlers. + **/ + +/** + * Deflate.msg -> String + * + * Error message, if [[Deflate.err]] != 0 + **/ + + +/** + * new Deflate(options) + * - options (Object): zlib deflate options. + * + * Creates new deflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `level` + * - `windowBits` + * - `memLevel` + * - `strategy` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw deflate + * - `gzip` (Boolean) - create gzip wrapper + * - `to` (String) - if equal to 'string', then result will be "binary string" + * (each char code [0..255]) + * - `header` (Object) - custom header for gzip + * - `text` (Boolean) - true if compressed data believed to be text + * - `time` (Number) - modification time, unix timestamp + * - `os` (Number) - operation system code + * - `extra` (Array) - array of bytes with extra data (max 65536) + * - `name` (String) - file name (binary string) + * - `comment` (String) - comment (binary string) + * - `hcrc` (Boolean) - true if header crc should be added + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) + * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * var deflate = new pako.Deflate({ level: 3}); + * + * deflate.push(chunk1, false); + * deflate.push(chunk2, true); // true -> last chunk + * + * if (deflate.err) { throw new Error(deflate.err); } + * + * console.log(deflate.result); + * ``` + **/ +var Deflate = function(options) { + + this.options = utils.assign({ + level: Z_DEFAULT_COMPRESSION, + method: Z_DEFLATED, + chunkSize: 16384, + windowBits: 15, + memLevel: 8, + strategy: Z_DEFAULT_STRATEGY, + to: '' + }, options || {}); + + var opt = this.options; + + if (opt.raw && (opt.windowBits > 0)) { + opt.windowBits = -opt.windowBits; + } + + else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) { + opt.windowBits += 16; + } + + this.err = 0; // error code, if happens (0 = Z_OK) + this.msg = ''; // error message + this.ended = false; // used to avoid multiple onEnd() calls + this.chunks = []; // chunks of compressed data + + this.strm = new zstream(); + this.strm.avail_out = 0; + + var status = zlib_deflate.deflateInit2( + this.strm, + opt.level, + opt.method, + opt.windowBits, + opt.memLevel, + opt.strategy + ); + + if (status !== Z_OK) { + throw new Error(msg[status]); + } + + if (opt.header) { + zlib_deflate.deflateSetHeader(this.strm, opt.header); + } +}; + +/** + * Deflate#push(data[, mode]) -> Boolean + * - data (Uint8Array|Array|String): input data. Strings will be converted to + * utf8 byte sequence. + * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. + * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH. + * + * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with + * new compressed chunks. Returns `true` on success. The last data block must have + * mode Z_FINISH (or `true`). That flush internal pending buffers and call + * [[Deflate#onEnd]]. + * + * On fail call [[Deflate#onEnd]] with error code and return false. + * + * We strongly recommend to use `Uint8Array` on input for best speed (output + * array format is detected automatically). Also, don't skip last param and always + * use the same type in your code (boolean or number). That will improve JS speed. + * + * For regular `Array`-s make sure all elements are [0..255]. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ +Deflate.prototype.push = function(data, mode) { + var strm = this.strm; + var chunkSize = this.options.chunkSize; + var status, _mode; + + if (this.ended) { return false; } + + _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH); + + // Convert data if needed + if (typeof data === 'string') { + // If we need to compress text, change encoding to utf8. + strm.input = strings.string2buf(data); + } else { + strm.input = data; + } + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + do { + if (strm.avail_out === 0) { + strm.output = new utils.Buf8(chunkSize); + strm.next_out = 0; + strm.avail_out = chunkSize; + } + status = zlib_deflate.deflate(strm, _mode); /* no bad return value */ + + if (status !== Z_STREAM_END && status !== Z_OK) { + this.onEnd(status); + this.ended = true; + return false; + } + if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) { + if (this.options.to === 'string') { + this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out))); + } else { + this.onData(utils.shrinkBuf(strm.output, strm.next_out)); + } + } + } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END); + + // Finalize on the last chunk. + if (_mode === Z_FINISH) { + status = zlib_deflate.deflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return status === Z_OK; + } + + return true; +}; + + +/** + * Deflate#onData(chunk) -> Void + * - chunk (Uint8Array|Array|String): ouput data. Type of array depends + * on js engine support. When string output requested, each chunk + * will be string. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ +Deflate.prototype.onData = function(chunk) { + this.chunks.push(chunk); +}; + + +/** + * Deflate#onEnd(status) -> Void + * - status (Number): deflate status. 0 (Z_OK) on success, + * other if not. + * + * Called once after you tell deflate that input stream complete + * or error happenned. By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ +Deflate.prototype.onEnd = function(status) { + // On success - join + if (status === Z_OK) { + if (this.options.to === 'string') { + this.result = this.chunks.join(''); + } else { + this.result = utils.flattenChunks(this.chunks); + } + } + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; +}; + + +/** + * deflate(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * Compress `data` with deflate alrorythm and `options`. + * + * Supported options are: + * + * - level + * - windowBits + * - memLevel + * - strategy + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * - `to` (String) - if equal to 'string', then result will be "binary string" + * (each char code [0..255]) + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , data = Uint8Array([1,2,3,4,5,6,7,8,9]); + * + * console.log(pako.deflate(data)); + * ``` + **/ +function deflate(input, options) { + var deflator = new Deflate(options); + + deflator.push(input, true); + + // That will never happens, if you don't cheat with options :) + if (deflator.err) { throw deflator.msg; } + + return deflator.result; +} + + +/** + * deflateRaw(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ +function deflateRaw(input, options) { + options = options || {}; + options.raw = true; + return deflate(input, options); +} + + +/** + * gzip(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but create gzip wrapper instead of + * deflate one. + **/ +function gzip(input, options) { + options = options || {}; + options.gzip = true; + return deflate(input, options); +} + + +exports.Deflate = Deflate; +exports.deflate = deflate; +exports.deflateRaw = deflateRaw; +exports.gzip = gzip; +},{"./utils/common":27,"./utils/strings":28,"./zlib/deflate.js":32,"./zlib/messages":37,"./zlib/zstream":39}],26:[function(_dereq_,module,exports){ +'use strict'; + + +var zlib_inflate = _dereq_('./zlib/inflate.js'); +var utils = _dereq_('./utils/common'); +var strings = _dereq_('./utils/strings'); +var c = _dereq_('./zlib/constants'); +var msg = _dereq_('./zlib/messages'); +var zstream = _dereq_('./zlib/zstream'); +var gzheader = _dereq_('./zlib/gzheader'); + + +/** + * class Inflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[inflate]] + * and [[inflateRaw]]. + **/ + +/* internal + * inflate.chunks -> Array + * + * Chunks of output data, if [[Inflate#onData]] not overriden. + **/ + +/** + * Inflate.result -> Uint8Array|Array|String + * + * Uncompressed result, generated by default [[Inflate#onData]] + * and [[Inflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Inflate#push]] with `Z_FINISH` / `true` param). + **/ + +/** + * Inflate.err -> Number + * + * Error code after inflate finished. 0 (Z_OK) on success. + * Should be checked if broken data possible. + **/ + +/** + * Inflate.msg -> String + * + * Error message, if [[Inflate.err]] != 0 + **/ + + +/** + * new Inflate(options) + * - options (Object): zlib inflate options. + * + * Creates new inflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `windowBits` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw inflate + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * By default, when no options set, autodetect deflate/gzip data format via + * wrapper header. + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) + * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * var inflate = new pako.Inflate({ level: 3}); + * + * inflate.push(chunk1, false); + * inflate.push(chunk2, true); // true -> last chunk + * + * if (inflate.err) { throw new Error(inflate.err); } + * + * console.log(inflate.result); + * ``` + **/ +var Inflate = function(options) { + + this.options = utils.assign({ + chunkSize: 16384, + windowBits: 0, + to: '' + }, options || {}); + + var opt = this.options; + + // Force window size for `raw` data, if not set directly, + // because we have no header for autodetect. + if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) { + opt.windowBits = -opt.windowBits; + if (opt.windowBits === 0) { opt.windowBits = -15; } + } + + // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate + if ((opt.windowBits >= 0) && (opt.windowBits < 16) && + !(options && options.windowBits)) { + opt.windowBits += 32; + } + + // Gzip header has no info about windows size, we can do autodetect only + // for deflate. So, if window size not set, force it to max when gzip possible + if ((opt.windowBits > 15) && (opt.windowBits < 48)) { + // bit 3 (16) -> gzipped data + // bit 4 (32) -> autodetect gzip/deflate + if ((opt.windowBits & 15) === 0) { + opt.windowBits |= 15; + } + } + + this.err = 0; // error code, if happens (0 = Z_OK) + this.msg = ''; // error message + this.ended = false; // used to avoid multiple onEnd() calls + this.chunks = []; // chunks of compressed data + + this.strm = new zstream(); + this.strm.avail_out = 0; + + var status = zlib_inflate.inflateInit2( + this.strm, + opt.windowBits + ); + + if (status !== c.Z_OK) { + throw new Error(msg[status]); + } + + this.header = new gzheader(); + + zlib_inflate.inflateGetHeader(this.strm, this.header); +}; + +/** + * Inflate#push(data[, mode]) -> Boolean + * - data (Uint8Array|Array|String): input data + * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. + * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH. + * + * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with + * new output chunks. Returns `true` on success. The last data block must have + * mode Z_FINISH (or `true`). That flush internal pending buffers and call + * [[Inflate#onEnd]]. + * + * On fail call [[Inflate#onEnd]] with error code and return false. + * + * We strongly recommend to use `Uint8Array` on input for best speed (output + * format is detected automatically). Also, don't skip last param and always + * use the same type in your code (boolean or number). That will improve JS speed. + * + * For regular `Array`-s make sure all elements are [0..255]. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ +Inflate.prototype.push = function(data, mode) { + var strm = this.strm; + var chunkSize = this.options.chunkSize; + var status, _mode; + var next_out_utf8, tail, utf8str; + + if (this.ended) { return false; } + _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH); + + // Convert data if needed + if (typeof data === 'string') { + // Only binary strings can be decompressed on practice + strm.input = strings.binstring2buf(data); + } else { + strm.input = data; + } + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + do { + if (strm.avail_out === 0) { + strm.output = new utils.Buf8(chunkSize); + strm.next_out = 0; + strm.avail_out = chunkSize; + } + + status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */ + + if (status !== c.Z_STREAM_END && status !== c.Z_OK) { + this.onEnd(status); + this.ended = true; + return false; + } + + if (strm.next_out) { + if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) { + + if (this.options.to === 'string') { + + next_out_utf8 = strings.utf8border(strm.output, strm.next_out); + + tail = strm.next_out - next_out_utf8; + utf8str = strings.buf2string(strm.output, next_out_utf8); + + // move tail + strm.next_out = tail; + strm.avail_out = chunkSize - tail; + if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); } + + this.onData(utf8str); + + } else { + this.onData(utils.shrinkBuf(strm.output, strm.next_out)); + } + } + } + } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END); + + if (status === c.Z_STREAM_END) { + _mode = c.Z_FINISH; + } + // Finalize on the last chunk. + if (_mode === c.Z_FINISH) { + status = zlib_inflate.inflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return status === c.Z_OK; + } + + return true; +}; + + +/** + * Inflate#onData(chunk) -> Void + * - chunk (Uint8Array|Array|String): ouput data. Type of array depends + * on js engine support. When string output requested, each chunk + * will be string. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ +Inflate.prototype.onData = function(chunk) { + this.chunks.push(chunk); +}; + + +/** + * Inflate#onEnd(status) -> Void + * - status (Number): inflate status. 0 (Z_OK) on success, + * other if not. + * + * Called once after you tell inflate that input stream complete + * or error happenned. By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ +Inflate.prototype.onEnd = function(status) { + // On success - join + if (status === c.Z_OK) { + if (this.options.to === 'string') { + // Glue & convert here, until we teach pako to send + // utf8 alligned strings to onData + this.result = this.chunks.join(''); + } else { + this.result = utils.flattenChunks(this.chunks); + } + } + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; +}; + + +/** + * inflate(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to decompress. + * - options (Object): zlib inflate options. + * + * Decompress `data` with inflate/ungzip and `options`. Autodetect + * format via wrapper header by default. That's why we don't provide + * separate `ungzip` method. + * + * Supported options are: + * + * - windowBits + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , input = pako.deflate([1,2,3,4,5,6,7,8,9]) + * , output; + * + * try { + * output = pako.inflate(input); + * } catch (err) + * console.log(err); + * } + * ``` + **/ +function inflate(input, options) { + var inflator = new Inflate(options); + + inflator.push(input, true); + + // That will never happens, if you don't cheat with options :) + if (inflator.err) { throw inflator.msg; } + + return inflator.result; +} + + +/** + * inflateRaw(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to decompress. + * - options (Object): zlib inflate options. + * + * The same as [[inflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ +function inflateRaw(input, options) { + options = options || {}; + options.raw = true; + return inflate(input, options); +} + + +/** + * ungzip(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to decompress. + * - options (Object): zlib inflate options. + * + * Just shortcut to [[inflate]], because it autodetects format + * by header.content. Done for convenience. + **/ + + +exports.Inflate = Inflate; +exports.inflate = inflate; +exports.inflateRaw = inflateRaw; +exports.ungzip = inflate; + +},{"./utils/common":27,"./utils/strings":28,"./zlib/constants":30,"./zlib/gzheader":33,"./zlib/inflate.js":35,"./zlib/messages":37,"./zlib/zstream":39}],27:[function(_dereq_,module,exports){ +'use strict'; + + +var TYPED_OK = (typeof Uint8Array !== 'undefined') && + (typeof Uint16Array !== 'undefined') && + (typeof Int32Array !== 'undefined'); + + +exports.assign = function (obj /*from1, from2, from3, ...*/) { + var sources = Array.prototype.slice.call(arguments, 1); + while (sources.length) { + var source = sources.shift(); + if (!source) { continue; } + + if (typeof(source) !== 'object') { + throw new TypeError(source + 'must be non-object'); + } + + for (var p in source) { + if (source.hasOwnProperty(p)) { + obj[p] = source[p]; + } + } + } + + return obj; +}; + + +// reduce buffer size, avoiding mem copy +exports.shrinkBuf = function (buf, size) { + if (buf.length === size) { return buf; } + if (buf.subarray) { return buf.subarray(0, size); } + buf.length = size; + return buf; +}; + + +var fnTyped = { + arraySet: function (dest, src, src_offs, len, dest_offs) { + if (src.subarray && dest.subarray) { + dest.set(src.subarray(src_offs, src_offs+len), dest_offs); + return; + } + // Fallback to ordinary array + for(var i=0; i= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1); +} +_utf8len[254]=_utf8len[254]=1; // Invalid sequence start + + +// convert string to array (typed, when possible) +exports.string2buf = function (str) { + var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; + + // count binary size + for (m_pos = 0; m_pos < str_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { + c2 = str.charCodeAt(m_pos+1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; + } + + // allocate buffer + buf = new utils.Buf8(buf_len); + + // convert + for (i=0, m_pos = 0; i < buf_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { + c2 = str.charCodeAt(m_pos+1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + if (c < 0x80) { + /* one byte */ + buf[i++] = c; + } else if (c < 0x800) { + /* two bytes */ + buf[i++] = 0xC0 | (c >>> 6); + buf[i++] = 0x80 | (c & 0x3f); + } else if (c < 0x10000) { + /* three bytes */ + buf[i++] = 0xE0 | (c >>> 12); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } else { + /* four bytes */ + buf[i++] = 0xf0 | (c >>> 18); + buf[i++] = 0x80 | (c >>> 12 & 0x3f); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } + } + + return buf; +}; + +// Helper (used in 2 places) +function buf2binstring(buf, len) { + // use fallback for big arrays to avoid stack overflow + if (len < 65537) { + if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) { + return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len)); + } + } + + var result = ''; + for(var i=0; i < len; i++) { + result += String.fromCharCode(buf[i]); + } + return result; +} + + +// Convert byte array to binary string +exports.buf2binstring = function(buf) { + return buf2binstring(buf, buf.length); +}; + + +// Convert binary string (typed, when possible) +exports.binstring2buf = function(str) { + var buf = new utils.Buf8(str.length); + for(var i=0, len=buf.length; i < len; i++) { + buf[i] = str.charCodeAt(i); + } + return buf; +}; + + +// convert array to string +exports.buf2string = function (buf, max) { + var i, out, c, c_len; + var len = max || buf.length; + + // Reserve max possible length (2 words per char) + // NB: by unknown reasons, Array is significantly faster for + // String.fromCharCode.apply than Uint16Array. + var utf16buf = new Array(len*2); + + for (out=0, i=0; i 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; } + + // apply mask on first byte + c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; + // join the rest + while (c_len > 1 && i < len) { + c = (c << 6) | (buf[i++] & 0x3f); + c_len--; + } + + // terminated by end of string? + if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } + + if (c < 0x10000) { + utf16buf[out++] = c; + } else { + c -= 0x10000; + utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); + utf16buf[out++] = 0xdc00 | (c & 0x3ff); + } + } + + return buf2binstring(utf16buf, out); +}; + + +// Calculate max possible position in utf8 buffer, +// that will not break sequence. If that's not possible +// - (very small limits) return max size as is. +// +// buf[] - utf8 bytes array +// max - length limit (mandatory); +exports.utf8border = function(buf, max) { + var pos; + + max = max || buf.length; + if (max > buf.length) { max = buf.length; } + + // go back from last position, until start of sequence found + pos = max-1; + while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } + + // Fuckup - very small and broken sequence, + // return max, because we should return something anyway. + if (pos < 0) { return max; } + + // If we came to start of buffer - that means vuffer is too small, + // return max too. + if (pos === 0) { return max; } + + return (pos + _utf8len[buf[pos]] > max) ? pos : max; +}; + +},{"./common":27}],29:[function(_dereq_,module,exports){ +'use strict'; + +// Note: adler32 takes 12% for level 0 and 2% for level 6. +// It doesn't worth to make additional optimizationa as in original. +// Small size is preferable. + +function adler32(adler, buf, len, pos) { + var s1 = (adler & 0xffff) |0 + , s2 = ((adler >>> 16) & 0xffff) |0 + , n = 0; + + while (len !== 0) { + // Set limit ~ twice less than 5552, to keep + // s2 in 31-bits, because we force signed ints. + // in other case %= will fail. + n = len > 2000 ? 2000 : len; + len -= n; + + do { + s1 = (s1 + buf[pos++]) |0; + s2 = (s2 + s1) |0; + } while (--n); + + s1 %= 65521; + s2 %= 65521; + } + + return (s1 | (s2 << 16)) |0; +} + + +module.exports = adler32; +},{}],30:[function(_dereq_,module,exports){ +module.exports = { + + /* Allowed flush values; see deflate() and inflate() below for details */ + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + Z_TREES: 6, + + /* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + Z_OK: 0, + Z_STREAM_END: 1, + Z_NEED_DICT: 2, + Z_ERRNO: -1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + //Z_MEM_ERROR: -4, + Z_BUF_ERROR: -5, + //Z_VERSION_ERROR: -6, + + /* compression levels */ + Z_NO_COMPRESSION: 0, + Z_BEST_SPEED: 1, + Z_BEST_COMPRESSION: 9, + Z_DEFAULT_COMPRESSION: -1, + + + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + + /* Possible values of the data_type field (though see inflate()) */ + Z_BINARY: 0, + Z_TEXT: 1, + //Z_ASCII: 1, // = Z_TEXT (deprecated) + Z_UNKNOWN: 2, + + /* The deflate compression method */ + Z_DEFLATED: 8 + //Z_NULL: null // Use -1 or null inline, depending on var type +}; +},{}],31:[function(_dereq_,module,exports){ +'use strict'; + +// Note: we can't get significant speed boost here. +// So write code to minimize size - no pregenerated tables +// and array tools dependencies. + + +// Use ordinary array, since untyped makes no boost here +function makeTable() { + var c, table = []; + + for(var n =0; n < 256; n++){ + c = n; + for(var k =0; k < 8; k++){ + c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); + } + table[n] = c; + } + + return table; +} + +// Create table on load. Just 255 signed longs. Not a problem. +var crcTable = makeTable(); + + +function crc32(crc, buf, len, pos) { + var t = crcTable + , end = pos + len; + + crc = crc ^ (-1); + + for (var i = pos; i < end; i++ ) { + crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; + } + + return (crc ^ (-1)); // >>> 0; +} + + +module.exports = crc32; +},{}],32:[function(_dereq_,module,exports){ +'use strict'; + +var utils = _dereq_('../utils/common'); +var trees = _dereq_('./trees'); +var adler32 = _dereq_('./adler32'); +var crc32 = _dereq_('./crc32'); +var msg = _dereq_('./messages'); + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +/* Allowed flush values; see deflate() and inflate() below for details */ +var Z_NO_FLUSH = 0; +var Z_PARTIAL_FLUSH = 1; +//var Z_SYNC_FLUSH = 2; +var Z_FULL_FLUSH = 3; +var Z_FINISH = 4; +var Z_BLOCK = 5; +//var Z_TREES = 6; + + +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ +var Z_OK = 0; +var Z_STREAM_END = 1; +//var Z_NEED_DICT = 2; +//var Z_ERRNO = -1; +var Z_STREAM_ERROR = -2; +var Z_DATA_ERROR = -3; +//var Z_MEM_ERROR = -4; +var Z_BUF_ERROR = -5; +//var Z_VERSION_ERROR = -6; + + +/* compression levels */ +//var Z_NO_COMPRESSION = 0; +//var Z_BEST_SPEED = 1; +//var Z_BEST_COMPRESSION = 9; +var Z_DEFAULT_COMPRESSION = -1; + + +var Z_FILTERED = 1; +var Z_HUFFMAN_ONLY = 2; +var Z_RLE = 3; +var Z_FIXED = 4; +var Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ +//var Z_BINARY = 0; +//var Z_TEXT = 1; +//var Z_ASCII = 1; // = Z_TEXT +var Z_UNKNOWN = 2; + + +/* The deflate compression method */ +var Z_DEFLATED = 8; + +/*============================================================================*/ + + +var MAX_MEM_LEVEL = 9; +/* Maximum value for memLevel in deflateInit2 */ +var MAX_WBITS = 15; +/* 32K LZ77 window */ +var DEF_MEM_LEVEL = 8; + + +var LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ +var LITERALS = 256; +/* number of literal bytes 0..255 */ +var L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ +var D_CODES = 30; +/* number of distance codes */ +var BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ +var HEAP_SIZE = 2*L_CODES + 1; +/* maximum heap size */ +var MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +var MIN_MATCH = 3; +var MAX_MATCH = 258; +var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); + +var PRESET_DICT = 0x20; + +var INIT_STATE = 42; +var EXTRA_STATE = 69; +var NAME_STATE = 73; +var COMMENT_STATE = 91; +var HCRC_STATE = 103; +var BUSY_STATE = 113; +var FINISH_STATE = 666; + +var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ +var BS_BLOCK_DONE = 2; /* block flush performed */ +var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ +var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ + +var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. + +function err(strm, errorCode) { + strm.msg = msg[errorCode]; + return errorCode; +} + +function rank(f) { + return ((f) << 1) - ((f) > 4 ? 9 : 0); +} + +function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->output buffer and copying into it. + * (See also read_buf()). + */ +function flush_pending(strm) { + var s = strm.state; + + //_tr_flush_bits(s); + var len = s.pending; + if (len > strm.avail_out) { + len = strm.avail_out; + } + if (len === 0) { return; } + + utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); + strm.next_out += len; + s.pending_out += len; + strm.total_out += len; + strm.avail_out -= len; + s.pending -= len; + if (s.pending === 0) { + s.pending_out = 0; + } +} + + +function flush_block_only (s, last) { + trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); + s.block_start = s.strstart; + flush_pending(s.strm); +} + + +function put_byte(s, b) { + s.pending_buf[s.pending++] = b; +} + + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +function putShortMSB(s, b) { +// put_byte(s, (Byte)(b >> 8)); +// put_byte(s, (Byte)(b & 0xff)); + s.pending_buf[s.pending++] = (b >>> 8) & 0xff; + s.pending_buf[s.pending++] = b & 0xff; +} + + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->input buffer and copying from it. + * (See also flush_pending()). + */ +function read_buf(strm, buf, start, size) { + var len = strm.avail_in; + + if (len > size) { len = size; } + if (len === 0) { return 0; } + + strm.avail_in -= len; + + utils.arraySet(buf, strm.input, strm.next_in, len, start); + if (strm.state.wrap === 1) { + strm.adler = adler32(strm.adler, buf, len, start); + } + + else if (strm.state.wrap === 2) { + strm.adler = crc32(strm.adler, buf, len, start); + } + + strm.next_in += len; + strm.total_in += len; + + return len; +} + + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +function longest_match(s, cur_match) { + var chain_length = s.max_chain_length; /* max hash chain length */ + var scan = s.strstart; /* current string */ + var match; /* matched string */ + var len; /* length of current match */ + var best_len = s.prev_length; /* best match length so far */ + var nice_match = s.nice_match; /* stop if match long enough */ + var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? + s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; + + var _win = s.window; // shortcut + + var wmask = s.w_mask; + var prev = s.prev; + + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + var strend = s.strstart + MAX_MATCH; + var scan_end1 = _win[scan + best_len - 1]; + var scan_end = _win[scan + best_len]; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s.prev_length >= s.good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if (nice_match > s.lookahead) { nice_match = s.lookahead; } + + // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + // Assert(cur_match < s->strstart, "no future"); + match = cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ + + if (_win[match + best_len] !== scan_end || + _win[match + best_len - 1] !== scan_end1 || + _win[match] !== _win[scan] || + _win[++match] !== _win[scan + 1]) { + continue; + } + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2; + match++; + // Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + /*jshint noempty:false*/ + } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + scan < strend); + + // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) { + s.match_start = cur_match; + best_len = len; + if (len >= nice_match) { + break; + } + scan_end1 = _win[scan + best_len - 1]; + scan_end = _win[scan + best_len]; + } + } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); + + if (best_len <= s.lookahead) { + return best_len; + } + return s.lookahead; +} + + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +function fill_window(s) { + var _w_size = s.w_size; + var p, n, m, more, str; + + //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = s.window_size - s.lookahead - s.strstart; + + // JS ints have 32 bit, block below not needed + /* Deal with !@#$% 64K limit: */ + //if (sizeof(int) <= 2) { + // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + // more = wsize; + // + // } else if (more == (unsigned)(-1)) { + // /* Very unlikely, but possible on 16 bit machine if + // * strstart == 0 && lookahead == 1 (input done a byte at time) + // */ + // more--; + // } + //} + + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { + + utils.arraySet(s.window, s.window, _w_size, _w_size, 0); + s.match_start -= _w_size; + s.strstart -= _w_size; + /* we now have strstart >= MAX_DIST */ + s.block_start -= _w_size; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + + n = s.hash_size; + p = n; + do { + m = s.head[--p]; + s.head[p] = (m >= _w_size ? m - _w_size : 0); + } while (--n); + + n = _w_size; + p = n; + do { + m = s.prev[--p]; + s.prev[p] = (m >= _w_size ? m - _w_size : 0); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + + more += _w_size; + } + if (s.strm.avail_in === 0) { + break; + } + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + //Assert(more >= 2, "more < 2"); + n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); + s.lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s.lookahead + s.insert >= MIN_MATCH) { + str = s.strstart - s.insert; + s.ins_h = s.window[str]; + + /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask; +//#if MIN_MATCH != 3 +// Call update_hash() MIN_MATCH-3 more times +//#endif + while (s.insert) { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask; + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = str; + str++; + s.insert--; + if (s.lookahead + s.insert < MIN_MATCH) { + break; + } + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ +// if (s.high_water < s.window_size) { +// var curr = s.strstart + s.lookahead; +// var init = 0; +// +// if (s.high_water < curr) { +// /* Previous high water mark below current data -- zero WIN_INIT +// * bytes or up to end of window, whichever is less. +// */ +// init = s.window_size - curr; +// if (init > WIN_INIT) +// init = WIN_INIT; +// zmemzero(s->window + curr, (unsigned)init); +// s->high_water = curr + init; +// } +// else if (s->high_water < (ulg)curr + WIN_INIT) { +// /* High water mark at or above current data, but below current data +// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up +// * to end of window, whichever is less. +// */ +// init = (ulg)curr + WIN_INIT - s->high_water; +// if (init > s->window_size - s->high_water) +// init = s->window_size - s->high_water; +// zmemzero(s->window + s->high_water, (unsigned)init); +// s->high_water += init; +// } +// } +// +// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, +// "not enough room for search"); +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +function deflate_stored(s, flush) { + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + var max_block_size = 0xffff; + + if (max_block_size > s.pending_buf_size - 5) { + max_block_size = s.pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s.lookahead <= 1) { + + //Assert(s->strstart < s->w_size+MAX_DIST(s) || + // s->block_start >= (long)s->w_size, "slide too late"); +// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || +// s.block_start >= s.w_size)) { +// throw new Error("slide too late"); +// } + + fill_window(s); + if (s.lookahead === 0 && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + } + //Assert(s->block_start >= 0L, "block gone"); +// if (s.block_start < 0) throw new Error("block gone"); + + s.strstart += s.lookahead; + s.lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + var max_start = s.block_start + max_block_size; + + if (s.strstart === 0 || s.strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s.lookahead = s.strstart - max_start; + s.strstart = max_start; + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + + s.insert = 0; + + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + + if (s.strstart > s.block_start) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_NEED_MORE; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +function deflate_fast(s, flush) { + var hash_head; /* head of the hash chain */ + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { + break; /* flush the current block */ + } + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + } + if (s.match_length >= MIN_MATCH) { + // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only + + /*** _tr_tally_dist(s, s.strstart - s.match_start, + s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { + s.match_length--; /* string at strstart already in table */ + do { + s.strstart++; + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s.match_length !== 0); + s.strstart++; + } else + { + s.strstart += s.match_length; + s.match_length = 0; + s.ins_h = s.window[s.strstart]; + /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask; + +//#if MIN_MATCH != 3 +// Call UPDATE_HASH() MIN_MATCH-3 more times +//#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s.window[s.strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1); + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +function deflate_slow(s, flush) { + var hash_head; /* head of hash chain */ + var bflush; /* set if current block must be flushed */ + + var max_insert; + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + */ + s.prev_length = s.match_length; + s.prev_match = s.match_start; + s.match_length = MIN_MATCH-1; + + if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && + s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if (s.match_length <= 5 && + (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s.match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { + max_insert = s.strstart + s.lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + //check_match(s, s.strstart-1, s.prev_match, s.prev_length); + + /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, + s.prev_length - MIN_MATCH, bflush);***/ + bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH); + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s.lookahead -= s.prev_length-1; + s.prev_length -= 2; + do { + if (++s.strstart <= max_insert) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + } while (--s.prev_length !== 0); + s.match_available = 0; + s.match_length = MIN_MATCH-1; + s.strstart++; + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + } else if (s.match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); + + if (bflush) { + /*** FLUSH_BLOCK_ONLY(s, 0) ***/ + flush_block_only(s, false); + /***/ + } + s.strstart++; + s.lookahead--; + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s.match_available = 1; + s.strstart++; + s.lookahead--; + } + } + //Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s.match_available) { + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); + + s.match_available = 0; + } + s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_BLOCK_DONE; +} + + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +function deflate_rle(s, flush) { + var bflush; /* set if current block must be flushed */ + var prev; /* byte at distance one to match */ + var scan, strend; /* scan goes up to strend for length of run */ + + var _win = s.window; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s.lookahead <= MAX_MATCH) { + fill_window(s); + if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s.match_length = 0; + if (s.lookahead >= MIN_MATCH && s.strstart > 0) { + scan = s.strstart - 1; + prev = _win[scan]; + if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { + strend = s.strstart + MAX_MATCH; + do { + /*jshint noempty:false*/ + } while (prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + scan < strend); + s.match_length = MAX_MATCH - (strend - scan); + if (s.match_length > s.lookahead) { + s.match_length = s.lookahead; + } + } + //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s.match_length >= MIN_MATCH) { + //check_match(s, s.strstart, s.strstart - 1, s.match_length); + + /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + s.strstart += s.match_length; + s.match_length = 0; + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +function deflate_huff(s, flush) { + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s.lookahead === 0) { + fill_window(s); + if (s.lookahead === 0) { + if (flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s.match_length = 0; + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + s.lookahead--; + s.strstart++; + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +var Config = function (good_length, max_lazy, nice_length, max_chain, func) { + this.good_length = good_length; + this.max_lazy = max_lazy; + this.nice_length = nice_length; + this.max_chain = max_chain; + this.func = func; +}; + +var configuration_table; + +configuration_table = [ + /* good lazy nice chain */ + new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ + new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ + new Config(4, 5, 16, 8, deflate_fast), /* 2 */ + new Config(4, 6, 32, 32, deflate_fast), /* 3 */ + + new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ + new Config(8, 16, 32, 32, deflate_slow), /* 5 */ + new Config(8, 16, 128, 128, deflate_slow), /* 6 */ + new Config(8, 32, 128, 256, deflate_slow), /* 7 */ + new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ + new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ +]; + + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +function lm_init(s) { + s.window_size = 2 * s.w_size; + + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + + /* Set the default configuration parameters: + */ + s.max_lazy_match = configuration_table[s.level].max_lazy; + s.good_match = configuration_table[s.level].good_length; + s.nice_match = configuration_table[s.level].nice_length; + s.max_chain_length = configuration_table[s.level].max_chain; + + s.strstart = 0; + s.block_start = 0; + s.lookahead = 0; + s.insert = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + s.ins_h = 0; +} + + +function DeflateState() { + this.strm = null; /* pointer back to this zlib stream */ + this.status = 0; /* as the name implies */ + this.pending_buf = null; /* output still pending */ + this.pending_buf_size = 0; /* size of pending_buf */ + this.pending_out = 0; /* next pending byte to output to the stream */ + this.pending = 0; /* nb of bytes in the pending buffer */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.gzhead = null; /* gzip header information to write */ + this.gzindex = 0; /* where in extra, name, or comment */ + this.method = Z_DEFLATED; /* can only be DEFLATED */ + this.last_flush = -1; /* value of flush param for previous deflate call */ + + this.w_size = 0; /* LZ77 window size (32K by default) */ + this.w_bits = 0; /* log2(w_size) (8..16) */ + this.w_mask = 0; /* w_size - 1 */ + + this.window = null; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. + */ + + this.window_size = 0; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + this.prev = null; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + this.head = null; /* Heads of the hash chains or NIL. */ + + this.ins_h = 0; /* hash index of string to be inserted */ + this.hash_size = 0; /* number of elements in hash table */ + this.hash_bits = 0; /* log2(hash_size) */ + this.hash_mask = 0; /* hash_size-1 */ + + this.hash_shift = 0; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + this.block_start = 0; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + this.match_length = 0; /* length of best match */ + this.prev_match = 0; /* previous match */ + this.match_available = 0; /* set if previous match exists */ + this.strstart = 0; /* start of string to insert */ + this.match_start = 0; /* start of matching string */ + this.lookahead = 0; /* number of valid bytes ahead in window */ + + this.prev_length = 0; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + this.max_chain_length = 0; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + this.max_lazy_match = 0; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ + // That's alias to max_lazy_match, don't use directly + //this.max_insert_length = 0; + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + this.level = 0; /* compression level (1..9) */ + this.strategy = 0; /* favor or force Huffman coding*/ + + this.good_match = 0; + /* Use a faster search when the previous match is longer than this */ + + this.nice_match = 0; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + + /* Didn't use ct_data typedef below to suppress compiler warning */ + + // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + // Use flat array of DOUBLE size, with interleaved fata, + // because JS does not support effective + this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); + this.dyn_dtree = new utils.Buf16((2*D_CODES+1) * 2); + this.bl_tree = new utils.Buf16((2*BL_CODES+1) * 2); + zero(this.dyn_ltree); + zero(this.dyn_dtree); + zero(this.bl_tree); + + this.l_desc = null; /* desc. for literal tree */ + this.d_desc = null; /* desc. for distance tree */ + this.bl_desc = null; /* desc. for bit length tree */ + + //ush bl_count[MAX_BITS+1]; + this.bl_count = new utils.Buf16(MAX_BITS+1); + /* number of codes at each bit length for an optimal tree */ + + //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + this.heap = new utils.Buf16(2*L_CODES+1); /* heap used to build the Huffman trees */ + zero(this.heap); + + this.heap_len = 0; /* number of elements in the heap */ + this.heap_max = 0; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1]; + zero(this.depth); + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + this.l_buf = 0; /* buffer index for literals or lengths */ + + this.lit_bufsize = 0; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + this.last_lit = 0; /* running index in l_buf */ + + this.d_buf = 0; + /* Buffer index for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + this.opt_len = 0; /* bit length of current block with optimal trees */ + this.static_len = 0; /* bit length of current block with static trees */ + this.matches = 0; /* number of string matches in current block */ + this.insert = 0; /* bytes at end of window left to insert */ + + + this.bi_buf = 0; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + this.bi_valid = 0; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + // Used for window memory init. We safely ignore it for JS. That makes + // sense only for pointers and memory check tools. + //this.high_water = 0; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ +} + + +function deflateResetKeep(strm) { + var s; + + if (!strm || !strm.state) { + return err(strm, Z_STREAM_ERROR); + } + + strm.total_in = strm.total_out = 0; + strm.data_type = Z_UNKNOWN; + + s = strm.state; + s.pending = 0; + s.pending_out = 0; + + if (s.wrap < 0) { + s.wrap = -s.wrap; + /* was made negative by deflate(..., Z_FINISH); */ + } + s.status = (s.wrap ? INIT_STATE : BUSY_STATE); + strm.adler = (s.wrap === 2) ? + 0 // crc32(0, Z_NULL, 0) + : + 1; // adler32(0, Z_NULL, 0) + s.last_flush = Z_NO_FLUSH; + trees._tr_init(s); + return Z_OK; +} + + +function deflateReset(strm) { + var ret = deflateResetKeep(strm); + if (ret === Z_OK) { + lm_init(strm.state); + } + return ret; +} + + +function deflateSetHeader(strm, head) { + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; } + strm.state.gzhead = head; + return Z_OK; +} + + +function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { + if (!strm) { // === Z_NULL + return Z_STREAM_ERROR; + } + var wrap = 1; + + if (level === Z_DEFAULT_COMPRESSION) { + level = 6; + } + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } + + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } + + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return err(strm, Z_STREAM_ERROR); + } + + + if (windowBits === 8) { + windowBits = 9; + } + /* until 256-byte window bug fixed */ + + var s = new DeflateState(); + + strm.state = s; + s.strm = strm; + + s.wrap = wrap; + s.gzhead = null; + s.w_bits = windowBits; + s.w_size = 1 << s.w_bits; + s.w_mask = s.w_size - 1; + + s.hash_bits = memLevel + 7; + s.hash_size = 1 << s.hash_bits; + s.hash_mask = s.hash_size - 1; + s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); + + s.window = new utils.Buf8(s.w_size * 2); + s.head = new utils.Buf16(s.hash_size); + s.prev = new utils.Buf16(s.w_size); + + // Don't need mem init magic for JS. + //s.high_water = 0; /* nothing written to s->window yet */ + + s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + s.pending_buf_size = s.lit_bufsize * 4; + s.pending_buf = new utils.Buf8(s.pending_buf_size); + + s.d_buf = s.lit_bufsize >> 1; + s.l_buf = (1 + 2) * s.lit_bufsize; + + s.level = level; + s.strategy = strategy; + s.method = method; + + return deflateReset(strm); +} + +function deflateInit(strm, level) { + return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); +} + + +function deflate(strm, flush) { + var old_flush, s; + var beg, val; // for gzip header write only + + if (!strm || !strm.state || + flush > Z_BLOCK || flush < 0) { + return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; + } + + s = strm.state; + + if (!strm.output || + (!strm.input && strm.avail_in !== 0) || + (s.status === FINISH_STATE && flush !== Z_FINISH)) { + return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR); + } + + s.strm = strm; /* just in case */ + old_flush = s.last_flush; + s.last_flush = flush; + + /* Write the header */ + if (s.status === INIT_STATE) { + + if (s.wrap === 2) { // GZIP header + strm.adler = 0; //crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (!s.gzhead) { // s->gzhead == Z_NULL + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s.status = BUSY_STATE; + } + else { + put_byte(s, (s.gzhead.text ? 1 : 0) + + (s.gzhead.hcrc ? 2 : 0) + + (!s.gzhead.extra ? 0 : 4) + + (!s.gzhead.name ? 0 : 8) + + (!s.gzhead.comment ? 0 : 16) + ); + put_byte(s, s.gzhead.time & 0xff); + put_byte(s, (s.gzhead.time >> 8) & 0xff); + put_byte(s, (s.gzhead.time >> 16) & 0xff); + put_byte(s, (s.gzhead.time >> 24) & 0xff); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, s.gzhead.os & 0xff); + if (s.gzhead.extra && s.gzhead.extra.length) { + put_byte(s, s.gzhead.extra.length & 0xff); + put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); + } + if (s.gzhead.hcrc) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); + } + s.gzindex = 0; + s.status = EXTRA_STATE; + } + } + else // DEFLATE header + { + var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; + var level_flags = -1; + + if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { + level_flags = 0; + } else if (s.level < 6) { + level_flags = 1; + } else if (s.level === 6) { + level_flags = 2; + } else { + level_flags = 3; + } + header |= (level_flags << 6); + if (s.strstart !== 0) { header |= PRESET_DICT; } + header += 31 - (header % 31); + + s.status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s.strstart !== 0) { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + strm.adler = 1; // adler32(0L, Z_NULL, 0); + } + } + +//#ifdef GZIP + if (s.status === EXTRA_STATE) { + if (s.gzhead.extra/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + + while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + break; + } + } + put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); + s.gzindex++; + } + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (s.gzindex === s.gzhead.extra.length) { + s.gzindex = 0; + s.status = NAME_STATE; + } + } + else { + s.status = NAME_STATE; + } + } + if (s.status === NAME_STATE) { + if (s.gzhead.name/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.name.length) { + val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg){ + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.gzindex = 0; + s.status = COMMENT_STATE; + } + } + else { + s.status = COMMENT_STATE; + } + } + if (s.status === COMMENT_STATE) { + if (s.gzhead.comment/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.comment.length) { + val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.status = HCRC_STATE; + } + } + else { + s.status = HCRC_STATE; + } + } + if (s.status === HCRC_STATE) { + if (s.gzhead.hcrc) { + if (s.pending + 2 > s.pending_buf_size) { + flush_pending(strm); + } + if (s.pending + 2 <= s.pending_buf_size) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + strm.adler = 0; //crc32(0L, Z_NULL, 0); + s.status = BUSY_STATE; + } + } + else { + s.status = BUSY_STATE; + } + } +//#endif + + /* Flush as much pending output as possible */ + if (s.pending !== 0) { + flush_pending(strm); + if (strm.avail_out === 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s.last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && + flush !== Z_FINISH) { + return err(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s.status === FINISH_STATE && strm.avail_in !== 0) { + return err(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm.avail_in !== 0 || s.lookahead !== 0 || + (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) { + var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) : + (s.strategy === Z_RLE ? deflate_rle(s, flush) : + configuration_table[s.level].func(s, flush)); + + if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { + s.status = FINISH_STATE; + } + if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate === BS_BLOCK_DONE) { + if (flush === Z_PARTIAL_FLUSH) { + trees._tr_align(s); + } + else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + + trees._tr_stored_block(s, 0, 0, false); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush === Z_FULL_FLUSH) { + /*** CLEAR_HASH(s); ***/ /* forget history */ + zero(s.head); // Fill with NIL (= 0); + + if (s.lookahead === 0) { + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + } + } + flush_pending(strm); + if (strm.avail_out === 0) { + s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + //Assert(strm->avail_out > 0, "bug2"); + //if (strm.avail_out <= 0) { throw new Error("bug2");} + + if (flush !== Z_FINISH) { return Z_OK; } + if (s.wrap <= 0) { return Z_STREAM_END; } + + /* Write the trailer */ + if (s.wrap === 2) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + put_byte(s, (strm.adler >> 16) & 0xff); + put_byte(s, (strm.adler >> 24) & 0xff); + put_byte(s, strm.total_in & 0xff); + put_byte(s, (strm.total_in >> 8) & 0xff); + put_byte(s, (strm.total_in >> 16) & 0xff); + put_byte(s, (strm.total_in >> 24) & 0xff); + } + else + { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s.wrap > 0) { s.wrap = -s.wrap; } + /* write the trailer only once! */ + return s.pending !== 0 ? Z_OK : Z_STREAM_END; +} + +function deflateEnd(strm) { + var status; + + if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { + return Z_STREAM_ERROR; + } + + status = strm.state.status; + if (status !== INIT_STATE && + status !== EXTRA_STATE && + status !== NAME_STATE && + status !== COMMENT_STATE && + status !== HCRC_STATE && + status !== BUSY_STATE && + status !== FINISH_STATE + ) { + return err(strm, Z_STREAM_ERROR); + } + + strm.state = null; + + return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state + */ +//function deflateCopy(dest, source) { +// +//} + +exports.deflateInit = deflateInit; +exports.deflateInit2 = deflateInit2; +exports.deflateReset = deflateReset; +exports.deflateResetKeep = deflateResetKeep; +exports.deflateSetHeader = deflateSetHeader; +exports.deflate = deflate; +exports.deflateEnd = deflateEnd; +exports.deflateInfo = 'pako deflate (from Nodeca project)'; + +/* Not implemented +exports.deflateBound = deflateBound; +exports.deflateCopy = deflateCopy; +exports.deflateSetDictionary = deflateSetDictionary; +exports.deflateParams = deflateParams; +exports.deflatePending = deflatePending; +exports.deflatePrime = deflatePrime; +exports.deflateTune = deflateTune; +*/ +},{"../utils/common":27,"./adler32":29,"./crc32":31,"./messages":37,"./trees":38}],33:[function(_dereq_,module,exports){ +'use strict'; + + +function GZheader() { + /* true if compressed data believed to be text */ + this.text = 0; + /* modification time */ + this.time = 0; + /* extra flags (not used when writing a gzip file) */ + this.xflags = 0; + /* operating system */ + this.os = 0; + /* pointer to extra field or Z_NULL if none */ + this.extra = null; + /* extra field length (valid if extra != Z_NULL) */ + this.extra_len = 0; // Actually, we don't need it in JS, + // but leave for few code modifications + + // + // Setup limits is not necessary because in js we should not preallocate memory + // for inflate use constant limit in 65536 bytes + // + + /* space at extra (only when reading header) */ + // this.extra_max = 0; + /* pointer to zero-terminated file name or Z_NULL */ + this.name = ''; + /* space at name (only when reading header) */ + // this.name_max = 0; + /* pointer to zero-terminated comment or Z_NULL */ + this.comment = ''; + /* space at comment (only when reading header) */ + // this.comm_max = 0; + /* true if there was or will be a header crc */ + this.hcrc = 0; + /* true when done reading gzip header (not used when writing a gzip file) */ + this.done = false; +} + +module.exports = GZheader; +},{}],34:[function(_dereq_,module,exports){ +'use strict'; + +// See state defs from inflate.js +var BAD = 30; /* got a data error -- remain here until reset */ +var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state.mode === LEN + strm.avail_in >= 6 + strm.avail_out >= 258 + start >= strm.avail_out + state.bits < 8 + + On return, state.mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm.avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm.avail_out >= 258 for each loop to avoid checking for + output space. + */ +module.exports = function inflate_fast(strm, start) { + var state; + var _in; /* local strm.input */ + var last; /* have enough input while in < last */ + var _out; /* local strm.output */ + var beg; /* inflate()'s initial strm.output */ + var end; /* while out < end, enough space available */ +//#ifdef INFLATE_STRICT + var dmax; /* maximum distance from zlib header */ +//#endif + var wsize; /* window size or zero if not using window */ + var whave; /* valid bytes in the window */ + var wnext; /* window write index */ + var window; /* allocated sliding window, if wsize != 0 */ + var hold; /* local strm.hold */ + var bits; /* local strm.bits */ + var lcode; /* local strm.lencode */ + var dcode; /* local strm.distcode */ + var lmask; /* mask for first level of length codes */ + var dmask; /* mask for first level of distance codes */ + var here; /* retrieved table entry */ + var op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + var len; /* match length, unused bytes */ + var dist; /* match distance */ + var from; /* where to copy match from */ + var from_source; + + + var input, output; // JS specific, because we have no pointers + + /* copy state to local variables */ + state = strm.state; + //here = state.here; + _in = strm.next_in; + input = strm.input; + last = _in + (strm.avail_in - 5); + _out = strm.next_out; + output = strm.output; + beg = _out - (start - strm.avail_out); + end = _out + (strm.avail_out - 257); +//#ifdef INFLATE_STRICT + dmax = state.dmax; +//#endif + wsize = state.wsize; + whave = state.whave; + wnext = state.wnext; + window = state.window; + hold = state.hold; + bits = state.bits; + lcode = state.lencode; + dcode = state.distcode; + lmask = (1 << state.lenbits) - 1; + dmask = (1 << state.distbits) - 1; + + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + top: + do { + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + + here = lcode[hold & lmask]; + + dolen: + for (;;) { // Goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + if (op === 0) { /* literal */ + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + output[_out++] = here & 0xffff/*here.val*/; + } + else if (op & 16) { /* length base */ + len = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + len += hold & ((1 << op) - 1); + hold >>>= op; + bits -= op; + } + //Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + here = dcode[hold & dmask]; + + dodist: + for (;;) { // goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + + if (op & 16) { /* distance base */ + dist = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + } + dist += hold & ((1 << op) - 1); +//#ifdef INFLATE_STRICT + if (dist > dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break top; + } +//#endif + hold >>>= op; + bits -= op; + //Tracevv((stderr, "inflate: distance %u\n", dist)); + op = _out - beg; /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break top; + } + +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility +//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR +// if (len <= op - whave) { +// do { +// output[_out++] = 0; +// } while (--len); +// continue top; +// } +// len -= op - whave; +// do { +// output[_out++] = 0; +// } while (--op > whave); +// if (op === 0) { +// from = _out - dist; +// do { +// output[_out++] = output[from++]; +// } while (--len); +// continue top; +// } +//#endif + } + from = 0; // window index + from_source = window; + if (wnext === 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = 0; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + while (len > 2) { + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + len -= 3; + } + if (len) { + output[_out++] = from_source[from++]; + if (len > 1) { + output[_out++] = from_source[from++]; + } + } + } + else { + from = _out - dist; /* copy direct from output */ + do { /* minimum length is three */ + output[_out++] = output[from++]; + output[_out++] = output[from++]; + output[_out++] = output[from++]; + len -= 3; + } while (len > 2); + if (len) { + output[_out++] = output[from++]; + if (len > 1) { + output[_out++] = output[from++]; + } + } + } + } + else if ((op & 64) === 0) { /* 2nd level distance code */ + here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dodist; + } + else { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } + else if ((op & 64) === 0) { /* 2nd level length code */ + here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dolen; + } + else if (op & 32) { /* end-of-block */ + //Tracevv((stderr, "inflate: end of block\n")); + state.mode = TYPE; + break top; + } + else { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } while (_in < last && _out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + _in -= len; + bits -= len << 3; + hold &= (1 << bits) - 1; + + /* update state and return */ + strm.next_in = _in; + strm.next_out = _out; + strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); + strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); + state.hold = hold; + state.bits = bits; + return; +}; + +},{}],35:[function(_dereq_,module,exports){ +'use strict'; + + +var utils = _dereq_('../utils/common'); +var adler32 = _dereq_('./adler32'); +var crc32 = _dereq_('./crc32'); +var inflate_fast = _dereq_('./inffast'); +var inflate_table = _dereq_('./inftrees'); + +var CODES = 0; +var LENS = 1; +var DISTS = 2; + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +/* Allowed flush values; see deflate() and inflate() below for details */ +//var Z_NO_FLUSH = 0; +//var Z_PARTIAL_FLUSH = 1; +//var Z_SYNC_FLUSH = 2; +//var Z_FULL_FLUSH = 3; +var Z_FINISH = 4; +var Z_BLOCK = 5; +var Z_TREES = 6; + + +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ +var Z_OK = 0; +var Z_STREAM_END = 1; +var Z_NEED_DICT = 2; +//var Z_ERRNO = -1; +var Z_STREAM_ERROR = -2; +var Z_DATA_ERROR = -3; +var Z_MEM_ERROR = -4; +var Z_BUF_ERROR = -5; +//var Z_VERSION_ERROR = -6; + +/* The deflate compression method */ +var Z_DEFLATED = 8; + + +/* STATES ====================================================================*/ +/* ===========================================================================*/ + + +var HEAD = 1; /* i: waiting for magic header */ +var FLAGS = 2; /* i: waiting for method and flags (gzip) */ +var TIME = 3; /* i: waiting for modification time (gzip) */ +var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ +var EXLEN = 5; /* i: waiting for extra length (gzip) */ +var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ +var NAME = 7; /* i: waiting for end of file name (gzip) */ +var COMMENT = 8; /* i: waiting for end of comment (gzip) */ +var HCRC = 9; /* i: waiting for header crc (gzip) */ +var DICTID = 10; /* i: waiting for dictionary check value */ +var DICT = 11; /* waiting for inflateSetDictionary() call */ +var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ +var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ +var STORED = 14; /* i: waiting for stored size (length and complement) */ +var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ +var COPY = 16; /* i/o: waiting for input or output to copy stored block */ +var TABLE = 17; /* i: waiting for dynamic block table lengths */ +var LENLENS = 18; /* i: waiting for code length code lengths */ +var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ +var LEN_ = 20; /* i: same as LEN below, but only first time in */ +var LEN = 21; /* i: waiting for length/lit/eob code */ +var LENEXT = 22; /* i: waiting for length extra bits */ +var DIST = 23; /* i: waiting for distance code */ +var DISTEXT = 24; /* i: waiting for distance extra bits */ +var MATCH = 25; /* o: waiting for output space to copy string */ +var LIT = 26; /* o: waiting for output space to write literal */ +var CHECK = 27; /* i: waiting for 32-bit check value */ +var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ +var DONE = 29; /* finished check, done -- remain here until reset */ +var BAD = 30; /* got a data error -- remain here until reset */ +var MEM = 31; /* got an inflate() memory error -- remain here until reset */ +var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ + +/* ===========================================================================*/ + + + +var ENOUGH_LENS = 852; +var ENOUGH_DISTS = 592; +//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +var MAX_WBITS = 15; +/* 32K LZ77 window */ +var DEF_WBITS = MAX_WBITS; + + +function ZSWAP32(q) { + return (((q >>> 24) & 0xff) + + ((q >>> 8) & 0xff00) + + ((q & 0xff00) << 8) + + ((q & 0xff) << 24)); +} + + +function InflateState() { + this.mode = 0; /* current inflate mode */ + this.last = false; /* true if processing last block */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.havedict = false; /* true if dictionary provided */ + this.flags = 0; /* gzip header method and flags (0 if zlib) */ + this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ + this.check = 0; /* protected copy of check value */ + this.total = 0; /* protected copy of output count */ + // TODO: may be {} + this.head = null; /* where to save gzip header information */ + + /* sliding window */ + this.wbits = 0; /* log base 2 of requested window size */ + this.wsize = 0; /* window size or zero if not using window */ + this.whave = 0; /* valid bytes in the window */ + this.wnext = 0; /* window write index */ + this.window = null; /* allocated sliding window, if needed */ + + /* bit accumulator */ + this.hold = 0; /* input bit accumulator */ + this.bits = 0; /* number of bits in "in" */ + + /* for string and stored block copying */ + this.length = 0; /* literal or length of data to copy */ + this.offset = 0; /* distance back to copy string from */ + + /* for table and code decoding */ + this.extra = 0; /* extra bits needed */ + + /* fixed and dynamic code tables */ + this.lencode = null; /* starting table for length/literal codes */ + this.distcode = null; /* starting table for distance codes */ + this.lenbits = 0; /* index bits for lencode */ + this.distbits = 0; /* index bits for distcode */ + + /* dynamic table building */ + this.ncode = 0; /* number of code length code lengths */ + this.nlen = 0; /* number of length code lengths */ + this.ndist = 0; /* number of distance code lengths */ + this.have = 0; /* number of code lengths in lens[] */ + this.next = null; /* next available space in codes[] */ + + this.lens = new utils.Buf16(320); /* temporary storage for code lengths */ + this.work = new utils.Buf16(288); /* work area for code table building */ + + /* + because we don't have pointers in js, we use lencode and distcode directly + as buffers so we don't need codes + */ + //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ + this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ + this.distdyn = null; /* dynamic table for distance codes (JS specific) */ + this.sane = 0; /* if false, allow invalid distance too far */ + this.back = 0; /* bits back of last unprocessed length/lit */ + this.was = 0; /* initial length of match */ +} + +function inflateResetKeep(strm) { + var state; + + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + strm.total_in = strm.total_out = state.total = 0; + strm.msg = ''; /*Z_NULL*/ + if (state.wrap) { /* to support ill-conceived Java test suite */ + strm.adler = state.wrap & 1; + } + state.mode = HEAD; + state.last = 0; + state.havedict = 0; + state.dmax = 32768; + state.head = null/*Z_NULL*/; + state.hold = 0; + state.bits = 0; + //state.lencode = state.distcode = state.next = state.codes; + state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); + state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); + + state.sane = 1; + state.back = -1; + //Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +function inflateReset(strm) { + var state; + + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + state.wsize = 0; + state.whave = 0; + state.wnext = 0; + return inflateResetKeep(strm); + +} + +function inflateReset2(strm, windowBits) { + var wrap; + var state; + + /* get the state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 1; + if (windowBits < 48) { + windowBits &= 15; + } + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) { + return Z_STREAM_ERROR; + } + if (state.window !== null && state.wbits !== windowBits) { + state.window = null; + } + + /* update state and reset the rest of it */ + state.wrap = wrap; + state.wbits = windowBits; + return inflateReset(strm); +} + +function inflateInit2(strm, windowBits) { + var ret; + var state; + + if (!strm) { return Z_STREAM_ERROR; } + //strm.msg = Z_NULL; /* in case we return an error */ + + state = new InflateState(); + + //if (state === Z_NULL) return Z_MEM_ERROR; + //Tracev((stderr, "inflate: allocated\n")); + strm.state = state; + state.window = null/*Z_NULL*/; + ret = inflateReset2(strm, windowBits); + if (ret !== Z_OK) { + strm.state = null/*Z_NULL*/; + } + return ret; +} + +function inflateInit(strm) { + return inflateInit2(strm, DEF_WBITS); +} + + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +var virgin = true; + +var lenfix, distfix; // We have no pointers in JS, so keep tables separate + +function fixedtables(state) { + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + var sym; + + lenfix = new utils.Buf32(512); + distfix = new utils.Buf32(32); + + /* literal/length table */ + sym = 0; + while (sym < 144) { state.lens[sym++] = 8; } + while (sym < 256) { state.lens[sym++] = 9; } + while (sym < 280) { state.lens[sym++] = 7; } + while (sym < 288) { state.lens[sym++] = 8; } + + inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, {bits: 9}); + + /* distance table */ + sym = 0; + while (sym < 32) { state.lens[sym++] = 5; } + + inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, {bits: 5}); + + /* do this just once */ + virgin = false; + } + + state.lencode = lenfix; + state.lenbits = 9; + state.distcode = distfix; + state.distbits = 5; +} + + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +function updatewindow(strm, src, end, copy) { + var dist; + var state = strm.state; + + /* if it hasn't been done already, allocate space for the window */ + if (state.window === null) { + state.wsize = 1 << state.wbits; + state.wnext = 0; + state.whave = 0; + + state.window = new utils.Buf8(state.wsize); + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state.wsize) { + utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0); + state.wnext = 0; + state.whave = state.wsize; + } + else { + dist = state.wsize - state.wnext; + if (dist > copy) { + dist = copy; + } + //zmemcpy(state->window + state->wnext, end - copy, dist); + utils.arraySet(state.window,src, end - copy, dist, state.wnext); + copy -= dist; + if (copy) { + //zmemcpy(state->window, end - copy, copy); + utils.arraySet(state.window,src, end - copy, copy, 0); + state.wnext = copy; + state.whave = state.wsize; + } + else { + state.wnext += dist; + if (state.wnext === state.wsize) { state.wnext = 0; } + if (state.whave < state.wsize) { state.whave += dist; } + } + } + return 0; +} + +function inflate(strm, flush) { + var state; + var input, output; // input/output buffers + var next; /* next input INDEX */ + var put; /* next output INDEX */ + var have, left; /* available input and output */ + var hold; /* bit buffer */ + var bits; /* bits in bit buffer */ + var _in, _out; /* save starting available input and output */ + var copy; /* number of stored or match bytes to copy */ + var from; /* where to copy match bytes from */ + var from_source; + var here = 0; /* current decoding table entry */ + var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) + //var last; /* parent table entry */ + var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) + var len; /* length to copy for repeats, bits to drop */ + var ret; /* return code */ + var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */ + var opts; + + var n; // temporary var for NEED_BITS + + var order = /* permutation of code lengths */ + [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; + + + if (!strm || !strm.state || !strm.output || + (!strm.input && strm.avail_in !== 0)) { + return Z_STREAM_ERROR; + } + + state = strm.state; + if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ + + + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + _in = have; + _out = left; + ret = Z_OK; + + inf_leave: // goto emulation + for (;;) { + switch (state.mode) { + case HEAD: + if (state.wrap === 0) { + state.mode = TYPEDO; + break; + } + //=== NEEDBITS(16); + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ + state.check = 0/*crc32(0L, Z_NULL, 0)*/; + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = FLAGS; + break; + } + state.flags = 0; /* expect zlib header */ + if (state.head) { + state.head.done = false; + } + if (!(state.wrap & 1) || /* check if zlib header allowed */ + (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { + strm.msg = 'incorrect header check'; + state.mode = BAD; + break; + } + if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// + len = (hold & 0x0f)/*BITS(4)*/ + 8; + if (state.wbits === 0) { + state.wbits = len; + } + else if (len > state.wbits) { + strm.msg = 'invalid window size'; + state.mode = BAD; + break; + } + state.dmax = 1 << len; + //Tracev((stderr, "inflate: zlib header ok\n")); + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = hold & 0x200 ? DICTID : TYPE; + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + break; + case FLAGS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.flags = hold; + if ((state.flags & 0xff) !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + if (state.flags & 0xe000) { + strm.msg = 'unknown header flags set'; + state.mode = BAD; + break; + } + if (state.head) { + state.head.text = ((hold >> 8) & 1); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = TIME; + /* falls through */ + case TIME: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.time = hold; + } + if (state.flags & 0x0200) { + //=== CRC4(state.check, hold) + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + hbuf[2] = (hold >>> 16) & 0xff; + hbuf[3] = (hold >>> 24) & 0xff; + state.check = crc32(state.check, hbuf, 4, 0); + //=== + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = OS; + /* falls through */ + case OS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.xflags = (hold & 0xff); + state.head.os = (hold >> 8); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = EXLEN; + /* falls through */ + case EXLEN: + if (state.flags & 0x0400) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length = hold; + if (state.head) { + state.head.extra_len = hold; + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + else if (state.head) { + state.head.extra = null/*Z_NULL*/; + } + state.mode = EXTRA; + /* falls through */ + case EXTRA: + if (state.flags & 0x0400) { + copy = state.length; + if (copy > have) { copy = have; } + if (copy) { + if (state.head) { + len = state.head.extra_len - state.length; + if (!state.head.extra) { + // Use untyped array for more conveniend processing later + state.head.extra = new Array(state.head.extra_len); + } + utils.arraySet( + state.head.extra, + input, + next, + // extra field is limited to 65536 bytes + // - no need for additional size check + copy, + /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ + len + ); + //zmemcpy(state.head.extra + len, next, + // len + copy > state.head.extra_max ? + // state.head.extra_max - len : copy); + } + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + state.length -= copy; + } + if (state.length) { break inf_leave; } + } + state.length = 0; + state.mode = NAME; + /* falls through */ + case NAME: + if (state.flags & 0x0800) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + // TODO: 2 or 1 bytes? + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.name_max*/)) { + state.head.name += String.fromCharCode(len); + } + } while (len && copy < have); + + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.name = null; + } + state.length = 0; + state.mode = COMMENT; + /* falls through */ + case COMMENT: + if (state.flags & 0x1000) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.comm_max*/)) { + state.head.comment += String.fromCharCode(len); + } + } while (len && copy < have); + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.comment = null; + } + state.mode = HCRC; + /* falls through */ + case HCRC: + if (state.flags & 0x0200) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.check & 0xffff)) { + strm.msg = 'header crc mismatch'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + if (state.head) { + state.head.hcrc = ((state.flags >> 9) & 1); + state.head.done = true; + } + strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/; + state.mode = TYPE; + break; + case DICTID: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + strm.adler = state.check = ZSWAP32(hold); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = DICT; + /* falls through */ + case DICT: + if (state.havedict === 0) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + return Z_NEED_DICT; + } + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = TYPE; + /* falls through */ + case TYPE: + if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } + /* falls through */ + case TYPEDO: + if (state.last) { + //--- BYTEBITS() ---// + hold >>>= bits & 7; + bits -= bits & 7; + //---// + state.mode = CHECK; + break; + } + //=== NEEDBITS(3); */ + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.last = (hold & 0x01)/*BITS(1)*/; + //--- DROPBITS(1) ---// + hold >>>= 1; + bits -= 1; + //---// + + switch ((hold & 0x03)/*BITS(2)*/) { + case 0: /* stored block */ + //Tracev((stderr, "inflate: stored block%s\n", + // state.last ? " (last)" : "")); + state.mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + //Tracev((stderr, "inflate: fixed codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = LEN_; /* decode codes */ + if (flush === Z_TREES) { + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break inf_leave; + } + break; + case 2: /* dynamic block */ + //Tracev((stderr, "inflate: dynamic codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = TABLE; + break; + case 3: + strm.msg = 'invalid block type'; + state.mode = BAD; + } + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break; + case STORED: + //--- BYTEBITS() ---// /* go to byte boundary */ + hold >>>= bits & 7; + bits -= bits & 7; + //---// + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { + strm.msg = 'invalid stored block lengths'; + state.mode = BAD; + break; + } + state.length = hold & 0xffff; + //Tracev((stderr, "inflate: stored length %u\n", + // state.length)); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = COPY_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case COPY_: + state.mode = COPY; + /* falls through */ + case COPY: + copy = state.length; + if (copy) { + if (copy > have) { copy = have; } + if (copy > left) { copy = left; } + if (copy === 0) { break inf_leave; } + //--- zmemcpy(put, next, copy); --- + utils.arraySet(output, input, next, copy, put); + //---// + have -= copy; + next += copy; + left -= copy; + put += copy; + state.length -= copy; + break; + } + //Tracev((stderr, "inflate: stored end\n")); + state.mode = TYPE; + break; + case TABLE: + //=== NEEDBITS(14); */ + while (bits < 14) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// +//#ifndef PKZIP_BUG_WORKAROUND + if (state.nlen > 286 || state.ndist > 30) { + strm.msg = 'too many length or distance symbols'; + state.mode = BAD; + break; + } +//#endif + //Tracev((stderr, "inflate: table sizes ok\n")); + state.have = 0; + state.mode = LENLENS; + /* falls through */ + case LENLENS: + while (state.have < state.ncode) { + //=== NEEDBITS(3); + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + while (state.have < 19) { + state.lens[order[state.have++]] = 0; + } + // We have separate tables & no pointers. 2 commented lines below not needed. + //state.next = state.codes; + //state.lencode = state.next; + // Switch to use dynamic table + state.lencode = state.lendyn; + state.lenbits = 7; + + opts = {bits: state.lenbits}; + ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); + state.lenbits = opts.bits; + + if (ret) { + strm.msg = 'invalid code lengths set'; + state.mode = BAD; + break; + } + //Tracev((stderr, "inflate: code lengths ok\n")); + state.have = 0; + state.mode = CODELENS; + /* falls through */ + case CODELENS: + while (state.have < state.nlen + state.ndist) { + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_val < 16) { + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.lens[state.have++] = here_val; + } + else { + if (here_val === 16) { + //=== NEEDBITS(here.bits + 2); + n = here_bits + 2; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + if (state.have === 0) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + len = state.lens[state.have - 1]; + copy = 3 + (hold & 0x03);//BITS(2); + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + } + else if (here_val === 17) { + //=== NEEDBITS(here.bits + 3); + n = here_bits + 3; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 3 + (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + else { + //=== NEEDBITS(here.bits + 7); + n = here_bits + 7; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 11 + (hold & 0x7f);//BITS(7); + //--- DROPBITS(7) ---// + hold >>>= 7; + bits -= 7; + //---// + } + if (state.have + copy > state.nlen + state.ndist) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + while (copy--) { + state.lens[state.have++] = len; + } + } + } + + /* handle error breaks in while */ + if (state.mode === BAD) { break; } + + /* check for end-of-block code (better have one) */ + if (state.lens[256] === 0) { + strm.msg = 'invalid code -- missing end-of-block'; + state.mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state.lenbits = 9; + + opts = {bits: state.lenbits}; + ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.lenbits = opts.bits; + // state.lencode = state.next; + + if (ret) { + strm.msg = 'invalid literal/lengths set'; + state.mode = BAD; + break; + } + + state.distbits = 6; + //state.distcode.copy(state.codes); + // Switch to use dynamic table + state.distcode = state.distdyn; + opts = {bits: state.distbits}; + ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.distbits = opts.bits; + // state.distcode = state.next; + + if (ret) { + strm.msg = 'invalid distances set'; + state.mode = BAD; + break; + } + //Tracev((stderr, 'inflate: codes ok\n')); + state.mode = LEN_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case LEN_: + state.mode = LEN; + /* falls through */ + case LEN: + if (have >= 6 && left >= 258) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + inflate_fast(strm, _out); + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + if (state.mode === TYPE) { + state.back = -1; + } + break; + } + state.back = 0; + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) -1)]; /*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if (here_bits <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_op && (here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.lencode[last_val + + ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + state.length = here_val; + if (here_op === 0) { + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + state.mode = LIT; + break; + } + if (here_op & 32) { + //Tracevv((stderr, "inflate: end of block\n")); + state.back = -1; + state.mode = TYPE; + break; + } + if (here_op & 64) { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break; + } + state.extra = here_op & 15; + state.mode = LENEXT; + /* falls through */ + case LENEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } + //Tracevv((stderr, "inflate: length %u\n", state.length)); + state.was = state.length; + state.mode = DIST; + /* falls through */ + case DIST: + for (;;) { + here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if ((here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.distcode[last_val + + ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + if (here_op & 64) { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break; + } + state.offset = here_val; + state.extra = (here_op) & 15; + state.mode = DISTEXT; + /* falls through */ + case DISTEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } +//#ifdef INFLATE_STRICT + if (state.offset > state.dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } +//#endif + //Tracevv((stderr, "inflate: distance %u\n", state.offset)); + state.mode = MATCH; + /* falls through */ + case MATCH: + if (left === 0) { break inf_leave; } + copy = _out - left; + if (state.offset > copy) { /* copy from window */ + copy = state.offset - copy; + if (copy > state.whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility +//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR +// Trace((stderr, "inflate.c too far\n")); +// copy -= state.whave; +// if (copy > state.length) { copy = state.length; } +// if (copy > left) { copy = left; } +// left -= copy; +// state.length -= copy; +// do { +// output[put++] = 0; +// } while (--copy); +// if (state.length === 0) { state.mode = LEN; } +// break; +//#endif + } + if (copy > state.wnext) { + copy -= state.wnext; + from = state.wsize - copy; + } + else { + from = state.wnext - copy; + } + if (copy > state.length) { copy = state.length; } + from_source = state.window; + } + else { /* copy from output */ + from_source = output; + from = put - state.offset; + copy = state.length; + } + if (copy > left) { copy = left; } + left -= copy; + state.length -= copy; + do { + output[put++] = from_source[from++]; + } while (--copy); + if (state.length === 0) { state.mode = LEN; } + break; + case LIT: + if (left === 0) { break inf_leave; } + output[put++] = state.length; + left--; + state.mode = LEN; + break; + case CHECK: + if (state.wrap) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + // Use '|' insdead of '+' to make sure that result is signed + hold |= input[next++] << bits; + bits += 8; + } + //===// + _out -= left; + strm.total_out += _out; + state.total += _out; + if (_out) { + strm.adler = state.check = + /*UPDATE(state.check, put - _out, _out);*/ + (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out)); + + } + _out = left; + // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too + if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) { + strm.msg = 'incorrect data check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: check matches trailer\n")); + } + state.mode = LENGTH; + /* falls through */ + case LENGTH: + if (state.wrap && state.flags) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.total & 0xffffffff)) { + strm.msg = 'incorrect length check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: length matches trailer\n")); + } + state.mode = DONE; + /* falls through */ + case DONE: + ret = Z_STREAM_END; + break inf_leave; + case BAD: + ret = Z_DATA_ERROR; + break inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* falls through */ + default: + return Z_STREAM_ERROR; + } + } + + // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + + if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && + (state.mode < CHECK || flush !== Z_FINISH))) { + if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) { + state.mode = MEM; + return Z_MEM_ERROR; + } + } + _in -= strm.avail_in; + _out -= strm.avail_out; + strm.total_in += _in; + strm.total_out += _out; + state.total += _out; + if (state.wrap && _out) { + strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ + (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out)); + } + strm.data_type = state.bits + (state.last ? 64 : 0) + + (state.mode === TYPE ? 128 : 0) + + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); + if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { + ret = Z_BUF_ERROR; + } + return ret; +} + +function inflateEnd(strm) { + + if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { + return Z_STREAM_ERROR; + } + + var state = strm.state; + if (state.window) { + state.window = null; + } + strm.state = null; + return Z_OK; +} + +function inflateGetHeader(strm, head) { + var state; + + /* check state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; } + + /* save header structure */ + state.head = head; + head.done = false; + return Z_OK; +} + + +exports.inflateReset = inflateReset; +exports.inflateReset2 = inflateReset2; +exports.inflateResetKeep = inflateResetKeep; +exports.inflateInit = inflateInit; +exports.inflateInit2 = inflateInit2; +exports.inflate = inflate; +exports.inflateEnd = inflateEnd; +exports.inflateGetHeader = inflateGetHeader; +exports.inflateInfo = 'pako inflate (from Nodeca project)'; + +/* Not implemented +exports.inflateCopy = inflateCopy; +exports.inflateGetDictionary = inflateGetDictionary; +exports.inflateMark = inflateMark; +exports.inflatePrime = inflatePrime; +exports.inflateSetDictionary = inflateSetDictionary; +exports.inflateSync = inflateSync; +exports.inflateSyncPoint = inflateSyncPoint; +exports.inflateUndermine = inflateUndermine; +*/ +},{"../utils/common":27,"./adler32":29,"./crc32":31,"./inffast":34,"./inftrees":36}],36:[function(_dereq_,module,exports){ +'use strict'; + + +var utils = _dereq_('../utils/common'); + +var MAXBITS = 15; +var ENOUGH_LENS = 852; +var ENOUGH_DISTS = 592; +//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +var CODES = 0; +var LENS = 1; +var DISTS = 2; + +var lbase = [ /* Length codes 257..285 base */ + 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, 0, 0 +]; + +var lext = [ /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 +]; + +var dbase = [ /* Distance codes 0..29 base */ + 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, 0, 0 +]; + +var dext = [ /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64 +]; + +module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) +{ + var bits = opts.bits; + //here = opts.here; /* table entry for duplication */ + + var len = 0; /* a code's length in bits */ + var sym = 0; /* index of code symbols */ + var min = 0, max = 0; /* minimum and maximum code lengths */ + var root = 0; /* number of index bits for root table */ + var curr = 0; /* number of index bits for current table */ + var drop = 0; /* code bits to drop for sub-table */ + var left = 0; /* number of prefix codes available */ + var used = 0; /* code entries in table used */ + var huff = 0; /* Huffman code */ + var incr; /* for incrementing code, index */ + var fill; /* index for replicating entries */ + var low; /* low bits for current root entry */ + var mask; /* mask for low root bits */ + var next; /* next available space in table */ + var base = null; /* base value table to use */ + var base_index = 0; +// var shoextra; /* extra bits table to use */ + var end; /* use base and extra for symbol > end */ + var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */ + var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */ + var extra = null; + var extra_index = 0; + + var here_bits, here_op, here_val; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) { + count[len] = 0; + } + for (sym = 0; sym < codes; sym++) { + count[lens[lens_index + sym]]++; + } + + /* bound code lengths, force root to be within code lengths */ + root = bits; + for (max = MAXBITS; max >= 1; max--) { + if (count[max] !== 0) { break; } + } + if (root > max) { + root = max; + } + if (max === 0) { /* no symbols to code at all */ + //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ + //table.bits[opts.table_index] = 1; //here.bits = (var char)1; + //table.val[opts.table_index++] = 0; //here.val = (var short)0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + + //table.op[opts.table_index] = 64; + //table.bits[opts.table_index] = 1; + //table.val[opts.table_index++] = 0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + opts.bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) { + if (count[min] !== 0) { break; } + } + if (root < min) { + root = min; + } + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) { + return -1; + } /* over-subscribed */ + } + if (left > 0 && (type === CODES || max !== 1)) { + return -1; /* incomplete set */ + } + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) { + offs[len + 1] = offs[len] + count[len]; + } + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) { + if (lens[lens_index + sym] !== 0) { + work[offs[lens[lens_index + sym]]++] = sym; + } + } + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + // poor man optimization - use if-else instead of switch, + // to avoid deopts in old v8 + if (type === CODES) { + base = extra = work; /* dummy value--not used */ + end = 19; + } else if (type === LENS) { + base = lbase; + base_index -= 257; + extra = lext; + extra_index -= 257; + end = 256; + } else { /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize opts for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = table_index; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = -1; /* trigger new sub-table when len > root */ + used = 1 << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type === LENS && used > ENOUGH_LENS) || + (type === DISTS && used > ENOUGH_DISTS)) { + return 1; + } + + var i=0; + /* process all codes and make table entries */ + for (;;) { + i++; + /* create table entry */ + here_bits = len - drop; + if (work[sym] < end) { + here_op = 0; + here_val = work[sym]; + } + else if (work[sym] > end) { + here_op = extra[extra_index + work[sym]]; + here_val = base[base_index + work[sym]]; + } + else { + here_op = 32 + 64; /* end of block */ + here_val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1 << (len - drop); + fill = 1 << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; + } while (fill !== 0); + + /* backwards increment the len-bit code huff */ + incr = 1 << (len - 1); + while (huff & incr) { + incr >>= 1; + } + if (incr !== 0) { + huff &= incr - 1; + huff += incr; + } else { + huff = 0; + } + + /* go to next symbol, update count, len */ + sym++; + if (--count[len] === 0) { + if (len === max) { break; } + len = lens[lens_index + work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) !== low) { + /* if first time, transition to sub-tables */ + if (drop === 0) { + drop = root; + } + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = 1 << curr; + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) { break; } + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1 << curr; + if ((type === LENS && used > ENOUGH_LENS) || + (type === DISTS && used > ENOUGH_DISTS)) { + return 1; + } + + /* point entry in root table to sub-table */ + low = huff & mask; + /*table.op[low] = curr; + table.bits[low] = root; + table.val[low] = next - opts.table_index;*/ + table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff !== 0) { + //table.op[next + huff] = 64; /* invalid code marker */ + //table.bits[next + huff] = len - drop; + //table.val[next + huff] = 0; + table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; + } + + /* set return parameters */ + //opts.table_index += used; + opts.bits = root; + return 0; +}; + +},{"../utils/common":27}],37:[function(_dereq_,module,exports){ +'use strict'; + +module.exports = { + '2': 'need dictionary', /* Z_NEED_DICT 2 */ + '1': 'stream end', /* Z_STREAM_END 1 */ + '0': '', /* Z_OK 0 */ + '-1': 'file error', /* Z_ERRNO (-1) */ + '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ + '-3': 'data error', /* Z_DATA_ERROR (-3) */ + '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ + '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ + '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ +}; +},{}],38:[function(_dereq_,module,exports){ +'use strict'; + + +var utils = _dereq_('../utils/common'); + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +//var Z_FILTERED = 1; +//var Z_HUFFMAN_ONLY = 2; +//var Z_RLE = 3; +var Z_FIXED = 4; +//var Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ +var Z_BINARY = 0; +var Z_TEXT = 1; +//var Z_ASCII = 1; // = Z_TEXT +var Z_UNKNOWN = 2; + +/*============================================================================*/ + + +function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + +// From zutil.h + +var STORED_BLOCK = 0; +var STATIC_TREES = 1; +var DYN_TREES = 2; +/* The three kinds of block type */ + +var MIN_MATCH = 3; +var MAX_MATCH = 258; +/* The minimum and maximum match lengths */ + +// From deflate.h +/* =========================================================================== + * Internal compression state. + */ + +var LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ + +var LITERALS = 256; +/* number of literal bytes 0..255 */ + +var L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ + +var D_CODES = 30; +/* number of distance codes */ + +var BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ + +var HEAP_SIZE = 2*L_CODES + 1; +/* maximum heap size */ + +var MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +var Buf_size = 16; +/* size of bit buffer in bi_buf */ + + +/* =========================================================================== + * Constants + */ + +var MAX_BL_BITS = 7; +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +var END_BLOCK = 256; +/* end of block literal code */ + +var REP_3_6 = 16; +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +var REPZ_3_10 = 17; +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +var REPZ_11_138 = 18; +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +var extra_lbits = /* extra bits for each length code */ + [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]; + +var extra_dbits = /* extra bits for each distance code */ + [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]; + +var extra_blbits = /* extra bits for each bit length code */ + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]; + +var bl_order = + [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +// We pre-fill arrays with 0 to avoid uninitialized gaps + +var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ + +// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1 +var static_ltree = new Array((L_CODES+2) * 2); +zero(static_ltree); +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +var static_dtree = new Array(D_CODES * 2); +zero(static_dtree); +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +var _dist_code = new Array(DIST_CODE_LEN); +zero(_dist_code); +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +var _length_code = new Array(MAX_MATCH-MIN_MATCH+1); +zero(_length_code); +/* length code for each normalized match length (0 == MIN_MATCH) */ + +var base_length = new Array(LENGTH_CODES); +zero(base_length); +/* First normalized length for each code (0 = MIN_MATCH) */ + +var base_dist = new Array(D_CODES); +zero(base_dist); +/* First normalized distance for each code (0 = distance of 1) */ + + +var StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) { + + this.static_tree = static_tree; /* static tree or NULL */ + this.extra_bits = extra_bits; /* extra bits for each code or NULL */ + this.extra_base = extra_base; /* base index for extra_bits */ + this.elems = elems; /* max number of elements in the tree */ + this.max_length = max_length; /* max bit length for the codes */ + + // show if `static_tree` has data or dummy - needed for monomorphic objects + this.has_stree = static_tree && static_tree.length; +}; + + +var static_l_desc; +var static_d_desc; +var static_bl_desc; + + +var TreeDesc = function(dyn_tree, stat_desc) { + this.dyn_tree = dyn_tree; /* the dynamic tree */ + this.max_code = 0; /* largest code with non zero frequency */ + this.stat_desc = stat_desc; /* the corresponding static tree */ +}; + + + +function d_code(dist) { + return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; +} + + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +function put_short (s, w) { +// put_byte(s, (uch)((w) & 0xff)); +// put_byte(s, (uch)((ush)(w) >> 8)); + s.pending_buf[s.pending++] = (w) & 0xff; + s.pending_buf[s.pending++] = (w >>> 8) & 0xff; +} + + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +function send_bits(s, value, length) { + if (s.bi_valid > (Buf_size - length)) { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + put_short(s, s.bi_buf); + s.bi_buf = value >> (Buf_size - s.bi_valid); + s.bi_valid += length - Buf_size; + } else { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + s.bi_valid += length; + } +} + + +function send_code(s, c, tree) { + send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/); +} + + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +function bi_reverse(code, len) { + var res = 0; + do { + res |= code & 1; + code >>>= 1; + res <<= 1; + } while (--len > 0); + return res >>> 1; +} + + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +function bi_flush(s) { + if (s.bi_valid === 16) { + put_short(s, s.bi_buf); + s.bi_buf = 0; + s.bi_valid = 0; + + } else if (s.bi_valid >= 8) { + s.pending_buf[s.pending++] = s.bi_buf & 0xff; + s.bi_buf >>= 8; + s.bi_valid -= 8; + } +} + + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +function gen_bitlen(s, desc) +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + var tree = desc.dyn_tree; + var max_code = desc.max_code; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var extra = desc.stat_desc.extra_bits; + var base = desc.stat_desc.extra_base; + var max_length = desc.stat_desc.max_length; + var h; /* heap index */ + var n, m; /* iterate over the tree elements */ + var bits; /* bit length */ + var xbits; /* extra bits */ + var f; /* frequency */ + var overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) { + s.bl_count[bits] = 0; + } + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */ + + for (h = s.heap_max+1; h < HEAP_SIZE; h++) { + n = s.heap[h]; + bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; + if (bits > max_length) { + bits = max_length; + overflow++; + } + tree[n*2 + 1]/*.Len*/ = bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) { continue; } /* not a leaf node */ + + s.bl_count[bits]++; + xbits = 0; + if (n >= base) { + xbits = extra[n-base]; + } + f = tree[n * 2]/*.Freq*/; + s.opt_len += f * (bits + xbits); + if (has_stree) { + s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits); + } + } + if (overflow === 0) { return; } + + // Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s.bl_count[bits] === 0) { bits--; } + s.bl_count[bits]--; /* move one leaf down the tree */ + s.bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits !== 0; bits--) { + n = s.bl_count[bits]; + while (n !== 0) { + m = s.heap[--h]; + if (m > max_code) { continue; } + if (tree[m*2 + 1]/*.Len*/ !== bits) { + // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/; + tree[m*2 + 1]/*.Len*/ = bits; + } + n--; + } + } +} + + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +function gen_codes(tree, max_code, bl_count) +// ct_data *tree; /* the tree to decorate */ +// int max_code; /* largest code with non zero frequency */ +// ushf *bl_count; /* number of codes at each bit length */ +{ + var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */ + var code = 0; /* running code value */ + var bits; /* bit index */ + var n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + //Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) { + bl_count[bits] = 0; + } + + n = 0; + while (n <= 143) { + static_ltree[n*2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + while (n <= 255) { + static_ltree[n*2 + 1]/*.Len*/ = 9; + n++; + bl_count[9]++; + } + while (n <= 279) { + static_ltree[n*2 + 1]/*.Len*/ = 7; + n++; + bl_count[7]++; + } + while (n <= 287) { + static_ltree[n*2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes(static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n*2 + 1]/*.Len*/ = 5; + static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5); + } + + // Now data ready and we can init static trees + static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS); + static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); + static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); + + //static_init_done = true; +} + + +/* =========================================================================== + * Initialize a new block. + */ +function init_block(s) { + var n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; } + for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; } + for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; } + + s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1; + s.opt_len = s.static_len = 0; + s.last_lit = s.matches = 0; +} + + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +function bi_windup(s) +{ + if (s.bi_valid > 8) { + put_short(s, s.bi_buf); + } else if (s.bi_valid > 0) { + //put_byte(s, (Byte)s->bi_buf); + s.pending_buf[s.pending++] = s.bi_buf; + } + s.bi_buf = 0; + s.bi_valid = 0; +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +function copy_block(s, buf, len, header) +//DeflateState *s; +//charf *buf; /* the input data */ +//unsigned len; /* its length */ +//int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + + if (header) { + put_short(s, len); + put_short(s, ~len); + } +// while (len--) { +// put_byte(s, *buf++); +// } + utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); + s.pending += len; +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +function smaller(tree, n, m, depth) { + var _n2 = n*2; + var _m2 = m*2; + return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || + (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); +} + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +function pqdownheap(s, tree, k) +// deflate_state *s; +// ct_data *tree; /* the tree to restore */ +// int k; /* node to move down */ +{ + var v = s.heap[k]; + var j = k << 1; /* left son of k */ + while (j <= s.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s.heap_len && + smaller(tree, s.heap[j+1], s.heap[j], s.depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s.heap[j], s.depth)) { break; } + + /* Exchange v with the smallest son */ + s.heap[k] = s.heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s.heap[k] = v; +} + + +// inlined manually +// var SMALLEST = 1; + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +function compress_block(s, ltree, dtree) +// deflate_state *s; +// const ct_data *ltree; /* literal tree */ +// const ct_data *dtree; /* distance tree */ +{ + var dist; /* distance of matched string */ + var lc; /* match length or unmatched char (if dist == 0) */ + var lx = 0; /* running index in l_buf */ + var code; /* the code to send */ + var extra; /* number of extra bits to send */ + + if (s.last_lit !== 0) { + do { + dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]); + lc = s.pending_buf[s.l_buf + lx]; + lx++; + + if (dist === 0) { + send_code(s, lc, ltree); /* send a literal byte */ + //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra !== 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + //Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra !== 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + // "pendingBuf overflow"); + + } while (lx < s.last_lit); + } + + send_code(s, END_BLOCK, ltree); +} + + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +function build_tree(s, desc) +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + var tree = desc.dyn_tree; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var elems = desc.stat_desc.elems; + var n, m; /* iterate over heap elements */ + var max_code = -1; /* largest code with non zero frequency */ + var node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n * 2]/*.Freq*/ !== 0) { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; + + } else { + tree[n*2 + 1]/*.Len*/ = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s.heap_len < 2) { + node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); + tree[node * 2]/*.Freq*/ = 1; + s.depth[node] = 0; + s.opt_len--; + + if (has_stree) { + s.static_len -= stree[node*2 + 1]/*.Len*/; + } + /* node is 0 or 1 so it does not have extra bits */ + } + desc.max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + //pqremove(s, tree, n); /* n = node of least frequency */ + /*** pqremove ***/ + n = s.heap[1/*SMALLEST*/]; + s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; + pqdownheap(s, tree, 1/*SMALLEST*/); + /***/ + + m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ + + s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ + s.heap[--s.heap_max] = m; + + /* Create a new node father of n and m */ + tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; + s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; + tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node; + + /* and insert the new node in the heap */ + s.heap[1/*SMALLEST*/] = node++; + pqdownheap(s, tree, 1/*SMALLEST*/); + + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes(tree, max_code, s.bl_count); +} + + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +function scan_tree(s, tree, max_code) +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n+1)*2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + s.bl_tree[curlen * 2]/*.Freq*/ += count; + + } else if (curlen !== 0) { + + if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } + s.bl_tree[REP_3_6*2]/*.Freq*/++; + + } else if (count <= 10) { + s.bl_tree[REPZ_3_10*2]/*.Freq*/++; + + } else { + s.bl_tree[REPZ_11_138*2]/*.Freq*/++; + } + + count = 0; + prevlen = curlen; + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +} + + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +function send_tree(s, tree, max_code) +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n+1)*2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); + + } else if (curlen !== 0) { + if (curlen !== prevlen) { + send_code(s, curlen, s.bl_tree); + count--; + } + //Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s.bl_tree); + send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s.bl_tree); + send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s.bl_tree); + send_bits(s, count-11, 7); + } + + count = 0; + prevlen = curlen; + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +} + + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +function build_bl_tree(s) { + var max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, s.dyn_ltree, s.l_desc.max_code); + scan_tree(s, s.dyn_dtree, s.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, s.bl_desc); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) { + break; + } + } + /* Update opt_len to include the bit length tree and counts */ + s.opt_len += 3*(max_blindex+1) + 5+5+4; + //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + // s->opt_len, s->static_len)); + + return max_blindex; +} + + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +function send_all_trees(s, lcodes, dcodes, blcodes) +// deflate_state *s; +// int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + var rank; /* index in bl_order */ + + //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + // "too many codes"); + //Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3); + } + //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */ + //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */ + //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +function detect_data_type(s) { + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + var black_mask = 0xf3ffc07f; + var n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>>= 1) { + if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) { + return Z_BINARY; + } + } + + /* Check for textual ("white-listed") bytes. */ + if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || + s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + for (n = 32; n < LITERALS; n++) { + if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + } + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + + +var static_init_done = false; + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +function _tr_init(s) +{ + + if (!static_init_done) { + tr_static_init(); + static_init_done = true; + } + + s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); + s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); + s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); + + s.bi_buf = 0; + s.bi_valid = 0; + + /* Initialize the first block of the first file: */ + init_block(s); +} + + +/* =========================================================================== + * Send a stored block + */ +function _tr_stored_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3); /* send block type */ + copy_block(s, buf, stored_len, true); /* with header */ +} + + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +function _tr_align(s) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + bi_flush(s); +} + + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +function _tr_flush_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block, or NULL if too old */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + var opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + var max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s.level > 0) { + + /* Check if the file is binary or text */ + if (s.strm.data_type === Z_UNKNOWN) { + s.strm.data_type = detect_data_type(s); + } + + /* Construct the literal and distance trees */ + build_tree(s, s.l_desc); + // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + + build_tree(s, s.d_desc); + // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s.opt_len+3+7) >>> 3; + static_lenb = (s.static_len+3+7) >>> 3; + + // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + // s->last_lit)); + + if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } + + } else { + // Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + if ((stored_len+4 <= opt_lenb) && (buf !== -1)) { + /* 4: two words for the lengths */ + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + + } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { + + send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3); + compress_block(s, static_ltree, static_dtree); + + } else { + send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3); + send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1); + compress_block(s, s.dyn_ltree, s.dyn_dtree); + } + // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); + } + // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + // s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +function _tr_tally(s, dist, lc) +// deflate_state *s; +// unsigned dist; /* distance of matched string */ +// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + //var out_length, in_length, dcode; + + s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff; + s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; + + s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; + s.last_lit++; + + if (dist === 0) { + /* lc is the unmatched char */ + s.dyn_ltree[lc*2]/*.Freq*/++; + } else { + s.matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + //Assert((ush)dist < (ush)MAX_DIST(s) && + // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++; + s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; + } + +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility + +//#ifdef TRUNCATE_BLOCK +// /* Try to guess if it is profitable to stop the current block here */ +// if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { +// /* Compute an upper bound for the compressed length */ +// out_length = s.last_lit*8; +// in_length = s.strstart - s.block_start; +// +// for (dcode = 0; dcode < D_CODES; dcode++) { +// out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); +// } +// out_length >>>= 3; +// //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", +// // s->last_lit, in_length, out_length, +// // 100L - out_length*100L/in_length)); +// if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { +// return true; +// } +// } +//#endif + + return (s.last_lit === s.lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +exports._tr_init = _tr_init; +exports._tr_stored_block = _tr_stored_block; +exports._tr_flush_block = _tr_flush_block; +exports._tr_tally = _tr_tally; +exports._tr_align = _tr_align; +},{"../utils/common":27}],39:[function(_dereq_,module,exports){ +'use strict'; + + +function ZStream() { + /* next input byte */ + this.input = null; // JS specific, because we have no pointers + this.next_in = 0; + /* number of bytes available at input */ + this.avail_in = 0; + /* total number of input bytes read so far */ + this.total_in = 0; + /* next output byte should be put there */ + this.output = null; // JS specific, because we have no pointers + this.next_out = 0; + /* remaining free space at output */ + this.avail_out = 0; + /* total number of bytes output so far */ + this.total_out = 0; + /* last error message, NULL if no error */ + this.msg = ''/*Z_NULL*/; + /* not visible by applications */ + this.state = null; + /* best guess about the data type: binary or text */ + this.data_type = 2/*Z_UNKNOWN*/; + /* adler32 value of the uncompressed data */ + this.adler = 0; +} + +module.exports = ZStream; +},{}]},{},[9]) +(9) +}); \ No newline at end of file diff --git a/public/js/lib/jszip/dist/jszip.min.js b/public/js/lib/jszip/dist/jszip.min.js new file mode 100644 index 0000000..6bbf366 --- /dev/null +++ b/public/js/lib/jszip/dist/jszip.min.js @@ -0,0 +1,12 @@ +/* + +JSZip - A Javascript class for generating and reading zip files + + +(c) 2009-2014 Stuart Knightley +Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. + +JSZip uses the library pako released under the MIT license : +https://github.com/nodeca/pako/blob/master/LICENSE +*/ +!function(b){if("object"==typeof exports&&"undefined"!=typeof module){module.exports=b()}else{if("function"==typeof define&&define.amd){define([],b)}else{var a;"undefined"!=typeof window?a=window:"undefined"!=typeof global?a=global:"undefined"!=typeof self&&(a=self),a.JSZip=b()}}}(function(){var d,b,a;return(function c(f,k,h){function g(n,l){if(!k[n]){if(!f[n]){var i=typeof require=="function"&&require;if(!l&&i){return i(n,!0)}if(e){return e(n,!0)}throw new Error("Cannot find module '"+n+"'")}var m=k[n]={exports:{}};f[n][0].call(m.exports,function(o){var p=f[n][1][o];return g(p?p:o)},m,m.exports,c,f,k,h)}return k[n].exports}var e=typeof require=="function"&&require;for(var j=0;j>2;q=((t&3)<<4)|(r>>4);o=((r&15)<<2)|(p>>6);n=p&63;if(isNaN(r)){o=n=64}else{if(isNaN(p)){n=64}}j=j+f.charAt(s)+f.charAt(q)+f.charAt(o)+f.charAt(n)}return j};e.decode=function(m,l){var j="";var t,r,p;var s,q,o,n;var k=0;m=m.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(k>4);r=((q&15)<<4)|(o>>2);p=((o&3)<<6)|n;j=j+String.fromCharCode(t);if(o!=64){j=j+String.fromCharCode(r)}if(n!=64){j=j+String.fromCharCode(p)}}return j}},{}],2:[function(h,f,e){function g(){this.compressedSize=0;this.uncompressedSize=0;this.crc32=0;this.compressionMethod=null;this.compressedContent=null}g.prototype={getContent:function(){return null},getCompressedContent:function(){return null}};f.exports=g},{}],3:[function(g,f,e){e.STORE={magic:"\x00\x00",compress:function(h,i){return h},uncompress:function(h){return h},compressInputType:null,uncompressInputType:null};e.DEFLATE=g("./flate")},{"./flate":8}],4:[function(j,g,f){var e=j("./utils");var i=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918000,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117];g.exports=function h(n,p){if(typeof n==="undefined"||!n.length){return 0}var m=e.getTypeOf(n)!=="string";if(typeof(p)=="undefined"){p=0}var l=0;var r=0;var k=0;p=p^(-1);for(var o=0,q=n.length;o>>8)^l}return p^(-1)}},{"./utils":21}],5:[function(h,g,f){var e=h("./utils");function i(j){this.data=null;this.length=0;this.index=0}i.prototype={checkOffset:function(j){this.checkIndex(this.index+j)},checkIndex:function(j){if(this.length=this.index;k--){j=(j<<8)+this.byteAt(k)}this.index+=l;return j},readString:function(j){return e.transformTo("string",this.readData(j))},readData:function(j){},lastIndexOfSignature:function(j){},readDate:function(){var j=this.readInt(4);return new Date(((j>>25)&127)+1980,((j>>21)&15)-1,(j>>16)&31,(j>>11)&31,(j>>5)&63,(j&31)<<1)}};g.exports=i},{"./utils":21}],6:[function(g,f,e){e.base64=false;e.binary=false;e.dir=false;e.createFolders=false;e.date=null;e.compression=null;e.compressionOptions=null;e.comment=null;e.unixPermissions=null;e.dosPermissions=null},{}],7:[function(h,g,f){var e=h("./utils");f.string2binary=function(i){return e.string2binary(i)};f.string2Uint8Array=function(i){return e.transformTo("uint8array",i)};f.uint8Array2String=function(i){return e.transformTo("string",i)};f.string2Blob=function(j){var i=e.transformTo("arraybuffer",j);return e.arrayBuffer2Blob(i)};f.arrayBuffer2Blob=function(i){return e.arrayBuffer2Blob(i)};f.transformTo=function(j,i){return e.transformTo(j,i)};f.getTypeOf=function(i){return e.getTypeOf(i)};f.checkSupport=function(i){return e.checkSupport(i)};f.MAX_VALUE_16BITS=e.MAX_VALUE_16BITS;f.MAX_VALUE_32BITS=e.MAX_VALUE_32BITS;f.pretty=function(i){return e.pretty(i)};f.findCompression=function(i){return e.findCompression(i)};f.isRegExp=function(i){return e.isRegExp(i)}},{"./utils":21}],8:[function(i,g,e){var f=(typeof Uint8Array!=="undefined")&&(typeof Uint16Array!=="undefined")&&(typeof Uint32Array!=="undefined");var h=i("pako");e.uncompressInputType=f?"uint8array":"array";e.compressInputType=f?"uint8array":"array";e.magic="\x08\x00";e.compress=function(j,k){return h.deflateRaw(j,{level:k.level||-1})};e.uncompress=function(j){return h.inflateRaw(j)}},{pako:24}],9:[function(h,g,f){var e=h("./base64");function i(k,j){if(!(this instanceof i)){return new i(k,j)}this.files={};this.comment=null;this.root="";if(k){this.load(k,j)}this.clone=function(){var l=new i();for(var m in this){if(typeof this[m]!=="function"){l[m]=this[m]}}return l}}i.prototype=h("./object");i.prototype.load=h("./load");i.support=h("./support");i.defaults=h("./defaults");i.utils=h("./deprecatedPublicUtils");i.base64={encode:function(j){return e.encode(j)},decode:function(j){return e.decode(j)}};i.compressions=h("./compressions");g.exports=i},{"./base64":1,"./compressions":3,"./defaults":6,"./deprecatedPublicUtils":7,"./load":10,"./object":13,"./support":17}],10:[function(i,h,g){var f=i("./base64");var e=i("./zipEntries");h.exports=function(o,k){var n,m,l,j;k=k||{};if(k.base64){o=f.decode(o)}m=new e(o,k);n=m.files;for(l=0;l>>8}return L};var D=function(){var K={},L,J;for(L=0;L0)?K.substring(0,J):""};var q=function(J){if(J.slice(-1)!="/"){J+="/"}return J};var G=function(J,K){K=(typeof K!=="undefined")?K:false;J=q(J);if(!this.files[J]){A.call(this,J,null,{dir:true,createFolders:K})}return this.files[J]};var v=function(L,K,N){var J=new i(),M;if(L._data instanceof i){J.uncompressedSize=L._data.uncompressedSize;J.crc32=L._data.crc32;if(J.uncompressedSize===0||L.dir){K=B.STORE;J.compressedContent="";J.crc32=0}else{if(L._data.compressionMethod===K.magic){J.compressedContent=L._data.getCompressedContent()}else{M=L._data.getContent();J.compressedContent=K.compress(F.transformTo(K.compressInputType,M),N)}}}else{M=H(L);if(!M||M.length===0||L.dir){K=B.STORE;M=""}J.uncompressedSize=M.length;J.crc32=j(M);J.compressedContent=K.compress(F.transformTo(K.compressInputType,M),N)}J.compressedSize=J.compressedContent.length;J.compressionMethod=K.magic;return J};var k=function(K,L){var J=K;if(!K){J=L?16893:33204}return(J&65535)<<16};var y=function(J,K){return(J||0)&63};var x=function(ag,Z,L,O,ae){var ad=L.compressedContent,J=F.transformTo("string",h.utf8encode(Z.name)),K=Z.comment||"",N=F.transformTo("string",h.utf8encode(K)),ac=J.length!==Z.name.length,aa=N.length!==K.length,S=Z.options,M,W,Q="",ab="",P="",R,Y;if(Z._initialMetadata.dir!==Z.dir){R=Z.dir}else{R=S.dir}if(Z._initialMetadata.date!==Z.date){Y=Z.date}else{Y=S.date}var af=0;var X=0;if(R){af|=16}if(ae==="UNIX"){X=798;af|=k(Z.unixPermissions,R)}else{X=20;af|=y(Z.dosPermissions,R)}M=Y.getHours();M=M<<6;M=M|Y.getMinutes();M=M<<5;M=M|Y.getSeconds()/2;W=Y.getFullYear()-1980;W=W<<4;W=W|(Y.getMonth()+1);W=W<<5;W=W|Y.getDate();if(ac){ab=e(1,1)+e(j(J),4)+J;Q+="\x75\x70"+e(ab.length,2)+ab}if(aa){P=e(1,1)+e(this.crc32(N),4)+N;Q+="\x75\x63"+e(P.length,2)+P}var V="";V+="\x0A\x00";V+=(ac||aa)?"\x00\x08":"\x00\x00";V+=L.compressionMethod;V+=e(M,2);V+=e(W,2);V+=e(L.crc32,4);V+=e(L.compressedSize,4);V+=e(L.uncompressedSize,4);V+=e(J.length,2);V+=e(Q.length,2);var U=w.LOCAL_FILE_HEADER+V+J+Q;var T=w.CENTRAL_FILE_HEADER+e(X,2)+V+e(N.length,2)+"\x00\x00\x00\x00"+e(af,4)+e(O,4)+J+Q+N;return{fileRecord:U,dirRecord:T,compressedObject:L}};var z={load:function(K,J){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(O){var J=[],L,K,N,M;for(L in this.files){if(!this.files.hasOwnProperty(L)){continue}N=this.files[L];M=new r(N.name,N._data,D(N.options));K=L.slice(this.root.length,L.length);if(L.slice(0,this.root.length)===this.root&&O(K,M)){J.push(M)}}return J},file:function(J,L,M){if(arguments.length===1){if(F.isRegExp(J)){var K=J;return this.filter(function(N,O){return !O.dir&&K.test(N)})}else{return this.filter(function(N,O){return !O.dir&&N===J})[0]||null}}else{J=this.root+J;A.call(this,J,L,M)}return this},folder:function(J){if(!J){return this}if(F.isRegExp(J)){return this.filter(function(N,O){return O.dir&&J.test(N)})}var L=this.root+J;var M=G.call(this,L);var K=this.clone();K.root=M.name;return K},remove:function(K){K=this.root+K;var M=this.files[K];if(!M){if(K.slice(-1)!="/"){K+="/"}M=this.files[K]}if(M&&!M.dir){delete this.files[K]}else{var J=this.filter(function(N,O){return O.name.slice(0,K.length)===K});for(var L=0;L=0;--j){if(this.data[j]===n&&this.data[j+1]===m&&this.data[j+2]===l&&this.data[j+3]===k){return j}}return -1};e.prototype.readData=function(k){this.checkOffset(k);if(k===0){return new Uint8Array(0)}var j=this.data.subarray(this.index,this.index+k);this.index+=k;return j};g.exports=e},{"./dataReader":5}],19:[function(h,g,f){var e=h("./utils");var i=function(j){this.data=new Uint8Array(j);this.index=0};i.prototype={append:function(j){if(j.length!==0){j=e.transformTo("uint8array",j);this.data.set(j,this.index);this.index+=j.length}},finalize:function(){return this.data}};g.exports=i},{"./utils":21}],20:[function(e,f,k){var p=e("./utils");var q=e("./support");var n=e("./nodeBuffer");var j=new Array(256);for(var l=0;l<256;l++){j[l]=(l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1)}j[254]=j[254]=1;var r=function(y){var s,z,u,v,t,x=y.length,w=0;for(v=0;v>>6);s[t++]=128|(z&63)}else{if(z<65536){s[t++]=224|(z>>>12);s[t++]=128|(z>>>6&63);s[t++]=128|(z&63)}else{s[t++]=240|(z>>>18);s[t++]=128|(z>>>12&63);s[t++]=128|(z>>>6&63);s[t++]=128|(z&63)}}}}return s};var m=function(s,i){var t;i=i||s.length;if(i>s.length){i=s.length}t=i-1;while(t>=0&&(s[t]&192)===128){t--}if(t<0){return i}if(t===0){return i}return(t+j[s[t]]>i)?t:i};var h=function(w){var y,x,v,z,u;var t=w.length;var s=new Array(t*2);for(v=0,x=0;x4){s[v++]=65533;x+=u-1;continue}z&=u===2?31:u===3?15:7;while(u>1&&x1){s[v++]=65533;continue}if(z<65536){s[v++]=z}else{z-=65536;s[v++]=55296|((z>>10)&1023);s[v++]=56320|(z&1023)}}if(s.length!==v){if(s.subarray){s=s.subarray(0,v)}else{s.length=v}}return p.applyFromCharCode(s)};k.utf8encode=function o(i){if(q.nodebuffer){return n(i,"utf-8")}return r(i)};k.utf8decode=function g(v){if(q.nodebuffer){return p.transformTo("nodebuffer",v).toString("utf-8")}v=p.transformTo(q.uint8array?"uint8array":"array",v);var s=[],t=0,i=v.length,u=65536;while(t1){try{if(w==="array"||w==="nodebuffer"){y.push(String.fromCharCode.apply(null,t.slice(q,Math.min(q+x,s))))}else{y.push(String.fromCharCode.apply(null,t.subarray(q,Math.min(q+x,s))))}q+=x}catch(u){x=Math.floor(x/2)}}return y.join("")}h.applyFromCharCode=n;function i(q,r){for(var p=0;p1){throw new Error("Multi-volumes zip are not supported")}},readLocalFiles:function(){var r,q;for(r=0;r>8;this.dir=this.externalFileAttributes&16?true:false;if(o===j){this.dosPermissions=this.externalFileAttributes&63}if(o===g){this.unixPermissions=(this.externalFileAttributes>>16)&65535}if(!this.dir&&this.fileName.slice(-1)==="/"){this.dir=true}},parseZIP64ExtraField:function(o){if(!this.extraFields[1]){return}var p=new h(this.extraFields[1].value);if(this.uncompressedSize===m.MAX_VALUE_32BITS){this.uncompressedSize=p.readInt(8)}if(this.compressedSize===m.MAX_VALUE_32BITS){this.compressedSize=p.readInt(8)}if(this.localHeaderOffset===m.MAX_VALUE_32BITS){this.localHeaderOffset=p.readInt(8)}if(this.diskNumberStart===m.MAX_VALUE_32BITS){this.diskNumberStart=p.readInt(4)}},readExtraFields:function(p){var s=p.index,q,r,o;this.extraFields=this.extraFields||{};while(p.index0)){z.windowBits=-z.windowBits}else{if(z.gzip&&(z.windowBits>0)&&(z.windowBits<16)){z.windowBits+=16}}this.err=0;this.msg="";this.ended=false;this.chunks=[];this.strm=new s();this.strm.avail_out=0;var x=p.deflateInit2(this.strm,z.level,z.method,z.windowBits,z.memLevel,z.strategy);if(x!==k){throw new Error(l[x])}if(z.header){p.deflateSetHeader(this.strm,z.header)}};v.prototype.push=function(A,B){var y=this.strm;var C=this.options.chunkSize;var x,z;if(this.ended){return false}z=(B===~~B)?B:((B===true)?w:q);if(typeof A==="string"){y.input=j.string2buf(A)}else{y.input=A}y.next_in=0;y.avail_in=y.input.length;do{if(y.avail_out===0){y.output=new t.Buf8(C);y.next_out=0;y.avail_out=C}x=p.deflate(y,z);if(x!==n&&x!==k){this.onEnd(x);this.ended=true;return false}if(y.avail_out===0||(y.avail_in===0&&z===w)){if(this.options.to==="string"){this.onData(j.buf2binstring(t.shrinkBuf(y.output,y.next_out)))}else{this.onData(t.shrinkBuf(y.output,y.next_out))}}}while((y.avail_in>0||y.avail_out===0)&&x!==n);if(z===w){x=p.deflateEnd(this.strm);this.onEnd(x);this.ended=true;return x===k}return true};v.prototype.onData=function(x){this.chunks.push(x)};v.prototype.onEnd=function(x){if(x===k){if(this.options.to==="string"){this.result=this.chunks.join("")}else{this.result=t.flattenChunks(this.chunks)}}this.chunks=[];this.err=x;this.msg=this.strm.msg};function m(x,y){var z=new v(y);z.push(x,true);if(z.err){throw z.msg}return z.result}function r(x,y){y=y||{};y.raw=true;return m(x,y)}function h(x,y){y=y||{};y.gzip=true;return m(x,y)}u.Deflate=v;u.deflate=m;u.deflateRaw=r;u.gzip=h},{"./utils/common":27,"./utils/strings":28,"./zlib/deflate.js":32,"./zlib/messages":37,"./zlib/zstream":39}],26:[function(g,h,l){var e=g("./zlib/inflate.js");var o=g("./utils/common");var p=g("./utils/strings");var n=g("./zlib/constants");var j=g("./zlib/messages");var k=g("./zlib/zstream");var f=g("./zlib/gzheader");var m=function(s){this.options=o.assign({chunkSize:16384,windowBits:0,to:""},s||{});var t=this.options;if(t.raw&&(t.windowBits>=0)&&(t.windowBits<16)){t.windowBits=-t.windowBits;if(t.windowBits===0){t.windowBits=-15}}if((t.windowBits>=0)&&(t.windowBits<16)&&!(s&&s.windowBits)){t.windowBits+=32}if((t.windowBits>15)&&(t.windowBits<48)){if((t.windowBits&15)===0){t.windowBits|=15}}this.err=0;this.msg="";this.ended=false;this.chunks=[];this.strm=new k();this.strm.avail_out=0;var r=e.inflateInit2(this.strm,t.windowBits);if(r!==n.Z_OK){throw new Error(j[r])}this.header=new f();e.inflateGetHeader(this.strm,this.header)};m.prototype.push=function(w,x){var z=this.strm;var u=this.options.chunkSize;var v,t;var s,y,r;if(this.ended){return false}t=(x===~~x)?x:((x===true)?n.Z_FINISH:n.Z_NO_FLUSH);if(typeof w==="string"){z.input=p.binstring2buf(w)}else{z.input=w}z.next_in=0;z.avail_in=z.input.length;do{if(z.avail_out===0){z.output=new o.Buf8(u);z.next_out=0;z.avail_out=u}v=e.inflate(z,n.Z_NO_FLUSH);if(v!==n.Z_STREAM_END&&v!==n.Z_OK){this.onEnd(v);this.ended=true;return false}if(z.next_out){if(z.avail_out===0||v===n.Z_STREAM_END||(z.avail_in===0&&t===n.Z_FINISH)){if(this.options.to==="string"){s=p.utf8border(z.output,z.next_out);y=z.next_out-s;r=p.buf2string(z.output,s);z.next_out=y;z.avail_out=u-y;if(y){o.arraySet(z.output,z.output,s,y,0)}this.onData(r)}else{this.onData(o.shrinkBuf(z.output,z.next_out))}}}}while((z.avail_in>0)&&v!==n.Z_STREAM_END);if(v===n.Z_STREAM_END){t=n.Z_FINISH}if(t===n.Z_FINISH){v=e.inflateEnd(this.strm);this.onEnd(v);this.ended=true;return v===n.Z_OK}return true};m.prototype.onData=function(r){this.chunks.push(r)};m.prototype.onEnd=function(r){if(r===n.Z_OK){if(this.options.to==="string"){this.result=this.chunks.join("")}else{this.result=o.flattenChunks(this.chunks)}}this.chunks=[];this.err=r;this.msg=this.strm.msg};function q(r,s){var t=new m(s);t.push(r,true);if(t.err){throw t.msg}return t.result}function i(r,s){s=s||{};s.raw=true;return q(r,s)}l.Inflate=m;l.inflate=q;l.inflateRaw=i;l.ungzip=q},{"./utils/common":27,"./utils/strings":28,"./zlib/constants":30,"./zlib/gzheader":33,"./zlib/inflate.js":35,"./zlib/messages":37,"./zlib/zstream":39}],27:[function(g,f,e){var j=(typeof Uint8Array!=="undefined")&&(typeof Uint16Array!=="undefined")&&(typeof Int32Array!=="undefined");e.assign=function(n){var k=Array.prototype.slice.call(arguments,1);while(k.length){var l=k.shift();if(!l){continue}if(typeof(l)!=="object"){throw new TypeError(l+"must be non-object")}for(var m in l){if(l.hasOwnProperty(m)){n[m]=l[m]}}}return n};e.shrinkBuf=function(k,l){if(k.length===l){return k}if(k.subarray){return k.subarray(0,l)}k.length=l;return k};var h={arraySet:function(l,n,p,k,o){if(n.subarray&&l.subarray){l.set(n.subarray(p,p+k),o);return}for(var m=0;m=252?6:j>=248?5:j>=240?4:j>=224?3:j>=192?2:1)}g[254]=g[254]=1;h.string2buf=function(v){var p,w,r,s,q,u=v.length,t=0;for(s=0;s>>6);p[q++]=128|(w&63)}else{if(w<65536){p[q++]=224|(w>>>12);p[q++]=128|(w>>>6&63);p[q++]=128|(w&63)}else{p[q++]=240|(w>>>18);p[q++]=128|(w>>>12&63);p[q++]=128|(w>>>6&63);p[q++]=128|(w&63)}}}}return p};function l(r,q){if(q<65537){if((r.subarray&&k)||(!r.subarray&&m)){return String.fromCharCode.apply(null,o.shrinkBuf(r,q))}}var p="";for(var s=0;s4){p[t++]=65533;v+=s-1;continue}w&=s===2?31:s===3?15:7;while(s>1&&v1){p[t++]=65533;continue}if(w<65536){p[t++]=w}else{w-=65536;p[t++]=55296|((w>>10)&1023);p[t++]=56320|(w&1023)}}return l(p,t)};h.utf8border=function(p,i){var q;i=i||p.length;if(i>p.length){i=p.length}q=i-1;while(q>=0&&(p[q]&192)===128){q--}if(q<0){return i}if(q===0){return i}return(q+g[p[q]]>i)?q:i}},{"./common":27}],29:[function(h,f,e){function g(l,k,i,p){var m=(l&65535)|0,j=((l>>>16)&65535)|0,o=0;while(i!==0){o=i>2000?2000:i;i-=o;do{m=(m+k[p++])|0;j=(j+m)|0}while(--o);m%=65521;j%=65521}return(m|(j<<16))|0}f.exports=g},{}],30:[function(g,f,e){f.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],31:[function(j,g,f){function h(){var p,m=[];for(var o=0;o<256;o++){p=o;for(var l=0;l<8;l++){p=((p&1)?(3988292384^(p>>>1)):(p>>>1))}m[o]=p}return m}var e=h();function i(p,m,k,q){var o=e,l=q+k;p=p^(-1);for(var n=q;n>>8)^o[(p^m[n])&255]}return(p^(-1))}g.exports=i},{}],32:[function(U,aC,L){var S=U("../utils/common");var aA=U("./trees");var K=U("./adler32");var aa=U("./crc32");var F=U("./messages");var N=0;var Z=1;var at=3;var n=4;var T=5;var t=0;var x=1;var ap=-2;var w=-3;var i=-5;var k=-1;var O=1;var D=2;var z=3;var u=4;var au=0;var J=2;var Y=8;var av=9;var Q=15;var p=8;var al=29;var az=256;var aB=az+1+al;var C=30;var ag=19;var an=2*aB+1;var R=15;var H=3;var aq=258;var g=(aq+H+1);var l=32;var W=42;var r=69;var ab=73;var am=91;var s=103;var aE=113;var B=666;var ao=1;var v=2;var V=3;var h=4;var ar=3;function ah(aF,aG){aF.msg=F[aG];return aG}function P(aF){return((aF)<<1)-((aF)>4?9:0)}function ay(aG){var aF=aG.length;while(--aF>=0){aG[aF]=0}}function j(aG){var aH=aG.state;var aF=aH.pending;if(aF>aG.avail_out){aF=aG.avail_out}if(aF===0){return}S.arraySet(aG.output,aH.pending_buf,aH.pending_out,aF,aG.next_out);aG.next_out+=aF;aH.pending_out+=aF;aG.total_out+=aF;aG.avail_out-=aF;aH.pending-=aF;if(aH.pending===0){aH.pending_out=0}}function m(aF,aG){aA._tr_flush_block(aF,(aF.block_start>=0?aF.block_start:-1),aF.strstart-aF.block_start,aG);aF.block_start=aF.strstart;j(aF.strm)}function f(aG,aF){aG.pending_buf[aG.pending++]=aF}function A(aG,aF){aG.pending_buf[aG.pending++]=(aF>>>8)&255;aG.pending_buf[aG.pending++]=aF&255}function E(aG,aH,aJ,aI){var aF=aG.avail_in;if(aF>aI){aF=aI}if(aF===0){return 0}aG.avail_in-=aF;S.arraySet(aH,aG.input,aG.next_in,aF,aJ);if(aG.state.wrap===1){aG.adler=K(aG.adler,aH,aF,aJ)}else{if(aG.state.wrap===2){aG.adler=aa(aG.adler,aH,aF,aJ)}}aG.next_in+=aF;aG.total_in+=aF;return aF}function ax(aS,aJ){var aM=aS.max_chain_length;var aT=aS.strstart;var aK;var aL;var aF=aS.prev_length;var aG=aS.nice_match;var aI=(aS.strstart>(aS.w_size-g))?aS.strstart-(aS.w_size-g):0;var aQ=aS.window;var aN=aS.w_mask;var aH=aS.prev;var aP=aS.strstart+aq;var aR=aQ[aT+aF-1];var aO=aQ[aT+aF];if(aS.prev_length>=aS.good_match){aM>>=2}if(aG>aS.lookahead){aG=aS.lookahead}do{aK=aJ;if(aQ[aK+aF]!==aO||aQ[aK+aF-1]!==aR||aQ[aK]!==aQ[aT]||aQ[++aK]!==aQ[aT+1]){continue}aT+=2;aK++;do{}while(aQ[++aT]===aQ[++aK]&&aQ[++aT]===aQ[++aK]&&aQ[++aT]===aQ[++aK]&&aQ[++aT]===aQ[++aK]&&aQ[++aT]===aQ[++aK]&&aQ[++aT]===aQ[++aK]&&aQ[++aT]===aQ[++aK]&&aQ[++aT]===aQ[++aK]&&aTaF){aS.match_start=aJ;aF=aL;if(aL>=aG){break}aR=aQ[aT+aF-1];aO=aQ[aT+aF]}}while((aJ=aH[aJ&aN])>aI&&--aM!==0);if(aF<=aS.lookahead){return aF}return aS.lookahead}function ak(aH){var aL=aH.w_size;var aI,aK,aF,aG,aJ;do{aG=aH.window_size-aH.lookahead-aH.strstart;if(aH.strstart>=aL+(aL-g)){S.arraySet(aH.window,aH.window,aL,aL,0);aH.match_start-=aL;aH.strstart-=aL;aH.block_start-=aL;aK=aH.hash_size;aI=aK;do{aF=aH.head[--aI];aH.head[aI]=(aF>=aL?aF-aL:0)}while(--aK);aK=aL;aI=aK;do{aF=aH.prev[--aI];aH.prev[aI]=(aF>=aL?aF-aL:0)}while(--aK);aG+=aL}if(aH.strm.avail_in===0){break}aK=E(aH.strm,aH.window,aH.strstart+aH.lookahead,aG);aH.lookahead+=aK;if(aH.lookahead+aH.insert>=H){aJ=aH.strstart-aH.insert;aH.ins_h=aH.window[aJ];aH.ins_h=((aH.ins_h<aI.pending_buf_size-5){aH=aI.pending_buf_size-5}for(;;){if(aI.lookahead<=1){ak(aI);if(aI.lookahead===0&&aF===N){return ao}if(aI.lookahead===0){break}}aI.strstart+=aI.lookahead;aI.lookahead=0;var aG=aI.block_start+aH;if(aI.strstart===0||aI.strstart>=aG){aI.lookahead=aI.strstart-aG;aI.strstart=aG;m(aI,false);if(aI.strm.avail_out===0){return ao}}if(aI.strstart-aI.block_start>=(aI.w_size-g)){m(aI,false);if(aI.strm.avail_out===0){return ao}}}aI.insert=0;if(aF===n){m(aI,true);if(aI.strm.avail_out===0){return V}return h}if(aI.strstart>aI.block_start){m(aI,false);if(aI.strm.avail_out===0){return ao}}return ao}function o(aH,aF){var aI;var aG;for(;;){if(aH.lookahead=H){aH.ins_h=((aH.ins_h<=H){aG=aA._tr_tally(aH,aH.strstart-aH.match_start,aH.match_length-H);aH.lookahead-=aH.match_length;if(aH.match_length<=aH.max_lazy_match&&aH.lookahead>=H){aH.match_length--;do{aH.strstart++;aH.ins_h=((aH.ins_h<=H){aI.ins_h=((aI.ins_h<4096))){aI.match_length=H-1}}if(aI.prev_length>=H&&aI.match_length<=aI.prev_length){aF=aI.strstart+aI.lookahead-H;aH=aA._tr_tally(aI,aI.strstart-1-aI.prev_match,aI.prev_length-H);aI.lookahead-=aI.prev_length-1;aI.prev_length-=2;do{if(++aI.strstart<=aF){aI.ins_h=((aI.ins_h<=H&&aJ.strstart>0){aH=aJ.strstart-1;aK=aL[aH];if(aK===aL[++aH]&&aK===aL[++aH]&&aK===aL[++aH]){aF=aJ.strstart+aq;do{}while(aK===aL[++aH]&&aK===aL[++aH]&&aK===aL[++aH]&&aK===aL[++aH]&&aK===aL[++aH]&&aK===aL[++aH]&&aK===aL[++aH]&&aK===aL[++aH]&&aHaJ.lookahead){aJ.match_length=aJ.lookahead}}}if(aJ.match_length>=H){aI=aA._tr_tally(aJ,1,aJ.match_length-H);aJ.lookahead-=aJ.match_length;aJ.strstart+=aJ.match_length;aJ.match_length=0}else{aI=aA._tr_tally(aJ,0,aJ.window[aJ.strstart]);aJ.lookahead--;aJ.strstart++}if(aI){m(aJ,false);if(aJ.strm.avail_out===0){return ao}}}aJ.insert=0;if(aG===n){m(aJ,true);if(aJ.strm.avail_out===0){return V}return h}if(aJ.last_lit){m(aJ,false);if(aJ.strm.avail_out===0){return ao}}return v}function af(aH,aF){var aG;for(;;){if(aH.lookahead===0){ak(aH);if(aH.lookahead===0){if(aF===N){return ao}break}}aH.match_length=0;aG=aA._tr_tally(aH,0,aH.window[aH.strstart]);aH.lookahead--;aH.strstart++;if(aG){m(aH,false);if(aH.strm.avail_out===0){return ao}}}aH.insert=0;if(aF===n){m(aH,true);if(aH.strm.avail_out===0){return V}return h}if(aH.last_lit){m(aH,false);if(aH.strm.avail_out===0){return ao}}return v}var ad=function(aF,aJ,aG,aI,aH){this.good_length=aF;this.max_lazy=aJ;this.nice_length=aG;this.max_chain=aI;this.func=aH};var ac;ac=[new ad(0,0,0,0,M),new ad(4,4,8,4,o),new ad(4,5,16,8,o),new ad(4,6,32,32,o),new ad(4,4,16,16,ai),new ad(8,16,32,32,ai),new ad(8,16,128,128,ai),new ad(8,32,128,256,ai),new ad(32,128,258,1024,ai),new ad(32,258,258,4096,ai)];function I(aF){aF.window_size=2*aF.w_size;ay(aF.head);aF.max_lazy_match=ac[aF.level].max_lazy;aF.good_match=ac[aF.level].good_length;aF.nice_match=ac[aF.level].nice_length;aF.max_chain_length=ac[aF.level].max_chain;aF.strstart=0;aF.block_start=0;aF.lookahead=0;aF.insert=0;aF.match_length=aF.prev_length=H-1;aF.match_available=0;aF.ins_h=0}function e(){this.strm=null;this.status=0;this.pending_buf=null;this.pending_buf_size=0;this.pending_out=0;this.pending=0;this.wrap=0;this.gzhead=null;this.gzindex=0;this.method=Y;this.last_flush=-1;this.w_size=0;this.w_bits=0;this.w_mask=0;this.window=null;this.window_size=0;this.prev=null;this.head=null;this.ins_h=0;this.hash_size=0;this.hash_bits=0;this.hash_mask=0;this.hash_shift=0;this.block_start=0;this.match_length=0;this.prev_match=0;this.match_available=0;this.strstart=0;this.match_start=0;this.lookahead=0;this.prev_length=0;this.max_chain_length=0;this.max_lazy_match=0;this.level=0;this.strategy=0;this.good_match=0;this.nice_match=0;this.dyn_ltree=new S.Buf16(an*2);this.dyn_dtree=new S.Buf16((2*C+1)*2);this.bl_tree=new S.Buf16((2*ag+1)*2);ay(this.dyn_ltree);ay(this.dyn_dtree);ay(this.bl_tree);this.l_desc=null;this.d_desc=null;this.bl_desc=null;this.bl_count=new S.Buf16(R+1);this.heap=new S.Buf16(2*aB+1);ay(this.heap);this.heap_len=0;this.heap_max=0;this.depth=new S.Buf16(2*aB+1);ay(this.depth);this.l_buf=0;this.lit_bufsize=0;this.last_lit=0;this.d_buf=0;this.opt_len=0;this.static_len=0;this.matches=0;this.insert=0;this.bi_buf=0;this.bi_valid=0}function aj(aF){var aG;if(!aF||!aF.state){return ah(aF,ap)}aF.total_in=aF.total_out=0;aF.data_type=J;aG=aF.state;aG.pending=0;aG.pending_out=0;if(aG.wrap<0){aG.wrap=-aG.wrap}aG.status=(aG.wrap?W:aE);aF.adler=(aG.wrap===2)?0:1;aG.last_flush=N;aA._tr_init(aG);return t}function y(aF){var aG=aj(aF);if(aG===t){I(aF.state)}return aG}function aD(aF,aG){if(!aF||!aF.state){return ap}if(aF.state.wrap!==2){return ap}aF.state.gzhead=aG;return t}function G(aF,aM,aL,aI,aK,aJ){if(!aF){return ap}var aH=1;if(aM===k){aM=6}if(aI<0){aH=0;aI=-aI}else{if(aI>15){aH=2;aI-=16}}if(aK<1||aK>av||aL!==Y||aI<8||aI>15||aM<0||aM>9||aJ<0||aJ>u){return ah(aF,ap)}if(aI===8){aI=9}var aG=new e();aF.state=aG;aG.strm=aF;aG.wrap=aH;aG.gzhead=null;aG.w_bits=aI;aG.w_size=1<>1;aG.l_buf=(1+2)*aG.lit_bufsize;aG.level=aM;aG.strategy=aJ;aG.method=aL;return y(aF)}function X(aF,aG){return G(aF,aG,Y,Q,p,au)}function q(aK,aL){var aJ,aN;var aI,aG;if(!aK||!aK.state||aL>T||aL<0){return aK?ah(aK,ap):ap}aN=aK.state;if(!aK.output||(!aK.input&&aK.avail_in!==0)||(aN.status===B&&aL!==n)){return ah(aK,(aK.avail_out===0)?i:ap)}aN.strm=aK;aJ=aN.last_flush;aN.last_flush=aL;if(aN.status===W){if(aN.wrap===2){aK.adler=0;f(aN,31);f(aN,139);f(aN,8);if(!aN.gzhead){f(aN,0);f(aN,0);f(aN,0);f(aN,0);f(aN,0);f(aN,aN.level===9?2:(aN.strategy>=D||aN.level<2?4:0));f(aN,ar);aN.status=aE}else{f(aN,(aN.gzhead.text?1:0)+(aN.gzhead.hcrc?2:0)+(!aN.gzhead.extra?0:4)+(!aN.gzhead.name?0:8)+(!aN.gzhead.comment?0:16));f(aN,aN.gzhead.time&255);f(aN,(aN.gzhead.time>>8)&255);f(aN,(aN.gzhead.time>>16)&255);f(aN,(aN.gzhead.time>>24)&255);f(aN,aN.level===9?2:(aN.strategy>=D||aN.level<2?4:0));f(aN,aN.gzhead.os&255);if(aN.gzhead.extra&&aN.gzhead.extra.length){f(aN,aN.gzhead.extra.length&255);f(aN,(aN.gzhead.extra.length>>8)&255)}if(aN.gzhead.hcrc){aK.adler=aa(aK.adler,aN.pending_buf,aN.pending,0)}aN.gzindex=0;aN.status=r}}else{var aH=(Y+((aN.w_bits-8)<<4))<<8;var aM=-1;if(aN.strategy>=D||aN.level<2){aM=0}else{if(aN.level<6){aM=1}else{if(aN.level===6){aM=2}else{aM=3}}}aH|=(aM<<6);if(aN.strstart!==0){aH|=l}aH+=31-(aH%31);aN.status=aE;A(aN,aH);if(aN.strstart!==0){A(aN,aK.adler>>>16);A(aN,aK.adler&65535)}aK.adler=1}}if(aN.status===r){if(aN.gzhead.extra){aI=aN.pending;while(aN.gzindex<(aN.gzhead.extra.length&65535)){if(aN.pending===aN.pending_buf_size){if(aN.gzhead.hcrc&&aN.pending>aI){aK.adler=aa(aK.adler,aN.pending_buf,aN.pending-aI,aI)}j(aK);aI=aN.pending;if(aN.pending===aN.pending_buf_size){break}}f(aN,aN.gzhead.extra[aN.gzindex]&255);aN.gzindex++}if(aN.gzhead.hcrc&&aN.pending>aI){aK.adler=aa(aK.adler,aN.pending_buf,aN.pending-aI,aI)}if(aN.gzindex===aN.gzhead.extra.length){aN.gzindex=0;aN.status=ab}}else{aN.status=ab}}if(aN.status===ab){if(aN.gzhead.name){aI=aN.pending;do{if(aN.pending===aN.pending_buf_size){if(aN.gzhead.hcrc&&aN.pending>aI){aK.adler=aa(aK.adler,aN.pending_buf,aN.pending-aI,aI)}j(aK);aI=aN.pending;if(aN.pending===aN.pending_buf_size){aG=1;break}}if(aN.gzindexaI){aK.adler=aa(aK.adler,aN.pending_buf,aN.pending-aI,aI)}if(aG===0){aN.gzindex=0;aN.status=am}}else{aN.status=am}}if(aN.status===am){if(aN.gzhead.comment){aI=aN.pending;do{if(aN.pending===aN.pending_buf_size){if(aN.gzhead.hcrc&&aN.pending>aI){aK.adler=aa(aK.adler,aN.pending_buf,aN.pending-aI,aI)}j(aK);aI=aN.pending;if(aN.pending===aN.pending_buf_size){aG=1;break}}if(aN.gzindexaI){aK.adler=aa(aK.adler,aN.pending_buf,aN.pending-aI,aI)}if(aG===0){aN.status=s}}else{aN.status=s}}if(aN.status===s){if(aN.gzhead.hcrc){if(aN.pending+2>aN.pending_buf_size){j(aK)}if(aN.pending+2<=aN.pending_buf_size){f(aN,aK.adler&255);f(aN,(aK.adler>>8)&255);aK.adler=0;aN.status=aE}}else{aN.status=aE}}if(aN.pending!==0){j(aK);if(aK.avail_out===0){aN.last_flush=-1;return t}}else{if(aK.avail_in===0&&P(aL)<=P(aJ)&&aL!==n){return ah(aK,i)}}if(aN.status===B&&aK.avail_in!==0){return ah(aK,i)}if(aK.avail_in!==0||aN.lookahead!==0||(aL!==N&&aN.status!==B)){var aF=(aN.strategy===D)?af(aN,aL):(aN.strategy===z?ae(aN,aL):ac[aN.level].func(aN,aL));if(aF===V||aF===h){aN.status=B}if(aF===ao||aF===V){if(aK.avail_out===0){aN.last_flush=-1}return t}if(aF===v){if(aL===Z){aA._tr_align(aN)}else{if(aL!==T){aA._tr_stored_block(aN,0,0,false);if(aL===at){ay(aN.head);if(aN.lookahead===0){aN.strstart=0;aN.block_start=0;aN.insert=0}}}}j(aK);if(aK.avail_out===0){aN.last_flush=-1;return t}}}if(aL!==n){return t}if(aN.wrap<=0){return x}if(aN.wrap===2){f(aN,aK.adler&255);f(aN,(aK.adler>>8)&255);f(aN,(aK.adler>>16)&255);f(aN,(aK.adler>>24)&255);f(aN,aK.total_in&255);f(aN,(aK.total_in>>8)&255);f(aN,(aK.total_in>>16)&255);f(aN,(aK.total_in>>24)&255)}else{A(aN,aK.adler>>>16);A(aN,aK.adler&65535)}j(aK);if(aN.wrap>0){aN.wrap=-aN.wrap}return aN.pending!==0?t:x}function aw(aG){var aF;if(!aG||!aG.state){return ap}aF=aG.state.status;if(aF!==W&&aF!==r&&aF!==ab&&aF!==am&&aF!==s&&aF!==aE&&aF!==B){return ah(aG,ap)}aG.state=null;return aF===aE?ah(aG,w):t}L.deflateInit=X;L.deflateInit2=G;L.deflateReset=y;L.deflateResetKeep=aj;L.deflateSetHeader=aD;L.deflate=q;L.deflateEnd=aw;L.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":27,"./adler32":29,"./crc32":31,"./messages":37,"./trees":38}],33:[function(g,f,e){function h(){this.text=0;this.time=0;this.xflags=0;this.os=0;this.extra=null;this.extra_len=0;this.name="";this.comment="";this.hcrc=0;this.done=false}f.exports=h},{}],34:[function(i,g,f){var h=30;var j=12;g.exports=function e(I,p){var q;var K;var w;var J;var v;var o;var C;var l;var A;var m;var r;var z;var F;var D;var G;var u;var x;var k;var t;var H;var B;var E;var n;var y,s;q=I.state;K=I.next_in;y=I.input;w=K+(I.avail_in-5);J=I.next_out;s=I.output;v=J-(p-I.avail_out);o=J+(I.avail_out-257);C=q.dmax;l=q.wsize;A=q.whave;m=q.wnext;r=q.window;z=q.hold;F=q.bits;D=q.lencode;G=q.distcode;u=(1<>>24;z>>>=t;F-=t;t=(k>>>16)&255;if(t===0){s[J++]=k&65535}else{if(t&16){H=k&65535;t&=15;if(t){if(F>>=t;F-=t}if(F<15){z+=y[K++]<>>24;z>>>=t;F-=t;t=(k>>>16)&255;if(t&16){B=k&65535;t&=15;if(FC){I.msg="invalid distance too far back";q.mode=h;break top}z>>>=t;F-=t;t=J-v;if(B>t){t=B-t;if(t>A){if(q.sane){I.msg="invalid distance too far back";q.mode=h;break top}}E=0;n=r;if(m===0){E+=l-t;if(t2){s[J++]=n[E++];s[J++]=n[E++];s[J++]=n[E++];H-=3}if(H){s[J++]=n[E++];if(H>1){s[J++]=n[E++]}}}else{E=J-B;do{s[J++]=s[E++];s[J++]=s[E++];s[J++]=s[E++];H-=3}while(H>2);if(H){s[J++]=s[E++];if(H>1){s[J++]=s[E++]}}}}else{if((t&64)===0){k=G[(k&65535)+(z&((1<>3;K-=H;F-=H<<3;z&=(1<>>24)&255)+((aA>>>8)&65280)+((aA&65280)<<8)+((aA&255)<<24))}function ag(){this.mode=0;this.last=false;this.wrap=0;this.havedict=false;this.flags=0;this.dmax=0;this.check=0;this.total=0;this.head=null;this.wbits=0;this.wsize=0;this.whave=0;this.wnext=0;this.window=null;this.hold=0;this.bits=0;this.length=0;this.offset=0;this.extra=0;this.lencode=null;this.distcode=null;this.lenbits=0;this.distbits=0;this.ncode=0;this.nlen=0;this.ndist=0;this.have=0;this.next=null;this.lens=new S.Buf16(320);this.work=new S.Buf16(288);this.lendyn=null;this.distdyn=null;this.sane=0;this.back=0;this.was=0}function R(aA){var aB;if(!aA||!aA.state){return at}aB=aA.state;aA.total_in=aA.total_out=aB.total=0;aA.msg="";if(aB.wrap){aA.adler=aB.wrap&1}aB.mode=am;aB.last=0;aB.havedict=0;aB.dmax=32768;aB.head=null;aB.hold=0;aB.bits=0;aB.lencode=aB.lendyn=new S.Buf32(Y);aB.distcode=aB.distdyn=new S.Buf32(P);aB.sane=1;aB.back=-1;return v}function av(aA){var aB;if(!aA||!aA.state){return at}aB=aA.state;aB.wsize=0;aB.whave=0;aB.wnext=0;return R(aA)}function y(aA,aC){var aB;var aD;if(!aA||!aA.state){return at}aD=aA.state;if(aC<0){aB=0;aC=-aC}else{aB=(aC>>4)+1;if(aC<48){aC&=15}}if(aC&&(aC<8||aC>15)){return at}if(aD.window!==null&&aD.wbits!==aC){aD.window=null}aD.wrap=aB;aD.wbits=aC;return av(aA)}function q(aA,aC){var aB;var aD;if(!aA){return at}aD=new ag();aA.state=aD;aD.window=null;aB=y(aA,aC);if(aB!==v){aA.state=null}return aB}function I(aA){return q(aA,K)}var ai=true;var an,l;function H(aB){if(ai){var aA;an=new S.Buf32(512);l=new S.Buf32(32);aA=0;while(aA<144){aB.lens[aA++]=8}while(aA<256){aB.lens[aA++]=9}while(aA<280){aB.lens[aA++]=7}while(aA<288){aB.lens[aA++]=8}n(af,aB.lens,0,288,an,0,aB.work,{bits:9});aA=0;while(aA<32){aB.lens[aA++]=5}n(J,aB.lens,0,32,l,0,aB.work,{bits:5});ai=false}aB.lencode=an;aB.lenbits=9;aB.distcode=l;aB.distbits=5}function O(aB,aE,aA,aF){var aD;var aC=aB.state;if(aC.window===null){aC.wsize=1<=aC.wsize){S.arraySet(aC.window,aE,aA-aC.wsize,aC.wsize,0);aC.wnext=0;aC.whave=aC.wsize}else{aD=aC.wsize-aC.wnext;if(aD>aF){aD=aF}S.arraySet(aC.window,aE,aA-aF,aD,aC.wnext);aF-=aD;if(aF){S.arraySet(aC.window,aE,aA-aF,aF,0);aC.wnext=aF;aC.whave=aC.wsize}else{aC.wnext+=aD;if(aC.wnext===aC.wsize){aC.wnext=0}if(aC.whave>>8)&255;aF.check=ae(aF.check,aH,2,0);aN=0;aT=0;aF.mode=al;break}aF.flags=0;if(aF.head){aF.head.done=false}if(!(aF.wrap&1)||(((aN&255)<<8)+(aN>>8))%31){aX.msg="incorrect header check";aF.mode=g;break}if((aN&15)!==ab){aX.msg="unknown compression method";aF.mode=g;break}aN>>>=4;aT-=4;aW=(aN&15)+8;if(aF.wbits===0){aF.wbits=aW}else{if(aW>aF.wbits){aX.msg="invalid window size";aF.mode=g;break}}aF.dmax=1<>8)&1)}if(aF.flags&512){aH[0]=aN&255;aH[1]=(aN>>>8)&255;aF.check=ae(aF.check,aH,2,0)}aN=0;aT=0;aF.mode=k;case k:while(aT<32){if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>>8)&255;aH[2]=(aN>>>16)&255;aH[3]=(aN>>>24)&255;aF.check=ae(aF.check,aH,4,0)}aN=0;aT=0;aF.mode=ah;case ah:while(aT<16){if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>8)}if(aF.flags&512){aH[0]=aN&255;aH[1]=(aN>>>8)&255;aF.check=ae(aF.check,aH,2,0)}aN=0;aT=0;aF.mode=E;case E:if(aF.flags&1024){while(aT<16){if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>>8)&255;aF.check=ae(aF.check,aH,2,0)}aN=0;aT=0}else{if(aF.head){aF.head.extra=null}}aF.mode=f;case f:if(aF.flags&1024){aS=aF.length;if(aS>aD){aS=aD}if(aS){if(aF.head){aW=aF.head.extra_len-aF.length;if(!aF.head.extra){aF.head.extra=new Array(aF.head.extra_len)}S.arraySet(aF.head.extra,aK,aP,aS,aW)}if(aF.flags&512){aF.check=ae(aF.check,aK,aS,aP)}aD-=aS;aP+=aS;aF.length-=aS}if(aF.length){break inf_leave}}aF.length=0;aF.mode=t;case t:if(aF.flags&2048){if(aD===0){break inf_leave}aS=0;do{aW=aK[aP+aS++];if(aF.head&&aW&&(aF.length<65536)){aF.head.name+=String.fromCharCode(aW)}}while(aW&&aS>9)&1);aF.head.done=true}aX.adler=aF.check=0;aF.mode=m;break;case ar:while(aT<32){if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>>=aT&7;aT-=aT&7;aF.mode=ao;break}while(aT<3){if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>>=1;aT-=1;switch((aN&3)){case 0:aF.mode=h;break;case 1:H(aF);aF.mode=aa;if(aR===C){aN>>>=2;aT-=2;break inf_leave}break;case 2:aF.mode=o;break;case 3:aX.msg="invalid block type";aF.mode=g}aN>>>=2;aT-=2;break;case h:aN>>>=aT&7;aT-=aT&7;while(aT<32){if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>>16)^65535)){aX.msg="invalid stored block lengths";aF.mode=g;break}aF.length=aN&65535;aN=0;aT=0;aF.mode=az;if(aR===C){break inf_leave}case az:aF.mode=ap;case ap:aS=aF.length;if(aS){if(aS>aD){aS=aD}if(aS>aE){aS=aE}if(aS===0){break inf_leave}S.arraySet(aI,aK,aP,aS,aG);aD-=aS;aP+=aS;aE-=aS;aG+=aS;aF.length-=aS;break}aF.mode=m;break;case o:while(aT<14){if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>>=5;aT-=5;aF.ndist=(aN&31)+1;aN>>>=5;aT-=5;aF.ncode=(aN&15)+4;aN>>>=4;aT-=4;if(aF.nlen>286||aF.ndist>30){aX.msg="too many length or distance symbols";aF.mode=g;break}aF.have=0;aF.mode=A;case A:while(aF.have>>=3;aT-=3}while(aF.have<19){aF.lens[aV[aF.have++]]=0}aF.lencode=aF.lendyn;aF.lenbits=7;aM={bits:aF.lenbits};a2=n(ad,aF.lens,0,19,aF.lencode,0,aF.work,aM);aF.lenbits=aM.bits;if(a2){aX.msg="invalid code lengths set";aF.mode=g;break}aF.have=0;aF.mode=U;case U:while(aF.have>>24;aJ=(aA>>>16)&255;aZ=aA&65535;if((aY)<=aT){break}if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>>=aY;aT-=aY;aF.lens[aF.have++]=aZ}else{if(aZ===16){aQ=aY+2;while(aT>>=aY;aT-=aY;if(aF.have===0){aX.msg="invalid bit length repeat";aF.mode=g;break}aW=aF.lens[aF.have-1];aS=3+(aN&3);aN>>>=2;aT-=2}else{if(aZ===17){aQ=aY+3;while(aT>>=aY;aT-=aY;aW=0;aS=3+(aN&7);aN>>>=3;aT-=3}else{aQ=aY+7;while(aT>>=aY;aT-=aY;aW=0;aS=11+(aN&127);aN>>>=7;aT-=7}}if(aF.have+aS>aF.nlen+aF.ndist){aX.msg="invalid bit length repeat";aF.mode=g;break}while(aS--){aF.lens[aF.have++]=aW}}}if(aF.mode===g){break}if(aF.lens[256]===0){aX.msg="invalid code -- missing end-of-block";aF.mode=g;break}aF.lenbits=9;aM={bits:aF.lenbits};a2=n(af,aF.lens,0,aF.nlen,aF.lencode,0,aF.work,aM);aF.lenbits=aM.bits;if(a2){aX.msg="invalid literal/lengths set";aF.mode=g;break}aF.distbits=6;aF.distcode=aF.distdyn;aM={bits:aF.distbits};a2=n(J,aF.lens,aF.nlen,aF.ndist,aF.distcode,0,aF.work,aM);aF.distbits=aM.bits;if(a2){aX.msg="invalid distances set";aF.mode=g;break}aF.mode=aa;if(aR===C){break inf_leave}case aa:aF.mode=e;case e:if(aD>=6&&aE>=258){aX.next_out=aG;aX.avail_out=aE;aX.next_in=aP;aX.avail_in=aD;aF.hold=aN;aF.bits=aT;aq(aX,a0);aG=aX.next_out;aI=aX.output;aE=aX.avail_out;aP=aX.next_in;aK=aX.input;aD=aX.avail_in;aN=aF.hold;aT=aF.bits;if(aF.mode===m){aF.back=-1}break}aF.back=0;for(;;){aA=aF.lencode[aN&((1<>>24;aJ=(aA>>>16)&255;aZ=aA&65535;if(aY<=aT){break}if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>aO)];aY=aA>>>24;aJ=(aA>>>16)&255;aZ=aA&65535;if((aO+aY)<=aT){break}if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>>=aO;aT-=aO;aF.back+=aO}aN>>>=aY;aT-=aY;aF.back+=aY;aF.length=aZ;if(aJ===0){aF.mode=F;break}if(aJ&32){aF.back=-1;aF.mode=m;break}if(aJ&64){aX.msg="invalid literal/length code";aF.mode=g;break}aF.extra=aJ&15;aF.mode=aw;case aw:if(aF.extra){aQ=aF.extra;while(aT>>=aF.extra;aT-=aF.extra;aF.back+=aF.extra}aF.was=aF.length;aF.mode=V;case V:for(;;){aA=aF.distcode[aN&((1<>>24;aJ=(aA>>>16)&255;aZ=aA&65535;if((aY)<=aT){break}if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>aO)];aY=aA>>>24;aJ=(aA>>>16)&255;aZ=aA&65535;if((aO+aY)<=aT){break}if(aD===0){break inf_leave}aD--;aN+=aK[aP++]<>>=aO;aT-=aO;aF.back+=aO}aN>>>=aY;aT-=aY;aF.back+=aY;if(aJ&64){aX.msg="invalid distance code";aF.mode=g;break}aF.offset=aZ;aF.extra=(aJ)&15;aF.mode=au;case au:if(aF.extra){aQ=aF.extra;while(aT>>=aF.extra;aT-=aF.extra;aF.back+=aF.extra}if(aF.offset>aF.dmax){aX.msg="invalid distance too far back";aF.mode=g;break}aF.mode=D;case D:if(aE===0){break inf_leave}aS=a0-aE;if(aF.offset>aS){aS=aF.offset-aS;if(aS>aF.whave){if(aF.sane){aX.msg="invalid distance too far back";aF.mode=g;break}}if(aS>aF.wnext){aS-=aF.wnext;aU=aF.wsize-aS}else{aU=aF.wnext-aS}if(aS>aF.length){aS=aF.length}aC=aF.window}else{aC=aI;aU=aG-aF.offset;aS=aF.length}if(aS>aE){aS=aE}aE-=aS;aF.length-=aS;do{aI[aG++]=aC[aU++]}while(--aS);if(aF.length===0){aF.mode=e}break;case F:if(aE===0){break inf_leave}aI[aG++]=aF.length;aE--;aF.mode=e;break;case ao:if(aF.wrap){while(aT<32){if(aD===0){break inf_leave}aD--;aN|=aK[aP++]<=1;R--){if(A[R]!==0){break}}if(J>R){J=R}if(R===0){W[U++]=(1<<24)|(64<<16)|0;W[U++]=(1<<24)|(64<<16)|0;E.bits=1;return 0}for(K=1;K0&&(v===p||R!==1)){return -1}x[1]=0;for(S=1;Sn)||(v===h&&z>m)){return 1}var N=0;for(;;){N++;T=S-B;if(H[D]u){C=t[Z+H[D]];Y=y[F+H[D]]}else{C=32+64;Y=0}}P=1<<(S-B);M=1<>B)+M]=(T<<24)|(C<<16)|Y|0}while(M!==0);P=1<<(S-1);while(Q&P){P>>=1}if(P!==0){Q&=P-1;Q+=P}else{Q=0}D++;if(--A[S]===0){if(S===R){break}S=aa[I+H[D]]}if(S>J&&(Q&O)!==ab){if(B===0){B=J}G+=K;V=S-B;w=1<n)||(v===h&&z>m)){return 1}ab=Q&O;W[ab]=(J<<24)|(V<<16)|(G-U)|0}}if(Q!==0){W[G+Q]=((S-B)<<24)|(64<<16)|0}E.bits=J;return 0}},{"../utils/common":27}],37:[function(g,f,e){f.exports={"2":"need dictionary","1":"stream end","0":"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],38:[function(J,k,al){var aw=J("../utils/common");var T=4;var t=0;var D=1;var E=2;function e(ay){var ax=ay.length;while(--ax>=0){ay[ax]=0}}var X=0;var an=1;var M=2;var av=3;var F=258;var q=29;var h=256;var i=h+1+q;var f=30;var w=19;var j=2*i+1;var ar=15;var z=16;var ag=7;var g=256;var I=16;var H=17;var N=18;var l=[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];var x=[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];var C=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];var U=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];var V=512;var P=new Array((i+2)*2);e(P);var ab=new Array(f*2);e(ab);var ah=new Array(V);e(ah);var A=new Array(F-av+1);e(A);var O=new Array(q);e(O);var aq=new Array(f);e(aq);var ae=function(aA,az,ay,ax,aB){this.static_tree=aA;this.extra_bits=az;this.extra_base=ay;this.elems=ax;this.max_length=aB;this.has_stree=aA&&aA.length};var aj;var aa;var y;var au=function(ay,ax){this.dyn_tree=ay;this.max_code=0;this.stat_desc=ax};function ac(ax){return ax<256?ah[ax]:ah[256+(ax>>>7)]}function o(ay,ax){ay.pending_buf[ay.pending++]=(ax)&255;ay.pending_buf[ay.pending++]=(ax>>>8)&255}function ai(ax,az,ay){if(ax.bi_valid>(z-ay)){ax.bi_buf|=(az<>(z-ax.bi_valid);ax.bi_valid+=ay-z}else{ax.bi_buf|=(az<>>=1;ay<<=1}while(--ax>0);return ay>>>1}function v(ax){if(ax.bi_valid===16){o(ax,ax.bi_buf);ax.bi_buf=0;ax.bi_valid=0}else{if(ax.bi_valid>=8){ax.pending_buf[ax.pending++]=ax.bi_buf&255;ax.bi_buf>>=8;ax.bi_valid-=8}}}function n(aL,aG){var aM=aG.dyn_tree;var aH=aG.max_code;var aK=aG.stat_desc.static_tree;var az=aG.stat_desc.has_stree;var aB=aG.stat_desc.extra_bits;var ax=aG.stat_desc.extra_base;var aJ=aG.stat_desc.max_length;var aE;var ay,aA;var aI;var aD;var aF;var aC=0;for(aI=0;aI<=ar;aI++){aL.bl_count[aI]=0}aM[aL.heap[aL.heap_max]*2+1]=0;for(aE=aL.heap_max+1;aEaJ){aI=aJ;aC++}aM[ay*2+1]=aI;if(ay>aH){continue}aL.bl_count[aI]++;aD=0;if(ay>=ax){aD=aB[ay-ax]}aF=aM[ay*2];aL.opt_len+=aF*(aI+aD);if(az){aL.static_len+=aF*(aK[ay*2+1]+aD)}}if(aC===0){return}do{aI=aJ-1;while(aL.bl_count[aI]===0){aI--}aL.bl_count[aI]--;aL.bl_count[aI+1]+=2;aL.bl_count[aJ]--;aC-=2}while(aC>0);for(aI=aJ;aI!==0;aI--){ay=aL.bl_count[aI];while(ay!==0){aA=aL.heap[--aE];if(aA>aH){continue}if(aM[aA*2+1]!==aI){aL.opt_len+=(aI-aM[aA*2+1])*aM[aA*2];aM[aA*2+1]=aI}ay--}}}function ak(ay,aE,az){var aB=new Array(ar+1);var aA=0;var aC;var aD;for(aC=1;aC<=ar;aC++){aB[aC]=aA=(aA+az[aC-1])<<1}for(aD=0;aD<=aE;aD++){var ax=ay[aD*2+1];if(ax===0){continue}ay[aD*2]=B(aB[ax]++,ax)}}function W(){var aC;var aA;var az;var ay;var aB;var ax=new Array(ar+1);az=0;for(ay=0;ay>=7;for(;ay8){o(ax,ax.bi_buf)}else{if(ax.bi_valid>0){ax.pending_buf[ax.pending++]=ax.bi_buf}}ax.bi_buf=0;ax.bi_valid=0}function s(az,ay,ax,aA){m(az);if(aA){o(az,ax);o(az,~ax)}aw.arraySet(az.pending_buf,az.window,ay,ax,az.pending);az.pending+=ax}function Z(ay,aC,ax,aB){var aA=aC*2;var az=ax*2;return(ay[aA]>1);ay>=1;ay--){at(aF,aG,ay)}aA=ax;do{ay=aF.heap[1];aF.heap[1]=aF.heap[aF.heap_len--];at(aF,aG,1);aB=aF.heap[1];aF.heap[--aF.heap_max]=ay;aF.heap[--aF.heap_max]=aB;aG[aA*2]=aG[ay*2]+aG[aB*2];aF.depth[aA]=(aF.depth[ay]>=aF.depth[aB]?aF.depth[ay]:aF.depth[aB])+1;aG[ay*2+1]=aG[aB*2+1]=aA;aF.heap[1]=aA++;at(aF,aG,1)}while(aF.heap_len>=2);aF.heap[--aF.heap_max]=aF.heap[1];n(aF,aC);ak(aG,aD,aF.bl_count)}function r(aF,aG,aE){var ay;var aC=-1;var ax;var aA=aG[0*2+1];var aB=0;var az=7;var aD=4;if(aA===0){az=138;aD=3}aG[(aE+1)*2+1]=65535;for(ay=0;ay<=aE;ay++){ax=aA;aA=aG[(ay+1)*2+1];if(++aB=3;ax--){if(ay.bl_tree[U[ax]*2+1]!==0){break}}ay.opt_len+=3*(ax+1)+5+5+4;return ax}function R(ay,az,ax,aA){var aB;ai(ay,az-257,5);ai(ay,ax-1,5);ai(ay,aA-4,4);for(aB=0;aB>>=1){if((ax&1)&&(ay.dyn_ltree[az*2]!==0)){return t}}if(ay.dyn_ltree[9*2]!==0||ay.dyn_ltree[10*2]!==0||ay.dyn_ltree[13*2]!==0){return D}for(az=32;az0){if(aC.strm.data_type===E){aC.strm.data_type=Q(aC)}Y(aC,aC.l_desc);Y(aC,aC.d_desc);aA=G(aC);ay=(aC.opt_len+3+7)>>>3;ax=(aC.static_len+3+7)>>>3;if(ax<=ay){ay=ax}}else{ay=ax=aB+5}if((aB+4<=ay)&&(az!==-1)){S(aC,az,aB,aD)}else{if(aC.strategy===T||ax===ay){ai(aC,(an<<1)+(aD?1:0),3);ap(aC,P,ab)}else{ai(aC,(M<<1)+(aD?1:0),3);R(aC,aC.l_desc.max_code+1,aC.d_desc.max_code+1,aA+1);ap(aC,aC.dyn_ltree,aC.dyn_dtree)}}L(aC);if(aD){m(aC)}}function ao(ax,az,ay){ax.pending_buf[ax.d_buf+ax.last_lit*2]=(az>>>8)&255;ax.pending_buf[ax.d_buf+ax.last_lit*2+1]=az&255;ax.pending_buf[ax.l_buf+ax.last_lit]=ay&255;ax.last_lit++;if(az===0){ax.dyn_ltree[ay*2]++}else{ax.matches++;az--;ax.dyn_ltree[(A[ay]+h+1)*2]++;ax.dyn_dtree[ac(az)*2]++}return(ax.last_lit===ax.lit_bufsize-1)}al._tr_init=K;al._tr_stored_block=S;al._tr_flush_block=p;al._tr_tally=ao;al._tr_align=ad},{"../utils/common":27}],39:[function(g,f,e){function h(){this.input=null;this.next_in=0;this.avail_in=0;this.total_in=0;this.output=null;this.next_out=0;this.avail_out=0;this.total_out=0;this.msg="";this.state=null;this.data_type=2;this.adler=0}f.exports=h},{}]},{},[9])(9)}); \ No newline at end of file diff --git a/public/js/lib/jszip/docs/APPNOTE.TXT b/public/js/lib/jszip/docs/APPNOTE.TXT new file mode 100644 index 0000000..e658f95 --- /dev/null +++ b/public/js/lib/jszip/docs/APPNOTE.TXT @@ -0,0 +1,3217 @@ +File: APPNOTE.TXT - .ZIP File Format Specification +Version: 6.3.2 +Revised: September 28, 2007 +Copyright (c) 1989 - 2007 PKWARE Inc., All Rights Reserved. + +The use of certain technological aspects disclosed in the current +APPNOTE is available pursuant to the below section entitled +"Incorporating PKWARE Proprietary Technology into Your Product". + +I. Purpose +---------- + +This specification is intended to define a cross-platform, +interoperable file storage and transfer format. Since its +first publication in 1989, PKWARE has remained committed to +ensuring the interoperability of the .ZIP file format through +publication and maintenance of this specification. We trust that +all .ZIP compatible vendors and application developers that have +adopted and benefited from this format will share and support +this commitment to interoperability. + +II. Contacting PKWARE +--------------------- + + PKWARE, Inc. + 648 N. Plankinton Avenue, Suite 220 + Milwaukee, WI 53203 + +1-414-289-9788 + +1-414-289-9789 FAX + zipformat@pkware.com + +III. Disclaimer +--------------- + +Although PKWARE will attempt to supply current and accurate +information relating to its file formats, algorithms, and the +subject programs, the possibility of error or omission cannot +be eliminated. PKWARE therefore expressly disclaims any warranty +that the information contained in the associated materials relating +to the subject programs and/or the format of the files created or +accessed by the subject programs and/or the algorithms used by +the subject programs, or any other matter, is current, correct or +accurate as delivered. Any risk of damage due to any possible +inaccurate information is assumed by the user of the information. +Furthermore, the information relating to the subject programs +and/or the file formats created or accessed by the subject +programs and/or the algorithms used by the subject programs is +subject to change without notice. + +If the version of this file is marked as a NOTIFICATION OF CHANGE, +the content defines an Early Feature Specification (EFS) change +to the .ZIP file format that may be subject to modification prior +to publication of the Final Feature Specification (FFS). This +document may also contain information on Planned Feature +Specifications (PFS) defining recognized future extensions. + +IV. Change Log +-------------- + +Version Change Description Date +------- ------------------ ---------- +5.2 -Single Password Symmetric Encryption 06/02/2003 + storage + +6.1.0 -Smartcard compatibility 01/20/2004 + -Documentation on certificate storage + +6.2.0 -Introduction of Central Directory 04/26/2004 + Encryption for encrypting metadata + -Added OS/X to Version Made By values + +6.2.1 -Added Extra Field placeholder for 04/01/2005 + POSZIP using ID 0x4690 + + -Clarified size field on + "zip64 end of central directory record" + +6.2.2 -Documented Final Feature Specification 01/06/2006 + for Strong Encryption + + -Clarifications and typographical + corrections + +6.3.0 -Added tape positioning storage 09/29/2006 + parameters + + -Expanded list of supported hash algorithms + + -Expanded list of supported compression + algorithms + + -Expanded list of supported encryption + algorithms + + -Added option for Unicode filename + storage + + -Clarifications for consistent use + of Data Descriptor records + + -Added additional "Extra Field" + definitions + +6.3.1 -Corrected standard hash values for 04/11/2007 + SHA-256/384/512 + +6.3.2 -Added compression method 97 09/28/2007 + + -Documented InfoZIP "Extra Field" + values for UTF-8 file name and + file comment storage + +V. General Format of a .ZIP file +-------------------------------- + + Files stored in arbitrary order. Large .ZIP files can span multiple + volumes or be split into user-defined segment sizes. All values + are stored in little-endian byte order unless otherwise specified. + + Overall .ZIP file format: + + [local file header 1] + [file data 1] + [data descriptor 1] + . + . + . + [local file header n] + [file data n] + [data descriptor n] + [archive decryption header] + [archive extra data record] + [central directory] + [zip64 end of central directory record] + [zip64 end of central directory locator] + [end of central directory record] + + + A. Local file header: + + local file header signature 4 bytes (0x04034b50) + version needed to extract 2 bytes + general purpose bit flag 2 bytes + compression method 2 bytes + last mod file time 2 bytes + last mod file date 2 bytes + crc-32 4 bytes + compressed size 4 bytes + uncompressed size 4 bytes + file name length 2 bytes + extra field length 2 bytes + + file name (variable size) + extra field (variable size) + + B. File data + + Immediately following the local header for a file + is the compressed or stored data for the file. + The series of [local file header][file data][data + descriptor] repeats for each file in the .ZIP archive. + + C. Data descriptor: + + crc-32 4 bytes + compressed size 4 bytes + uncompressed size 4 bytes + + This descriptor exists only if bit 3 of the general + purpose bit flag is set (see below). It is byte aligned + and immediately follows the last byte of compressed data. + This descriptor is used only when it was not possible to + seek in the output .ZIP file, e.g., when the output .ZIP file + was standard output or a non-seekable device. For ZIP64(tm) format + archives, the compressed and uncompressed sizes are 8 bytes each. + + When compressing files, compressed and uncompressed sizes + should be stored in ZIP64 format (as 8 byte values) when a + files size exceeds 0xFFFFFFFF. However ZIP64 format may be + used regardless of the size of a file. When extracting, if + the zip64 extended information extra field is present for + the file the compressed and uncompressed sizes will be 8 + byte values. + + Although not originally assigned a signature, the value + 0x08074b50 has commonly been adopted as a signature value + for the data descriptor record. Implementers should be + aware that ZIP files may be encountered with or without this + signature marking data descriptors and should account for + either case when reading ZIP files to ensure compatibility. + When writing ZIP files, it is recommended to include the + signature value marking the data descriptor record. When + the signature is used, the fields currently defined for + the data descriptor record will immediately follow the + signature. + + An extensible data descriptor will be released in a future + version of this APPNOTE. This new record is intended to + resolve conflicts with the use of this record going forward, + and to provide better support for streamed file processing. + + When the Central Directory Encryption method is used, the data + descriptor record is not required, but may be used. If present, + and bit 3 of the general purpose bit field is set to indicate + its presence, the values in fields of the data descriptor + record should be set to binary zeros. + + D. Archive decryption header: + + The Archive Decryption Header is introduced in version 6.2 + of the ZIP format specification. This record exists in support + of the Central Directory Encryption Feature implemented as part of + the Strong Encryption Specification as described in this document. + When the Central Directory Structure is encrypted, this decryption + header will precede the encrypted data segment. The encrypted + data segment will consist of the Archive extra data record (if + present) and the encrypted Central Directory Structure data. + The format of this data record is identical to the Decryption + header record preceding compressed file data. If the central + directory structure is encrypted, the location of the start of + this data record is determined using the Start of Central Directory + field in the Zip64 End of Central Directory record. Refer to the + section on the Strong Encryption Specification for information + on the fields used in the Archive Decryption Header record. + + + E. Archive extra data record: + + archive extra data signature 4 bytes (0x08064b50) + extra field length 4 bytes + extra field data (variable size) + + The Archive Extra Data Record is introduced in version 6.2 + of the ZIP format specification. This record exists in support + of the Central Directory Encryption Feature implemented as part of + the Strong Encryption Specification as described in this document. + When present, this record immediately precedes the central + directory data structure. The size of this data record will be + included in the Size of the Central Directory field in the + End of Central Directory record. If the central directory structure + is compressed, but not encrypted, the location of the start of + this data record is determined using the Start of Central Directory + field in the Zip64 End of Central Directory record. + + + F. Central directory structure: + + [file header 1] + . + . + . + [file header n] + [digital signature] + + File header: + + central file header signature 4 bytes (0x02014b50) + version made by 2 bytes + version needed to extract 2 bytes + general purpose bit flag 2 bytes + compression method 2 bytes + last mod file time 2 bytes + last mod file date 2 bytes + crc-32 4 bytes + compressed size 4 bytes + uncompressed size 4 bytes + file name length 2 bytes + extra field length 2 bytes + file comment length 2 bytes + disk number start 2 bytes + internal file attributes 2 bytes + external file attributes 4 bytes + relative offset of local header 4 bytes + + file name (variable size) + extra field (variable size) + file comment (variable size) + + Digital signature: + + header signature 4 bytes (0x05054b50) + size of data 2 bytes + signature data (variable size) + + With the introduction of the Central Directory Encryption + feature in version 6.2 of this specification, the Central + Directory Structure may be stored both compressed and encrypted. + Although not required, it is assumed when encrypting the + Central Directory Structure, that it will be compressed + for greater storage efficiency. Information on the + Central Directory Encryption feature can be found in the section + describing the Strong Encryption Specification. The Digital + Signature record will be neither compressed nor encrypted. + + G. Zip64 end of central directory record + + zip64 end of central dir + signature 4 bytes (0x06064b50) + size of zip64 end of central + directory record 8 bytes + version made by 2 bytes + version needed to extract 2 bytes + number of this disk 4 bytes + number of the disk with the + start of the central directory 4 bytes + total number of entries in the + central directory on this disk 8 bytes + total number of entries in the + central directory 8 bytes + size of the central directory 8 bytes + offset of start of central + directory with respect to + the starting disk number 8 bytes + zip64 extensible data sector (variable size) + + The value stored into the "size of zip64 end of central + directory record" should be the size of the remaining + record and should not include the leading 12 bytes. + + Size = SizeOfFixedFields + SizeOfVariableData - 12. + + The above record structure defines Version 1 of the + zip64 end of central directory record. Version 1 was + implemented in versions of this specification preceding + 6.2 in support of the ZIP64 large file feature. The + introduction of the Central Directory Encryption feature + implemented in version 6.2 as part of the Strong Encryption + Specification defines Version 2 of this record structure. + Refer to the section describing the Strong Encryption + Specification for details on the version 2 format for + this record. + + Special purpose data may reside in the zip64 extensible data + sector field following either a V1 or V2 version of this + record. To ensure identification of this special purpose data + it must include an identifying header block consisting of the + following: + + Header ID - 2 bytes + Data Size - 4 bytes + + The Header ID field indicates the type of data that is in the + data block that follows. + + Data Size identifies the number of bytes that follow for this + data block type. + + Multiple special purpose data blocks may be present, but each + must be preceded by a Header ID and Data Size field. Current + mappings of Header ID values supported in this field are as + defined in APPENDIX C. + + H. Zip64 end of central directory locator + + zip64 end of central dir locator + signature 4 bytes (0x07064b50) + number of the disk with the + start of the zip64 end of + central directory 4 bytes + relative offset of the zip64 + end of central directory record 8 bytes + total number of disks 4 bytes + + I. End of central directory record: + + end of central dir signature 4 bytes (0x06054b50) + number of this disk 2 bytes + number of the disk with the + start of the central directory 2 bytes + total number of entries in the + central directory on this disk 2 bytes + total number of entries in + the central directory 2 bytes + size of the central directory 4 bytes + offset of start of central + directory with respect to + the starting disk number 4 bytes + .ZIP file comment length 2 bytes + .ZIP file comment (variable size) + + J. Explanation of fields: + + version made by (2 bytes) + + The upper byte indicates the compatibility of the file + attribute information. If the external file attributes + are compatible with MS-DOS and can be read by PKZIP for + DOS version 2.04g then this value will be zero. If these + attributes are not compatible, then this value will + identify the host system on which the attributes are + compatible. Software can use this information to determine + the line record format for text files etc. The current + mappings are: + + 0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems) + 1 - Amiga 2 - OpenVMS + 3 - UNIX 4 - VM/CMS + 5 - Atari ST 6 - OS/2 H.P.F.S. + 7 - Macintosh 8 - Z-System + 9 - CP/M 10 - Windows NTFS + 11 - MVS (OS/390 - Z/OS) 12 - VSE + 13 - Acorn Risc 14 - VFAT + 15 - alternate MVS 16 - BeOS + 17 - Tandem 18 - OS/400 + 19 - OS/X (Darwin) 20 thru 255 - unused + + The lower byte indicates the ZIP specification version + (the version of this document) supported by the software + used to encode the file. The value/10 indicates the major + version number, and the value mod 10 is the minor version + number. + + version needed to extract (2 bytes) + + The minimum supported ZIP specification version needed to + extract the file, mapped as above. This value is based on + the specific format features a ZIP program must support to + be able to extract the file. If multiple features are + applied to a file, the minimum version should be set to the + feature having the highest value. New features or feature + changes affecting the published format specification will be + implemented using higher version numbers than the last + published value to avoid conflict. + + Current minimum feature versions are as defined below: + + 1.0 - Default value + 1.1 - File is a volume label + 2.0 - File is a folder (directory) + 2.0 - File is compressed using Deflate compression + 2.0 - File is encrypted using traditional PKWARE encryption + 2.1 - File is compressed using Deflate64(tm) + 2.5 - File is compressed using PKWARE DCL Implode + 2.7 - File is a patch data set + 4.5 - File uses ZIP64 format extensions + 4.6 - File is compressed using BZIP2 compression* + 5.0 - File is encrypted using DES + 5.0 - File is encrypted using 3DES + 5.0 - File is encrypted using original RC2 encryption + 5.0 - File is encrypted using RC4 encryption + 5.1 - File is encrypted using AES encryption + 5.1 - File is encrypted using corrected RC2 encryption** + 5.2 - File is encrypted using corrected RC2-64 encryption** + 6.1 - File is encrypted using non-OAEP key wrapping*** + 6.2 - Central directory encryption + 6.3 - File is compressed using LZMA + 6.3 - File is compressed using PPMd+ + 6.3 - File is encrypted using Blowfish + 6.3 - File is encrypted using Twofish + + + * Early 7.x (pre-7.2) versions of PKZIP incorrectly set the + version needed to extract for BZIP2 compression to be 50 + when it should have been 46. + + ** Refer to the section on Strong Encryption Specification + for additional information regarding RC2 corrections. + + *** Certificate encryption using non-OAEP key wrapping is the + intended mode of operation for all versions beginning with 6.1. + Support for OAEP key wrapping should only be used for + backward compatibility when sending ZIP files to be opened by + versions of PKZIP older than 6.1 (5.0 or 6.0). + + + Files compressed using PPMd should set the version + needed to extract field to 6.3, however, not all ZIP + programs enforce this and may be unable to decompress + data files compressed using PPMd if this value is set. + + When using ZIP64 extensions, the corresponding value in the + zip64 end of central directory record should also be set. + This field should be set appropriately to indicate whether + Version 1 or Version 2 format is in use. + + general purpose bit flag: (2 bytes) + + Bit 0: If set, indicates that the file is encrypted. + + (For Method 6 - Imploding) + Bit 1: If the compression method used was type 6, + Imploding, then this bit, if set, indicates + an 8K sliding dictionary was used. If clear, + then a 4K sliding dictionary was used. + Bit 2: If the compression method used was type 6, + Imploding, then this bit, if set, indicates + 3 Shannon-Fano trees were used to encode the + sliding dictionary output. If clear, then 2 + Shannon-Fano trees were used. + + (For Methods 8 and 9 - Deflating) + Bit 2 Bit 1 + 0 0 Normal (-en) compression option was used. + 0 1 Maximum (-exx/-ex) compression option was used. + 1 0 Fast (-ef) compression option was used. + 1 1 Super Fast (-es) compression option was used. + + (For Method 14 - LZMA) + Bit 1: If the compression method used was type 14, + LZMA, then this bit, if set, indicates + an end-of-stream (EOS) marker is used to + mark the end of the compressed data stream. + If clear, then an EOS marker is not present + and the compressed data size must be known + to extract. + + Note: Bits 1 and 2 are undefined if the compression + method is any other. + + Bit 3: If this bit is set, the fields crc-32, compressed + size and uncompressed size are set to zero in the + local header. The correct values are put in the + data descriptor immediately following the compressed + data. (Note: PKZIP version 2.04g for DOS only + recognizes this bit for method 8 compression, newer + versions of PKZIP recognize this bit for any + compression method.) + + Bit 4: Reserved for use with method 8, for enhanced + deflating. + + Bit 5: If this bit is set, this indicates that the file is + compressed patched data. (Note: Requires PKZIP + version 2.70 or greater) + + Bit 6: Strong encryption. If this bit is set, you should + set the version needed to extract value to at least + 50 and you must also set bit 0. If AES encryption + is used, the version needed to extract value must + be at least 51. + + Bit 7: Currently unused. + + Bit 8: Currently unused. + + Bit 9: Currently unused. + + Bit 10: Currently unused. + + Bit 11: Language encoding flag (EFS). If this bit is set, + the filename and comment fields for this file + must be encoded using UTF-8. (see APPENDIX D) + + Bit 12: Reserved by PKWARE for enhanced compression. + + Bit 13: Used when encrypting the Central Directory to indicate + selected data values in the Local Header are masked to + hide their actual values. See the section describing + the Strong Encryption Specification for details. + + Bit 14: Reserved by PKWARE. + + Bit 15: Reserved by PKWARE. + + compression method: (2 bytes) + + (see accompanying documentation for algorithm + descriptions) + + 0 - The file is stored (no compression) + 1 - The file is Shrunk + 2 - The file is Reduced with compression factor 1 + 3 - The file is Reduced with compression factor 2 + 4 - The file is Reduced with compression factor 3 + 5 - The file is Reduced with compression factor 4 + 6 - The file is Imploded + 7 - Reserved for Tokenizing compression algorithm + 8 - The file is Deflated + 9 - Enhanced Deflating using Deflate64(tm) + 10 - PKWARE Data Compression Library Imploding (old IBM TERSE) + 11 - Reserved by PKWARE + 12 - File is compressed using BZIP2 algorithm + 13 - Reserved by PKWARE + 14 - LZMA (EFS) + 15 - Reserved by PKWARE + 16 - Reserved by PKWARE + 17 - Reserved by PKWARE + 18 - File is compressed using IBM TERSE (new) + 19 - IBM LZ77 z Architecture (PFS) + 97 - WavPack compressed data + 98 - PPMd version I, Rev 1 + + date and time fields: (2 bytes each) + + The date and time are encoded in standard MS-DOS format. + If input came from standard input, the date and time are + those at which compression was started for this data. + If encrypting the central directory and general purpose bit + flag 13 is set indicating masking, the value stored in the + Local Header will be zero. + + CRC-32: (4 bytes) + + The CRC-32 algorithm was generously contributed by + David Schwaderer and can be found in his excellent + book "C Programmers Guide to NetBIOS" published by + Howard W. Sams & Co. Inc. The 'magic number' for + the CRC is 0xdebb20e3. The proper CRC pre and post + conditioning is used, meaning that the CRC register + is pre-conditioned with all ones (a starting value + of 0xffffffff) and the value is post-conditioned by + taking the one's complement of the CRC residual. + If bit 3 of the general purpose flag is set, this + field is set to zero in the local header and the correct + value is put in the data descriptor and in the central + directory. When encrypting the central directory, if the + local header is not in ZIP64 format and general purpose + bit flag 13 is set indicating masking, the value stored + in the Local Header will be zero. + + compressed size: (4 bytes) + uncompressed size: (4 bytes) + + The size of the file compressed and uncompressed, + respectively. When a decryption header is present it will + be placed in front of the file data and the value of the + compressed file size will include the bytes of the decryption + header. If bit 3 of the general purpose bit flag is set, + these fields are set to zero in the local header and the + correct values are put in the data descriptor and + in the central directory. If an archive is in ZIP64 format + and the value in this field is 0xFFFFFFFF, the size will be + in the corresponding 8 byte ZIP64 extended information + extra field. When encrypting the central directory, if the + local header is not in ZIP64 format and general purpose bit + flag 13 is set indicating masking, the value stored for the + uncompressed size in the Local Header will be zero. + + file name length: (2 bytes) + extra field length: (2 bytes) + file comment length: (2 bytes) + + The length of the file name, extra field, and comment + fields respectively. The combined length of any + directory record and these three fields should not + generally exceed 65,535 bytes. If input came from standard + input, the file name length is set to zero. + + disk number start: (2 bytes) + + The number of the disk on which this file begins. If an + archive is in ZIP64 format and the value in this field is + 0xFFFF, the size will be in the corresponding 4 byte zip64 + extended information extra field. + + internal file attributes: (2 bytes) + + Bits 1 and 2 are reserved for use by PKWARE. + + The lowest bit of this field indicates, if set, that + the file is apparently an ASCII or text file. If not + set, that the file apparently contains binary data. + The remaining bits are unused in version 1.0. + + The 0x0002 bit of this field indicates, if set, that a + 4 byte variable record length control field precedes each + logical record indicating the length of the record. The + record length control field is stored in little-endian byte + order. This flag is independent of text control characters, + and if used in conjunction with text data, includes any + control characters in the total length of the record. This + value is provided for mainframe data transfer support. + + external file attributes: (4 bytes) + + The mapping of the external attributes is + host-system dependent (see 'version made by'). For + MS-DOS, the low order byte is the MS-DOS directory + attribute byte. If input came from standard input, this + field is set to zero. + + relative offset of local header: (4 bytes) + + This is the offset from the start of the first disk on + which this file appears, to where the local header should + be found. If an archive is in ZIP64 format and the value + in this field is 0xFFFFFFFF, the size will be in the + corresponding 8 byte zip64 extended information extra field. + + file name: (Variable) + + The name of the file, with optional relative path. + The path stored should not contain a drive or + device letter, or a leading slash. All slashes + should be forward slashes '/' as opposed to + backwards slashes '\' for compatibility with Amiga + and UNIX file systems etc. If input came from standard + input, there is no file name field. If encrypting + the central directory and general purpose bit flag 13 is set + indicating masking, the file name stored in the Local Header + will not be the actual file name. A masking value consisting + of a unique hexadecimal value will be stored. This value will + be sequentially incremented for each file in the archive. See + the section on the Strong Encryption Specification for details + on retrieving the encrypted file name. + + extra field: (Variable) + + This is for expansion. If additional information + needs to be stored for special needs or for specific + platforms, it should be stored here. Earlier versions + of the software can then safely skip this file, and + find the next file or header. This field will be 0 + length in version 1.0. + + In order to allow different programs and different types + of information to be stored in the 'extra' field in .ZIP + files, the following structure should be used for all + programs storing data in this field: + + header1+data1 + header2+data2 . . . + + Each header should consist of: + + Header ID - 2 bytes + Data Size - 2 bytes + + Note: all fields stored in Intel low-byte/high-byte order. + + The Header ID field indicates the type of data that is in + the following data block. + + Header ID's of 0 thru 31 are reserved for use by PKWARE. + The remaining ID's can be used by third party vendors for + proprietary usage. + + The current Header ID mappings defined by PKWARE are: + + 0x0001 Zip64 extended information extra field + 0x0007 AV Info + 0x0008 Reserved for extended language encoding data (PFS) + (see APPENDIX D) + 0x0009 OS/2 + 0x000a NTFS + 0x000c OpenVMS + 0x000d UNIX + 0x000e Reserved for file stream and fork descriptors + 0x000f Patch Descriptor + 0x0014 PKCS#7 Store for X.509 Certificates + 0x0015 X.509 Certificate ID and Signature for + individual file + 0x0016 X.509 Certificate ID for Central Directory + 0x0017 Strong Encryption Header + 0x0018 Record Management Controls + 0x0019 PKCS#7 Encryption Recipient Certificate List + 0x0065 IBM S/390 (Z390), AS/400 (I400) attributes + - uncompressed + 0x0066 Reserved for IBM S/390 (Z390), AS/400 (I400) + attributes - compressed + 0x4690 POSZIP 4690 (reserved) + + Third party mappings commonly used are: + + + 0x07c8 Macintosh + 0x2605 ZipIt Macintosh + 0x2705 ZipIt Macintosh 1.3.5+ + 0x2805 ZipIt Macintosh 1.3.5+ + 0x334d Info-ZIP Macintosh + 0x4341 Acorn/SparkFS + 0x4453 Windows NT security descriptor (binary ACL) + 0x4704 VM/CMS + 0x470f MVS + 0x4b46 FWKCS MD5 (see below) + 0x4c41 OS/2 access control list (text ACL) + 0x4d49 Info-ZIP OpenVMS + 0x4f4c Xceed original location extra field + 0x5356 AOS/VS (ACL) + 0x5455 extended timestamp + 0x554e Xceed unicode extra field + 0x5855 Info-ZIP UNIX (original, also OS/2, NT, etc) + 0x6375 Info-ZIP Unicode Comment Extra Field + 0x6542 BeOS/BeBox + 0x7075 Info-ZIP Unicode Path Extra Field + 0x756e ASi UNIX + 0x7855 Info-ZIP UNIX (new) + 0xa220 Microsoft Open Packaging Growth Hint + 0xfd4a SMS/QDOS + + Detailed descriptions of Extra Fields defined by third + party mappings will be documented as information on + these data structures is made available to PKWARE. + PKWARE does not guarantee the accuracy of any published + third party data. + + The Data Size field indicates the size of the following + data block. Programs can use this value to skip to the + next header block, passing over any data blocks that are + not of interest. + + Note: As stated above, the size of the entire .ZIP file + header, including the file name, comment, and extra + field should not exceed 64K in size. + + In case two different programs should appropriate the same + Header ID value, it is strongly recommended that each + program place a unique signature of at least two bytes in + size (and preferably 4 bytes or bigger) at the start of + each data area. Every program should verify that its + unique signature is present, in addition to the Header ID + value being correct, before assuming that it is a block of + known type. + + -Zip64 Extended Information Extra Field (0x0001): + + The following is the layout of the zip64 extended + information "extra" block. If one of the size or + offset fields in the Local or Central directory + record is too small to hold the required data, + a Zip64 extended information record is created. + The order of the fields in the zip64 extended + information record is fixed, but the fields will + only appear if the corresponding Local or Central + directory record field is set to 0xFFFF or 0xFFFFFFFF. + + Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + (ZIP64) 0x0001 2 bytes Tag for this "extra" block type + Size 2 bytes Size of this "extra" block + Original + Size 8 bytes Original uncompressed file size + Compressed + Size 8 bytes Size of compressed data + Relative Header + Offset 8 bytes Offset of local header record + Disk Start + Number 4 bytes Number of the disk on which + this file starts + + This entry in the Local header must include BOTH original + and compressed file size fields. If encrypting the + central directory and bit 13 of the general purpose bit + flag is set indicating masking, the value stored in the + Local Header for the original file size will be zero. + + + -OS/2 Extra Field (0x0009): + + The following is the layout of the OS/2 attributes "extra" + block. (Last Revision 09/05/95) + + Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + (OS/2) 0x0009 2 bytes Tag for this "extra" block type + TSize 2 bytes Size for the following data block + BSize 4 bytes Uncompressed Block Size + CType 2 bytes Compression type + EACRC 4 bytes CRC value for uncompress block + (var) variable Compressed block + + The OS/2 extended attribute structure (FEA2LIST) is + compressed and then stored in it's entirety within this + structure. There will only ever be one "block" of data in + VarFields[]. + + -NTFS Extra Field (0x000a): + + The following is the layout of the NTFS attributes + "extra" block. (Note: At this time the Mtime, Atime + and Ctime values may be used on any WIN32 system.) + + Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + (NTFS) 0x000a 2 bytes Tag for this "extra" block type + TSize 2 bytes Size of the total "extra" block + Reserved 4 bytes Reserved for future use + Tag1 2 bytes NTFS attribute tag value #1 + Size1 2 bytes Size of attribute #1, in bytes + (var.) Size1 Attribute #1 data + . + . + . + TagN 2 bytes NTFS attribute tag value #N + SizeN 2 bytes Size of attribute #N, in bytes + (var.) SizeN Attribute #N data + + For NTFS, values for Tag1 through TagN are as follows: + (currently only one set of attributes is defined for NTFS) + + Tag Size Description + ----- ---- ----------- + 0x0001 2 bytes Tag for attribute #1 + Size1 2 bytes Size of attribute #1, in bytes + Mtime 8 bytes File last modification time + Atime 8 bytes File last access time + Ctime 8 bytes File creation time + + -OpenVMS Extra Field (0x000c): + + The following is the layout of the OpenVMS attributes + "extra" block. + + Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + (VMS) 0x000c 2 bytes Tag for this "extra" block type + TSize 2 bytes Size of the total "extra" block + CRC 4 bytes 32-bit CRC for remainder of the block + Tag1 2 bytes OpenVMS attribute tag value #1 + Size1 2 bytes Size of attribute #1, in bytes + (var.) Size1 Attribute #1 data + . + . + . + TagN 2 bytes OpenVMS attribute tag value #N + SizeN 2 bytes Size of attribute #N, in bytes + (var.) SizeN Attribute #N data + + Rules: + + 1. There will be one or more of attributes present, which + will each be preceded by the above TagX & SizeX values. + These values are identical to the ATR$C_XXXX and + ATR$S_XXXX constants which are defined in ATR.H under + OpenVMS C. Neither of these values will ever be zero. + + 2. No word alignment or padding is performed. + + 3. A well-behaved PKZIP/OpenVMS program should never produce + more than one sub-block with the same TagX value. Also, + there will never be more than one "extra" block of type + 0x000c in a particular directory record. + + -UNIX Extra Field (0x000d): + + The following is the layout of the UNIX "extra" block. + Note: all fields are stored in Intel low-byte/high-byte + order. + + Value Size Description + ----- ---- ----------- + (UNIX) 0x000d 2 bytes Tag for this "extra" block type + TSize 2 bytes Size for the following data block + Atime 4 bytes File last access time + Mtime 4 bytes File last modification time + Uid 2 bytes File user ID + Gid 2 bytes File group ID + (var) variable Variable length data field + + The variable length data field will contain file type + specific data. Currently the only values allowed are + the original "linked to" file names for hard or symbolic + links, and the major and minor device node numbers for + character and block device nodes. Since device nodes + cannot be either symbolic or hard links, only one set of + variable length data is stored. Link files will have the + name of the original file stored. This name is NOT NULL + terminated. Its size can be determined by checking TSize - + 12. Device entries will have eight bytes stored as two 4 + byte entries (in little endian format). The first entry + will be the major device number, and the second the minor + device number. + + -PATCH Descriptor Extra Field (0x000f): + + The following is the layout of the Patch Descriptor "extra" + block. + + Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + (Patch) 0x000f 2 bytes Tag for this "extra" block type + TSize 2 bytes Size of the total "extra" block + Version 2 bytes Version of the descriptor + Flags 4 bytes Actions and reactions (see below) + OldSize 4 bytes Size of the file about to be patched + OldCRC 4 bytes 32-bit CRC of the file to be patched + NewSize 4 bytes Size of the resulting file + NewCRC 4 bytes 32-bit CRC of the resulting file + + Actions and reactions + + Bits Description + ---- ---------------- + 0 Use for auto detection + 1 Treat as a self-patch + 2-3 RESERVED + 4-5 Action (see below) + 6-7 RESERVED + 8-9 Reaction (see below) to absent file + 10-11 Reaction (see below) to newer file + 12-13 Reaction (see below) to unknown file + 14-15 RESERVED + 16-31 RESERVED + + Actions + + Action Value + ------ ----- + none 0 + add 1 + delete 2 + patch 3 + + Reactions + + Reaction Value + -------- ----- + ask 0 + skip 1 + ignore 2 + fail 3 + + Patch support is provided by PKPatchMaker(tm) technology and is + covered under U.S. Patents and Patents Pending. The use or + implementation in a product of certain technological aspects set + forth in the current APPNOTE, including those with regard to + strong encryption, patching, or extended tape operations requires + a license from PKWARE. Please contact PKWARE with regard to + acquiring a license. + + -PKCS#7 Store for X.509 Certificates (0x0014): + + This field contains information about each of the certificates + files may be signed with. When the Central Directory Encryption + feature is enabled for a ZIP file, this record will appear in + the Archive Extra Data Record, otherwise it will appear in the + first central directory record and will be ignored in any + other record. + + Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + (Store) 0x0014 2 bytes Tag for this "extra" block type + TSize 2 bytes Size of the store data + TData TSize Data about the store + + + -X.509 Certificate ID and Signature for individual file (0x0015): + + This field contains the information about which certificate in + the PKCS#7 store was used to sign a particular file. It also + contains the signature data. This field can appear multiple + times, but can only appear once per certificate. + + Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + (CID) 0x0015 2 bytes Tag for this "extra" block type + TSize 2 bytes Size of data that follows + TData TSize Signature Data + + -X.509 Certificate ID and Signature for central directory (0x0016): + + This field contains the information about which certificate in + the PKCS#7 store was used to sign the central directory structure. + When the Central Directory Encryption feature is enabled for a + ZIP file, this record will appear in the Archive Extra Data Record, + otherwise it will appear in the first central directory record. + + Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + (CDID) 0x0016 2 bytes Tag for this "extra" block type + TSize 2 bytes Size of data that follows + TData TSize Data + + -Strong Encryption Header (0x0017): + + Value Size Description + ----- ---- ----------- + 0x0017 2 bytes Tag for this "extra" block type + TSize 2 bytes Size of data that follows + Format 2 bytes Format definition for this record + AlgID 2 bytes Encryption algorithm identifier + Bitlen 2 bytes Bit length of encryption key + Flags 2 bytes Processing flags + CertData TSize-8 Certificate decryption extra field data + (refer to the explanation for CertData + in the section describing the + Certificate Processing Method under + the Strong Encryption Specification) + + + -Record Management Controls (0x0018): + + Value Size Description + ----- ---- ----------- +(Rec-CTL) 0x0018 2 bytes Tag for this "extra" block type + CSize 2 bytes Size of total extra block data + Tag1 2 bytes Record control attribute 1 + Size1 2 bytes Size of attribute 1, in bytes + Data1 Size1 Attribute 1 data + . + . + . + TagN 2 bytes Record control attribute N + SizeN 2 bytes Size of attribute N, in bytes + DataN SizeN Attribute N data + + + -PKCS#7 Encryption Recipient Certificate List (0x0019): + + This field contains information about each of the certificates + used in encryption processing and it can be used to identify who is + allowed to decrypt encrypted files. This field should only appear + in the archive extra data record. This field is not required and + serves only to aide archive modifications by preserving public + encryption key data. Individual security requirements may dictate + that this data be omitted to deter information exposure. + + Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + (CStore) 0x0019 2 bytes Tag for this "extra" block type + TSize 2 bytes Size of the store data + TData TSize Data about the store + + TData: + + Value Size Description + ----- ---- ----------- + Version 2 bytes Format version number - must 0x0001 at this time + CStore (var) PKCS#7 data blob + + + -MVS Extra Field (0x0065): + + The following is the layout of the MVS "extra" block. + Note: Some fields are stored in Big Endian format. + All text is in EBCDIC format unless otherwise specified. + + Value Size Description + ----- ---- ----------- + (MVS) 0x0065 2 bytes Tag for this "extra" block type + TSize 2 bytes Size for the following data block + ID 4 bytes EBCDIC "Z390" 0xE9F3F9F0 or + "T4MV" for TargetFour + (var) TSize-4 Attribute data (see APPENDIX B) + + + -OS/400 Extra Field (0x0065): + + The following is the layout of the OS/400 "extra" block. + Note: Some fields are stored in Big Endian format. + All text is in EBCDIC format unless otherwise specified. + + Value Size Description + ----- ---- ----------- + (OS400) 0x0065 2 bytes Tag for this "extra" block type + TSize 2 bytes Size for the following data block + ID 4 bytes EBCDIC "I400" 0xC9F4F0F0 or + "T4MV" for TargetFour + (var) TSize-4 Attribute data (see APPENDIX A) + + + Third-party Mappings: + + -ZipIt Macintosh Extra Field (long) (0x2605): + + The following is the layout of the ZipIt extra block + for Macintosh. The local-header and central-header versions + are identical. This block must be present if the file is + stored MacBinary-encoded and it should not be used if the file + is not stored MacBinary-encoded. + + Value Size Description + ----- ---- ----------- + (Mac2) 0x2605 Short tag for this extra block type + TSize Short total data size for this block + "ZPIT" beLong extra-field signature + FnLen Byte length of FileName + FileName variable full Macintosh filename + FileType Byte[4] four-byte Mac file type string + Creator Byte[4] four-byte Mac creator string + + + -ZipIt Macintosh Extra Field (short, for files) (0x2705): + + The following is the layout of a shortened variant of the + ZipIt extra block for Macintosh (without "full name" entry). + This variant is used by ZipIt 1.3.5 and newer for entries of + files (not directories) that do not have a MacBinary encoded + file. The local-header and central-header versions are identical. + + Value Size Description + ----- ---- ----------- + (Mac2b) 0x2705 Short tag for this extra block type + TSize Short total data size for this block (12) + "ZPIT" beLong extra-field signature + FileType Byte[4] four-byte Mac file type string + Creator Byte[4] four-byte Mac creator string + fdFlags beShort attributes from FInfo.frFlags, + may be omitted + 0x0000 beShort reserved, may be omitted + + + -ZipIt Macintosh Extra Field (short, for directories) (0x2805): + + The following is the layout of a shortened variant of the + ZipIt extra block for Macintosh used only for directory + entries. This variant is used by ZipIt 1.3.5 and newer to + save some optional Mac-specific information about directories. + The local-header and central-header versions are identical. + + Value Size Description + ----- ---- ----------- + (Mac2c) 0x2805 Short tag for this extra block type + TSize Short total data size for this block (12) + "ZPIT" beLong extra-field signature + frFlags beShort attributes from DInfo.frFlags, may + be omitted + View beShort ZipIt view flag, may be omitted + + + The View field specifies ZipIt-internal settings as follows: + + Bits of the Flags: + bit 0 if set, the folder is shown expanded (open) + when the archive contents are viewed in ZipIt. + bits 1-15 reserved, zero; + + + -FWKCS MD5 Extra Field (0x4b46): + + The FWKCS Contents_Signature System, used in + automatically identifying files independent of file name, + optionally adds and uses an extra field to support the + rapid creation of an enhanced contents_signature: + + Header ID = 0x4b46 + Data Size = 0x0013 + Preface = 'M','D','5' + followed by 16 bytes containing the uncompressed file's + 128_bit MD5 hash(1), low byte first. + + When FWKCS revises a .ZIP file central directory to add + this extra field for a file, it also replaces the + central directory entry for that file's uncompressed + file length with a measured value. + + FWKCS provides an option to strip this extra field, if + present, from a .ZIP file central directory. In adding + this extra field, FWKCS preserves .ZIP file Authenticity + Verification; if stripping this extra field, FWKCS + preserves all versions of AV through PKZIP version 2.04g. + + FWKCS, and FWKCS Contents_Signature System, are + trademarks of Frederick W. Kantor. + + (1) R. Rivest, RFC1321.TXT, MIT Laboratory for Computer + Science and RSA Data Security, Inc., April 1992. + ll.76-77: "The MD5 algorithm is being placed in the + public domain for review and possible adoption as a + standard." + + + -Info-ZIP Unicode Comment Extra Field (0x6375): + + Stores the UTF-8 version of the file comment as stored in the + central directory header. (Last Revision 20070912) + + Value Size Description + ----- ---- ----------- + (UCom) 0x6375 Short tag for this extra block type ("uc") + TSize Short total data size for this block + Version 1 byte version of this extra field, currently 1 + ComCRC32 4 bytes Comment Field CRC32 Checksum + UnicodeCom Variable UTF-8 version of the entry comment + + Currently Version is set to the number 1. If there is a need + to change this field, the version will be incremented. Changes + may not be backward compatible so this extra field should not be + used if the version is not recognized. + + The ComCRC32 is the standard zip CRC32 checksum of the File Comment + field in the central directory header. This is used to verify that + the comment field has not changed since the Unicode Comment extra field + was created. This can happen if a utility changes the File Comment + field but does not update the UTF-8 Comment extra field. If the CRC + check fails, this Unicode Comment extra field should be ignored and + the File Comment field in the header should be used instead. + + The UnicodeCom field is the UTF-8 version of the File Comment field + in the header. As UnicodeCom is defined to be UTF-8, no UTF-8 byte + order mark (BOM) is used. The length of this field is determined by + subtracting the size of the previous fields from TSize. If both the + File Name and Comment fields are UTF-8, the new General Purpose Bit + Flag, bit 11 (Language encoding flag (EFS)), can be used to indicate + both the header File Name and Comment fields are UTF-8 and, in this + case, the Unicode Path and Unicode Comment extra fields are not + needed and should not be created. Note that, for backward + compatibility, bit 11 should only be used if the native character set + of the paths and comments being zipped up are already in UTF-8. It is + expected that the same file comment storage method, either general + purpose bit 11 or extra fields, be used in both the Local and Central + Directory Header for a file. + + + -Info-ZIP Unicode Path Extra Field (0x7075): + + Stores the UTF-8 version of the file name field as stored in the + local header and central directory header. (Last Revision 20070912) + + Value Size Description + ----- ---- ----------- + (UPath) 0x7075 Short tag for this extra block type ("up") + TSize Short total data size for this block + Version 1 byte version of this extra field, currently 1 + NameCRC32 4 bytes File Name Field CRC32 Checksum + UnicodeName Variable UTF-8 version of the entry File Name + + Currently Version is set to the number 1. If there is a need + to change this field, the version will be incremented. Changes + may not be backward compatible so this extra field should not be + used if the version is not recognized. + + The NameCRC32 is the standard zip CRC32 checksum of the File Name + field in the header. This is used to verify that the header + File Name field has not changed since the Unicode Path extra field + was created. This can happen if a utility renames the File Name but + does not update the UTF-8 path extra field. If the CRC check fails, + this UTF-8 Path Extra Field should be ignored and the File Name field + in the header should be used instead. + + The UnicodeName is the UTF-8 version of the contents of the File Name + field in the header. As UnicodeName is defined to be UTF-8, no UTF-8 + byte order mark (BOM) is used. The length of this field is determined + by subtracting the size of the previous fields from TSize. If both + the File Name and Comment fields are UTF-8, the new General Purpose + Bit Flag, bit 11 (Language encoding flag (EFS)), can be used to + indicate that both the header File Name and Comment fields are UTF-8 + and, in this case, the Unicode Path and Unicode Comment extra fields + are not needed and should not be created. Note that, for backward + compatibility, bit 11 should only be used if the native character set + of the paths and comments being zipped up are already in UTF-8. It is + expected that the same file name storage method, either general + purpose bit 11 or extra fields, be used in both the Local and Central + Directory Header for a file. + + + -Microsoft Open Packaging Growth Hint (0xa220): + + Value Size Description + ----- ---- ----------- + 0xa220 Short tag for this extra block type + TSize Short size of Sig + PadVal + Padding + Sig Short verification signature (A028) + PadVal Short Initial padding value + Padding variable filled with NULL characters + + + file comment: (Variable) + + The comment for this file. + + number of this disk: (2 bytes) + + The number of this disk, which contains central + directory end record. If an archive is in ZIP64 format + and the value in this field is 0xFFFF, the size will + be in the corresponding 4 byte zip64 end of central + directory field. + + + number of the disk with the start of the central + directory: (2 bytes) + + The number of the disk on which the central + directory starts. If an archive is in ZIP64 format + and the value in this field is 0xFFFF, the size will + be in the corresponding 4 byte zip64 end of central + directory field. + + total number of entries in the central dir on + this disk: (2 bytes) + + The number of central directory entries on this disk. + If an archive is in ZIP64 format and the value in + this field is 0xFFFF, the size will be in the + corresponding 8 byte zip64 end of central + directory field. + + total number of entries in the central dir: (2 bytes) + + The total number of files in the .ZIP file. If an + archive is in ZIP64 format and the value in this field + is 0xFFFF, the size will be in the corresponding 8 byte + zip64 end of central directory field. + + size of the central directory: (4 bytes) + + The size (in bytes) of the entire central directory. + If an archive is in ZIP64 format and the value in + this field is 0xFFFFFFFF, the size will be in the + corresponding 8 byte zip64 end of central + directory field. + + offset of start of central directory with respect to + the starting disk number: (4 bytes) + + Offset of the start of the central directory on the + disk on which the central directory starts. If an + archive is in ZIP64 format and the value in this + field is 0xFFFFFFFF, the size will be in the + corresponding 8 byte zip64 end of central + directory field. + + .ZIP file comment length: (2 bytes) + + The length of the comment for this .ZIP file. + + .ZIP file comment: (Variable) + + The comment for this .ZIP file. ZIP file comment data + is stored unsecured. No encryption or data authentication + is applied to this area at this time. Confidential information + should not be stored in this section. + + zip64 extensible data sector (variable size) + + (currently reserved for use by PKWARE) + + + K. Splitting and Spanning ZIP files + + Spanning is the process of segmenting a ZIP file across + multiple removable media. This support has typically only + been provided for DOS formatted floppy diskettes. + + File splitting is a newer derivative of spanning. + Splitting follows the same segmentation process as + spanning, however, it does not require writing each + segment to a unique removable medium and instead supports + placing all pieces onto local or non-removable locations + such as file systems, local drives, folders, etc... + + A key difference between spanned and split ZIP files is + that all pieces of a spanned ZIP file have the same name. + Since each piece is written to a separate volume, no name + collisions occur and each segment can reuse the original + .ZIP file name given to the archive. + + Sequence ordering for DOS spanned archives uses the DOS + volume label to determine segment numbers. Volume labels + for each segment are written using the form PKBACK#xxx, + where xxx is the segment number written as a decimal + value from 001 - nnn. + + Split ZIP files are typically written to the same location + and are subject to name collisions if the spanned name + format is used since each segment will reside on the same + drive. To avoid name collisions, split archives are named + as follows. + + Segment 1 = filename.z01 + Segment n-1 = filename.z(n-1) + Segment n = filename.zip + + The .ZIP extension is used on the last segment to support + quickly reading the central directory. The segment number + n should be a decimal value. + + Spanned ZIP files may be PKSFX Self-extracting ZIP files. + PKSFX files may also be split, however, in this case + the first segment must be named filename.exe. The first + segment of a split PKSFX archive must be large enough to + include the entire executable program. + + Capacities for split archives are as follows. + + Maximum number of segments = 4,294,967,295 - 1 + Maximum .ZIP segment size = 4,294,967,295 bytes + Minimum segment size = 64K + Maximum PKSFX segment size = 2,147,483,647 bytes + + Segment sizes may be different however by convention, all + segment sizes should be the same with the exception of the + last, which may be smaller. Local and central directory + header records must never be split across a segment boundary. + When writing a header record, if the number of bytes remaining + within a segment is less than the size of the header record, + end the current segment and write the header at the start + of the next segment. The central directory may span segment + boundaries, but no single record in the central directory + should be split across segments. + + Spanned/Split archives created using PKZIP for Windows + (V2.50 or greater), PKZIP Command Line (V2.50 or greater), + or PKZIP Explorer will include a special spanning + signature as the first 4 bytes of the first segment of + the archive. This signature (0x08074b50) will be + followed immediately by the local header signature for + the first file in the archive. + + A special spanning marker may also appear in spanned/split + archives if the spanning or splitting process starts but + only requires one segment. In this case the 0x08074b50 + signature will be replaced with the temporary spanning + marker signature of 0x30304b50. Split archives can + only be uncompressed by other versions of PKZIP that + know how to create a split archive. + + The signature value 0x08074b50 is also used by some + ZIP implementations as a marker for the Data Descriptor + record. Conflict in this alternate assignment can be + avoided by ensuring the position of the signature + within the ZIP file to determine the use for which it + is intended. + + L. General notes: + + 1) All fields unless otherwise noted are unsigned and stored + in Intel low-byte:high-byte, low-word:high-word order. + + 2) String fields are not null terminated, since the + length is given explicitly. + + 3) The entries in the central directory may not necessarily + be in the same order that files appear in the .ZIP file. + + 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. + +VI. Explanation of compression methods +-------------------------------------- + +UnShrinking - Method 1 +---------------------- + +Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm +with partial clearing. The initial code size is 9 bits, and +the maximum code size is 13 bits. Shrinking differs from +conventional Dynamic Ziv-Lempel-Welch implementations in several +respects: + +1) The code size is controlled by the compressor, and is not + automatically increased when codes larger than the current + code size are created (but not necessarily used). When + the decompressor encounters the code sequence 256 + (decimal) followed by 1, it should increase the code size + read from the input stream to the next bit size. No + blocking of the codes is performed, so the next code at + the increased size should be read from the input stream + immediately after where the previous code at the smaller + bit size was read. Again, the decompressor should not + increase the code size used until the sequence 256,1 is + encountered. + +2) When the table becomes full, total clearing is not + performed. Rather, when the compressor emits the code + sequence 256,2 (decimal), the decompressor should clear + all leaf nodes from the Ziv-Lempel tree, and continue to + use the current code size. The nodes that are cleared + from the Ziv-Lempel tree are then re-used, with the lowest + code value re-used first, and the highest code value + re-used last. The compressor can emit the sequence 256,2 + at any time. + +Expanding - Methods 2-5 +----------------------- + +The Reducing algorithm is actually a combination of two +distinct algorithms. The first algorithm compresses repeated +byte sequences, and the second algorithm takes the compressed +stream from the first algorithm and applies a probabilistic +compression method. + +The probabilistic compression stores an array of 'follower +sets' S(j), for j=0 to 255, corresponding to each possible +ASCII character. Each set contains between 0 and 32 +characters, to be denoted as S(j)[0],...,S(j)[m], where m<32. +The sets are stored at the beginning of the data area for a +Reduced file, in reverse order, with S(255) first, and S(0) +last. + +The sets are encoded as { N(j), S(j)[0],...,S(j)[N(j)-1] }, +where N(j) is the size of set S(j). N(j) can be 0, in which +case the follower set for S(j) is empty. Each N(j) value is +encoded in 6 bits, followed by N(j) eight bit character values +corresponding to S(j)[0] to S(j)[N(j)-1] respectively. If +N(j) is 0, then no values for S(j) are stored, and the value +for N(j-1) immediately follows. + +Immediately after the follower sets, is the compressed data +stream. The compressed data stream can be interpreted for the +probabilistic decompression as follows: + +let Last-Character <- 0. +loop until done + if the follower set S(Last-Character) is empty then + read 8 bits from the input stream, and copy this + value to the output stream. + otherwise if the follower set S(Last-Character) is non-empty then + read 1 bit from the input stream. + if this bit is not zero then + read 8 bits from the input stream, and copy this + value to the output stream. + otherwise if this bit is zero then + read B(N(Last-Character)) bits from the input + stream, and assign this value to I. + Copy the value of S(Last-Character)[I] to the + output stream. + + assign the last value placed on the output stream to + Last-Character. +end loop + +B(N(j)) is defined as the minimal number of bits required to +encode the value N(j)-1. + +The decompressed stream from above can then be expanded to +re-create the original file as follows: + +let State <- 0. + +loop until done + read 8 bits from the input stream into C. + case State of + 0: if C is not equal to DLE (144 decimal) then + copy C to the output stream. + otherwise if C is equal to DLE then + let State <- 1. + + 1: if C is non-zero then + let V <- C. + let Len <- L(V) + let State <- F(Len). + otherwise if C is zero then + copy the value 144 (decimal) to the output stream. + let State <- 0 + + 2: let Len <- Len + C + let State <- 3. + + 3: move backwards D(V,C) bytes in the output stream + (if this position is before the start of the output + stream, then assume that all the data before the + start of the output stream is filled with zeros). + copy Len+3 bytes from this position to the output stream. + let State <- 0. + end case +end loop + +The functions F,L, and D are dependent on the 'compression +factor', 1 through 4, and are defined as follows: + +For compression factor 1: + L(X) equals the lower 7 bits of X. + F(X) equals 2 if X equals 127 otherwise F(X) equals 3. + D(X,Y) equals the (upper 1 bit of X) * 256 + Y + 1. +For compression factor 2: + L(X) equals the lower 6 bits of X. + F(X) equals 2 if X equals 63 otherwise F(X) equals 3. + D(X,Y) equals the (upper 2 bits of X) * 256 + Y + 1. +For compression factor 3: + L(X) equals the lower 5 bits of X. + F(X) equals 2 if X equals 31 otherwise F(X) equals 3. + D(X,Y) equals the (upper 3 bits of X) * 256 + Y + 1. +For compression factor 4: + L(X) equals the lower 4 bits of X. + F(X) equals 2 if X equals 15 otherwise F(X) equals 3. + D(X,Y) equals the (upper 4 bits of X) * 256 + Y + 1. + +Imploding - Method 6 +-------------------- + +The Imploding algorithm is actually a combination of two distinct +algorithms. The first algorithm compresses repeated byte +sequences using a sliding dictionary. The second algorithm is +used to compress the encoding of the sliding dictionary output, +using multiple Shannon-Fano trees. + +The Imploding algorithm can use a 4K or 8K sliding dictionary +size. The dictionary size used can be determined by bit 1 in the +general purpose flag word; a 0 bit indicates a 4K dictionary +while a 1 bit indicates an 8K dictionary. + +The Shannon-Fano trees are stored at the start of the compressed +file. The number of trees stored is defined by bit 2 in the +general purpose flag word; a 0 bit indicates two trees stored, a +1 bit indicates three trees are stored. If 3 trees are stored, +the first Shannon-Fano tree represents the encoding of the +Literal characters, the second tree represents the encoding of +the Length information, the third represents the encoding of the +Distance information. When 2 Shannon-Fano trees are stored, the +Length tree is stored first, followed by the Distance tree. + +The Literal Shannon-Fano tree, if present is used to represent +the entire ASCII character set, and contains 256 values. This +tree is used to compress any data not compressed by the sliding +dictionary algorithm. When this tree is present, the Minimum +Match Length for the sliding dictionary is 3. If this tree is +not present, the Minimum Match Length is 2. + +The Length Shannon-Fano tree is used to compress the Length part +of the (length,distance) pairs from the sliding dictionary +output. The Length tree contains 64 values, ranging from the +Minimum Match Length, to 63 plus the Minimum Match Length. + +The Distance Shannon-Fano tree is used to compress the Distance +part of the (length,distance) pairs from the sliding dictionary +output. The Distance tree contains 64 values, ranging from 0 to +63, representing the upper 6 bits of the distance value. The +distance values themselves will be between 0 and the sliding +dictionary size, either 4K or 8K. + +The Shannon-Fano trees themselves are stored in a compressed +format. The first byte of the tree data represents the number of +bytes of data representing the (compressed) Shannon-Fano tree +minus 1. The remaining bytes represent the Shannon-Fano tree +data encoded as: + + High 4 bits: Number of values at this bit length + 1. (1 - 16) + Low 4 bits: Bit Length needed to represent value + 1. (1 - 16) + +The Shannon-Fano codes can be constructed from the bit lengths +using the following algorithm: + +1) Sort the Bit Lengths in ascending order, while retaining the + order of the original lengths stored in the file. + +2) Generate the Shannon-Fano trees: + + Code <- 0 + CodeIncrement <- 0 + LastBitLength <- 0 + i <- number of Shannon-Fano codes - 1 (either 255 or 63) + + loop while i >= 0 + Code = Code + CodeIncrement + if BitLength(i) <> LastBitLength then + LastBitLength=BitLength(i) + CodeIncrement = 1 shifted left (16 - LastBitLength) + ShannonCode(i) = Code + i <- i - 1 + end loop + +3) Reverse the order of all the bits in the above ShannonCode() + vector, so that the most significant bit becomes the least + significant bit. For example, the value 0x1234 (hex) would + become 0x2C48 (hex). + +4) Restore the order of Shannon-Fano codes as originally stored + within the file. + +Example: + + This example will show the encoding of a Shannon-Fano tree + of size 8. Notice that the actual Shannon-Fano trees used + for Imploding are either 64 or 256 entries in size. + +Example: 0x02, 0x42, 0x01, 0x13 + + The first byte indicates 3 values in this table. Decoding the + bytes: + 0x42 = 5 codes of 3 bits long + 0x01 = 1 code of 2 bits long + 0x13 = 2 codes of 4 bits long + + This would generate the original bit length array of: + (3, 3, 3, 3, 3, 2, 4, 4) + + There are 8 codes in this table for the values 0 thru 7. Using + the algorithm to obtain the Shannon-Fano codes produces: + + Reversed Order Original +Val Sorted Constructed Code Value Restored Length +--- ------ ----------------- -------- -------- ------ +0: 2 1100000000000000 11 101 3 +1: 3 1010000000000000 101 001 3 +2: 3 1000000000000000 001 110 3 +3: 3 0110000000000000 110 010 3 +4: 3 0100000000000000 010 100 3 +5: 3 0010000000000000 100 11 2 +6: 4 0001000000000000 1000 1000 4 +7: 4 0000000000000000 0000 0000 4 + +The values in the Val, Order Restored and Original Length columns +now represent the Shannon-Fano encoding tree that can be used for +decoding the Shannon-Fano encoded data. How to parse the +variable length Shannon-Fano values from the data stream is beyond +the scope of this document. (See the references listed at the end of +this document for more information.) However, traditional decoding +schemes used for Huffman variable length decoding, such as the +Greenlaw algorithm, can be successfully applied. + +The compressed data stream begins immediately after the +compressed Shannon-Fano data. The compressed data stream can be +interpreted as follows: + +loop until done + read 1 bit from input stream. + + if this bit is non-zero then (encoded data is literal data) + if Literal Shannon-Fano tree is present + read and decode character using Literal Shannon-Fano tree. + otherwise + read 8 bits from input stream. + copy character to the output stream. + otherwise (encoded data is sliding dictionary match) + if 8K dictionary size + read 7 bits for offset Distance (lower 7 bits of offset). + otherwise + read 6 bits for offset Distance (lower 6 bits of offset). + + using the Distance Shannon-Fano tree, read and decode the + upper 6 bits of the Distance value. + + using the Length Shannon-Fano tree, read and decode + the Length value. + + Length <- Length + Minimum Match Length + + if Length = 63 + Minimum Match Length + read 8 bits from the input stream, + add this value to Length. + + move backwards Distance+1 bytes in the output stream, and + copy Length characters from this position to the output + stream. (if this position is before the start of the output + stream, then assume that all the data before the start of + the output stream is filled with zeros). +end loop + +Tokenizing - Method 7 +--------------------- + +This method is not used by PKZIP. + +Deflating - Method 8 +-------------------- + +The Deflate algorithm is similar to the Implode algorithm using +a sliding dictionary of up to 32K with secondary compression +from Huffman/Shannon-Fano codes. + +The compressed data is stored in blocks with a header describing +the block and the Huffman codes used in the data block. The header +format is as follows: + + Bit 0: Last Block bit This bit is set to 1 if this is the last + compressed block in the data. + Bits 1-2: Block type + 00 (0) - Block is stored - All stored data is byte aligned. + Skip bits until next byte, then next word = block + length, followed by the ones compliment of the block + length word. Remaining data in block is the stored + data. + + 01 (1) - Use fixed Huffman codes for literal and distance codes. + Lit Code Bits Dist Code Bits + --------- ---- --------- ---- + 0 - 143 8 0 - 31 5 + 144 - 255 9 + 256 - 279 7 + 280 - 287 8 + + Literal codes 286-287 and distance codes 30-31 are + never used but participate in the huffman construction. + + 10 (2) - Dynamic Huffman codes. (See expanding Huffman codes) + + 11 (3) - Reserved - Flag a "Error in compressed data" if seen. + +Expanding Huffman Codes +----------------------- +If the data block is stored with dynamic Huffman codes, the Huffman +codes are sent in the following compressed format: + + 5 Bits: # of Literal codes sent - 256 (256 - 286) + All other codes are never sent. + 5 Bits: # of Dist codes - 1 (1 - 32) + 4 Bits: # of Bit Length codes - 3 (3 - 19) + +The Huffman codes are sent as bit lengths and the codes are built as +described in the implode algorithm. The bit lengths themselves are +compressed with Huffman codes. There are 19 bit length codes: + + 0 - 15: Represent bit lengths of 0 - 15 + 16: Copy the previous bit length 3 - 6 times. + The next 2 bits indicate repeat length (0 = 3, ... ,3 = 6) + Example: Codes 8, 16 (+2 bits 11), 16 (+2 bits 10) will + expand to 12 bit lengths of 8 (1 + 6 + 5) + 17: Repeat a bit length of 0 for 3 - 10 times. (3 bits of length) + 18: Repeat a bit length of 0 for 11 - 138 times (7 bits of length) + +The lengths of the bit length codes are sent packed 3 bits per value +(0 - 7) in the following order: + + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + +The Huffman codes should be built as described in the Implode algorithm +except codes are assigned starting at the shortest bit length, i.e. the +shortest code should be all 0's rather than all 1's. Also, codes with +a bit length of zero do not participate in the tree construction. The +codes are then used to decode the bit lengths for the literal and +distance tables. + +The bit lengths for the literal tables are sent first with the number +of entries sent described by the 5 bits sent earlier. There are up +to 286 literal characters; the first 256 represent the respective 8 +bit character, code 256 represents the End-Of-Block code, the remaining +29 codes represent copy lengths of 3 thru 258. There are up to 30 +distance codes representing distances from 1 thru 32k as described +below. + + Length Codes + ------------ + Extra Extra Extra Extra + Code Bits Length Code Bits Lengths Code Bits Lengths Code Bits Length(s) + ---- ---- ------ ---- ---- ------- ---- ---- ------- ---- ---- --------- + 257 0 3 265 1 11,12 273 3 35-42 281 5 131-162 + 258 0 4 266 1 13,14 274 3 43-50 282 5 163-194 + 259 0 5 267 1 15,16 275 3 51-58 283 5 195-226 + 260 0 6 268 1 17,18 276 3 59-66 284 5 227-257 + 261 0 7 269 2 19-22 277 4 67-82 285 0 258 + 262 0 8 270 2 23-26 278 4 83-98 + 263 0 9 271 2 27-30 279 4 99-114 + 264 0 10 272 2 31-34 280 4 115-130 + + Distance Codes + -------------- + Extra Extra Extra Extra + Code Bits Dist Code Bits Dist Code Bits Distance Code Bits Distance + ---- ---- ---- ---- ---- ------ ---- ---- -------- ---- ---- -------- + 0 0 1 8 3 17-24 16 7 257-384 24 11 4097-6144 + 1 0 2 9 3 25-32 17 7 385-512 25 11 6145-8192 + 2 0 3 10 4 33-48 18 8 513-768 26 12 8193-12288 + 3 0 4 11 4 49-64 19 8 769-1024 27 12 12289-16384 + 4 1 5,6 12 5 65-96 20 9 1025-1536 28 13 16385-24576 + 5 1 7,8 13 5 97-128 21 9 1537-2048 29 13 24577-32768 + 6 2 9-12 14 6 129-192 22 10 2049-3072 + 7 2 13-16 15 6 193-256 23 10 3073-4096 + +The compressed data stream begins immediately after the +compressed header data. The compressed data stream can be +interpreted as follows: + +do + read header from input stream. + + if stored block + skip bits until byte aligned + read count and 1's compliment of count + copy count bytes data block + otherwise + loop until end of block code sent + decode literal character from input stream + if literal < 256 + copy character to the output stream + otherwise + if literal = end of block + break from loop + otherwise + decode distance from input stream + + move backwards distance bytes in the output stream, and + copy length characters from this position to the output + stream. + end loop +while not last block + +if data descriptor exists + skip bits until byte aligned + read crc and sizes +endif + +Enhanced Deflating - Method 9 +----------------------------- + +The Enhanced Deflating algorithm is similar to Deflate but +uses a sliding dictionary of up to 64K. Deflate64(tm) is supported +by the Deflate extractor. + +BZIP2 - Method 12 +----------------- + +BZIP2 is an open-source data compression algorithm developed by +Julian Seward. Information and source code for this algorithm +can be found on the internet. + +LZMA - Method 14 (EFS) +---------------------- + +LZMA is a block-oriented, general purpose data compression algorithm +developed and maintained by Igor Pavlov. It is a derivative of LZ77 +that utilizes Markov chains and a range coder. Information and +source code for this algorithm can be found on the internet. Consult +with the author of this algorithm for information on terms or +restrictions on use. + +Support for LZMA within the ZIP format is defined as follows: + +The Compression method field within the ZIP Local and Central +Header records will be set to the value 14 to indicate data was +compressed using LZMA. + +The Version needed to extract field within the ZIP Local and +Central Header records will be set to 6.3 to indicate the +minimum ZIP format version supporting this feature. + +File data compressed using the LZMA algorithm must be placed +immediately following the Local Header for the file. If a +standard ZIP encryption header is required, it will follow +the Local Header and will precede the LZMA compressed file +data segment. The location of LZMA compressed data segment +within the ZIP format will be as shown: + + [local header file 1] + [encryption header file 1] + [LZMA compressed data segment for file 1] + [data descriptor 1] + [local header file 2] + +The encryption header and data descriptor records may +be conditionally present. The LZMA Compressed Data Segment +will consist of an LZMA Properties Header followed by the +LZMA Compressed Data as shown: + + [LZMA properties header for file 1] + [LZMA compressed data for file 1] + +The LZMA Compressed Data will be stored as provided by the +LZMA compression library. Compressed size, uncompressed +size and other file characteristics about the file being +compressed must be stored in standard ZIP storage format. + +The LZMA Properties Header will store specific data required to +decompress the LZMA compressed Data. This data is set by the +LZMA compression engine using the function WriteCoderProperties() +as documented within the LZMA SDK. + +Storage fields for the property information within the LZMA +Properties Header are as follows: + + LZMA Version Information 2 bytes + LZMA Properties Size 2 bytes + LZMA Properties Data variable, defined by "LZMA Properties Size" + +LZMA Version Information - this field identifies which version of + the LZMA SDK was used to compress a file. The first byte will + store the major version number of the LZMA SDK and the second + byte will store the minor number. + +LZMA Properties Size - this field defines the size of the remaining + property data. Typically this size should be determined by the + version of the SDK. This size field is included as a convenience + and to help avoid any ambiguity should it arise in the future due + to changes in this compression algorithm. + +LZMA Property Data - this variable sized field records the required + values for the decompressor as defined by the LZMA SDK. The + data stored in this field should be obtained using the + WriteCoderProperties() in the version of the SDK defined by + the "LZMA Version Information" field. + +The layout of the "LZMA Properties Data" field is a function of the +LZMA compression algorithm. It is possible that this layout may be +changed by the author over time. The data layout in version 4.32 +of the LZMA SDK defines a 5 byte array that uses 4 bytes to store +the dictionary size in little-endian order. This is preceded by a +single packed byte as the first element of the array that contains +the following fields: + + PosStateBits + LiteralPosStateBits + LiteralContextBits + +Refer to the LZMA documentation for a more detailed explanation of +these fields. + +Data compressed with method 14, LZMA, may include an end-of-stream +(EOS) marker ending the compressed data stream. This marker is not +required, but its use is highly recommended to facilitate processing +and implementers should include the EOS marker whenever possible. +When the EOS marker is used, general purpose bit 1 must be set. If +general purpose bit 1 is not set, the EOS marker is not present. + +WavPack - Method 97 +------------------- + +Information describing the use of compression method 97 is +provided by WinZIP International, LLC. This method relies on the +open source WavPack audio compression utility developed by David Bryant. +Information on WavPack is available at www.wavpack.com. Please consult +with the author of this algorithm for information on terms and +restrictions on use. + +WavPack data for a file begins immediately after the end of the +local header data. This data is the output from WavPack compression +routines. Within the ZIP file, the use of WavPack compression is +indicated by setting the compression method field to a value of 97 +in both the local header and the central directory header. The Version +needed to extract and version made by fields use the same values as are +used for data compressed using the Deflate algorithm. + +An implementation note for storing digital sample data when using +WavPack compression within ZIP files is that all of the bytes of +the sample data should be compressed. This includes any unused +bits up to the byte boundary. An example is a 2 byte sample that +uses only 12 bits for the sample data with 4 unused bits. If only +12 bits are passed as the sample size to the WavPack routines, the 4 +unused bits will be set to 0 on extraction regardless of their original +state. To avoid this, the full 16 bits of the sample data size +should be provided. + +PPMd - Method 98 +---------------- + +PPMd is a data compression algorithm developed by Dmitry Shkarin +which includes a carryless rangecoder developed by Dmitry Subbotin. +This algorithm is based on predictive phrase matching on multiple +order contexts. Information and source code for this algorithm +can be found on the internet. Consult with the author of this +algorithm for information on terms or restrictions on use. + +Support for PPMd within the ZIP format currently is provided only +for version I, revision 1 of the algorithm. Storage requirements +for using this algorithm are as follows: + +Parameters needed to control the algorithm are stored in the two +bytes immediately preceding the compressed data. These bytes are +used to store the following fields: + +Model order - sets the maximum model order, default is 8, possible + values are from 2 to 16 inclusive + +Sub-allocator size - sets the size of sub-allocator in MB, default is 50, + possible values are from 1MB to 256MB inclusive + +Model restoration method - sets the method used to restart context + model at memory insufficiency, values are: + + 0 - restarts model from scratch - default + 1 - cut off model - decreases performance by as much as 2x + 2 - freeze context tree - not recommended + +An example for packing these fields into the 2 byte storage field is +illustrated below. These values are stored in Intel low-byte/high-byte +order. + +wPPMd = (Model order - 1) + + ((Sub-allocator size - 1) << 4) + + (Model restoration method << 12) + + +VII. Traditional PKWARE Encryption +---------------------------------- + +The following information discusses the decryption steps +required to support traditional PKWARE encryption. This +form of encryption is considered weak by today's standards +and its use is recommended only for situations with +low security needs or for compatibility with older .ZIP +applications. + +Decryption +---------- + +PKWARE is grateful to Mr. Roger Schlafly for his expert contribution +towards the development of PKWARE's traditional encryption. + +PKZIP encrypts the compressed data stream. Encrypted files must +be decrypted before they can be extracted. + +Each encrypted file has an extra 12 bytes stored at the start of +the data area defining the encryption header for that file. The +encryption header is originally set to random values, and then +itself encrypted, using three, 32-bit keys. The key values are +initialized using the supplied encryption password. After each byte +is encrypted, the keys are then updated using pseudo-random number +generation techniques in combination with the same CRC-32 algorithm +used in PKZIP and described elsewhere in this document. + +The following is the basic steps required to decrypt a file: + +1) Initialize the three 32-bit keys with the password. +2) Read and decrypt the 12-byte encryption header, further + initializing the encryption keys. +3) Read and decrypt the compressed data stream using the + encryption keys. + +Step 1 - Initializing the encryption keys +----------------------------------------- + +Key(0) <- 305419896 +Key(1) <- 591751049 +Key(2) <- 878082192 + +loop for i <- 0 to length(password)-1 + update_keys(password(i)) +end loop + +Where update_keys() is defined as: + +update_keys(char): + Key(0) <- crc32(key(0),char) + Key(1) <- Key(1) + (Key(0) & 000000ffH) + Key(1) <- Key(1) * 134775813 + 1 + Key(2) <- crc32(key(2),key(1) >> 24) +end update_keys + +Where crc32(old_crc,char) is a routine that given a CRC value and a +character, returns an updated CRC value after applying the CRC-32 +algorithm described elsewhere in this document. + +Step 2 - Decrypting the encryption header +----------------------------------------- + +The purpose of this step is to further initialize the encryption +keys, based on random data, to render a plaintext attack on the +data ineffective. + +Read the 12-byte encryption header into Buffer, in locations +Buffer(0) thru Buffer(11). + +loop for i <- 0 to 11 + C <- buffer(i) ^ decrypt_byte() + update_keys(C) + buffer(i) <- C +end loop + +Where decrypt_byte() is defined as: + +unsigned char decrypt_byte() + local unsigned short temp + temp <- Key(2) | 2 + decrypt_byte <- (temp * (temp ^ 1)) >> 8 +end decrypt_byte + +After the header is decrypted, the last 1 or 2 bytes in Buffer +should be the high-order word/byte of the CRC for the file being +decrypted, stored in Intel low-byte/high-byte order. Versions of +PKZIP prior to 2.0 used a 2 byte CRC check; a 1 byte CRC check is +used on versions after 2.0. This can be used to test if the password +supplied is correct or not. + +Step 3 - Decrypting the compressed data stream +---------------------------------------------- + +The compressed data stream can be decrypted as follows: + +loop until done + read a character into C + Temp <- C ^ decrypt_byte() + update_keys(temp) + output Temp +end loop + + +VIII. Strong Encryption Specification +------------------------------------- + +The Strong Encryption technology defined in this specification is +covered under a pending patent application. The use or implementation +in a product of certain technological aspects set forth in the current +APPNOTE, including those with regard to strong encryption, patching, +or extended tape operations requires a license from PKWARE. Portions +of this Strong Encryption technology are available for use at no charge. +Contact PKWARE for licensing terms and conditions. Refer to section II +of this APPNOTE (Contacting PKWARE) for information on how to +contact PKWARE. + +Version 5.x of this specification introduced support for strong +encryption algorithms. These algorithms can be used with either +a password or an X.509v3 digital certificate to encrypt each file. +This format specification supports either password or certificate +based encryption to meet the security needs of today, to enable +interoperability between users within both PKI and non-PKI +environments, and to ensure interoperability between different +computing platforms that are running a ZIP program. + +Password based encryption is the most common form of encryption +people are familiar with. However, inherent weaknesses with +passwords (e.g. susceptibility to dictionary/brute force attack) +as well as password management and support issues make certificate +based encryption a more secure and scalable option. Industry +efforts and support are defining and moving towards more advanced +security solutions built around X.509v3 digital certificates and +Public Key Infrastructures(PKI) because of the greater scalability, +administrative options, and more robust security over traditional +password based encryption. + +Most standard encryption algorithms are supported with this +specification. Reference implementations for many of these +algorithms are available from either commercial or open source +distributors. Readily available cryptographic toolkits make +implementation of the encryption features straight-forward. +This document is not intended to provide a treatise on data +encryption principles or theory. Its purpose is to document the +data structures required for implementing interoperable data +encryption within the .ZIP format. It is strongly recommended that +you have a good understanding of data encryption before reading +further. + +The algorithms introduced in Version 5.0 of this specification +include: + + RC2 40 bit, 64 bit, and 128 bit + RC4 40 bit, 64 bit, and 128 bit + DES + 3DES 112 bit and 168 bit + +Version 5.1 adds support for the following: + + AES 128 bit, 192 bit, and 256 bit + + +Version 6.1 introduces encryption data changes to support +interoperability with Smartcard and USB Token certificate storage +methods which do not support the OAEP strengthening standard. + +Version 6.2 introduces support for encrypting metadata by compressing +and encrypting the central directory data structure to reduce information +leakage. Information leakage can occur in legacy ZIP applications +through exposure of information about a file even though that file is +stored encrypted. The information exposed consists of file +characteristics stored within the records and fields defined by this +specification. This includes data such as a files name, its original +size, timestamp and CRC32 value. + +Version 6.3 introduces support for encrypting data using the Blowfish +and Twofish algorithms. These are symmetric block ciphers developed +by Bruce Schneier. Blowfish supports using a variable length key from +32 to 448 bits. Block size is 64 bits. Implementations should use 16 +rounds and the only mode supported within ZIP files is CBC. Twofish +supports key sizes 128, 192 and 256 bits. Block size is 128 bits. +Implementations should use 16 rounds and the only mode supported within +ZIP files is CBC. Information and source code for both Blowfish and +Twofish algorithms can be found on the internet. Consult with the author +of these algorithms for information on terms or restrictions on use. + +Central Directory Encryption provides greater protection against +information leakage by encrypting the Central Directory structure and +by masking key values that are replicated in the unencrypted Local +Header. ZIP compatible programs that cannot interpret an encrypted +Central Directory structure cannot rely on the data in the corresponding +Local Header for decompression information. + +Extra Field records that may contain information about a file that should +not be exposed should not be stored in the Local Header and should only +be written to the Central Directory where they can be encrypted. This +design currently does not support streaming. Information in the End of +Central Directory record, the Zip64 End of Central Directory Locator, +and the Zip64 End of Central Directory records are not encrypted. Access +to view data on files within a ZIP file with an encrypted Central Directory +requires the appropriate password or private key for decryption prior to +viewing any files, or any information about the files, in the archive. + +Older ZIP compatible programs not familiar with the Central Directory +Encryption feature will no longer be able to recognize the Central +Directory and may assume the ZIP file is corrupt. Programs that +attempt streaming access using Local Headers will see invalid +information for each file. Central Directory Encryption need not be +used for every ZIP file. Its use is recommended for greater security. +ZIP files not using Central Directory Encryption should operate as +in the past. + +This strong encryption feature specification is intended to provide for +scalable, cross-platform encryption needs ranging from simple password +encryption to authenticated public/private key encryption. + +Encryption provides data confidentiality and privacy. It is +recommended that you combine X.509 digital signing with encryption +to add authentication and non-repudiation. + + +Single Password Symmetric Encryption Method: +------------------------------------------- + +The Single Password Symmetric Encryption Method using strong +encryption algorithms operates similarly to the traditional +PKWARE encryption defined in this format. Additional data +structures are added to support the processing needs of the +strong algorithms. + +The Strong Encryption data structures are: + +1. General Purpose Bits - Bits 0 and 6 of the General Purpose bit +flag in both local and central header records. Both bits set +indicates strong encryption. Bit 13, when set indicates the Central +Directory is encrypted and that selected fields in the Local Header +are masked to hide their actual value. + + +2. Extra Field 0x0017 in central header only. + + Fields to consider in this record are: + + Format - the data format identifier for this record. The only + value allowed at this time is the integer value 2. + + AlgId - integer identifier of the encryption algorithm from the + following range + + 0x6601 - DES + 0x6602 - RC2 (version needed to extract < 5.2) + 0x6603 - 3DES 168 + 0x6609 - 3DES 112 + 0x660E - AES 128 + 0x660F - AES 192 + 0x6610 - AES 256 + 0x6702 - RC2 (version needed to extract >= 5.2) + 0x6720 - Blowfish + 0x6721 - Twofish + 0x6801 - RC4 + 0xFFFF - Unknown algorithm + + Bitlen - Explicit bit length of key + + 32 - 448 bits + + Flags - Processing flags needed for decryption + + 0x0001 - Password is required to decrypt + 0x0002 - Certificates only + 0x0003 - Password or certificate required to decrypt + + Values > 0x0003 reserved for certificate processing + + +3. Decryption header record preceding compressed file data. + + -Decryption Header: + + Value Size Description + ----- ---- ----------- + IVSize 2 bytes Size of initialization vector (IV) + IVData IVSize Initialization vector for this file + Size 4 bytes Size of remaining decryption header data + Format 2 bytes Format definition for this record + AlgID 2 bytes Encryption algorithm identifier + Bitlen 2 bytes Bit length of encryption key + Flags 2 bytes Processing flags + ErdSize 2 bytes Size of Encrypted Random Data + ErdData ErdSize Encrypted Random Data + Reserved1 4 bytes Reserved certificate processing data + Reserved2 (var) Reserved for certificate processing data + VSize 2 bytes Size of password validation data + VData VSize-4 Password validation data + VCRC32 4 bytes Standard ZIP CRC32 of password validation data + + IVData - The size of the IV should match the algorithm block size. + The IVData can be completely random data. If the size of + the randomly generated data does not match the block size + it should be complemented with zero's or truncated as + necessary. If IVSize is 0,then IV = CRC32 + Uncompressed + File Size (as a 64 bit little-endian, unsigned integer value). + + Format - the data format identifier for this record. The only + value allowed at this time is the integer value 3. + + AlgId - integer identifier of the encryption algorithm from the + following range + + 0x6601 - DES + 0x6602 - RC2 (version needed to extract < 5.2) + 0x6603 - 3DES 168 + 0x6609 - 3DES 112 + 0x660E - AES 128 + 0x660F - AES 192 + 0x6610 - AES 256 + 0x6702 - RC2 (version needed to extract >= 5.2) + 0x6720 - Blowfish + 0x6721 - Twofish + 0x6801 - RC4 + 0xFFFF - Unknown algorithm + + Bitlen - Explicit bit length of key + + 32 - 448 bits + + Flags - Processing flags needed for decryption + + 0x0001 - Password is required to decrypt + 0x0002 - Certificates only + 0x0003 - Password or certificate required to decrypt + + Values > 0x0003 reserved for certificate processing + + ErdData - Encrypted random data is used to store random data that + is used to generate a file session key for encrypting + each file. SHA1 is used to calculate hash data used to + derive keys. File session keys are derived from a master + session key generated from the user-supplied password. + If the Flags field in the decryption header contains + the value 0x4000, then the ErdData field must be + decrypted using 3DES. If the value 0x4000 is not set, + then the ErdData field must be decrypted using AlgId. + + + Reserved1 - Reserved for certificate processing, if value is + zero, then Reserved2 data is absent. See the explanation + under the Certificate Processing Method for details on + this data structure. + + Reserved2 - If present, the size of the Reserved2 data structure + is located by skipping the first 4 bytes of this field + and using the next 2 bytes as the remaining size. See + the explanation under the Certificate Processing Method + for details on this data structure. + + VSize - This size value will always include the 4 bytes of the + VCRC32 data and will be greater than 4 bytes. + + VData - Random data for password validation. This data is VSize + in length and VSize must be a multiple of the encryption + block size. VCRC32 is a checksum value of VData. + VData and VCRC32 are stored encrypted and start the + stream of encrypted data for a file. + + +4. Useful Tips + +Strong Encryption is always applied to a file after compression. The +block oriented algorithms all operate in Cypher Block Chaining (CBC) +mode. The block size used for AES encryption is 16. All other block +algorithms use a block size of 8. Two ID's are defined for RC2 to +account for a discrepancy found in the implementation of the RC2 +algorithm in the cryptographic library on Windows XP SP1 and all +earlier versions of Windows. It is recommended that zero length files +not be encrypted, however programs should be prepared to extract them +if they are found within a ZIP file. + +A pseudo-code representation of the encryption process is as follows: + +Password = GetUserPassword() +MasterSessionKey = DeriveKey(SHA1(Password)) +RD = CryptographicStrengthRandomData() +For Each File + IV = CryptographicStrengthRandomData() + VData = CryptographicStrengthRandomData() + VCRC32 = CRC32(VData) + FileSessionKey = DeriveKey(SHA1(IV + RD) + ErdData = Encrypt(RD,MasterSessionKey,IV) + Encrypt(VData + VCRC32 + FileData, FileSessionKey,IV) +Done + +The function names and parameter requirements will depend on +the choice of the cryptographic toolkit selected. Almost any +toolkit supporting the reference implementations for each +algorithm can be used. The RSA BSAFE(r), OpenSSL, and Microsoft +CryptoAPI libraries are all known to work well. + + +Single Password - Central Directory Encryption: +----------------------------------------------- + +Central Directory Encryption is achieved within the .ZIP format by +encrypting the Central Directory structure. This encapsulates the metadata +most often used for processing .ZIP files. Additional metadata is stored for +redundancy in the Local Header for each file. The process of concealing +metadata by encrypting the Central Directory does not protect the data within +the Local Header. To avoid information leakage from the exposed metadata +in the Local Header, the fields containing information about a file are masked. + +Local Header: + +Masking replaces the true content of the fields for a file in the Local +Header with false information. When masked, the Local Header is not +suitable for streaming access and the options for data recovery of damaged +archives is reduced. Extra Data fields that may contain confidential +data should not be stored within the Local Header. The value set into +the Version needed to extract field should be the correct value needed to +extract the file without regard to Central Directory Encryption. The fields +within the Local Header targeted for masking when the Central Directory is +encrypted are: + + Field Name Mask Value + ------------------ --------------------------- + compression method 0 + last mod file time 0 + last mod file date 0 + crc-32 0 + compressed size 0 + uncompressed size 0 + file name (variable size) Base 16 value from the + range 1 - 0xFFFFFFFFFFFFFFFF + represented as a string whose + size will be set into the + file name length field + +The Base 16 value assigned as a masked file name is simply a sequentially +incremented value for each file starting with 1 for the first file. +Modifications to a ZIP file may cause different values to be stored for +each file. For compatibility, the file name field in the Local Header +should never be left blank. As of Version 6.2 of this specification, +the Compression Method and Compressed Size fields are not yet masked. +Fields having a value of 0xFFFF or 0xFFFFFFFF for the ZIP64 format +should not be masked. + +Encrypting the Central Directory: + +Encryption of the Central Directory does not include encryption of the +Central Directory Signature data, the Zip64 End of Central Directory +record, the Zip64 End of Central Directory Locator, or the End +of Central Directory record. The ZIP file comment data is never +encrypted. + +Before encrypting the Central Directory, it may optionally be compressed. +Compression is not required, but for storage efficiency it is assumed +this structure will be compressed before encrypting. Similarly, this +specification supports compressing the Central Directory without +requiring that it also be encrypted. Early implementations of this +feature will assume the encryption method applied to files matches the +encryption applied to the Central Directory. + +Encryption of the Central Directory is done in a manner similar to +that of file encryption. The encrypted data is preceded by a +decryption header. The decryption header is known as the Archive +Decryption Header. The fields of this record are identical to +the decryption header preceding each encrypted file. The location +of the Archive Decryption Header is determined by the value in the +Start of the Central Directory field in the Zip64 End of Central +Directory record. When the Central Directory is encrypted, the +Zip64 End of Central Directory record will always be present. + +The layout of the Zip64 End of Central Directory record for all +versions starting with 6.2 of this specification will follow the +Version 2 format. The Version 2 format is as follows: + +The leading fixed size fields within the Version 1 format for this +record remain unchanged. The record signature for both Version 1 +and Version 2 will be 0x06064b50. Immediately following the last +byte of the field known as the Offset of Start of Central +Directory With Respect to the Starting Disk Number will begin the +new fields defining Version 2 of this record. + +New fields for Version 2: + +Note: all fields stored in Intel low-byte/high-byte order. + + Value Size Description + ----- ---- ----------- + Compression Method 2 bytes Method used to compress the + Central Directory + Compressed Size 8 bytes Size of the compressed data + Original Size 8 bytes Original uncompressed size + AlgId 2 bytes Encryption algorithm ID + BitLen 2 bytes Encryption key length + Flags 2 bytes Encryption flags + HashID 2 bytes Hash algorithm identifier + Hash Length 2 bytes Length of hash data + Hash Data (variable) Hash data + +The Compression Method accepts the same range of values as the +corresponding field in the Central Header. + +The Compressed Size and Original Size values will not include the +data of the Central Directory Signature which is compressed or +encrypted. + +The AlgId, BitLen, and Flags fields accept the same range of values +the corresponding fields within the 0x0017 record. + +Hash ID identifies the algorithm used to hash the Central Directory +data. This data does not have to be hashed, in which case the +values for both the HashID and Hash Length will be 0. Possible +values for HashID are: + + Value Algorithm + ------ --------- + 0x0000 none + 0x0001 CRC32 + 0x8003 MD5 + 0x8004 SHA1 + 0x8007 RIPEMD160 + 0x800C SHA256 + 0x800D SHA384 + 0x800E SHA512 + +When the Central Directory data is signed, the same hash algorithm +used to hash the Central Directory for signing should be used. +This is recommended for processing efficiency, however, it is +permissible for any of the above algorithms to be used independent +of the signing process. + +The Hash Data will contain the hash data for the Central Directory. +The length of this data will vary depending on the algorithm used. + +The Version Needed to Extract should be set to 62. + +The value for the Total Number of Entries on the Current Disk will +be 0. These records will no longer support random access when +encrypting the Central Directory. + +When the Central Directory is compressed and/or encrypted, the +End of Central Directory record will store the value 0xFFFFFFFF +as the value for the Total Number of Entries in the Central +Directory. The value stored in the Total Number of Entries in +the Central Directory on this Disk field will be 0. The actual +values will be stored in the equivalent fields of the Zip64 +End of Central Directory record. + +Decrypting and decompressing the Central Directory is accomplished +in the same manner as decrypting and decompressing a file. + +Certificate Processing Method: +----------------------------- + +The Certificate Processing Method of for ZIP file encryption +defines the following additional data fields: + +1. Certificate Flag Values + +Additional processing flags that can be present in the Flags field of both +the 0x0017 field of the central directory Extra Field and the Decryption +header record preceding compressed file data are: + + 0x0007 - reserved for future use + 0x000F - reserved for future use + 0x0100 - Indicates non-OAEP key wrapping was used. If this + this field is set, the version needed to extract must + be at least 61. This means OAEP key wrapping is not + used when generating a Master Session Key using + ErdData. + 0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the + same algorithm used for encrypting the file contents. + 0x8000 - reserved for future use + + +2. CertData - Extra Field 0x0017 record certificate data structure + +The data structure used to store certificate data within the section +of the Extra Field defined by the CertData field of the 0x0017 +record are as shown: + + Value Size Description + ----- ---- ----------- + RCount 4 bytes Number of recipients. + HashAlg 2 bytes Hash algorithm identifier + HSize 2 bytes Hash size + SRList (var) Simple list of recipients hashed public keys + + + RCount This defines the number intended recipients whose + public keys were used for encryption. This identifies + the number of elements in the SRList. + + HashAlg This defines the hash algorithm used to calculate + the public key hash of each public key used + for encryption. This field currently supports + only the following value for SHA-1 + + 0x8004 - SHA1 + + HSize This defines the size of a hashed public key. + + SRList This is a variable length list of the hashed + public keys for each intended recipient. Each + element in this list is HSize. The total size of + SRList is determined using RCount * HSize. + + +3. Reserved1 - Certificate Decryption Header Reserved1 Data: + + Value Size Description + ----- ---- ----------- + RCount 4 bytes Number of recipients. + + RCount This defines the number intended recipients whose + public keys were used for encryption. This defines + the number of elements in the REList field defined below. + + +4. Reserved2 - Certificate Decryption Header Reserved2 Data Structures: + + + Value Size Description + ----- ---- ----------- + HashAlg 2 bytes Hash algorithm identifier + HSize 2 bytes Hash size + REList (var) List of recipient data elements + + + HashAlg This defines the hash algorithm used to calculate + the public key hash of each public key used + for encryption. This field currently supports + only the following value for SHA-1 + + 0x8004 - SHA1 + + HSize This defines the size of a hashed public key + defined in REHData. + + REList This is a variable length of list of recipient data. + Each element in this list consists of a Recipient + Element data structure as follows: + + + Recipient Element (REList) Data Structure: + + Value Size Description + ----- ---- ----------- + RESize 2 bytes Size of REHData + REKData + REHData HSize Hash of recipients public key + REKData (var) Simple key blob + + + RESize This defines the size of an individual REList + element. This value is the combined size of the + REHData field + REKData field. REHData is defined by + HSize. REKData is variable and can be calculated + for each REList element using RESize and HSize. + + REHData Hashed public key for this recipient. + + REKData Simple Key Blob. The format of this data structure + is identical to that defined in the Microsoft + CryptoAPI and generated using the CryptExportKey() + function. The version of the Simple Key Blob + supported at this time is 0x02 as defined by + Microsoft. + +Certificate Processing - Central Directory Encryption: +------------------------------------------------------ + +Central Directory Encryption using Digital Certificates will +operate in a manner similar to that of Single Password Central +Directory Encryption. This record will only be present when there +is data to place into it. Currently, data is placed into this +record when digital certificates are used for either encrypting +or signing the files within a ZIP file. When only password +encryption is used with no certificate encryption or digital +signing, this record is not currently needed. When present, this +record will appear before the start of the actual Central Directory +data structure and will be located immediately after the Archive +Decryption Header if the Central Directory is encrypted. + +The Archive Extra Data record will be used to store the following +information. Additional data may be added in future versions. + +Extra Data Fields: + +0x0014 - PKCS#7 Store for X.509 Certificates +0x0016 - X.509 Certificate ID and Signature for central directory +0x0019 - PKCS#7 Encryption Recipient Certificate List + +The 0x0014 and 0x0016 Extra Data records that otherwise would be +located in the first record of the Central Directory for digital +certificate processing. When encrypting or compressing the Central +Directory, the 0x0014 and 0x0016 records must be located in the +Archive Extra Data record and they should not remain in the first +Central Directory record. The Archive Extra Data record will also +be used to store the 0x0019 data. + +When present, the size of the Archive Extra Data record will be +included in the size of the Central Directory. The data of the +Archive Extra Data record will also be compressed and encrypted +along with the Central Directory data structure. + +Certificate Processing Differences: + +The Certificate Processing Method of encryption differs from the +Single Password Symmetric Encryption Method as follows. Instead +of using a user-defined password to generate a master session key, +cryptographically random data is used. The key material is then +wrapped using standard key-wrapping techniques. This key material +is wrapped using the public key of each recipient that will need +to decrypt the file using their corresponding private key. + +This specification currently assumes digital certificates will follow +the X.509 V3 format for 1024 bit and higher RSA format digital +certificates. Implementation of this Certificate Processing Method +requires supporting logic for key access and management. This logic +is outside the scope of this specification. + +OAEP Processing with Certificate-based Encryption: + +OAEP stands for Optimal Asymmetric Encryption Padding. It is a +strengthening technique used for small encoded items such as decryption +keys. This is commonly applied in cryptographic key-wrapping techniques +and is supported by PKCS #1. Versions 5.0 and 6.0 of this specification +were designed to support OAEP key-wrapping for certificate-based +decryption keys for additional security. + +Support for private keys stored on Smartcards or Tokens introduced +a conflict with this OAEP logic. Most card and token products do +not support the additional strengthening applied to OAEP key-wrapped +data. In order to resolve this conflict, versions 6.1 and above of this +specification will no longer support OAEP when encrypting using +digital certificates. + +Versions of PKZIP available during initial development of the +certificate processing method set a value of 61 into the +version needed to extract field for a file. This indicates that +non-OAEP key wrapping is used. This affects certificate encryption +only, and password encryption functions should not be affected by +this value. This means values of 61 may be found on files encrypted +with certificates only, or on files encrypted with both password +encryption and certificate encryption. Files encrypted with both +methods can safely be decrypted using the password methods documented. + +IX. Change Process +------------------ + +In order for the .ZIP file format to remain a viable definition, this +specification should be considered as open for periodic review and +revision. Although this format was originally designed with a +certain level of extensibility, not all changes in technology +(present or future) were or will be necessarily considered in its +design. If your application requires new definitions to the +extensible sections in this format, or if you would like to +submit new data structures, please forward your request to +zipformat@pkware.com. All submissions will be reviewed by the +ZIP File Specification Committee for possible inclusion into +future versions of this specification. Periodic revisions +to this specification will be published to ensure interoperability. +We encourage comments and feedback that may help improve clarity +or content. + +X. Incorporating PKWARE Proprietary Technology into Your Product +---------------------------------------------------------------- + +PKWARE is committed to the interoperability and advancement of the +.ZIP format. PKWARE offers a free license for certain technological +aspects described above under certain restrictions and conditions. +However, the use or implementation in a product of certain technological +aspects set forth in the current APPNOTE, including those with regard to +strong encryption, patching, or extended tape operations requires a +license from PKWARE. Please contact PKWARE with regard to acquiring +a license. + +XI. Acknowledgements +--------------------- + +In addition to the above mentioned contributors to PKZIP and PKUNZIP, +I would like to extend special thanks to Robert Mahoney for suggesting +the extension .ZIP for this software. + +XII. References +--------------- + + Fiala, Edward R., and Greene, Daniel H., "Data compression with + finite windows", Communications of the ACM, Volume 32, Number 4, + April 1989, pages 490-505. + + Held, Gilbert, "Data Compression, Techniques and Applications, + Hardware and Software Considerations", John Wiley & Sons, 1987. + + Huffman, D.A., "A method for the construction of minimum-redundancy + codes", Proceedings of the IRE, Volume 40, Number 9, September 1952, + pages 1098-1101. + + Nelson, Mark, "LZW Data Compression", Dr. Dobbs Journal, Volume 14, + Number 10, October 1989, pages 29-37. + + Nelson, Mark, "The Data Compression Book", M&T Books, 1991. + + Storer, James A., "Data Compression, Methods and Theory", + Computer Science Press, 1988 + + Welch, Terry, "A Technique for High-Performance Data Compression", + IEEE Computer, Volume 17, Number 6, June 1984, pages 8-19. + + Ziv, J. and Lempel, A., "A universal algorithm for sequential data + compression", Communications of the ACM, Volume 30, Number 6, + June 1987, pages 520-540. + + Ziv, J. and Lempel, A., "Compression of individual sequences via + variable-rate coding", IEEE Transactions on Information Theory, + Volume 24, Number 5, September 1978, pages 530-536. + + +APPENDIX A - AS/400 Extra Field (0x0065) Attribute Definitions +-------------------------------------------------------------- + +Field Definition Structure: + + a. field length including length 2 bytes + b. field code 2 bytes + c. data x bytes + +Field Code Description + 4001 Source type i.e. CLP etc + 4002 The text description of the library + 4003 The text description of the file + 4004 The text description of the member + 4005 x'F0' or 0 is PF-DTA, x'F1' or 1 is PF_SRC + 4007 Database Type Code 1 byte + 4008 Database file and fields definition + 4009 GZIP file type 2 bytes + 400B IFS code page 2 bytes + 400C IFS Creation Time 4 bytes + 400D IFS Access Time 4 bytes + 400E IFS Modification time 4 bytes + 005C Length of the records in the file 2 bytes + 0068 GZIP two words 8 bytes + +APPENDIX B - z/OS Extra Field (0x0065) Attribute Definitions +------------------------------------------------------------ + +Field Definition Structure: + + a. field length including length 2 bytes + b. field code 2 bytes + c. data x bytes + +Field Code Description + 0001 File Type 2 bytes + 0002 NonVSAM Record Format 1 byte + 0003 Reserved + 0004 NonVSAM Block Size 2 bytes Big Endian + 0005 Primary Space Allocation 3 bytes Big Endian + 0006 Secondary Space Allocation 3 bytes Big Endian + 0007 Space Allocation Type1 byte flag + 0008 Modification Date Retired with PKZIP 5.0 + + 0009 Expiration Date Retired with PKZIP 5.0 + + 000A PDS Directory Block Allocation 3 bytes Big Endian binary value + 000B NonVSAM Volume List variable + 000C UNIT Reference Retired with PKZIP 5.0 + + 000D DF/SMS Management Class 8 bytes EBCDIC Text Value + 000E DF/SMS Storage Class 8 bytes EBCDIC Text Value + 000F DF/SMS Data Class 8 bytes EBCDIC Text Value + 0010 PDS/PDSE Member Info. 30 bytes + 0011 VSAM sub-filetype 2 bytes + 0012 VSAM LRECL 13 bytes EBCDIC "(num_avg num_max)" + 0013 VSAM Cluster Name Retired with PKZIP 5.0 + + 0014 VSAM KSDS Key Information 13 bytes EBCDIC "(num_length num_position)" + 0015 VSAM Average LRECL 5 bytes EBCDIC num_value padded with blanks + 0016 VSAM Maximum LRECL 5 bytes EBCDIC num_value padded with blanks + 0017 VSAM KSDS Key Length 5 bytes EBCDIC num_value padded with blanks + 0018 VSAM KSDS Key Position 5 bytes EBCDIC num_value padded with blanks + 0019 VSAM Data Name 1-44 bytes EBCDIC text string + 001A VSAM KSDS Index Name 1-44 bytes EBCDIC text string + 001B VSAM Catalog Name 1-44 bytes EBCDIC text string + 001C VSAM Data Space Type 9 bytes EBCDIC text string + 001D VSAM Data Space Primary 9 bytes EBCDIC num_value left-justified + 001E VSAM Data Space Secondary 9 bytes EBCDIC num_value left-justified + 001F VSAM Data Volume List variable EBCDIC text list of 6-character Volume IDs + 0020 VSAM Data Buffer Space 8 bytes EBCDIC num_value left-justified + 0021 VSAM Data CISIZE 5 bytes EBCDIC num_value left-justified + 0022 VSAM Erase Flag 1 byte flag + 0023 VSAM Free CI % 3 bytes EBCDIC num_value left-justified + 0024 VSAM Free CA % 3 bytes EBCDIC num_value left-justified + 0025 VSAM Index Volume List variable EBCDIC text list of 6-character Volume IDs + 0026 VSAM Ordered Flag 1 byte flag + 0027 VSAM REUSE Flag 1 byte flag + 0028 VSAM SPANNED Flag 1 byte flag + 0029 VSAM Recovery Flag 1 byte flag + 002A VSAM WRITECHK Flag 1 byte flag + 002B VSAM Cluster/Data SHROPTS 3 bytes EBCDIC "n,y" + 002C VSAM Index SHROPTS 3 bytes EBCDIC "n,y" + 002D VSAM Index Space Type 9 bytes EBCDIC text string + 002E VSAM Index Space Primary 9 bytes EBCDIC num_value left-justified + 002F VSAM Index Space Secondary 9 bytes EBCDIC num_value left-justified + 0030 VSAM Index CISIZE 5 bytes EBCDIC num_value left-justified + 0031 VSAM Index IMBED 1 byte flag + 0032 VSAM Index Ordered Flag 1 byte flag + 0033 VSAM REPLICATE Flag 1 byte flag + 0034 VSAM Index REUSE Flag 1 byte flag + 0035 VSAM Index WRITECHK Flag 1 byte flag Retired with PKZIP 5.0 + + 0036 VSAM Owner 8 bytes EBCDIC text string + 0037 VSAM Index Owner 8 bytes EBCDIC text string + 0038 Reserved + 0039 Reserved + 003A Reserved + 003B Reserved + 003C Reserved + 003D Reserved + 003E Reserved + 003F Reserved + 0040 Reserved + 0041 Reserved + 0042 Reserved + 0043 Reserved + 0044 Reserved + 0045 Reserved + 0046 Reserved + 0047 Reserved + 0048 Reserved + 0049 Reserved + 004A Reserved + 004B Reserved + 004C Reserved + 004D Reserved + 004E Reserved + 004F Reserved + 0050 Reserved + 0051 Reserved + 0052 Reserved + 0053 Reserved + 0054 Reserved + 0055 Reserved + 0056 Reserved + 0057 Reserved + 0058 PDS/PDSE Member TTR Info. 6 bytes Big Endian + 0059 PDS 1st LMOD Text TTR 3 bytes Big Endian + 005A PDS LMOD EP Rec # 4 bytes Big Endian + 005B Reserved + 005C Max Length of records 2 bytes Big Endian + 005D PDSE Flag 1 byte flag + 005E Reserved + 005F Reserved + 0060 Reserved + 0061 Reserved + 0062 Reserved + 0063 Reserved + 0064 Reserved + 0065 Last Date Referenced 4 bytes Packed Hex "yyyymmdd" + 0066 Date Created 4 bytes Packed Hex "yyyymmdd" + 0068 GZIP two words 8 bytes + 0071 Extended NOTE Location 12 bytes Big Endian + 0072 Archive device UNIT 6 bytes EBCDIC + 0073 Archive 1st Volume 6 bytes EBCDIC + 0074 Archive 1st VOL File Seq# 2 bytes Binary + +APPENDIX C - Zip64 Extensible Data Sector Mappings (EFS) +-------------------------------------------------------- + + -Z390 Extra Field: + + The following is the general layout of the attributes for the + ZIP 64 "extra" block for extended tape operations. Portions of + this extended tape processing technology is covered under a + pending patent application. The use or implementation in a + product of certain technological aspects set forth in the + current APPNOTE, including those with regard to strong encryption, + patching or extended tape operations, requires a license from + PKWARE. Please contact PKWARE with regard to acquiring a license. + + + Note: some fields stored in Big Endian format. All text is + in EBCDIC format unless otherwise specified. + + Value Size Description + ----- ---- ----------- + (Z390) 0x0065 2 bytes Tag for this "extra" block type + Size 4 bytes Size for the following data block + Tag 4 bytes EBCDIC "Z390" + Length71 2 bytes Big Endian + Subcode71 2 bytes Enote type code + FMEPos 1 byte + Length72 2 bytes Big Endian + Subcode72 2 bytes Unit type code + Unit 1 byte Unit + Length73 2 bytes Big Endian + Subcode73 2 bytes Volume1 type code + FirstVol 1 byte Volume + Length74 2 bytes Big Endian + Subcode74 2 bytes FirstVol file sequence + FileSeq 2 bytes Sequence + +APPENDIX D - Language Encoding (EFS) +------------------------------------ + +The ZIP format has historically supported only the original IBM PC character +encoding set, commonly referred to as IBM Code Page 437. This limits storing +file name characters to only those within the original MS-DOS range of values +and does not properly support file names in other character encodings, or +languages. To address this limitation, this specification will support the +following change. + +If general purpose bit 11 is unset, the file name and comment should conform +to the original ZIP character encoding. If general purpose bit 11 is set, the +filename and comment must support The Unicode Standard, Version 4.1.0 or +greater using the character encoding form defined by the UTF-8 storage +specification. The Unicode Standard is published by the The Unicode +Consortium (www.unicode.org). UTF-8 encoded data stored within ZIP files +is expected to not include a byte order mark (BOM). + +Applications may choose to supplement this file name storage through the use +of the 0x0008 Extra Field. Storage for this optional field is currently +undefined, however it will be used to allow storing extended information +on source or target encoding that may further assist applications with file +name, or file content encoding tasks. Please contact PKWARE with any +requirements on how this field should be used. + +The 0x0008 Extra Field storage may be used with either setting for general +purpose bit 11. Examples of the intended usage for this field is to store +whether "modified-UTF-8" (JAVA) is used, or UTF-8-MAC. Similarly, other +commonly used character encoding (code page) designations can be indicated +through this field. Formalized values for use of the 0x0008 record remain +undefined at this time. The definition for the layout of the 0x0008 field +will be published when available. Use of the 0x0008 Extra Field provides +for storing data within a ZIP file in an encoding other than IBM Code +Page 437 or UTF-8. + +General purpose bit 11 will not imply any encoding of file content or +password. Values defining character encoding for file content or +password must be stored within the 0x0008 Extended Language Encoding +Extra Field. + +Ed Gordon of the Info-ZIP group has defined a pair of "extra field" records +that can be used to store UTF-8 file name and file comment fields. These +records can be used for cases when the general purpose bit 11 method +for storing UTF-8 data in the standard file name and comment fields is +not desirable. A common case for this alternate method is if backward +compatibility with older programs is required. + +Definitions for the record structure of these fields are included above +in the section on 3rd party mappings for "extra field" records. These +records are identified by Header ID's 0x6375 (Info-ZIP Unicode Comment +Extra Field) and 0x7075 (Info-ZIP Unicode Path Extra Field). + +The choice of which storage method to use when writing a ZIP file is left +to the implementation. Developers should expect that a ZIP file may +contain either method and should provide support for reading data in +either format. Use of general purpose bit 11 reduces storage requirements +for file name data by not requiring additional "extra field" data for +each file, but can result in older ZIP programs not being able to extract +files. Use of the 0x6375 and 0x7075 records will result in a ZIP file +that should always be readable by older ZIP programs, but requires more +storage per file to write file name and/or file comment fields. + + + + diff --git a/public/js/lib/jszip/docs/ZIP spec.txt b/public/js/lib/jszip/docs/ZIP spec.txt new file mode 100644 index 0000000..bb1485e --- /dev/null +++ b/public/js/lib/jszip/docs/ZIP spec.txt @@ -0,0 +1,66 @@ +Here are the notes I made while working through the ZIP file specification. + +For each file: + + local file header signature 4 bytes (0x04034b50) + version needed to extract 2 bytes + general purpose bit flag 2 bytes + compression method 2 bytes + last mod file time 2 bytes + last mod file date 2 bytes + crc-32 4 bytes + compressed size 4 bytes + uncompressed size 4 bytes + file name length 2 bytes + extra field length 2 bytes + +|sig |v |g |c |t |d |crc |csz |usz |n |x | + PK.. ## 00 00 ?? ?? xxxx ???? ???? ?? 00 + + +Central directory: + + central file header signature 4 bytes (0x02014b50) + version made by 2 bytes + version needed to extract 2 bytes * + general purpose bit flag 2 bytes * + compression method 2 bytes * + last mod file time 2 bytes * + last mod file date 2 bytes * + crc-32 4 bytes * + compressed size 4 bytes * + uncompressed size 4 bytes * + file name length 2 bytes * + extra field length 2 bytes * + file comment length 2 bytes + disk number start 2 bytes + internal file attributes 2 bytes + external file attributes 4 bytes + relative offset of local header 4 bytes + + file name (variable size) + extra field (variable size) + file comment (variable size) + +|sig |vm|vx|g |c |d |t |crc |csz |usz |n |x |cm|dn|ia|xa |roff| + PK.. ## ## 00 00 ?? ?? xxxx ???? ???? ?? 00 00 00 00 xxxx ???? + +End of central directory: + + end of central dir signature 4 bytes (0x06054b50) + number of this disk 2 bytes + number of the disk with the + start of the central directory 2 bytes + total number of entries in the + central directory on this disk 2 bytes + total number of entries in + the central directory 2 bytes + size of the central directory 4 bytes + offset of start of central + directory with respect to + the starting disk number 4 bytes + .ZIP file comment length 2 bytes + .ZIP file comment (variable size) + +|sig |n1|n2|e |ne|size|off |cm| + PK.. 00 00 ?? ?? ???? ???? 00 diff --git a/public/js/lib/jszip/docs/references.txt b/public/js/lib/jszip/docs/references.txt new file mode 100644 index 0000000..9aab182 --- /dev/null +++ b/public/js/lib/jszip/docs/references.txt @@ -0,0 +1,18 @@ +Zip format +---------- +http://www.pkware.com/support/zip-application-note +http://www.xxcopy.com/xxcopy06.htm + +Data URL +-------- +https://developer.mozilla.org/en/The_data_URL_scheme +http://msdn.microsoft.com/en-us/library/cc848897(VS.85).aspx +http://www.phpied.com/mhtml-when-you-need-data-uris-in-ie7-and-under/ + +http://www.motobit.com/util/base64-decoder-encoder.asp + +Saving files +------------ +http://msdn.microsoft.com/en-us/library/ms536676(VS.85).aspx +http://msdn.microsoft.com/en-us/library/ms536419(VS.85).aspx +http://msdn.microsoft.com/en-us/library/ms537418(VS.85).aspx diff --git a/public/js/lib/jszip/documentation/_layouts/default.html b/public/js/lib/jszip/documentation/_layouts/default.html new file mode 100644 index 0000000..d1694cf --- /dev/null +++ b/public/js/lib/jszip/documentation/_layouts/default.html @@ -0,0 +1,158 @@ + + + + + + + + {{page.title}} + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + {% if page.section and page.fullpage != true %} +
+ + {% endif %} +
+

{{page.title}}

+ + + + + {{content}} + + + + +
+
+
+ + + + diff --git a/public/js/lib/jszip/documentation/api_jszip.md b/public/js/lib/jszip/documentation/api_jszip.md new file mode 100644 index 0000000..1eb759c --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip.md @@ -0,0 +1,15 @@ +--- +title: "JSZip API" +layout: default +section: api +--- + +An instance of JSZip represents a set of files. You can add them, remove them, +modify them. You can also import an existing zip file or generate one. + +### Attributes + +attribute name | type | description +---------------------|-------------|------------- +`files` | object | the [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html)s inside the zip with the name as key. See [file(name)]({{site.baseurl}}/documentation/api_jszip/file_name.html). +`comment` | string | the comment of the zip file. diff --git a/public/js/lib/jszip/documentation/api_jszip/constructor.md b/public/js/lib/jszip/documentation/api_jszip/constructor.md new file mode 100644 index 0000000..5564737 --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/constructor.md @@ -0,0 +1,23 @@ +--- +title: "new JSZip() or JSZip()" +layout: default +section: api +--- + +__Description__ : Create a new JSZip instance. + +__Arguments__ : None + +__Returns__ : A new JSZip. + +__Throws__ : Nothing. + + + +__Example__ + +```js +var zip = new JSZip(); +// same as +var zip = JSZip(); +``` diff --git a/public/js/lib/jszip/documentation/api_jszip/constructor_load.md b/public/js/lib/jszip/documentation/api_jszip/constructor_load.md new file mode 100644 index 0000000..4e6f7ed --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/constructor_load.md @@ -0,0 +1,22 @@ +--- +title: "new JSZip(data [,options]) or JSZip(data [,options])" +layout: default +section: api +--- + +This is a shortcut for + +```js +var zip = new JSZip(); +zip.load(data, options); +``` + +Please see the documentation of [load]({{site.baseurl}}/documentation/api_jszip/load.html). + +__Example__ + +```js +var zip = new JSZip(data, options); +// same as +var zip = JSZip(data, options); +``` diff --git a/public/js/lib/jszip/documentation/api_jszip/file_data.md b/public/js/lib/jszip/documentation/api_jszip/file_data.md new file mode 100644 index 0000000..69adecb --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/file_data.md @@ -0,0 +1,90 @@ +--- +title: "file(name, data [,options])" +layout: default +section: api +--- + +__Description__ : Add (or update) a file to the zip file. + +__Arguments__ + +name | type | description +--------------------|---------|------------ +name | string | the name of the file. You can specify folders in the name : the folder separator is a forward slash ("/"). +data | String/ArrayBuffer/Uint8Array/Buffer | the content of the file. +options | object | the options. + +Content of `options` : + +name | type | default | description +------------|---------|---------|------------ +base64 | boolean | `false` | set to `true` if the data is base64 encoded. For example image data from a `` element. Plain text and HTML do not need this option. +binary | boolean | `false` | set to `true` if the data should be treated as raw content, `false` if this is a text. If base64 is used, this defaults to `true`, if the data is not a string, this will be set to `true`. +date | date | the current date | the last modification date. +compression | string | null | If set, specifies compression method to use for this specific file. If not, the default file compression will be used, see [generate(options)]({{site.baseurl}}/documentation/api_jszip/generate.html). +compressionOptions | object | `null` | the options to use when compressing the file, see [generate(options)]({{site.baseurl}}/documentation/api_jszip/generate.html). +comment | string | null | The comment for this file. +optimizedBinaryString | boolean | `false` | Set to true if (and only if) the input is a "binary string" and has already been prepared with a 0xFF mask. +createFolders | boolean | `false` | Set to true if folders in the file path should be automatically created, otherwise there will only be virtual folders that represent the path to the file. +unixPermissions | 16 bits number | null | The UNIX permissions of the file, if any. +dosPermissions | 6 bits number | null | The DOS permissions of the file, if any. +dir | boolean | false | Set to true if this is a directory and content should be ignored. + +You shouldn't update the data given to this method : it is kept as it so any +update will impact the stored data. + +__For the permissions__ : + +The field `unixPermissions` also accepts a string representing the octal value : +"644", "755", etc. On nodejs you can use the `mode` attribute of +[nodejs' fs.Stats](http://nodejs.org/api/fs.html#fs_class_fs_stats). + +See also [the platform option of generate()]({{site.baseurl}}/documentation/api_jszip/generate.html). + +__About `dir`__ : + +If `dir` is true or if a permission says it's a folder, this entry be flagged +as a folder and the content will be ignored. + +__Returns__ : The current JSZip object, for chaining. + +__Throws__ : An exception if the data is not in a supported format. + + + +__Example__ + +```js +zip.file("Hello.txt", "Hello World\n"); + +// base64 +zip.file("smile.gif", "R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=", {base64: true}); +// from an ajax call with xhr.responseType = 'arraybuffer' +zip.file("smile.gif", arraybufferFromXhr); +// or on nodejs +zip.file("smile.gif", fs.readFileSync("smile.gif")); + +zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")}); +zip.file("folder/file.txt", "file in folder"); + +zip.file("animals.txt", "dog,platypus\n").file("people.txt", "james,sebastian\n"); + +// result : Hello.txt, smile.gif, Xmas.txt, animals.txt, people.txt, +// folder/, folder/file.txt +// In the above case, the "folder" folder will not have a 'D'irectory attribute or Method property. The +// folder only exists as part of the path to "file.txt". + +zip.file("folder/file.txt", "file in folder", {createFolders: true}); +// In this case, the "folder" folder WILL have a 'D'irectory attribute and a Method property of "store". +// It will exist whether or not "file.txt" is present. + +zip.file("script.sh", "echo 'hello world'", { + unixPermissions : "755" +}); +// when generated with platform:UNIX, the script.sh file will be executable +``` diff --git a/public/js/lib/jszip/documentation/api_jszip/file_name.md b/public/js/lib/jszip/documentation/api_jszip/file_name.md new file mode 100644 index 0000000..88b6d43 --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/file_name.md @@ -0,0 +1,46 @@ +--- +title: "file(name)" +layout: default +section: api +--- + +__Description__ : Get a file with the specified name. You can specify folders +in the name : the folder separator is a forward slash ("/"). + +__Arguments__ + +name | type | description +-----|--------|------------- +name | string | the name of the file. + +__Returns__ : An instance of [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html) representing +the file if any, `null` otherwise. + +__Throws__ : Nothing. + + + +__Examples__ + +```js +var zip = new JSZip(); +zip.file("file.txt", "content"); + +zip.file("file.txt").name // "file.txt" +zip.file("file.txt").asText() // "content" +zip.file("file.txt").options.dir // false + +// utf8 example +var zip = new JSZip(zipFromAjaxWithUTF8); +zip.file("amount.txt").asText() // "€15" +zip.file("amount.txt").asArrayBuffer() // an ArrayBuffer containing €15 encoded as utf8 +zip.file("amount.txt").asUint8Array() // an Uint8Array containing €15 encoded as utf8 + +// with folders +zip.folder("sub").file("file.txt", "content"); +zip.file("sub/file.txt"); // the file +// or +zip.folder("sub").file("file.txt") // the file +``` + + diff --git a/public/js/lib/jszip/documentation/api_jszip/file_regex.md b/public/js/lib/jszip/documentation/api_jszip/file_regex.md new file mode 100644 index 0000000..5dd2416 --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/file_regex.md @@ -0,0 +1,49 @@ +--- +title: "file(regex)" +layout: default +section: api +--- + +__Description__ : Search a file in the current folder and subfolders with a +[regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions). +The regex is tested against the relative filename. + +__Arguments__ + +name | type | description +------|--------|------------ +regex | RegExp | the regex to use. + +__Returns__ : An array of matching files (an empty array if none matched). Each +maching file is an instance of [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html). + +__Throws__ : Nothing. + + + +__Example__ + +```js +var zip = new JSZip(); +zip.file("file1.txt", "content"); +zip.file("file2.txt", "content"); + +zip.file(/file/); // array of size 2 + +// example with a relative path : +var folder = zip.folder("sub"); +folder + .file("file3.txt", "content") // relative path from folder : file3.txt + .file("file4.txt", "content"); // relative path from folder : file4.txt + +folder.file(/file/); // array of size 2 +folder.file(/^file/); // array of size 2, the relative paths start with file + +// arrays contain objects in the form: +// {name: "file2.txt", dir: false, asText : function () {...}, ...} +``` + + diff --git a/public/js/lib/jszip/documentation/api_jszip/filter.md b/public/js/lib/jszip/documentation/api_jszip/filter.md new file mode 100644 index 0000000..3afc435 --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/filter.md @@ -0,0 +1,43 @@ +--- +title: "filter(predicate)" +layout: default +section: api +--- + +__Description__ : Filter nested files/folders with the specified function. + +__Arguments__ + +name | type | description +----------|----------|------------ +predicate | function | the predicate to use. + +The predicate has the following signature : `function (relativePath, file) {...}` : + +name | type | description +-------------|-----------|------------ +relativePath | string | the filename and its path, reliatively to the current folder. +file | ZipObject | the file being tested. See [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html). + +The predicate must return true if the file should be included, false otherwise. + + +__Returns__ : An array of matching ZipObject. + +__Throws__ : Nothing. + + + +__Example__ + +```js +var zip = new JSZip().folder("dir"); +zip.file("readme.txt", "content"); +zip.filter(function (relativePath, file){ + // relativePath == "readme.txt" + // file = {name:"dir/readme.txt",options:{...},asText:function} + return true/false; +}); +``` + + diff --git a/public/js/lib/jszip/documentation/api_jszip/folder_data.md b/public/js/lib/jszip/documentation/api_jszip/folder_data.md new file mode 100644 index 0000000..9f8bd44 --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/folder_data.md @@ -0,0 +1,34 @@ +--- +title: "folder(name)" +layout: default +section: api +--- + +__Description__ : Create a directory if it doesn't exist, return a new JSZip +object with the new folder as root. + +See also [the `dir` option of file()]({{site.baseurl}}/documentation/api_jszip/file_data.html). + +__Arguments__ + +name | type | description +-----|--------|------------ +name | string | the name of the directory. + +__Returns__ : A new JSZip (for chaining), with the new folder as root. + +__Throws__ : Nothing. + + + +__Example__ + +```js +zip.folder("images"); +zip.folder("css").file("style.css", "body {background: #FF0000}"); +// or specify an absolute path (using forward slashes) +zip.file("css/font.css", "body {font-family: sans-serif}") + +// result : images/, css/, css/style.css, css/font.css +``` + diff --git a/public/js/lib/jszip/documentation/api_jszip/folder_regex.md b/public/js/lib/jszip/documentation/api_jszip/folder_regex.md new file mode 100644 index 0000000..8d9e021 --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/folder_regex.md @@ -0,0 +1,40 @@ +--- +title: "folder(regex)" +layout: default +section: api +--- + +__Description__ : Search a subdirectory in the current directory with a +[regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions). +The regex is tested against the relative path. + +__Arguments__ + +name | type | description +------|--------|------------ +regex | RegExp | the regex to use. + +__Returns__ : An array of matching folders (an empty array if none matched). +Each maching folder is an instance of [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html). + +__Throws__ : Nothing. + + + +__Example__ + +```js +var zip = new JSZip(); +zip.folder("home/Pierre/videos"); +zip.folder("home/Pierre/photos"); +zip.folder("home/Jean/videos"); +zip.folder("home/Jean/photos"); + +zip.folder(/videos/); // array of size 2 + +zip.folder("home/Jean").folder(/^vid/); // array of 1 +``` + diff --git a/public/js/lib/jszip/documentation/api_jszip/generate.md b/public/js/lib/jszip/documentation/api_jszip/generate.md new file mode 100644 index 0000000..7b00f97 --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/generate.md @@ -0,0 +1,139 @@ +--- +title: "generate(options)" +layout: default +section: api +--- + +__Description__ : Generates the complete zip file. + +__Arguments__ + +name | type | default | description +--------------------|---------|---------|------------ +options | object | | the options to generate the zip file : +options.base64 | boolean | false | **deprecated**, use `type` instead. If `type` is not used, set to `false` to get the result as a raw byte string, `true` to encode it as base64. +options.compression | string | `STORE` (no compression) | the default file compression method to use. Available methods are `STORE` and `DEFLATE`. You can also provide your own compression method. +options.compressionOptions | object | `null` | the options to use when compressing the file, see below. +options.type | string | `base64` | The type of zip to return, see below for the other types. +options.comment | string | | The comment to use for the zip file. +options.mimeType | string | `application/zip` | mime-type for the generated file. Useful when you need to generate a file with a different extension, ie: ".ods". +options.platform | string | `DOS` | The platform to use when generating the zip file. + +Possible values for `type` : + +* `base64` (default) : the result will be a string, the binary in a base64 form. +* `string` : the result will be a string in "binary" form, using 1 byte per char (2 bytes). +* `uint8array` : the result will be a Uint8Array containing the zip. This requires a compatible browser. +* `arraybuffer` : the result will be a ArrayBuffer containing the zip. This requires a compatible browser. +* `blob` : the result will be a Blob containing the zip. This requires a compatible browser. +* `nodebuffer` : the result will be a nodejs Buffer containing the zip. This requires nodejs. + +Note : when using type = "uint8array", "arraybuffer" or "blob", be sure to +check if the browser supports it (you can use [`JSZip.support`]({{site.baseurl}}/documentation/api_jszip/support.html)). + +The `compressionOptions` parameter depends on the compression type. With +`STORE` (no compression), this parameter is ignored. With `DEFLATE`, you can +give the compression level with `compressionOptions : {level:6}` (or any level +between 1 (best speed) and 9 (best compression)). + +Note : if the entry is *already* compressed (coming from a compressed zip file), +calling `generate()` with a different compression level won't update the entry. +The reason is simple : JSZip doesn't know how compressed the content was and +how to match the compression level with the implementation we use. + +Note for the `comment` option : the zip format has no flag or field to give the +encoding of this field and JSZip will use UTF-8. With non ASCII characters you +might get encoding issues if the file archiver doesn't use UTF-8 to decode the +comment. + +If not set, JSZip will use the field `comment` on its `options`. + +Possible values for `platform` : `DOS` and `UNIX`. It also accepts nodejs +`process.platform` values. +When using `DOS`, the attribute `dosPermissions` of each file is used. +When using `UNIX`, the attribute `unixPermissions` of each file is used. + +If you set the platform value on nodejs, be sure to use `process.platform`. +`fs.stats` returns a non executable mode for folders on windows, if you +force the platform to `UNIX` the generated zip file will have a strange +behavior on UNIX platforms. + +__Returns__ : The generated zip file. + +__Throws__ : An exception if the asked `type` is not available in the browser, +see [JSZip.support]({{site.baseurl}}/documentation/api_jszip/support.html). + + + +__Example__ + +```js +var content = zip.generate({type:"blob"}); +// see FileSaver.js +saveAs(content, "hello.zip"); +``` + +```js +var content = zip.generate({type:"base64"}); +location.href="data:application/zip;base64,"+content; +``` + +```js +var content = zip.generate({type:"nodebuffer"}); +require("fs").writeFile("hello.zip", content, function(err){/*...*/}); +``` + +```js +// on nodejs +zip.file(pathname, content, { + date: stat.mtime, + unixPermissions: stat.mode +}); + +// ... + +zip.generate({ + type: 'nodebuffer', + platform: process.platform +}); +``` + +```js +//This example will Generate a Open Document Spreasheet, with the correct mime type +var zip = new JSZip(); +zip.file("mimetype", "application/vnd.oasis.opendocument.spreadsheet"); +var conf2 = zip.folder("Configurations2"); +conf2.folder("acceleator"); +conf2.folder("images"); +conf2.folder("popupmenu"); +conf2.folder("statusbar"); +conf2.folder("floater"); +conf2.folder("menubar"); +conf2.folder("progressbar"); +conf2.folder("toolbar"); + +var manifest = "<..."; //xml containing manifest.xml +var styles = "<..."; //xml containing styles.xml +var settings = "<..."; //xml containing settings.xml +var meta = "<..."; //xml containing meta.xml +var content = "<..."; //xml containing content.xml + +var metaInf = zip.folder("META-INF"); +metaInf.file("manifest.xml", manifest); +zip.file("styles.xml", styles); +zip.file("settings.xml", settings); +zip.file("meta.xml", meta); +zip.file("content.xml", content); + +//Generate the file +var odsFile = zip.generate({type: "blob", mimeType: "application/ods", compression: "DEFLATE"}); + +var url = window.URL.createObjectURL(odsFile); +var link = document.getElementById("link"); //I suppose you'll have a link with this id :) +link.download = "testjs.ods"; +link.href = url; + + +``` + + diff --git a/public/js/lib/jszip/documentation/api_jszip/load.md b/public/js/lib/jszip/documentation/api_jszip/load.md new file mode 100644 index 0000000..a2f54ad --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/load.md @@ -0,0 +1,81 @@ +--- +title: "load(data [, options])" +layout: default +section: api +--- + +__Description__ : Read an existing zip and merge the data in the current JSZip +object at the current folder level. This technique has some limitations, see +[here]({{site.baseurl}}/documentation/limitations.html). + +__Arguments__ + +name | type | description +-------------------|--------|------------ +data | String/ArrayBuffer/Uint8Array/Buffer | the zip file +options | object | the options to load the zip file + +Content of `options` : + +name | type | default | description +------------------------------|---------|---------|------------ +options.base64 | boolean | false | set to `true` if the data is base64 encoded, `false` for binary. +options.checkCRC32 | boolean | false | set to `true` if the read data should be checked against its CRC32. +options.optimizedBinaryString | boolean | false | set to true if (and only if) the input is a string and has already been prepared with a 0xFF mask. +options.createFolders | boolean | false | set to true to create folders in the file path automatically. Leaving it false will result in only virtual folders (i.e. folders that merely represent part of the file path) being created. + +You shouldn't update the data given to this method : it is kept as it so any +update will impact the stored data. + +Zip features supported by this method : + +* Compression (DEFLATE supported) +* zip with data descriptor +* ZIP64 +* UTF8 in file name, UTF8 in file content + +Zip features not (yet) supported : + +* password protected zip +* multi-volume zip + +__Returns__ : The current JSZip object. + +__Throws__ : An exception if the loaded data is not valid zip data or if it +uses features (multi volume, password protected, etc). + + + +__Example__ + +```js +var zip = new JSZip(); +zip.load(zipDataFromXHR); +``` + +```js +require("fs").readFile("hello.zip", function (err, data) { + if (err) throw err; + var zip = new JSZip(); + zip.load(data); +} +``` + +Using sub folders : + +```js +var zip = new JSZip(); +zip.folder("subfolder").load(data); +// the content of data will be loaded in subfolder/ +``` + diff --git a/public/js/lib/jszip/documentation/api_jszip/remove.md b/public/js/lib/jszip/documentation/api_jszip/remove.md new file mode 100644 index 0000000..af7aa78 --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/remove.md @@ -0,0 +1,37 @@ +--- +title: "remove(name)" +layout: default +section: api +--- + +__Description__ : Delete a file or folder (recursively). + +__Arguments__ + +name | type | description +-----|--------|------------ +name | string | the name of the file/folder to delete. + +__Returns__ : The current JSZip object. + +__Throws__ : Nothing. + + + +__Example__ + +```js +var zip = new JSZip(); +zip.file("Hello.txt", "Hello World\n"); +zip.file("temp.txt", "nothing").remove("temp.txt"); +// result : Hello.txt + +zip.folder("css").file("style.css", "body {background: #FF0000}"); +zip.remove("css"); +//result : empty zip +``` + + diff --git a/public/js/lib/jszip/documentation/api_jszip/support.md b/public/js/lib/jszip/documentation/api_jszip/support.md new file mode 100644 index 0000000..73d076f --- /dev/null +++ b/public/js/lib/jszip/documentation/api_jszip/support.md @@ -0,0 +1,16 @@ +--- +title: "JSZip.support" +layout: default +section: api +--- + +If the browser supports them, JSZip can take advantage of some "new" features : +ArrayBuffer, Blob, Uint8Array. To know if JSZip can use them, you can check the +JSZip.support object. It contains the following boolean properties : + +* `arraybuffer` : true if JSZip can read and generate ArrayBuffer, false otherwise. +* `uint8array` : true if JSZip can read and generate Uint8Array, false otherwise. +* `blob` : true if JSZip can generate Blob, false otherwise. +* `nodebuffer` : true if JSZip can read and generate nodejs Buffer, false otherwise. + + diff --git a/public/js/lib/jszip/documentation/api_zipobject.md b/public/js/lib/jszip/documentation/api_zipobject.md new file mode 100644 index 0000000..970fa8f --- /dev/null +++ b/public/js/lib/jszip/documentation/api_zipobject.md @@ -0,0 +1,37 @@ +--- +title: "ZipObject API" +layout: default +section: api +--- + +This represents an entry in the zip file. If the entry comes from an existing +archive previously [loaded]({{site.baseurl}}/documentation/api_jszip/load.html), the content +will be automatically decompressed/converted first. + +### Attributes + +attribute name | type | description +----------------------------|-------------|------------- +`name` | string | the absolute path of the file +`dir` | boolean | true if this is a directory +`date` | date | the last modification date +`comment` | string | the comment for this file +`unixPermissions` | 16 bits number | The UNIX permissions of the file, if any. +`dosPermissions` | 6 bits number | The DOS permissions of the file, if any. +`options` | object | the options of the file. The available options are : +`options.base64` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) +`options.binary` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) +`options.dir` | boolean | **Deprecated**, use `dir`. True if this is a directory +`options.date` | date | **Deprecated**, use `date`. See [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) +`options.compression` | compression | see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) + + +### Getters + +method | return type | description +------------------|---------------|------------- +`asText()` | string | the content as an unicode string. +`asBinary()` | string | the content as binary string. +`asArrayBuffer()` | ArrayBuffer | need a [compatible browser]({{site.baseurl}}/documentation/api_jszip/support.html). +`asUint8Array()` | Uint8Array | need a [compatible browser]({{site.baseurl}}/documentation/api_jszip/support.html). +`asNodeBuffer()` | nodejs Buffer | need [nodejs]({{site.baseurl}}/documentation/api_jszip/support.html). diff --git a/public/js/lib/jszip/documentation/contributing.md b/public/js/lib/jszip/documentation/contributing.md new file mode 100644 index 0000000..f1b5dd3 --- /dev/null +++ b/public/js/lib/jszip/documentation/contributing.md @@ -0,0 +1,62 @@ +--- +title: Contributing +layout: default +section: main +--- + + +### Download the sources + +You should create a [Github](https://github.com/) account and +[fork the repository](https://help.github.com/articles/fork-a-repo) (you will +need one to create the pull request). + +If you just want the get the source code, you can use git and do +`git clone https://github.com/Stuk/jszip.git` to get the sources. You can also +download the latest sources [here](https://github.com/Stuk/jszip/archive/master.zip). + +### Building the project + +#### Code + +The dependencies are handled by npm, the first step is to run +`npm install` to get the dependencies. +JSZip uses Grunt to handle the build, [see here to install its CLI](http://gruntjs.com/getting-started). + +Here are the interesting build commands : + +* `grunt` will generate the final js file in dist/ and the minified version. +* `npm run test-node` will run the tests in nodejs. +* `npm run test-browser` will the tests in some browsers using SauceLabs, see + below. +* `npm run test` will run the tests in nodejs and in the browser. +* `npm run lint` will use jshint the check the source code. + +#### Documentation + +The documentation uses jekyll on gh-pages. To render the documentation, you +need to [install jekyll](http://jekyllrb.com/docs/installation/) and then run +`jekyll serve --baseurl ''`. + +### Testing the project + +To test JSZip in nodejs, use `npm run test-node`. + +To test JSZip in a browser, you can open the file `test/index.html` in the +browser you want to test. Don't forget to update the dist/ files with `grunt`. + +You can also test JSZip in a lot of browsers at once with +[SauceLabs](https://saucelabs.com/). You will need a SauceLabs account and two +variables into your environment. On linux, just use + +```bash +export SAUCE_USERNAME=your-saucelabs-username +export SAUCE_ACCESS_KEY=your-saucelabs-access-key +``` + +before running the `npm run test-browser` command. + +### Merging the changes + +If you have tested bug fixes or new features, you can open a +[pull request](https://help.github.com/articles/using-pull-requests) on Github. diff --git a/public/js/lib/jszip/documentation/css/main.css b/public/js/lib/jszip/documentation/css/main.css new file mode 100644 index 0000000..f2a368c --- /dev/null +++ b/public/js/lib/jszip/documentation/css/main.css @@ -0,0 +1,24 @@ +ul.nav ul { + list-style:none; + margin: 0; + padding: 0 0 0 25px; +} + +#downloader_application form { + margin-bottom: 10px; +} + +#downloader_application ul { + list-style-type: none; +} + +.browser_support th { + border-bottom-width: 3px !important; +} + +.support_ie {border-bottom-color: #0275BA !important;} +.support_ff {border-bottom-color: #DF7215 !important;} +.support_sf {border-bottom-color: #43B3E9 !important;} +.support_cr {border-bottom-color: #39B642 !important;} +.support_op {border-bottom-color: #C42122 !important;} +.support_nd {border-bottom-color: #8CC84B !important;} diff --git a/public/js/lib/jszip/documentation/css/pygments.css b/public/js/lib/jszip/documentation/css/pygments.css new file mode 100644 index 0000000..2086339 --- /dev/null +++ b/public/js/lib/jszip/documentation/css/pygments.css @@ -0,0 +1,64 @@ +/* Generated with : + * pygmentize -S default -f html > pygments.css + */ +.hll { background-color: #ffffcc } +.c { color: #408080; font-style: italic } /* Comment */ +.err { border: 1px solid #FF0000 } /* Error */ +.k { color: #008000; font-weight: bold } /* Keyword */ +.o { color: #666666 } /* Operator */ +.cm { color: #408080; font-style: italic } /* Comment.Multiline */ +.cp { color: #BC7A00 } /* Comment.Preproc */ +.c1 { color: #408080; font-style: italic } /* Comment.Single */ +.cs { color: #408080; font-style: italic } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.gr { color: #FF0000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #00A000 } /* Generic.Inserted */ +.go { color: #888888 } /* Generic.Output */ +.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #0044DD } /* Generic.Traceback */ +.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #008000 } /* Keyword.Pseudo */ +.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #B00040 } /* Keyword.Type */ +.m { color: #666666 } /* Literal.Number */ +.s { color: #BA2121 } /* Literal.String */ +.na { color: #7D9029 } /* Name.Attribute */ +.nb { color: #008000 } /* Name.Builtin */ +.nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.no { color: #880000 } /* Name.Constant */ +.nd { color: #AA22FF } /* Name.Decorator */ +.ni { color: #999999; font-weight: bold } /* Name.Entity */ +.ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.nf { color: #0000FF } /* Name.Function */ +.nl { color: #A0A000 } /* Name.Label */ +.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.nt { color: #008000; font-weight: bold } /* Name.Tag */ +.nv { color: #19177C } /* Name.Variable */ +.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.w { color: #bbbbbb } /* Text.Whitespace */ +.mf { color: #666666 } /* Literal.Number.Float */ +.mh { color: #666666 } /* Literal.Number.Hex */ +.mi { color: #666666 } /* Literal.Number.Integer */ +.mo { color: #666666 } /* Literal.Number.Oct */ +.sb { color: #BA2121 } /* Literal.String.Backtick */ +.sc { color: #BA2121 } /* Literal.String.Char */ +.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.s2 { color: #BA2121 } /* Literal.String.Double */ +.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.sh { color: #BA2121 } /* Literal.String.Heredoc */ +.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.sx { color: #008000 } /* Literal.String.Other */ +.sr { color: #BB6688 } /* Literal.String.Regex */ +.s1 { color: #BA2121 } /* Literal.String.Single */ +.ss { color: #19177C } /* Literal.String.Symbol */ +.bp { color: #008000 } /* Name.Builtin.Pseudo */ +.vc { color: #19177C } /* Name.Variable.Class */ +.vg { color: #19177C } /* Name.Variable.Global */ +.vi { color: #19177C } /* Name.Variable.Instance */ +.il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/public/js/lib/jszip/documentation/examples.md b/public/js/lib/jszip/documentation/examples.md new file mode 100644 index 0000000..01d6e2d --- /dev/null +++ b/public/js/lib/jszip/documentation/examples.md @@ -0,0 +1,115 @@ +--- +title: "How to use JSZip" +layout: default +section: example +--- + +An instance of JSZip represents a set of files. You can add them, remove them, +modify them. You can also import an existing zip file or generate one. + +### Getting the object + +#### In a browser + +For a browser, there are two interesting files : `dist/jszip.js` and +`dist/jszip.min.js` (include just one). + +If you use an AMD loader (RequireJS for example) JSZip will register itself : +you just have to put the js file at the right place, or configure the loader +(see [here for RequireJS](http://requirejs.org/docs/api.html#config-paths)). + +Without any loader, JSZip will declare in the global scope a variable named `JSZip`. + +#### In nodejs + +In nodejs, you can `require` it : + +```js +var JSZip = require("jszip"); +``` + +### Basic manipulations + +The first step is to create an instance of JSZip : + +```js +var zip = new JSZip(); +``` + +On this instance, we can add (and update) files and folders with +`.file(name, content)` and `.folder(name)`. +They return the current JSZip instance so you can chain the calls. + +```js +// create a file +zip.file("hello.txt", "Hello[p my)6cxsw2q"); +// oops, cat on keyboard. Fixing ! +zip.file("hello.txt", "Hello World\n"); + +// create a file and a folder +zip.file("nested/hello.txt", "Hello World\n"); +// same as +zip.folder("nested").file("hello.txt", "Hello World\n"); +``` + +With `.folder(name)`, the returned object has a different root : if you add files +on this object, you will put them in the created subfolder. This is just a +view, the added files will also be in the "root" object. + +```js +var photoZip = zip.folder("photos"); +// this call will create photos/README +photoZip.file("README", "a folder with photos"); +``` + +You can access the file content with `.file(name)` and +[its getters]({{site.baseurl}}/documentation/api_zipobject.html) : + +```js +zip.file("hello.txt").asText(); // "Hello World\n" + +if (JSZip.support.uint8array) { + zip.file("hello.txt").asUint8Array(); // Uint8Array { 0=72, 1=101, 2=108, more...} +} +``` + +You can also remove files or folders with `.remove(name)` : + +```js +zip.remove("photos/README"); +zip.remove("photos"); +// same as +zip.remove("photos"); // by removing the folder, you also remove its content. +``` + +### Generate a zip file + +With `.generate(options)` you can generate a zip file (not a real file but its +representation in memory). Check +[this page]({{site.baseurl}}/documentation/howto/write_zip.html) for more +informations on how to write / give the file to the user. + +```js +var content = null; +if (JSZip.support.uint8array) { + content = zip.generate({type : "uint8array"}); +} else { + content = zip.generate({type : "string"}); +} +``` + +### Read a zip file + +With `.load(data)` you can load a zip file. Check +[this page]({{site.baseurl}}/documentation/howto/read_zip.html) to see how to +do properly (it's more tricky that it seems). + +```js +var new_zip = new JSZip(); +// more files ! +new_zip.load(content); + +// you now have every files contained in the loaded zip +new_zip.file("hello.txt").asText(); // "Hello World\n" +``` + diff --git a/public/js/lib/jszip/documentation/examples/download-zip-file.html b/public/js/lib/jszip/documentation/examples/download-zip-file.html new file mode 100644 index 0000000..869a54e --- /dev/null +++ b/public/js/lib/jszip/documentation/examples/download-zip-file.html @@ -0,0 +1,59 @@ +--- +title: "Download the generated zip file" +layout: default +section: example +--- + +

Tip : check the source of the page !

+

The FileSaver API

+
+ Works on firefox, chrome , opera >= 15 and IE >= 10 (but NOT in compatibility view).
+ +
+

The data URL

+
+ Does not work in IE, has restrictions on the length.
+ +
+ diff --git a/public/js/lib/jszip/documentation/examples/downloader.html b/public/js/lib/jszip/documentation/examples/downloader.html new file mode 100644 index 0000000..e3589db --- /dev/null +++ b/public/js/lib/jszip/documentation/examples/downloader.html @@ -0,0 +1,58 @@ +--- +title: "Mini app : Downloader" +layout: default +section: example +--- + +

Tip : check the source of the page !

+ +

+ This mini application let you choose the files you want in a list, download + them, zip them and give the result to the user. +

+

+ This demo requires a recent browser, see + the howto. +

+ + + +
+

Please select your files

+
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+ + +
+ +

+ + +
+ + diff --git a/public/js/lib/jszip/documentation/examples/downloader.js b/public/js/lib/jszip/documentation/examples/downloader.js new file mode 100644 index 0000000..13903cc --- /dev/null +++ b/public/js/lib/jszip/documentation/examples/downloader.js @@ -0,0 +1,89 @@ +jQuery(function ($) { + "use strict"; + + /** + * Reset the message. + */ + function resetMessage () { + $("#result") + .removeClass() + .text(""); + } + /** + * show a successful message. + * @param {String} text the text to show. + */ + function showMessage(text) { + resetMessage(); + $("#result") + .addClass("alert alert-success") + .text(text); + } + /** + * show an error message. + * @param {String} text the text to show. + */ + function showError(text) { + resetMessage(); + $("#result") + .addClass("alert alert-danger") + .text(text); + } + + /** + * Fetch the content, add it to the JSZip object + * and use a jQuery deferred to hold the result. + * @param {String} url the url of the content to fetch. + * @param {String} filename the filename to use in the JSZip object. + * @param {JSZip} zip the JSZip instance. + * @return {jQuery.Deferred} the deferred containing the data. + */ + function deferredAddZip(url, filename, zip) { + var deferred = $.Deferred(); + JSZipUtils.getBinaryContent(url, function (err, data) { + if(err) { + deferred.reject(err); + } else { + zip.file(filename, data, {binary:true}); + deferred.resolve(data); + } + }); + return deferred; + } + + if(!JSZip.support.blob) { + showError("This demo works only with a recent browser !"); + return; + } + + var $form = $("#download_form").on("submit", function () { + + resetMessage(); + + var zip = new JSZip(); + var deferreds = []; + + // find every checked item + $(this).find(":checked").each(function () { + var $this = $(this); + var url = $this.data("url"); + var filename = url.replace(/.*\//g, ""); + deferreds.push(deferredAddZip(url, filename, zip)); + }); + + // when everything has been downloaded, we can trigger the dl + $.when.apply($, deferreds).done(function () { + var blob = zip.generate({type:"blob"}); + + // see FileSaver.js + saveAs(blob, "example.zip"); + + showMessage("done !"); + }).fail(function (err) { + showError(err); + }); + return false; + }); +}); + +// vim: set shiftwidth=4 softtabstop=4: diff --git a/public/js/lib/jszip/documentation/examples/get-binary-files-ajax.html b/public/js/lib/jszip/documentation/examples/get-binary-files-ajax.html new file mode 100644 index 0000000..ee7594e --- /dev/null +++ b/public/js/lib/jszip/documentation/examples/get-binary-files-ajax.html @@ -0,0 +1,43 @@ +--- +title: "Get a file with an ajax call" +layout: default +section: example +--- + +

Tip : check the source of the page !

+ +

With JSZipUtils

+
+ + diff --git a/public/js/lib/jszip/documentation/examples/read-local-file-api.html b/public/js/lib/jszip/documentation/examples/read-local-file-api.html new file mode 100644 index 0000000..da307c2 --- /dev/null +++ b/public/js/lib/jszip/documentation/examples/read-local-file-api.html @@ -0,0 +1,87 @@ +--- +title: "Reading a local file with the File API" +layout: default +section: example +--- + +

Choose the local(s) zip file(s)

+

Note : your browser will process the zip file, don't choose a file too big !

+
+ + + + + + diff --git a/public/js/lib/jszip/documentation/faq.md b/public/js/lib/jszip/documentation/faq.md new file mode 100644 index 0000000..57059e2 --- /dev/null +++ b/public/js/lib/jszip/documentation/faq.md @@ -0,0 +1,19 @@ +--- +title: "Frequently Asked Questions" +layout: default +section: main +--- + +### "Corrupted zip or bug : unexpected signature" + +If you are sure that the zip file is correct, that error often comes from a +corrupted content. An ajax request, if not prepared correctly, will try to +decode the binary content as a text and corrupt it. See +[this page]({{site.baseurl}}/documentation/howto/read_zip.html). + +### My browser crashes / becomes unresponsive / never finish the execution + +That happens if you try to handle to much data. If possible, try again with a +small (some KB) zip file to see if your code is correct. See +[this page]({{site.baseurl}}/documentation/limitations.html) for more +informations. diff --git a/public/js/lib/jszip/documentation/howto/read_zip.md b/public/js/lib/jszip/documentation/howto/read_zip.md new file mode 100644 index 0000000..48a5240 --- /dev/null +++ b/public/js/lib/jszip/documentation/howto/read_zip.md @@ -0,0 +1,152 @@ +--- +title: "How to read a file" +layout: default +section: example +--- + +This page explains how to read an existing zip file or add a existing file into +the zip file. + + +### In the browser + +#### AJAX request + +Getting binary data with an ajax request is hard (mainly because of IE <= 9). +The easy way is to use [JSZipUtils.getBinaryContent](https://github.com/stuk/jszip-utils). +With JSZipUtils.getBinaryContent, you can do the following (see the +documentation for more examples) : + +```js +JSZipUtils.getBinaryContent('path/to/content.zip', function(err, data) { + if(err) { + throw err; // or handle err + } + + var zip = new JSZip(data); +}); +``` + +
+ +If you need to adapt an existing solution to what getBinaryContent does, here +are the details. When doing a XHR request (level 1, without setting the +`responseType`) the browser will try to interpret the response as a string and +decode it from its charset. To avoid this on Firefox/Chrome/Opera, you need to +set mime type : `xhr.overrideMimeType("text/plain; charset=x-user-defined");`. +On IE <= 9, this is harder. The overrideMimeType trick doesn't work so we need +to use [vbscript](http://stackoverflow.com/questions/1095102/how-do-i-load-binary-image-data-using-javascript-and-xmlhttprequest) +and non standard attributes. +On IE > 9, overrideMimeType doesn't work but xhr2 does. + +With [xhr 2](http://caniuse.com/xhr2), you can just set the responseType +attribute : `xhr.responseType = "arraybuffer";`. With this, the browser will +return an ArrayBuffer. + +#### Local files + +If the browser supports the [FileReader API](http://caniuse.com/filereader), +you can use it to read a zip file. JSZip can read ArrayBuffer, so you can use +`FileReader.readAsArrayBuffer(Blob)`, see this [example]({{site.baseurl}}/documentation/examples/read-local-file-api.html). + +### In nodejs + +JSZip can read Buffers so you can do the following : + +#### Local file + +```js +"use strict"; + +var fs = require("fs"); +var JSZip = require("jszip"); + +// read a zip file +fs.readFile("test.zip", function(err, data) { + if (err) throw err; + var zip = new JSZip(data); +}); + +// read a file and add it to a zip +fs.readFile("picture.png", function(err, data) { + if (err) throw err; + var zip = new JSZip(); + zip.file("picture.png", data); +}); +``` + +#### Remote file + +There are a lot of nodejs libraries doing http requests, from the built-in +[http](http://nodejs.org/docs/latest/api/http.html) to the +[npm packages](https://www.npmjs.org/browse/keyword/http). Here are two +examples, one with the default http API, the other with +[request](https://github.com/mikeal/request) (but you're free to use your +favorite library !). If possible, download the file as a Buffer (you will get +better performances). If it's not possible, you can fallback to a binary string +(the option is likely to be `encoding : "binary"`). + +##### With http : + +```js +"use strict"; + +var http = require("http"); +var url = require("url"); +var JSZip = require("jszip"); + +var req = http.get(url.parse("http://localhost/.../file.zip"), function (res) { + if (res.statusCode !== 200) { + console.log(res.statusCode); + // handle error + return; + } + var data = [], dataLen = 0; + + // don't set the encoding, it will break everything ! + // or, if you must, set it to null. In that case the chunk will be a string. + + res.on("data", function (chunk) { + data.push(chunk); + dataLen += chunk.length; + }); + + res.on("end", function () { + var buf = new Buffer(dataLen); + for (var i=0,len=data.length,pos=0; i + +#### Deprecated google gears + +[Franz Buchinger](http://www.picurl.org/blog/author/franz/) has written a +brilliant tutorial on [using JSZip with Google Gears](http://www.picurl.org/blog/2009/11/22/creating-zip-archives-with-gears) +([part 2](http://www.picurl.org/blog/2009/11/29/gearszipper-part2-adding-support-for-real-files-and-canvas-elements/)). +If you want to let your Gears users download several files at once I really +recommend having a look at some of his [examples](http://picurl.org/gears/zipper/). + + + +### In nodejs + +JSZip can generate Buffers so you can do the following : + +```js +var fs = require("fs"); +var JSZip = require("jszip"); + +var zip = new JSZip(); +// zip.file("file", content); +// ... and other manipulations + +var buffer = zip.generate({type:"nodebuffer"}); + +fs.writeFile("test.zip", buffer, function(err) { + if (err) throw err; +}); +``` + + diff --git a/public/js/lib/jszip/documentation/limitations.md b/public/js/lib/jszip/documentation/limitations.md new file mode 100644 index 0000000..62db22e --- /dev/null +++ b/public/js/lib/jszip/documentation/limitations.md @@ -0,0 +1,73 @@ +--- +title: "Limitations of JSZip" +layout: default +section: limitations +fullpage: true +--- + +### Not supported features + +All the features of zip files are not supported. Classic zip files will work +but encrypted zip, multi-volume, etc are not supported and the load() method +will throw an `Error`. + + +### ZIP64 and 32bit integers + +ZIP64 files can be loaded, but only if the zip file is not "too big". ZIP64 uses 64bits integers +but Javascript represents all numbers as +[64-bit double precision IEEE 754 floating point numbers](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf) +(see section 8.5). So, we have 53bits for integers and +[bitwise operations treat everything as 32bits](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators). +So if all the 64bits integers can fit into 32 bits integers, everything will be +fine. If it's not the case, you will have other problems anyway (see next +limitation). + +### Performance issues + +An other limitation comes from the browser (and the machine running the +browser). A compressed zip file of 10MB is "easily" opened by firefox / chrome +/ opera / IE10+ but will crash older IE. Also keep in mind that strings in +javascript are encoded in UTF-16 : a 10MB ascii text file will take 20MB of +memory. + +If you're having performance issues, please consider the following : + +* Don't use IE <= 9. Everything is better with typed arrays. +* Use typed arrays (Uint8Array, ArrayBuffer, etc) if possible : + * If you generate a zip file, you should use `type:"uint8array"` + (or blob, arraybuffer, nodebuffer). + * If you load the file from an ajax call, ask your XHR an ArrayBuffer. + Loading a string is asking for troubles. +* Don't use compression (see below). +* If you want to get the content of an ASCII file as a string, consider using + `asBinary()` instead of `asText()`. The transformation + "binary string" -> "unicode string" is a consuming process. + +Note about compression : +When reading a file, JSZip will store the content without decompressing it. +When generating a compressed file, JSZip will reuse if possible compressed +content : + +* If you read a zip file compressed with DEFLATE and call `generate` with the + DEFLATE compression, JSZip won't call the compression algorithms (same with + STORE everywhere.) +* If you read a zip file compressed with DEFLATE and call `generate` with the + STORE compression, JSZip will have to decompress everything. + +On IE <=9, typed arrays are not supported and the compression algorithm +will fallback on arrays. In that case, JSZip needs to convert the binary string +into an array, DEFLATE it and convert the result into a binary string. +You don't want that to happen. + +### The output zip will differ from the input zip + +Reading and generating a zip file won't give you back the same file. +Some data are discarded (file metadata) and other are added (subfolders). + +### Encodings support + +JSZip only supports utf8 : if the names of the files inside the zip are not in +utf8 (or ASCII), they won't be interpreted correctly. If the content is a text +not encoded with utf8 (or ASCII), the `asText()` method won't decode it +correctly. diff --git a/public/js/lib/jszip/documentation/upgrade_guide.md b/public/js/lib/jszip/documentation/upgrade_guide.md new file mode 100644 index 0000000..1dfac9c --- /dev/null +++ b/public/js/lib/jszip/documentation/upgrade_guide.md @@ -0,0 +1,57 @@ +--- +title: Upgrade Guide +layout: default +section: main +--- + +### From 2.2.2 to 2.3.0 + +* On `ZipObject#options`, the attributes `date` and `dir` have been + deprecated and are now on `ZipObject`. +* On `ZipObject#options`, the attributes `base64` and `binary` have been + deprecated. +* `JSZip.base64`, `JSZip.prototype.crc32`, `JSZip.prototype.utf8decode`, + `JSZip.prototype.utf8encode` and `JSZip.utils` have been deprecated. + +```js +// deprecated +zip.file("test.txt").options.date +zip.file("test.txt").options.dir +// new API +zip.file("test.txt").date +zip.file("test.txt").dir +``` + + +### From 2.0.0 to 2.1.0 + +* The packaging changed : instead of loading jszip.js, jszip-load.js, + jszip-inflate.js, jszip-deflate.js, just include dist/jszip.js or + dist/jszip.min.js. + For AMD loader users : JSZip now registers itself. You just have to put the + file at the right place or configure your loader. + + +### From 1.x to 2.x + +* `JSZipBase64` has been renamed to `JSZip.base64`. +* The `data` attribute doesn't exist anymore : + use the getters `asText()`, `asBinary()`, etc +* The compression/decompression methods now give their input type with the + `compressInputType` and `uncompressInputType` attributes. + +Example for the data attribute : + +```js +// before +zip.file("test.txt").data; +zip.files["test.txt"].data; +zip.file("image.png").data; +zip.files["image.png"].data; + +// after +zip.file("test.txt").asText(); +zip.files["test.txt"].asText(); +zip.file("image.png").asBinary(); +zip.files["image.png"].asBinary(); +``` diff --git a/public/js/lib/jszip/index.html b/public/js/lib/jszip/index.html new file mode 100644 index 0000000..0939ee9 --- /dev/null +++ b/public/js/lib/jszip/index.html @@ -0,0 +1,169 @@ +--- +title: JSZip +layout: default +section: main +--- + +
+
+ +JSZip is a javascript library for creating, reading and editing .zip files, with a +lovely and simple API. + +
+
+

+ Current version : v2.5.0 +

+

+ License : JSZip is dual-licensed. You may use it under the + MIT license or the GPLv3 license. See + LICENSE.markdown. +

+
+ +
+
+ +

Example

+ + + + + + +
+
+ +

Installation

+ +

+ With npm : npm install jszip +

+

+ With bower : bower install Stuk/jszip +

+

+ With component : component install Stuk/jszip +

+

+ Manually : download JSZip + and include the file dist/jszip.js or dist/jszip.min.js +

+
+

+ Installed ? Great ! You can now check our + guides and examples ! +

+
+
+ +

Support

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
OperaFirefoxSafariChromeInternet ExplorerNode.js
YesYesYesYesYesYes
Tested with the latest versionTested with 3.0 / 3.6 / latest versionTested with the latest versionTested with the latest versionTested with IE 6 / 7 / 8 / 9 / 10Tested with node.js 0.8 and 0.10
+ +

Getting help

+ +

+Having trouble ? We'd like to help ! +

+
    +
  • + Try the FAQ, it has + answers to common questions. +
  • +
  • + If you're looking for informations about a specific method, try the + documentation. +
  • +
  • + Check the + examples. +
  • +
  • + Report bugs in our + Bug tracker. +
  • +
+ +

Test status

+ +
+
Travis build :
+
+ + + +
+
Saucelabs build :
+
+ + + +
+
Live tests :
+
+ See for yourself ! +
+
diff --git a/public/js/lib/jszip/lib/base64.js b/public/js/lib/jszip/lib/base64.js new file mode 100644 index 0000000..13b4863 --- /dev/null +++ b/public/js/lib/jszip/lib/base64.js @@ -0,0 +1,70 @@ +'use strict'; +// private property +var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + +// public method for encoding +exports.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; + } + + output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); + + } + + return output; +}; + +// public method for decoding +exports.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); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + + } + + return output; + +}; diff --git a/public/js/lib/jszip/lib/compressedObject.js b/public/js/lib/jszip/lib/compressedObject.js new file mode 100644 index 0000000..d6de504 --- /dev/null +++ b/public/js/lib/jszip/lib/compressedObject.js @@ -0,0 +1,28 @@ +'use strict'; +function CompressedObject() { + this.compressedSize = 0; + this.uncompressedSize = 0; + this.crc32 = 0; + this.compressionMethod = null; + this.compressedContent = null; +} + +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 + } +}; +module.exports = CompressedObject; diff --git a/public/js/lib/jszip/lib/compressions.js b/public/js/lib/jszip/lib/compressions.js new file mode 100644 index 0000000..a2c13ff --- /dev/null +++ b/public/js/lib/jszip/lib/compressions.js @@ -0,0 +1,13 @@ +'use strict'; +exports.STORE = { + magic: "\x00\x00", + compress: function(content, compressionOptions) { + return content; // no compression + }, + uncompress: function(content) { + return content; // no compression + }, + compressInputType: null, + uncompressInputType: null +}; +exports.DEFLATE = require('./flate'); diff --git a/public/js/lib/jszip/lib/crc32.js b/public/js/lib/jszip/lib/crc32.js new file mode 100644 index 0000000..48d4a4a --- /dev/null +++ b/public/js/lib/jszip/lib/crc32.js @@ -0,0 +1,102 @@ +'use strict'; + +var utils = require('./utils'); + +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 +]; + +/** + * + * Javascript crc32 + * http://www.webtoolkit.info/ + * + */ +module.exports = function crc32(input, crc) { + if (typeof input === "undefined" || !input.length) { + return 0; + } + + var isArray = utils.getTypeOf(input) !== "string"; + + if (typeof(crc) == "undefined") { + crc = 0; + } + var x = 0; + var y = 0; + var b = 0; + + crc = crc ^ (-1); + for (var i = 0, iTop = input.length; i < iTop; i++) { + b = isArray ? input[i] : input.charCodeAt(i); + y = (crc ^ b) & 0xFF; + x = table[y]; + crc = (crc >>> 8) ^ x; + } + + return crc ^ (-1); +}; +// vim: set shiftwidth=4 softtabstop=4: diff --git a/public/js/lib/jszip/lib/dataReader.js b/public/js/lib/jszip/lib/dataReader.js new file mode 100644 index 0000000..22e8cb3 --- /dev/null +++ b/public/js/lib/jszip/lib/dataReader.js @@ -0,0 +1,107 @@ +'use strict'; +var utils = require('./utils'); + +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 utils.transformTo("string", this.readData(size)); + }, + /** + * Get raw data without conversion, 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 + } +}; +module.exports = DataReader; diff --git a/public/js/lib/jszip/lib/defaults.js b/public/js/lib/jszip/lib/defaults.js new file mode 100644 index 0000000..720c4da --- /dev/null +++ b/public/js/lib/jszip/lib/defaults.js @@ -0,0 +1,11 @@ +'use strict'; +exports.base64 = false; +exports.binary = false; +exports.dir = false; +exports.createFolders = false; +exports.date = null; +exports.compression = null; +exports.compressionOptions = null; +exports.comment = null; +exports.unixPermissions = null; +exports.dosPermissions = null; diff --git a/public/js/lib/jszip/lib/deprecatedPublicUtils.js b/public/js/lib/jszip/lib/deprecatedPublicUtils.js new file mode 100644 index 0000000..0c6b9b8 --- /dev/null +++ b/public/js/lib/jszip/lib/deprecatedPublicUtils.js @@ -0,0 +1,105 @@ +'use strict'; +var utils = require('./utils'); + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.string2binary = function(str) { + return utils.string2binary(str); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.string2Uint8Array = function(str) { + return utils.transformTo("uint8array", str); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.uint8Array2String = function(array) { + return utils.transformTo("string", array); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.string2Blob = function(str) { + var buffer = utils.transformTo("arraybuffer", str); + return utils.arrayBuffer2Blob(buffer); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.arrayBuffer2Blob = function(buffer) { + return utils.arrayBuffer2Blob(buffer); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.transformTo = function(outputType, input) { + return utils.transformTo(outputType, input); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.getTypeOf = function(input) { + return utils.getTypeOf(input); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.checkSupport = function(type) { + return utils.checkSupport(type); +}; + +/** + * @deprecated + * This value will be removed in a future version without replacement. + */ +exports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS; + +/** + * @deprecated + * This value will be removed in a future version without replacement. + */ +exports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS; + + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.pretty = function(str) { + return utils.pretty(str); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.findCompression = function(compressionMethod) { + return utils.findCompression(compressionMethod); +}; + +/** + * @deprecated + * This function will be removed in a future version without replacement. + */ +exports.isRegExp = function (object) { + return utils.isRegExp(object); +}; + diff --git a/public/js/lib/jszip/lib/flate.js b/public/js/lib/jszip/lib/flate.js new file mode 100644 index 0000000..d138177 --- /dev/null +++ b/public/js/lib/jszip/lib/flate.js @@ -0,0 +1,16 @@ +'use strict'; +var USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined'); + +var pako = require("pako"); +exports.uncompressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; +exports.compressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; + +exports.magic = "\x08\x00"; +exports.compress = function(input, compressionOptions) { + return pako.deflateRaw(input, { + level : compressionOptions.level || -1 // default compression + }); +}; +exports.uncompress = function(input) { + return pako.inflateRaw(input); +}; diff --git a/public/js/lib/jszip/lib/index.js b/public/js/lib/jszip/lib/index.js new file mode 100644 index 0000000..96c3389 --- /dev/null +++ b/public/js/lib/jszip/lib/index.js @@ -0,0 +1,79 @@ +'use strict'; + +var base64 = require('./base64'); + +/** +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(); + +**/ + +/** + * Representation a of zip file in js + * @constructor + * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional). + * @param {Object=} options the options for creating this objects (optional). + */ +function JSZip(data, options) { + // if this constructor is used without `new`, it adds `new` before itself: + if(!(this instanceof JSZip)) return new JSZip(data, options); + + // object containing the files : + // { + // "folder/" : {...}, + // "folder/data.txt" : {...} + // } + this.files = {}; + + this.comment = null; + + // Where we are in the hierarchy + this.root = ""; + if (data) { + this.load(data, options); + } + this.clone = function() { + var newObj = new JSZip(); + for (var i in this) { + if (typeof this[i] !== "function") { + newObj[i] = this[i]; + } + } + return newObj; + }; +} +JSZip.prototype = require('./object'); +JSZip.prototype.load = require('./load'); +JSZip.support = require('./support'); +JSZip.defaults = require('./defaults'); + +/** + * @deprecated + * This namespace will be removed in a future version without replacement. + */ +JSZip.utils = require('./deprecatedPublicUtils'); + +JSZip.base64 = { + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + encode : function(input) { + return base64.encode(input); + }, + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + decode : function(input) { + return base64.decode(input); + } +}; +JSZip.compressions = require('./compressions'); +module.exports = JSZip; diff --git a/public/js/lib/jszip/lib/license_header.js b/public/js/lib/jszip/lib/license_header.js new file mode 100644 index 0000000..b156bc7 --- /dev/null +++ b/public/js/lib/jszip/lib/license_header.js @@ -0,0 +1,11 @@ +/*! + +JSZip - A Javascript class for generating and reading zip files + + +(c) 2009-2014 Stuart Knightley +Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. + +JSZip uses the library pako released under the MIT license : +https://github.com/nodeca/pako/blob/master/LICENSE +*/ diff --git a/public/js/lib/jszip/lib/load.js b/public/js/lib/jszip/lib/load.js new file mode 100644 index 0000000..e003110 --- /dev/null +++ b/public/js/lib/jszip/lib/load.js @@ -0,0 +1,31 @@ +'use strict'; +var base64 = require('./base64'); +var ZipEntries = require('./zipEntries'); +module.exports = function(data, options) { + var files, zipEntries, i, input; + options = options || {}; + if (options.base64) { + data = 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, + comment : input.fileComment.length ? input.fileComment : null, + unixPermissions : input.unixPermissions, + dosPermissions : input.dosPermissions, + createFolders: options.createFolders + }); + } + if (zipEntries.zipComment.length) { + this.comment = zipEntries.zipComment; + } + + return this; +}; diff --git a/public/js/lib/jszip/lib/nodeBuffer.js b/public/js/lib/jszip/lib/nodeBuffer.js new file mode 100644 index 0000000..84694f6 --- /dev/null +++ b/public/js/lib/jszip/lib/nodeBuffer.js @@ -0,0 +1,7 @@ +'use strict'; +module.exports = function(data, encoding){ + return new Buffer(data, encoding); +}; +module.exports.test = function(b){ + return Buffer.isBuffer(b); +}; diff --git a/public/js/lib/jszip/lib/nodeBufferReader.js b/public/js/lib/jszip/lib/nodeBufferReader.js new file mode 100644 index 0000000..223bd0b --- /dev/null +++ b/public/js/lib/jszip/lib/nodeBufferReader.js @@ -0,0 +1,20 @@ +'use strict'; +var Uint8ArrayReader = require('./uint8ArrayReader'); + +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; +}; +module.exports = NodeBufferReader; diff --git a/public/js/lib/jszip/lib/object.js b/public/js/lib/jszip/lib/object.js new file mode 100644 index 0000000..3b5e5b8 --- /dev/null +++ b/public/js/lib/jszip/lib/object.js @@ -0,0 +1,883 @@ +'use strict'; +var support = require('./support'); +var utils = require('./utils'); +var crc32 = require('./crc32'); +var signature = require('./signature'); +var defaults = require('./defaults'); +var base64 = require('./base64'); +var compressions = require('./compressions'); +var CompressedObject = require('./compressedObject'); +var nodeBuffer = require('./nodeBuffer'); +var utf8 = require('./utf8'); +var StringWriter = require('./stringWriter'); +var Uint8ArrayWriter = require('./uint8ArrayWriter'); + +/** + * 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 CompressedObject) { + file._data = file._data.getContent(); + file.options.binary = true; + file.options.base64 = false; + + if (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 = 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 (support.nodebuffer) { + return nodeBuffer(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 = 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 = out.utf8decode(result); + } + else { + // no utf8 transformation, do the array => string step. + result = utils.transformTo("string", result); + } + + if (!asUTF8 && !this.options.binary) { + result = utils.transformTo("string", out.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.dir = options.dir; + this.date = options.date; + this.comment = options.comment; + this.unixPermissions = options.unixPermissions; + this.dosPermissions = options.dosPermissions; + + this._data = data; + this.options = options; + + /* + * This object contains initial values for dir and date. + * With them, we can check if the user changed the deprecated metadata in + * `ZipObject#options` or not. + */ + this._initialMetadata = { + dir : options.dir, + date : options.date + }; +}; + +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 utils.transformTo("nodebuffer", result); + }, + /** + * Returns the content as an Uint8Array. + * @return {Uint8Array} the content as an Uint8Array. + */ + asUint8Array: function() { + var result = getBinaryData(this); + return 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 || {}; + if (o.base64 === true && (o.binary === null || o.binary === undefined)) { + o.binary = true; + } + o = extend(o, 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 dataType = utils.getTypeOf(data), + parent; + + o = prepareFileAttrs(o); + + if (typeof o.unixPermissions === "string") { + o.unixPermissions = parseInt(o.unixPermissions, 8); + } + + // UNX_IFDIR 0040000 see zipinfo.c + if (o.unixPermissions && (o.unixPermissions & 0x4000)) { + o.dir = true; + } + // Bit 4 Directory + if (o.dosPermissions && (o.dosPermissions & 0x0010)) { + o.dir = true; + } + + if (o.dir) { + name = forceTrailingSlash(name); + } + + if (o.createFolders && (parent = parentFolder(name))) { + folderAdd.call(this, parent, true); + } + + if (o.dir || data === null || typeof data === "undefined") { + o.base64 = false; + o.binary = false; + data = null; + dataType = 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 = utils.string2binary(data); + } + } + } + else { // arraybuffer, uint8array, ... + o.base64 = false; + o.binary = true; + + if (!dataType && !(data instanceof 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 = 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) : ""; +}; + + +/** + * Returns the path with a slash at the end. + * @private + * @param {String} path the path to check. + * @return {String} the path with a trailing slash. + */ +var forceTrailingSlash = function(path) { + // Check the name ends with a / + if (path.slice(-1) != "/") { + path += "/"; // IE doesn't like substr(-1) + } + return path; +}; +/** + * Add a (sub) folder in the current folder. + * @private + * @param {string} name the folder's name + * @param {boolean=} [createFolders] If true, automatically create sub + * folders. Defaults to false. + * @return {Object} the new folder. + */ +var folderAdd = function(name, createFolders) { + createFolders = (typeof createFolders !== 'undefined') ? createFolders : false; + + name = forceTrailingSlash(name); + + // Does this folder already exist? + if (!this.files[name]) { + fileAdd.call(this, name, null, { + dir: true, + createFolders: createFolders + }); + } + 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. + * @param {Object} compressionOptions the options to use when compressing. + * @return {JSZip.CompressedObject} the compressed result. + */ +var generateCompressedObjectFrom = function(file, compression, compressionOptions) { + var result = new CompressedObject(), + content; + + // the data has not been decompressed, we might reuse things ! + if (file._data instanceof CompressedObject) { + result.uncompressedSize = file._data.uncompressedSize; + result.crc32 = file._data.crc32; + + if (result.uncompressedSize === 0 || file.dir) { + compression = 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(utils.transformTo(compression.compressInputType, content), compressionOptions); + } + } + else { + // have uncompressed data + content = getBinaryData(file); + if (!content || content.length === 0 || file.dir) { + compression = compressions['STORE']; + content = ""; + } + result.uncompressedSize = content.length; + result.crc32 = crc32(content); + result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions); + } + + result.compressedSize = result.compressedContent.length; + result.compressionMethod = compression.magic; + + return result; +}; + + + + +/** + * Generate the UNIX part of the external file attributes. + * @param {Object} unixPermissions the unix permissions or null. + * @param {Boolean} isDir true if the entry is a directory, false otherwise. + * @return {Number} a 32 bit integer. + * + * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute : + * + * TTTTsstrwxrwxrwx0000000000ADVSHR + * ^^^^____________________________ file type, see zipinfo.c (UNX_*) + * ^^^_________________________ setuid, setgid, sticky + * ^^^^^^^^^________________ permissions + * ^^^^^^^^^^______ not used ? + * ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only + */ +var generateUnixExternalFileAttr = function (unixPermissions, isDir) { + + var result = unixPermissions; + if (!unixPermissions) { + // I can't use octal values in strict mode, hence the hexa. + // 040775 => 0x41fd + // 0100664 => 0x81b4 + result = isDir ? 0x41fd : 0x81b4; + } + + return (result & 0xFFFF) << 16; +}; + +/** + * Generate the DOS part of the external file attributes. + * @param {Object} dosPermissions the dos permissions or null. + * @param {Boolean} isDir true if the entry is a directory, false otherwise. + * @return {Number} a 32 bit integer. + * + * Bit 0 Read-Only + * Bit 1 Hidden + * Bit 2 System + * Bit 3 Volume Label + * Bit 4 Directory + * Bit 5 Archive + */ +var generateDosExternalFileAttr = function (dosPermissions, isDir) { + + // the dir flag is already set for compatibility + + return (dosPermissions || 0) & 0x3F; +}; + +/** + * 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. + * @param {String} platform let's pretend we are this platform (change platform dependents fields) + * @return {object} the zip parts. + */ +var generateZipParts = function(name, file, compressedObject, offset, platform) { + var data = compressedObject.compressedContent, + utfEncodedFileName = utils.transformTo("string", utf8.utf8encode(file.name)), + comment = file.comment || "", + utfEncodedComment = utils.transformTo("string", utf8.utf8encode(comment)), + useUTF8ForFileName = utfEncodedFileName.length !== file.name.length, + useUTF8ForComment = utfEncodedComment.length !== comment.length, + o = file.options, + dosTime, + dosDate, + extraFields = "", + unicodePathExtraField = "", + unicodeCommentExtraField = "", + dir, date; + + + // handle the deprecated options.dir + if (file._initialMetadata.dir !== file.dir) { + dir = file.dir; + } else { + dir = o.dir; + } + + // handle the deprecated options.date + if(file._initialMetadata.date !== file.date) { + date = file.date; + } else { + date = o.date; + } + + var extFileAttr = 0; + var versionMadeBy = 0; + if (dir) { + // dos or unix, we set the dos dir flag + extFileAttr |= 0x00010; + } + if(platform === "UNIX") { + versionMadeBy = 0x031E; // UNIX, version 3.0 + extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir); + } else { // DOS or other, fallback to DOS + versionMadeBy = 0x0014; // DOS, version 2.0 + extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir); + } + + // 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 = date.getHours(); + dosTime = dosTime << 6; + dosTime = dosTime | date.getMinutes(); + dosTime = dosTime << 5; + dosTime = dosTime | date.getSeconds() / 2; + + dosDate = date.getFullYear() - 1980; + dosDate = dosDate << 4; + dosDate = dosDate | (date.getMonth() + 1); + dosDate = dosDate << 5; + dosDate = dosDate | date.getDate(); + + if (useUTF8ForFileName) { + // set the unicode path extra field. unzip needs at least one extra + // field to correctly handle unicode path, so using the path is as good + // as any other information. This could improve the situation with + // other archive managers too. + // This field is usually used without the utf8 flag, with a non + // unicode path in the header (winrar, winzip). This helps (a bit) + // with the messy Windows' default compressed folders feature but + // breaks on p7zip which doesn't seek the unicode path extra field. + // So for now, UTF-8 everywhere ! + unicodePathExtraField = + // Version + decToHex(1, 1) + + // NameCRC32 + decToHex(crc32(utfEncodedFileName), 4) + + // UnicodeName + utfEncodedFileName; + + extraFields += + // Info-ZIP Unicode Path Extra Field + "\x75\x70" + + // size + decToHex(unicodePathExtraField.length, 2) + + // content + unicodePathExtraField; + } + + if(useUTF8ForComment) { + + unicodeCommentExtraField = + // Version + decToHex(1, 1) + + // CommentCRC32 + decToHex(this.crc32(utfEncodedComment), 4) + + // UnicodeName + utfEncodedComment; + + extraFields += + // Info-ZIP Unicode Path Extra Field + "\x75\x63" + + // size + decToHex(unicodeCommentExtraField.length, 2) + + // content + unicodeCommentExtraField; + } + + var header = ""; + + // version needed to extract + header += "\x0A\x00"; + // general purpose bit flag + // set bit 11 if utf8 + header += (useUTF8ForFileName || useUTF8ForComment) ? "\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 += decToHex(extraFields.length, 2); + + + var fileRecord = signature.LOCAL_FILE_HEADER + header + utfEncodedFileName + extraFields; + + var dirRecord = signature.CENTRAL_FILE_HEADER + + // version made by (00: DOS) + decToHex(versionMadeBy, 2) + + // file header (common to file and central directory) + header + + // file comment length + decToHex(utfEncodedComment.length, 2) + + // disk number start + "\x00\x00" + + // internal file attributes TODO + "\x00\x00" + + // external file attributes + decToHex(extFileAttr, 4) + + // relative offset of local header + decToHex(offset, 4) + + // file name + utfEncodedFileName + + // extra field + extraFields + + // file comment + utfEncodedComment; + + return { + fileRecord: fileRecord, + dirRecord: dirRecord, + compressedObject: compressedObject + }; +}; + + +// return the actual prototype of JSZip +var out = { + /** + * 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 (utils.isRegExp(name)) { + var regexp = name; + return this.filter(function(relativePath, file) { + return !file.dir && regexp.test(relativePath); + }); + } + else { // text + return this.filter(function(relativePath, file) { + return !file.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) { + return this; + } + + if (utils.isRegExp(arg)) { + return this.filter(function(relativePath, file) { + return file.dir && arg.test(relativePath); + }); + } + + // else, name is a new folder + var name = this.root + arg; + var newFolder = folderAdd.call(this, name); + + // 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 && !file.dir) { + // file + delete this.files[name]; + } else { + // maybe a folder, delete recursively + 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", + compressionOptions : null, + type: "base64", + platform: "DOS", + comment: null, + mimeType: 'application/zip' + }); + + utils.checkSupport(options.type); + + // accept nodejs `process.platform` + if( + options.platform === 'darwin' || + options.platform === 'freebsd' || + options.platform === 'linux' || + options.platform === 'sunos' + ) { + options.platform = "UNIX"; + } + if (options.platform === 'win32') { + options.platform = "DOS"; + } + + var zipData = [], + localDirLength = 0, + centralDirLength = 0, + writer, i, + utfEncodedComment = utils.transformTo("string", this.utf8encode(options.comment || this.comment || "")); + + // 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 = compressions[compressionName]; + if (!compression) { + throw new Error(compressionName + " is not a valid compression method !"); + } + var compressionOptions = file.options.compressionOptions || options.compressionOptions || {}; + + var compressedObject = generateCompressedObjectFrom.call(this, file, compression, compressionOptions); + + var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength, options.platform); + localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize; + centralDirLength += zipPart.dirRecord.length; + zipData.push(zipPart); + } + + var dirEnd = ""; + + // end of central dir signature + dirEnd = 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 + decToHex(utfEncodedComment.length, 2) + + // .ZIP file comment + utfEncodedComment; + + + // we have all the parts (and the total length) + // time to create a writer ! + var typeName = options.type.toLowerCase(); + if(typeName==="uint8array"||typeName==="arraybuffer"||typeName==="blob"||typeName==="nodebuffer") { + writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length); + }else{ + writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length); + } + + 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 utils.transformTo(options.type.toLowerCase(), zip); + case "blob" : + return utils.arrayBuffer2Blob(utils.transformTo("arraybuffer", zip), options.mimeType); + // case "zip is a string" + case "base64" : + return (options.base64) ? base64.encode(zip) : zip; + default : // case "string" : + return zip; + } + + }, + + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + crc32: function (input, crc) { + return crc32(input, crc); + }, + + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + utf8encode: function (string) { + return utils.transformTo("string", utf8.utf8encode(string)); + }, + + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + utf8decode: function (input) { + return utf8.utf8decode(input); + } +}; +module.exports = out; diff --git a/public/js/lib/jszip/lib/signature.js b/public/js/lib/jszip/lib/signature.js new file mode 100644 index 0000000..4ee817b --- /dev/null +++ b/public/js/lib/jszip/lib/signature.js @@ -0,0 +1,7 @@ +'use strict'; +exports.LOCAL_FILE_HEADER = "PK\x03\x04"; +exports.CENTRAL_FILE_HEADER = "PK\x01\x02"; +exports.CENTRAL_DIRECTORY_END = "PK\x05\x06"; +exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07"; +exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06"; +exports.DATA_DESCRIPTOR = "PK\x07\x08"; diff --git a/public/js/lib/jszip/lib/stringReader.js b/public/js/lib/jszip/lib/stringReader.js new file mode 100644 index 0000000..895331e --- /dev/null +++ b/public/js/lib/jszip/lib/stringReader.js @@ -0,0 +1,36 @@ +'use strict'; +var DataReader = require('./dataReader'); +var utils = require('./utils'); + +function StringReader(data, optimizedBinaryString) { + this.data = data; + if (!optimizedBinaryString) { + this.data = 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; +}; +module.exports = StringReader; diff --git a/public/js/lib/jszip/lib/stringWriter.js b/public/js/lib/jszip/lib/stringWriter.js new file mode 100644 index 0000000..45db548 --- /dev/null +++ b/public/js/lib/jszip/lib/stringWriter.js @@ -0,0 +1,30 @@ +'use strict'; + +var utils = require('./utils'); + +/** + * 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 = 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(""); + } +}; + +module.exports = StringWriter; diff --git a/public/js/lib/jszip/lib/support.js b/public/js/lib/jszip/lib/support.js new file mode 100644 index 0000000..b9bbb1f --- /dev/null +++ b/public/js/lib/jszip/lib/support.js @@ -0,0 +1,34 @@ +'use strict'; +exports.base64 = true; +exports.array = true; +exports.string = true; +exports.arraybuffer = typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined"; +// contains true if JSZip can read/generate nodejs Buffer, false otherwise. +// Browserify will provide a Buffer implementation for browsers, which is +// an augmented Uint8Array (i.e., can be used as either Buffer or U8). +exports.nodebuffer = typeof Buffer !== "undefined"; +// contains true if JSZip can read/generate Uint8Array, false otherwise. +exports.uint8array = typeof Uint8Array !== "undefined"; + +if (typeof ArrayBuffer === "undefined") { + exports.blob = false; +} +else { + var buffer = new ArrayBuffer(0); + try { + exports.blob = new Blob([buffer], { + type: "application/zip" + }).size === 0; + } + catch (e) { + try { + var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + var builder = new Builder(); + builder.append(buffer); + exports.blob = builder.getBlob('application/zip').size === 0; + } + catch (e) { + exports.blob = false; + } + } +} diff --git a/public/js/lib/jszip/lib/uint8ArrayReader.js b/public/js/lib/jszip/lib/uint8ArrayReader.js new file mode 100644 index 0000000..ce8d1a8 --- /dev/null +++ b/public/js/lib/jszip/lib/uint8ArrayReader.js @@ -0,0 +1,47 @@ +'use strict'; +var DataReader = require('./dataReader'); + +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); + if(size === 0) { + // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of []. + return new Uint8Array(0); + } + var result = this.data.subarray(this.index, this.index + size); + this.index += size; + return result; +}; +module.exports = Uint8ArrayReader; diff --git a/public/js/lib/jszip/lib/uint8ArrayWriter.js b/public/js/lib/jszip/lib/uint8ArrayWriter.js new file mode 100644 index 0000000..405397f --- /dev/null +++ b/public/js/lib/jszip/lib/uint8ArrayWriter.js @@ -0,0 +1,36 @@ +'use strict'; + +var utils = require('./utils'); + +/** + * 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 = 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; + } +}; + +module.exports = Uint8ArrayWriter; diff --git a/public/js/lib/jszip/lib/utf8.js b/public/js/lib/jszip/lib/utf8.js new file mode 100644 index 0000000..8cc16b4 --- /dev/null +++ b/public/js/lib/jszip/lib/utf8.js @@ -0,0 +1,207 @@ +'use strict'; + +var utils = require('./utils'); +var support = require('./support'); +var nodeBuffer = require('./nodeBuffer'); + +/** + * The following functions come from pako, from pako/lib/utils/strings + * released under the MIT license, see pako https://github.com/nodeca/pako/ + */ + +// Table with utf8 lengths (calculated by first byte of sequence) +// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, +// because max possible codepoint is 0x10ffff +var _utf8len = new Array(256); +for (var i=0; i<256; i++) { + _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1); +} +_utf8len[254]=_utf8len[254]=1; // Invalid sequence start + +// convert string to array (typed, when possible) +var string2buf = function (str) { + var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; + + // count binary size + for (m_pos = 0; m_pos < str_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { + c2 = str.charCodeAt(m_pos+1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; + } + + // allocate buffer + if (support.uint8array) { + buf = new Uint8Array(buf_len); + } else { + buf = new Array(buf_len); + } + + // convert + for (i=0, m_pos = 0; i < buf_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { + c2 = str.charCodeAt(m_pos+1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + if (c < 0x80) { + /* one byte */ + buf[i++] = c; + } else if (c < 0x800) { + /* two bytes */ + buf[i++] = 0xC0 | (c >>> 6); + buf[i++] = 0x80 | (c & 0x3f); + } else if (c < 0x10000) { + /* three bytes */ + buf[i++] = 0xE0 | (c >>> 12); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } else { + /* four bytes */ + buf[i++] = 0xf0 | (c >>> 18); + buf[i++] = 0x80 | (c >>> 12 & 0x3f); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } + } + + return buf; +}; + +// Calculate max possible position in utf8 buffer, +// that will not break sequence. If that's not possible +// - (very small limits) return max size as is. +// +// buf[] - utf8 bytes array +// max - length limit (mandatory); +var utf8border = function(buf, max) { + var pos; + + max = max || buf.length; + if (max > buf.length) { max = buf.length; } + + // go back from last position, until start of sequence found + pos = max-1; + while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } + + // Fuckup - very small and broken sequence, + // return max, because we should return something anyway. + if (pos < 0) { return max; } + + // If we came to start of buffer - that means vuffer is too small, + // return max too. + if (pos === 0) { return max; } + + return (pos + _utf8len[buf[pos]] > max) ? pos : max; +}; + +// convert array to string +var buf2string = function (buf) { + var str, i, out, c, c_len; + var len = buf.length; + + // Reserve max possible length (2 words per char) + // NB: by unknown reasons, Array is significantly faster for + // String.fromCharCode.apply than Uint16Array. + var utf16buf = new Array(len*2); + + for (out=0, i=0; i 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; } + + // apply mask on first byte + c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; + // join the rest + while (c_len > 1 && i < len) { + c = (c << 6) | (buf[i++] & 0x3f); + c_len--; + } + + // terminated by end of string? + if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } + + if (c < 0x10000) { + utf16buf[out++] = c; + } else { + c -= 0x10000; + utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); + utf16buf[out++] = 0xdc00 | (c & 0x3ff); + } + } + + // shrinkBuf(utf16buf, out) + if (utf16buf.length !== out) { + if(utf16buf.subarray) { + utf16buf = utf16buf.subarray(0, out); + } else { + utf16buf.length = out; + } + } + + // return String.fromCharCode.apply(null, utf16buf); + return utils.applyFromCharCode(utf16buf); +}; + + +// That's all for the pako functions. + + +/** + * Transform a javascript string into an array (typed if possible) of bytes, + * UTF-8 encoded. + * @param {String} str the string to encode + * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string. + */ +exports.utf8encode = function utf8encode(str) { + if (support.nodebuffer) { + return nodeBuffer(str, "utf-8"); + } + + return string2buf(str); +}; + + +/** + * Transform a bytes array (or a representation) representing an UTF-8 encoded + * string into a javascript string. + * @param {Array|Uint8Array|Buffer} buf the data de decode + * @return {String} the decoded string. + */ +exports.utf8decode = function utf8decode(buf) { + if (support.nodebuffer) { + return utils.transformTo("nodebuffer", buf).toString("utf-8"); + } + + buf = utils.transformTo(support.uint8array ? "uint8array" : "array", buf); + + // return buf2string(buf); + // Chrome prefers to work with "small" chunks of data + // for the method buf2string. + // Firefox and Chrome has their own shortcut, IE doesn't seem to really care. + var result = [], k = 0, len = buf.length, chunk = 65536; + while (k < len) { + var nextBoundary = utf8border(buf, Math.min(k + chunk, len)); + if (support.uint8array) { + result.push(buf2string(buf.subarray(k, nextBoundary))); + } else { + result.push(buf2string(buf.slice(k, nextBoundary))); + } + k = nextBoundary; + } + return result.join(""); + +}; +// vim: set shiftwidth=4 softtabstop=4: diff --git a/public/js/lib/jszip/lib/utils.js b/public/js/lib/jszip/lib/utils.js new file mode 100644 index 0000000..da54747 --- /dev/null +++ b/public/js/lib/jszip/lib/utils.js @@ -0,0 +1,326 @@ +'use strict'; +var support = require('./support'); +var compressions = require('./compressions'); +var nodeBuffer = require('./nodeBuffer'); +/** + * Convert a string to a "binary string" : a string containing only char codes between 0 and 255. + * @param {string} str the string to transform. + * @return {String} the binary string. + */ +exports.string2binary = function(str) { + var result = ""; + for (var i = 0; i < str.length; i++) { + result += String.fromCharCode(str.charCodeAt(i) & 0xff); + } + return result; +}; +exports.arrayBuffer2Blob = function(buffer, mimeType) { + exports.checkSupport("blob"); + mimeType = mimeType || 'application/zip'; + + try { + // Blob constructor + return new Blob([buffer], { + type: mimeType + }); + } + catch (e) { + + try { + // deprecated, browser only, old way + var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + var builder = new Builder(); + builder.append(buffer); + return builder.getBlob(mimeType); + } + catch (e) { + + // well, fuck ?! + throw new Error("Bug : can't construct the Blob."); + } + } + + +}; +/** + * 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 = exports.getTypeOf(array), + k = 0, + canUseApply = true; + try { + switch(type) { + case "uint8array": + String.fromCharCode.apply(null, new Uint8Array(0)); + break; + case "nodebuffer": + String.fromCharCode.apply(null, nodeBuffer(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)))); + } + else { + 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(""); +} + +exports.applyFromCharCode = arrayLikeToString; + + +/** + * 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, nodeBuffer(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 nodeBuffer(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 nodeBuffer(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 nodeBuffer(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. + */ +exports.transformTo = function(outputType, input) { + if (!input) { + // undefined, null, etc + // an empty string won't harm. + input = ""; + } + if (!outputType) { + return input; + } + exports.checkSupport(outputType); + var inputType = exports.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. + */ +exports.getTypeOf = function(input) { + if (typeof input === "string") { + return "string"; + } + if (Object.prototype.toString.call(input) === "[object Array]") { + return "array"; + } + if (support.nodebuffer && nodeBuffer.test(input)) { + return "nodebuffer"; + } + if (support.uint8array && input instanceof Uint8Array) { + return "uint8array"; + } + if (support.arraybuffer && input instanceof ArrayBuffer) { + return "arraybuffer"; + } +}; + +/** + * 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. + */ +exports.checkSupport = function(type) { + var supported = support[type.toLowerCase()]; + if (!supported) { + throw new Error(type + " is not supported by this browser"); + } +}; +exports.MAX_VALUE_16BITS = 65535; +exports.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. + */ +exports.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. + */ +exports.findCompression = function(compressionMethod) { + for (var method in compressions) { + if (!compressions.hasOwnProperty(method)) { + continue; + } + if (compressions[method].magic === compressionMethod) { + return compressions[method]; + } + } + return null; +}; +/** +* Cross-window, cross-Node-context regular expression detection +* @param {Object} object Anything +* @return {Boolean} true if the object is a regular expression, +* false otherwise +*/ +exports.isRegExp = function (object) { + return Object.prototype.toString.call(object) === "[object RegExp]"; +}; + diff --git a/public/js/lib/jszip/lib/zipEntries.js b/public/js/lib/jszip/lib/zipEntries.js new file mode 100644 index 0000000..4b82561 --- /dev/null +++ b/public/js/lib/jszip/lib/zipEntries.js @@ -0,0 +1,221 @@ +'use strict'; +var StringReader = require('./stringReader'); +var NodeBufferReader = require('./nodeBufferReader'); +var Uint8ArrayReader = require('./uint8ArrayReader'); +var utils = require('./utils'); +var sig = require('./signature'); +var ZipEntry = require('./zipEntry'); +var support = require('./support'); +var jszipProto = require('./object'); +// class ZipEntries {{{ +/** + * All the entries in the zip file. + * @constructor + * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load. + * @param {Object} loadOptions Options for loading the stream. + */ +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 " + "(" + utils.pretty(signature) + ", expected " + utils.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); + // warning : the encoding depends of the system locale + // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded. + // On a windows machine, this field is encoded with the localized windows code page. + this.zipComment = this.reader.readString(this.zipCommentLength); + // To get consistent behavior with the generation part, we will assume that + // this is utf8 encoded. + this.zipComment = jszipProto.utf8decode(this.zipComment); + }, + /** + * 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(sig.LOCAL_FILE_HEADER); + file.readLocalPart(this.reader); + file.handleUTF8(); + file.processAttributes(); + } + }, + /** + * Read the central directory. + */ + readCentralDir: function() { + var file; + + this.reader.setIndex(this.centralDirOffset); + while (this.reader.readString(4) === sig.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(sig.CENTRAL_DIRECTORY_END); + if (offset === -1) { + // Check if the content is a truncated zip or complete garbage. + // A "LOCAL_FILE_HEADER" is not required at the beginning (auto + // extractible zip for example) but it can give a good hint. + // If an ajax request was used without responseType, we will also + // get unreadable data. + var isGarbage = true; + try { + this.reader.setIndex(0); + this.checkSignature(sig.LOCAL_FILE_HEADER); + isGarbage = false; + } catch (e) {} + + if (isGarbage) { + throw new Error("Can't find end of central directory : is this a zip file ? " + + "If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html"); + } else { + throw new Error("Corrupted zip : can't find end of central directory"); + } + } + this.reader.setIndex(offset); + this.checkSignature(sig.CENTRAL_DIRECTORY_END); + this.readBlockEndOfCentral(); + + + /* extract from the zip spec : + 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 === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) { + this.zip64 = true; + + /* + Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from + the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents + all numbers as 64-bit double precision IEEE 754 floating point numbers. + So, we have 53bits for integers and bitwise operations treat everything as 32bits. + 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(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); + if (offset === -1) { + throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator"); + } + this.reader.setIndex(offset); + this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); + this.readBlockZip64EndOfCentralLocator(); + + // now the zip64 EOCD record + this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir); + this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END); + this.readBlockZip64EndOfCentral(); + } + }, + prepareReader: function(data) { + var type = utils.getTypeOf(data); + if (type === "string" && !support.uint8array) { + this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString); + } + else if (type === "nodebuffer") { + this.reader = new NodeBufferReader(data); + } + else { + this.reader = new Uint8ArrayReader(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 +module.exports = ZipEntries; diff --git a/public/js/lib/jszip/lib/zipEntry.js b/public/js/lib/jszip/lib/zipEntry.js new file mode 100644 index 0000000..70a3ac0 --- /dev/null +++ b/public/js/lib/jszip/lib/zipEntry.js @@ -0,0 +1,310 @@ +'use strict'; +var StringReader = require('./stringReader'); +var utils = require('./utils'); +var CompressedObject = require('./compressedObject'); +var jszipProto = require('./object'); + +var MADE_BY_DOS = 0x00; +var MADE_BY_UNIX = 0x03; + +// class ZipEntry {{{ +/** + * An entry in the zip file. + * @constructor + * @param {Object} options Options of the current file. + * @param {Object} loadOptions Options for loading the stream. + */ +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 = utils.transformTo(compression.uncompressInputType, this.getCompressedContent()); + var uncompressedFileData = compression.uncompress(compressedFileData); + + if (uncompressedFileData.length !== uncompressedSize) { + throw new Error("Bug : uncompressed data size mismatch"); + } + + 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 = utils.findCompression(this.compressionMethod); + if (compression === null) { // no compression found + throw new Error("Corrupted zip : compression " + utils.pretty(this.compressionMethod) + " unknown (inner file : " + this.fileName + ")"); + } + this.decompressed = new 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 = utils.transformTo("string", this.decompressed.getContent()); + if (jszipProto.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.readInt(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); + }, + + /** + * Parse the external file attributes and get the unix/dos permissions. + */ + processAttributes: function () { + this.unixPermissions = null; + this.dosPermissions = null; + var madeBy = this.versionMadeBy >> 8; + + // Check if we have the DOS directory flag set. + // We look for it in the DOS and UNIX permissions + // but some unknown platform could set it as a compatibility flag. + this.dir = this.externalFileAttributes & 0x0010 ? true : false; + + if(madeBy === MADE_BY_DOS) { + // first 6 bits (0 to 5) + this.dosPermissions = this.externalFileAttributes & 0x3F; + } + + if(madeBy === MADE_BY_UNIX) { + this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF; + // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8); + } + + // fail safe : if the name ends with a / it probably means a folder + if (!this.dir && this.fileName.slice(-1) === '/') { + this.dir = true; + } + }, + + /** + * 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 === utils.MAX_VALUE_32BITS) { + this.uncompressedSize = extraReader.readInt(8); + } + if (this.compressedSize === utils.MAX_VALUE_32BITS) { + this.compressedSize = extraReader.readInt(8); + } + if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) { + this.localHeaderOffset = extraReader.readInt(8); + } + if (this.diskNumberStart === utils.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 = jszipProto.utf8decode(this.fileName); + this.fileComment = jszipProto.utf8decode(this.fileComment); + } else { + var upath = this.findExtraFieldUnicodePath(); + if (upath !== null) { + this.fileName = upath; + } + var ucomment = this.findExtraFieldUnicodeComment(); + if (ucomment !== null) { + this.fileComment = ucomment; + } + } + }, + + /** + * Find the unicode path declared in the extra field, if any. + * @return {String} the unicode path, null otherwise. + */ + findExtraFieldUnicodePath: function() { + var upathField = this.extraFields[0x7075]; + if (upathField) { + var extraReader = new StringReader(upathField.value); + + // wrong version + if (extraReader.readInt(1) !== 1) { + return null; + } + + // the crc of the filename changed, this field is out of date. + if (jszipProto.crc32(this.fileName) !== extraReader.readInt(4)) { + return null; + } + + return jszipProto.utf8decode(extraReader.readString(upathField.length - 5)); + } + return null; + }, + + /** + * Find the unicode comment declared in the extra field, if any. + * @return {String} the unicode comment, null otherwise. + */ + findExtraFieldUnicodeComment: function() { + var ucommentField = this.extraFields[0x6375]; + if (ucommentField) { + var extraReader = new StringReader(ucommentField.value); + + // wrong version + if (extraReader.readInt(1) !== 1) { + return null; + } + + // the crc of the comment changed, this field is out of date. + if (jszipProto.crc32(this.fileComment) !== extraReader.readInt(4)) { + return null; + } + + return jszipProto.utf8decode(extraReader.readString(ucommentField.length - 5)); + } + return null; + } +}; +module.exports = ZipEntry; diff --git a/public/js/lib/jszip/package.json b/public/js/lib/jszip/package.json new file mode 100644 index 0000000..21be5df --- /dev/null +++ b/public/js/lib/jszip/package.json @@ -0,0 +1,53 @@ +{ + "name": "jszip", + "version": "2.5.0", + "author": "Stuart Knightley ", + "description": "Create, read and edit .zip files with Javascript http://stuartk.com/jszip", + "scripts": { + "test": "npm run test-node && npm run test-browser", + "test-node": "cd test && qunit -c node.js -t test.js", + "test-browser": "grunt build && grunt test", + "lint": "grunt jshint" + }, + "contributors": [ + { + "name": "Franz Buchinger" + }, + { + "name": "António Afonso" + }, + { + "name": "David Duponchel" + }, + { + "name": "yiminghe" + } + ], + "main": "./lib/index", + "repository": { + "type": "git", + "url": "https://github.com/Stuk/jszip.git" + }, + "keywords": [ + "zip", + "deflate", + "inflate" + ], + "devDependencies": { + "qunit": "~0.6.3", + "grunt": "~0.4.1", + "grunt-cli": "~0.1.9", + "grunt-saucelabs": "~7.0.0", + "grunt-contrib-connect": "~0.7.1", + "jshint": "~2.5.1", + "browserify": "~4.1.4", + "grunt-browserify": "~2.1.0", + "grunt-contrib-jshint": "~0.10.0", + "grunt-contrib-uglify": "~0.4.0", + "jszip-utils": "~0.0.2" + }, + "dependencies":{ + "pako": "~0.2.5" + }, + "license": "(MIT OR GPL-3.0)" +} diff --git a/public/js/lib/jszip/test/browser-test-utils.js b/public/js/lib/jszip/test/browser-test-utils.js new file mode 100644 index 0000000..963524f --- /dev/null +++ b/public/js/lib/jszip/test/browser-test-utils.js @@ -0,0 +1,5 @@ +var JSZipTestUtils = { + loadZipFile : function (name, callback) { + JSZipUtils.getBinaryContent(name + "?_=" + ( new Date() ).getTime(), callback); + } +}; diff --git a/public/js/lib/jszip/test/index.html b/public/js/lib/jszip/test/index.html new file mode 100644 index 0000000..82ef3b0 --- /dev/null +++ b/public/js/lib/jszip/test/index.html @@ -0,0 +1,75 @@ + + + + +JSZip Testing + + + + + + + + + + + + + + + + + + + +
+
+ + + + diff --git a/public/js/lib/jszip/test/jquery-1.8.3.min.js b/public/js/lib/jszip/test/jquery-1.8.3.min.js new file mode 100644 index 0000000..83589da --- /dev/null +++ b/public/js/lib/jszip/test/jquery-1.8.3.min.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/public/js/lib/jszip/test/node.js b/public/js/lib/jszip/test/node.js new file mode 100644 index 0000000..61139d6 --- /dev/null +++ b/public/js/lib/jszip/test/node.js @@ -0,0 +1,9 @@ +var fs = require("fs"); + +global.JSZip = require("../lib/index"); + +global.JSZipTestUtils = { + loadZipFile: function(name, callback) { + fs.readFile(name, "binary", callback); + } +}; diff --git a/public/js/lib/jszip/test/qunit-1.11.0.css b/public/js/lib/jszip/test/qunit-1.11.0.css new file mode 100644 index 0000000..d7fc0c8 --- /dev/null +++ b/public/js/lib/jszip/test/qunit-1.11.0.css @@ -0,0 +1,244 @@ +/** + * QUnit v1.11.0 - A JavaScript Unit Testing Framework + * + * http://qunitjs.com + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +/** Font Family and Sizes */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; +} + +#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-tests { font-size: smaller; } + + +/** Resets */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { + margin: 0; + padding: 0; +} + + +/** Header */ + +#qunit-header { + padding: 0.5em 0 0.5em 1em; + + color: #8699a4; + background-color: #0d3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: normal; + + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-top-right-radius: 5px; + -webkit-border-top-left-radius: 5px; +} + +#qunit-header a { + text-decoration: none; + color: #c2ccd1; +} + +#qunit-header a:hover, +#qunit-header a:focus { + color: #fff; +} + +#qunit-testrunner-toolbar label { + display: inline-block; + padding: 0 .5em 0 .1em; +} + +#qunit-banner { + height: 5px; +} + +#qunit-testrunner-toolbar { + padding: 0.5em 0 0.5em 2em; + color: #5E740B; + background-color: #eee; + overflow: hidden; +} + +#qunit-userAgent { + padding: 0.5em 0 0.5em 2.5em; + background-color: #2b81af; + color: #fff; + text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; +} + +#qunit-modulefilter-container { + float: right; +} + +/** Tests: Pass/Fail */ + +#qunit-tests { + list-style-position: inside; +} + +#qunit-tests li { + padding: 0.4em 0.5em 0.4em 2.5em; + border-bottom: 1px solid #fff; + list-style-position: inside; +} + +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + +#qunit-tests li strong { + cursor: pointer; +} + +#qunit-tests li a { + padding: 0.5em; + color: #c2ccd1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + +#qunit-tests li .runtime { + float: right; + font-size: smaller; +} + +.qunit-assert-list { + margin-top: 0.5em; + padding: 0.5em; + + background-color: #fff; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.qunit-collapsed { + display: none; +} + +#qunit-tests table { + border-collapse: collapse; + margin-top: .2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 .5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #e0f2be; + color: #374e0c; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #ffcaca; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: black; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + +#qunit-tests li li { + padding: 5px; + background-color: #fff; + border-bottom: none; + list-style-position: inside; +} + +/*** Passing Styles */ + +#qunit-tests li li.pass { + color: #3c510c; + background-color: #fff; + border-left: 10px solid #C6E746; +} + +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } + +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999999; } + +#qunit-banner.qunit-pass { background-color: #C6E746; } + +/*** Failing Styles */ + +#qunit-tests li li.fail { + color: #710909; + background-color: #fff; + border-left: 10px solid #EE5757; + white-space: pre; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + -webkit-border-bottom-right-radius: 5px; + -webkit-border-bottom-left-radius: 5px; +} + +#qunit-tests .fail { color: #000000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: green; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + + +/** Result */ + +#qunit-testresult { + padding: 0.5em 0.5em 0.5em 2.5em; + + color: #2b81af; + background-color: #D2E0E6; + + border-bottom: 1px solid white; +} +#qunit-testresult .module-name { + font-weight: bold; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; + width: 1000px; + height: 1000px; +} diff --git a/public/js/lib/jszip/test/qunit-1.11.0.js b/public/js/lib/jszip/test/qunit-1.11.0.js new file mode 100644 index 0000000..302545f --- /dev/null +++ b/public/js/lib/jszip/test/qunit-1.11.0.js @@ -0,0 +1,2152 @@ +/** + * QUnit v1.11.0 - A JavaScript Unit Testing Framework + * + * http://qunitjs.com + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +(function( window ) { + +var QUnit, + assert, + config, + onErrorFnPrev, + testId = 0, + fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + // Keep a local reference to Date (GH-283) + Date = window.Date, + defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch( e ) { + return false; + } + }()) + }, + /** + * Provides a normalized error string, correcting an issue + * with IE 7 (and prior) where Error.prototype.toString is + * not properly implemented + * + * Based on http://es5.github.com/#x15.11.4.4 + * + * @param {String|Error} error + * @return {String} error message + */ + errorString = function( error ) { + var name, message, + errorString = error.toString(); + if ( errorString.substring( 0, 7 ) === "[object" ) { + name = error.name ? error.name.toString() : "Error"; + message = error.message ? error.message.toString() : ""; + if ( name && message ) { + return name + ": " + message; + } else if ( name ) { + return name; + } else if ( message ) { + return message; + } else { + return "Error"; + } + } else { + return errorString; + } + }, + /** + * Makes a clone of an object using only Array or Object as base, + * and copies over the own enumerable properties. + * + * @param {Object} obj + * @return {Object} New object with only the own properties (recursively). + */ + objectValues = function( obj ) { + // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392. + /*jshint newcap: false */ + var key, val, + vals = QUnit.is( "array", obj ) ? [] : {}; + for ( key in obj ) { + if ( hasOwn.call( obj, key ) ) { + val = obj[key]; + vals[key] = val === Object(val) ? objectValues(val) : val; + } + } + return vals; + }; + +function Test( settings ) { + extend( this, settings ); + this.assertions = []; + this.testNumber = ++Test.count; +} + +Test.count = 0; + +Test.prototype = { + init: function() { + var a, b, li, + tests = id( "qunit-tests" ); + + if ( tests ) { + b = document.createElement( "strong" ); + b.innerHTML = this.nameHtml; + + // `a` initialized at top of scope + a = document.createElement( "a" ); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ testNumber: this.testNumber }); + + li = document.createElement( "li" ); + li.appendChild( b ); + li.appendChild( a ); + li.className = "running"; + li.id = this.id = "qunit-test-output" + testId++; + + tests.appendChild( li ); + } + }, + setup: function() { + if ( this.module !== config.previousModule ) { + if ( config.previousModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } else if ( config.autorun ) { + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } + + config.current = this; + + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment ); + + this.started = +new Date(); + runLoggingCallbacks( "testStart", QUnit, { + name: this.testName, + module: this.module + }); + + // allow utility functions to access the current test environment + // TODO why?? + QUnit.current_testEnvironment = this.testEnvironment; + + if ( !config.pollution ) { + saveGlobal(); + } + if ( config.notrycatch ) { + this.testEnvironment.setup.call( this.testEnvironment ); + return; + } + try { + this.testEnvironment.setup.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); + } + }, + run: function() { + config.current = this; + + var running = id( "qunit-testresult" ); + + if ( running ) { + running.innerHTML = "Running:
" + this.nameHtml; + } + + if ( this.async ) { + QUnit.stop(); + } + + this.callbackStarted = +new Date(); + + if ( config.notrycatch ) { + this.callback.call( this.testEnvironment, QUnit.assert ); + this.callbackRuntime = +new Date() - this.callbackStarted; + return; + } + + try { + this.callback.call( this.testEnvironment, QUnit.assert ); + this.callbackRuntime = +new Date() - this.callbackStarted; + } catch( e ) { + this.callbackRuntime = +new Date() - this.callbackStarted; + + QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + QUnit.start(); + } + } + }, + teardown: function() { + config.current = this; + if ( config.notrycatch ) { + if ( typeof this.callbackRuntime === "undefined" ) { + this.callbackRuntime = +new Date() - this.callbackStarted; + } + this.testEnvironment.teardown.call( this.testEnvironment ); + return; + } else { + try { + this.testEnvironment.teardown.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); + } + } + checkPollution(); + }, + finish: function() { + config.current = this; + if ( config.requireExpects && this.expected === null ) { + QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); + } else if ( this.expected !== null && this.expected !== this.assertions.length ) { + QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); + } else if ( this.expected === null && !this.assertions.length ) { + QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); + } + + var i, assertion, a, b, time, li, ol, + test = this, + good = 0, + bad = 0, + tests = id( "qunit-tests" ); + + this.runtime = +new Date() - this.started; + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + ol = document.createElement( "ol" ); + ol.className = "qunit-assert-list"; + + for ( i = 0; i < this.assertions.length; i++ ) { + assertion = this.assertions[i]; + + li = document.createElement( "li" ); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + if ( QUnit.config.reorder && defined.sessionStorage ) { + if ( bad ) { + sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); + } else { + sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); + } + } + + if ( bad === 0 ) { + addClass( ol, "qunit-collapsed" ); + } + + // `b` initialized at top of scope + b = document.createElement( "strong" ); + b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; + + addEvent(b, "click", function() { + var next = b.parentNode.lastChild, + collapsed = hasClass( next, "qunit-collapsed" ); + ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" ); + }); + + addEvent(b, "dblclick", function( e ) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location = QUnit.url({ testNumber: test.testNumber }); + } + }); + + // `time` initialized at top of scope + time = document.createElement( "span" ); + time.className = "runtime"; + time.innerHTML = this.runtime + " ms"; + + // `li` initialized at top of scope + li = id( this.id ); + li.className = bad ? "fail" : "pass"; + li.removeChild( li.firstChild ); + a = li.firstChild; + li.appendChild( b ); + li.appendChild( a ); + li.appendChild( time ); + li.appendChild( ol ); + + } else { + for ( i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + runLoggingCallbacks( "testDone", QUnit, { + name: this.testName, + module: this.module, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length, + duration: this.runtime + }); + + QUnit.reset(); + + config.current = undefined; + }, + + queue: function() { + var bad, + test = this; + + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + + // `bad` initialized at top of scope + // defer when previous test run passed, if storage is available + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); + + if ( bad ) { + run(); + } else { + synchronize( run, true ); + } + } +}; + +// Root QUnit object. +// `QUnit` initialized at top of scope +QUnit = { + + // call on start of module test to prepend name to all tests + module: function( name, testEnvironment ) { + config.currentModule = name; + config.currentModuleTestEnvironment = testEnvironment; + config.modules[name] = true; + }, + + asyncTest: function( testName, expected, callback ) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test( testName, expected, callback, true ); + }, + + test: function( testName, expected, callback, async ) { + var test, + nameHtml = "" + escapeText( testName ) + ""; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + if ( config.currentModule ) { + nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml; + } + + test = new Test({ + nameHtml: nameHtml, + testName: testName, + expected: expected, + async: async, + callback: callback, + module: config.currentModule, + moduleTestEnvironment: config.currentModuleTestEnvironment, + stack: sourceFromStacktrace( 2 ) + }); + + if ( !validTest( test ) ) { + return; + } + + test.queue(); + }, + + // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + expect: function( asserts ) { + if (arguments.length === 1) { + config.current.expected = asserts; + } else { + return config.current.expected; + } + }, + + start: function( count ) { + // QUnit hasn't been initialized yet. + // Note: RequireJS (et al) may delay onLoad + if ( config.semaphore === undefined ) { + QUnit.begin(function() { + // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first + setTimeout(function() { + QUnit.start( count ); + }); + }); + return; + } + + config.semaphore -= count || 1; + // don't start until equal number of stop-calls + if ( config.semaphore > 0 ) { + return; + } + // ignore if start is called more often then stop + if ( config.semaphore < 0 ) { + config.semaphore = 0; + QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) ); + return; + } + // A slight delay, to avoid any current callbacks + if ( defined.setTimeout ) { + window.setTimeout(function() { + if ( config.semaphore > 0 ) { + return; + } + if ( config.timeout ) { + clearTimeout( config.timeout ); + } + + config.blocking = false; + process( true ); + }, 13); + } else { + config.blocking = false; + process( true ); + } + }, + + stop: function( count ) { + config.semaphore += count || 1; + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = window.setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + config.semaphore = 1; + QUnit.start(); + }, config.testTimeout ); + } + } +}; + +// `assert` initialized at top of scope +// Asssert helpers +// All of these must either call QUnit.push() or manually do: +// - runLoggingCallbacks( "log", .. ); +// - config.current.assertions.push({ .. }); +// We attach it to the QUnit object *after* we expose the public API, +// otherwise `assert` will become a global variable in browsers (#341). +assert = { + /** + * Asserts rough true-ish result. + * @name ok + * @function + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function( result, msg ) { + if ( !config.current ) { + throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + result = !!result; + + var source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: msg + }; + + msg = escapeText( msg || (result ? "okay" : "failed" ) ); + msg = "" + msg + ""; + + if ( !result ) { + source = sourceFromStacktrace( 2 ); + if ( source ) { + details.source = source; + msg += "
Source:
" + escapeText( source ) + "
"; + } + } + runLoggingCallbacks( "log", QUnit, details ); + config.current.assertions.push({ + result: result, + message: msg + }); + }, + + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @name equal + * @function + * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); + */ + equal: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected == actual, actual, expected, message ); + }, + + /** + * @name notEqual + * @function + */ + notEqual: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected != actual, actual, expected, message ); + }, + + /** + * @name propEqual + * @function + */ + propEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notPropEqual + * @function + */ + notPropEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name deepEqual + * @function + */ + deepEqual: function( actual, expected, message ) { + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notDeepEqual + * @function + */ + notDeepEqual: function( actual, expected, message ) { + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name strictEqual + * @function + */ + strictEqual: function( actual, expected, message ) { + QUnit.push( expected === actual, actual, expected, message ); + }, + + /** + * @name notStrictEqual + * @function + */ + notStrictEqual: function( actual, expected, message ) { + QUnit.push( expected !== actual, actual, expected, message ); + }, + + "throws": function( block, expected, message ) { + var actual, + expectedOutput = expected, + ok = false; + + // 'expected' is optional + if ( typeof expected === "string" ) { + message = expected; + expected = null; + } + + config.current.ignoreGlobalErrors = true; + try { + block.call( config.current.testEnvironment ); + } catch (e) { + actual = e; + } + config.current.ignoreGlobalErrors = false; + + if ( actual ) { + // we don't want to validate thrown error + if ( !expected ) { + ok = true; + expectedOutput = null; + // expected is a regexp + } else if ( QUnit.objectType( expected ) === "regexp" ) { + ok = expected.test( errorString( actual ) ); + // expected is a constructor + } else if ( actual instanceof expected ) { + ok = true; + // expected is a validation function which returns true is validation passed + } else if ( expected.call( {}, actual ) === true ) { + expectedOutput = null; + ok = true; + } + + QUnit.push( ok, actual, expectedOutput, message ); + } else { + QUnit.pushFailure( message, null, 'No exception was thrown.' ); + } + } +}; + +/** + * @deprecate since 1.8.0 + * Kept assertion helpers in root for backwards compatibility. + */ +extend( QUnit, assert ); + +/** + * @deprecated since 1.9.0 + * Kept root "raises()" for backwards compatibility. + * (Note that we don't introduce assert.raises). + */ +QUnit.raises = assert[ "throws" ]; + +/** + * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 + * Kept to avoid TypeErrors for undefined methods. + */ +QUnit.equals = function() { + QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); +}; +QUnit.same = function() { + QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); +}; + +// We want access to the constructor's prototype +(function() { + function F() {} + F.prototype = QUnit; + QUnit = new F(); + // Make F QUnit's constructor so that we can add to the prototype later + QUnit.constructor = F; +}()); + +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ +config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + // when enabled, all tests must call expect() + requireExpects: false, + + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." + } + ], + + // Set of all modules. + modules: {}, + + // logging callback queues + begin: [], + done: [], + log: [], + testStart: [], + testDone: [], + moduleStart: [], + moduleDone: [] +}; + +// Export global variables, unless an 'exports' object exists, +// in that case we assume we're in CommonJS (dealt with on the bottom of the script) +if ( typeof exports === "undefined" ) { + extend( window, QUnit ); + + // Expose QUnit object + window.QUnit = QUnit; +} + +// Initialize more QUnit.config and QUnit.urlParams +(function() { + var i, + location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}, + current; + + if ( params[ 0 ] ) { + for ( i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + urlParams[ current[ 0 ] ] = current[ 1 ]; + } + } + + QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName + config.filter = urlParams.filter; + + // Exact match of the module name + config.module = urlParams.module; + + config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = location.protocol === "file:"; +}()); + +// Extend QUnit object, +// these after set here because they should not be exposed as global functions +extend( QUnit, { + assert: assert, + + config: config, + + // Initialize the configuration options + init: function() { + extend( config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: +new Date(), + updateRate: 1000, + blocking: false, + autostart: true, + autorun: false, + filter: "", + queue: [], + semaphore: 1 + }); + + var tests, banner, result, + qunit = id( "qunit" ); + + if ( qunit ) { + qunit.innerHTML = + "

" + escapeText( document.title ) + "

" + + "

" + + "
" + + "

" + + "
    "; + } + + tests = id( "qunit-tests" ); + banner = id( "qunit-banner" ); + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...
     "; + } + }, + + // Resets the test setup. Useful for tests that modify the DOM. + reset: function() { + var fixture = id( "qunit-fixture" ); + if ( fixture ) { + fixture.innerHTML = config.fixture; + } + }, + + // Trigger an event on an element. + // @example triggerEvent( document.body, "click" ); + triggerEvent: function( elem, type, event ) { + if ( document.createEvent ) { + event = document.createEvent( "MouseEvents" ); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + + elem.dispatchEvent( event ); + } else if ( elem.fireEvent ) { + elem.fireEvent( "on" + type ); + } + }, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) === type; + }, + + objectType: function( obj ) { + if ( typeof obj === "undefined" ) { + return "undefined"; + // consider: typeof null === object + } + if ( obj === null ) { + return "null"; + } + + var match = toString.call( obj ).match(/^\[object\s(.*)\]$/), + type = match && match[1] || ""; + + switch ( type ) { + case "Number": + if ( isNaN(obj) ) { + return "nan"; + } + return "number"; + case "String": + case "Boolean": + case "Array": + case "Date": + case "RegExp": + case "Function": + return type.toLowerCase(); + } + if ( typeof obj === "object" ) { + return "object"; + } + return undefined; + }, + + push: function( result, actual, expected, message ) { + if ( !config.current ) { + throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); + } + + var output, source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeText( message ) || ( result ? "okay" : "failed" ); + message = "" + message + ""; + output = message; + + if ( !result ) { + expected = escapeText( QUnit.jsDump.parse(expected) ); + actual = escapeText( QUnit.jsDump.parse(actual) ); + output += ""; + + if ( actual !== expected ) { + output += ""; + output += ""; + } + + source = sourceFromStacktrace(); + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
    Expected:
    " + expected + "
    Result:
    " + actual + "
    Diff:
    " + QUnit.diff( expected, actual ) + "
    Source:
    " + escapeText( source ) + "
    "; + } + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + pushFailure: function( message, source, actual ) { + if ( !config.current ) { + throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + + var output, + details = { + module: config.current.module, + name: config.current.testName, + result: false, + message: message + }; + + message = escapeText( message ) || "error"; + message = "" + message + ""; + output = message; + + output += ""; + + if ( actual ) { + output += ""; + } + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
    Result:
    " + escapeText( actual ) + "
    Source:
    " + escapeText( source ) + "
    "; + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: false, + message: output + }); + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var key, + querystring = "?"; + + for ( key in params ) { + if ( !hasOwn.call( params, key ) ) { + continue; + } + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + return window.location.protocol + "//" + window.location.host + + window.location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + id: id, + addEvent: addEvent + // load, equiv, jsDump, diff: Attached later +}); + +/** + * @deprecated: Created for backwards compatibility with test runner that set the hook function + * into QUnit.{hook}, instead of invoking it and passing the hook function. + * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. + * Doing this allows us to tell if the following methods have been overwritten on the actual + * QUnit object. + */ +extend( QUnit.constructor.prototype, { + + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: registerLoggingCallback( "begin" ), + + // done: { failed, passed, total, runtime } + done: registerLoggingCallback( "done" ), + + // log: { result, actual, expected, message } + log: registerLoggingCallback( "log" ), + + // testStart: { name } + testStart: registerLoggingCallback( "testStart" ), + + // testDone: { name, failed, passed, total, duration } + testDone: registerLoggingCallback( "testDone" ), + + // moduleStart: { name } + moduleStart: registerLoggingCallback( "moduleStart" ), + + // moduleDone: { name, failed, passed, total } + moduleDone: registerLoggingCallback( "moduleDone" ) +}); + +if ( typeof document === "undefined" || document.readyState === "complete" ) { + config.autorun = true; +} + +QUnit.load = function() { + runLoggingCallbacks( "begin", QUnit, {} ); + + // Initialize the config, saving the execution queue + var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, + urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter, + numModules = 0, + moduleFilterHtml = "", + urlConfigHtml = "", + oldconfig = extend( {}, config ); + + QUnit.init(); + extend(config, oldconfig); + + config.blocking = false; + + len = config.urlConfig.length; + + for ( i = 0; i < len; i++ ) { + val = config.urlConfig[i]; + if ( typeof val === "string" ) { + val = { + id: val, + label: val, + tooltip: "[no tooltip available]" + }; + } + config[ val.id ] = QUnit.urlParams[ val.id ]; + urlConfigHtml += ""; + } + + moduleFilterHtml += ""; + + // `userAgent` initialized at top of scope + userAgent = id( "qunit-userAgent" ); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } + + // `banner` initialized at top of scope + banner = id( "qunit-header" ); + if ( banner ) { + banner.innerHTML = "" + banner.innerHTML + " "; + } + + // `toolbar` initialized at top of scope + toolbar = id( "qunit-testrunner-toolbar" ); + if ( toolbar ) { + // `filter` initialized at top of scope + filter = document.createElement( "input" ); + filter.type = "checkbox"; + filter.id = "qunit-filter-pass"; + + addEvent( filter, "click", function() { + var tmp, + ol = document.getElementById( "qunit-tests" ); + + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace( / hidepass /, " " ); + } + if ( defined.sessionStorage ) { + if (filter.checked) { + sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); + } else { + sessionStorage.removeItem( "qunit-filter-passed-tests" ); + } + } + }); + + if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { + filter.checked = true; + // `ol` initialized at top of scope + ol = document.getElementById( "qunit-tests" ); + ol.className = ol.className + " hidepass"; + } + toolbar.appendChild( filter ); + + // `label` initialized at top of scope + label = document.createElement( "label" ); + label.setAttribute( "for", "qunit-filter-pass" ); + label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." ); + label.innerHTML = "Hide passed tests"; + toolbar.appendChild( label ); + + urlConfigCheckboxesContainer = document.createElement("span"); + urlConfigCheckboxesContainer.innerHTML = urlConfigHtml; + urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input"); + // For oldIE support: + // * Add handlers to the individual elements instead of the container + // * Use "click" instead of "change" + // * Fallback from event.target to event.srcElement + addEvents( urlConfigCheckboxes, "click", function( event ) { + var params = {}, + target = event.target || event.srcElement; + params[ target.name ] = target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); + toolbar.appendChild( urlConfigCheckboxesContainer ); + + if (numModules > 1) { + moduleFilter = document.createElement( 'span' ); + moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' ); + moduleFilter.innerHTML = moduleFilterHtml; + addEvent( moduleFilter.lastChild, "change", function() { + var selectBox = moduleFilter.getElementsByTagName("select")[0], + selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); + + window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } ); + }); + toolbar.appendChild(moduleFilter); + } + } + + // `main` initialized at top of scope + main = id( "qunit-fixture" ); + if ( main ) { + config.fixture = main.innerHTML; + } + + if ( config.autostart ) { + QUnit.start(); + } +}; + +addEvent( window, "load", QUnit.load ); + +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will surpress the default browser handler, +// returning false will let it run. +window.onerror = function ( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not surpressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", extend( function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }, { validTest: validTest } ) ); + } + return false; + } + + return ret; +}; + +function done() { + config.autorun = true; + + // Log the last module results + if ( config.currentModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.currentModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + runtime = +new Date() - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + "Tests completed in ", + runtime, + " milliseconds.
    ", + "", + passed, + " assertions of ", + config.stats.all, + " passed, ", + config.stats.bad, + " failed." + ].join( "" ); + + if ( banner ) { + banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && typeof document !== "undefined" && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( config.stats.bad ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { + // `key` & `i` initialized at top of scope + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } + } + } + + // scroll back to top to show results + if ( window.scrollTo ) { + window.scrollTo(0, 0); + } + + runLoggingCallbacks( "done", QUnit, { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + }); +} + +/** @return Boolean: true if this test should be ran */ +function validTest( test ) { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = config.module && config.module.toLowerCase(), + fullName = (test.module + ": " + test.testName).toLowerCase(); + + // Internally-generated tests are always valid + if ( test.callback && test.callback.validTest === validTest ) { + delete test.callback.validTest; + return true; + } + + if ( config.testNumber ) { + return test.testNumber === config.testNumber; + } + + if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; +} + +// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) +// Later Safari and IE10 are supposed to support error.stack as well +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 3 : offset; + + var stack, include, i; + + if ( e.stacktrace ) { + // Opera + return e.stacktrace.split( "\n" )[ offset + 3 ]; + } else if ( e.stack ) { + // Firefox, Chrome + stack = e.stack.split( "\n" ); + if (/^error$/i.test( stack[0] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) !== -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } + return stack[ offset ]; + } else if ( e.sourceURL ) { + // Safari, PhantomJS + // hopefully one day Safari provides actual stacktraces + // exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + // for actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} +function sourceFromStacktrace( offset ) { + try { + throw new Error(); + } catch ( e ) { + return extractStacktrace( e, offset ); + } +} + +/** + * Escape text for attribute or text content. + */ +function escapeText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + // Both single quotes and double quotes (for attributes) + return s.replace( /['"<>&]/g, function( s ) { + switch( s ) { + case '\'': + return '''; + case '"': + return '"'; + case '<': + return '<'; + case '>': + return '>'; + case '&': + return '&'; + } + }); +} + +function synchronize( callback, last ) { + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process( last ); + } +} + +function process( last ) { + function next() { + process( last ); + } + var start = new Date().getTime(); + config.depth = config.depth ? config.depth + 1 : 1; + + while ( config.queue.length && !config.blocking ) { + if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { + config.queue.shift()(); + } else { + window.setTimeout( next, 13 ); + break; + } + } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } + } +} + +function checkPollution() { + var newGlobals, + deletedGlobals, + old = config.pollution; + + saveGlobal(); + + newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); + } + + deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { + if ( result[i] === b[j] ) { + result.splice( i, 1 ); + i--; + break; + } + } + } + return result; +} + +function extend( a, b ) { + for ( var prop in b ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + + // Avoid "Member not found" error in IE8 caused by setting window.constructor + } else if ( prop !== "constructor" || a !== window ) { + a[ prop ] = b[ prop ]; + } + } + + return a; +} + +/** + * @param {HTMLElement} elem + * @param {string} type + * @param {Function} fn + */ +function addEvent( elem, type, fn ) { + // Standards-based browsers + if ( elem.addEventListener ) { + elem.addEventListener( type, fn, false ); + // IE + } else { + elem.attachEvent( "on" + type, fn ); + } +} + +/** + * @param {Array|NodeList} elems + * @param {string} type + * @param {Function} fn + */ +function addEvents( elems, type, fn ) { + var i = elems.length; + while ( i-- ) { + addEvent( elems[i], type, fn ); + } +} + +function hasClass( elem, name ) { + return (" " + elem.className + " ").indexOf(" " + name + " ") > -1; +} + +function addClass( elem, name ) { + if ( !hasClass( elem, name ) ) { + elem.className += (elem.className ? " " : "") + name; + } +} + +function removeClass( elem, name ) { + var set = " " + elem.className + " "; + // Class name may appear multiple times + while ( set.indexOf(" " + name + " ") > -1 ) { + set = set.replace(" " + name + " " , " "); + } + // If possible, trim it for prettiness, but not neccecarily + elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set ); +} + +function id( name ) { + return !!( typeof document !== "undefined" && document && document.getElementById ) && + document.getElementById( name ); +} + +function registerLoggingCallback( key ) { + return function( callback ) { + config[key].push( callback ); + }; +} + +// Supports deprecated method of completely overwriting logging callbacks +function runLoggingCallbacks( key, scope, args ) { + var i, callbacks; + if ( QUnit.hasOwnProperty( key ) ) { + QUnit[ key ].call(scope, args ); + } else { + callbacks = config[ key ]; + for ( i = 0; i < callbacks.length; i++ ) { + callbacks[ i ].call( scope, args ); + } + } +} + +// Test for equality any JavaScript type. +// Author: Philippe Rathé +QUnit.equiv = (function() { + + // Call the o related callback with the given arguments. + function bindCallbacks( o, callbacks, args ) { + var prop = QUnit.objectType( o ); + if ( prop ) { + if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { + return callbacks[ prop ].apply( callbacks, args ); + } else { + return callbacks[ prop ]; // or undefined + } + } + } + + // the real equiv function + var innerEquiv, + // stack to decide between skip/abort functions + callers = [], + // stack to avoiding loops from circular referencing + parents = [], + + getProto = Object.getPrototypeOf || function ( obj ) { + return obj.__proto__; + }, + callbacks = (function () { + + // for string, boolean, number and null + function useStrictEquality( b, a ) { + /*jshint eqeqeq:false */ + if ( b instanceof a.constructor || a instanceof b.constructor ) { + // to catch short annotaion VS 'new' annotation of a + // declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function( b ) { + return isNaN( b ); + }, + + "date": function( b, a ) { + return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function( b, a ) { + return QUnit.objectType( b ) === "regexp" && + // the regex itself + a.source === b.source && + // and its modifers + a.global === b.global && + // (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline && + a.sticky === b.sticky; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function() { + var caller = callers[callers.length - 1]; + return caller !== Object && typeof caller !== "undefined"; + }, + + "array": function( b, a ) { + var i, j, len, loop; + + // b could be an object literal here + if ( QUnit.objectType( b ) !== "array" ) { + return false; + } + + len = a.length; + if ( len !== b.length ) { + // safe and faster + return false; + } + + // track reference to avoid circular references + parents.push( a ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + loop = true;// dont rewalk array + } + } + if ( !loop && !innerEquiv(a[i], b[i]) ) { + parents.pop(); + return false; + } + } + parents.pop(); + return true; + }, + + "object": function( b, a ) { + var i, j, loop, + // Default to true + eq = true, + aProperties = [], + bProperties = []; + + // comparing constructors is more strict than using + // instanceof + if ( a.constructor !== b.constructor ) { + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || + ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { + return false; + } + } + + // stack constructor before traversing properties + callers.push( a.constructor ); + // track reference to avoid circular references + parents.push( a ); + + for ( i in a ) { // be strict: don't ensures hasOwnProperty + // and go deep + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + // don't go down the same path twice + loop = true; + } + } + aProperties.push(i); // collect a's properties + + if (!loop && !innerEquiv( a[i], b[i] ) ) { + eq = false; + break; + } + } + + callers.pop(); // unstack, we are done + parents.pop(); + + for ( i in b ) { + bProperties.push( i ); // collect b's properties + } + + // Ensures identical properties name + return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + } + }; + }()); + + innerEquiv = function() { // can take multiple arguments + var args = [].slice.apply( arguments ); + if ( args.length < 2 ) { + return true; // end transition + } + + return (function( a, b ) { + if ( a === b ) { + return true; // catch the most you can + } else if ( a === null || b === null || typeof a === "undefined" || + typeof b === "undefined" || + QUnit.objectType(a) !== QUnit.objectType(b) ) { + return false; // don't lose time with error prone cases + } else { + return bindCallbacks(a, callbacks, [ b, a ]); + } + + // apply transition with (1..n) arguments + }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); + }; + + return innerEquiv; +}()); + +/** + * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | + * http://flesler.blogspot.com Licensed under BSD + * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 + * + * @projectDescription Advanced and extensible data dumping for Javascript. + * @version 1.0.0 + * @author Ariel Flesler + * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} + */ +QUnit.jsDump = (function() { + function quote( str ) { + return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; + } + function literal( o ) { + return o + ""; + } + function join( pre, arr, post ) { + var s = jsDump.separator(), + base = jsDump.indent(), + inner = jsDump.indent(1); + if ( arr.join ) { + arr = arr.join( "," + s + inner ); + } + if ( !arr ) { + return pre + post; + } + return [ pre, inner + arr, base + post ].join(s); + } + function array( arr, stack ) { + var i = arr.length, ret = new Array(i); + this.up(); + while ( i-- ) { + ret[i] = this.parse( arr[i] , undefined , stack); + } + this.down(); + return join( "[", ret, "]" ); + } + + var reName = /^function (\w+)/, + jsDump = { + // type is used mostly internally, you can fix a (custom)type in advance + parse: function( obj, type, stack ) { + stack = stack || [ ]; + var inStack, res, + parser = this.parsers[ type || this.typeOf(obj) ]; + + type = typeof parser; + inStack = inArray( obj, stack ); + + if ( inStack !== -1 ) { + return "recursion(" + (inStack - stack.length) + ")"; + } + if ( type === "function" ) { + stack.push( obj ); + res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + return ( type === "string" ) ? parser : this.parsers.error; + }, + typeOf: function( obj ) { + var type; + if ( obj === null ) { + type = "null"; + } else if ( typeof obj === "undefined" ) { + type = "undefined"; + } else if ( QUnit.is( "regexp", obj) ) { + type = "regexp"; + } else if ( QUnit.is( "date", obj) ) { + type = "date"; + } else if ( QUnit.is( "function", obj) ) { + type = "function"; + } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { + type = "window"; + } else if ( obj.nodeType === 9 ) { + type = "document"; + } else if ( obj.nodeType ) { + type = "node"; + } else if ( + // native arrays + toString.call( obj ) === "[object Array]" || + // NodeList objects + ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) + ) { + type = "array"; + } else if ( obj.constructor === Error.prototype.constructor ) { + type = "error"; + } else { + type = typeof obj; + } + return type; + }, + separator: function() { + return this.multiline ? this.HTML ? "
    " : "\n" : this.HTML ? " " : " "; + }, + // extra can be a number, shortcut for increasing-calling-decreasing + indent: function( extra ) { + if ( !this.multiline ) { + return ""; + } + var chr = this.indentChar; + if ( this.HTML ) { + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); + } + return new Array( this._depth_ + (extra||0) ).join(chr); + }, + up: function( a ) { + this._depth_ += a || 1; + }, + down: function( a ) { + this._depth_ -= a || 1; + }, + setParser: function( name, parser ) { + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote: quote, + literal: literal, + join: join, + // + _depth_: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers: { + window: "[Window]", + document: "[Document]", + error: function(error) { + return "Error(\"" + error.message + "\")"; + }, + unknown: "[Unknown]", + "null": "null", + "undefined": "undefined", + "function": function( fn ) { + var ret = "function", + // functions never have name in IE + name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1]; + + if ( name ) { + ret += " " + name; + } + ret += "( "; + + ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); + return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); + }, + array: array, + nodelist: array, + "arguments": array, + object: function( map, stack ) { + var ret = [ ], keys, key, val, i; + QUnit.jsDump.up(); + keys = []; + for ( key in map ) { + keys.push( key ); + } + keys.sort(); + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + val = map[ key ]; + ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); + } + QUnit.jsDump.down(); + return join( "{", ret, "}" ); + }, + node: function( node ) { + var len, i, val, + open = QUnit.jsDump.HTML ? "<" : "<", + close = QUnit.jsDump.HTML ? ">" : ">", + tag = node.nodeName.toLowerCase(), + ret = open + tag, + attrs = node.attributes; + + if ( attrs ) { + for ( i = 0, len = attrs.length; i < len; i++ ) { + val = attrs[i].nodeValue; + // IE6 includes all attributes in .attributes, even ones not explicitly set. + // Those have values like undefined, null, 0, false, "" or "inherit". + if ( val && val !== "inherit" ) { + ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" ); + } + } + } + ret += close; + + // Show content of TextNode or CDATASection + if ( node.nodeType === 3 || node.nodeType === 4 ) { + ret += node.nodeValue; + } + + return ret + open + "/" + tag + close; + }, + // function calls it internally, it's the arguments part of the function + functionArgs: function( fn ) { + var args, + l = fn.length; + + if ( !l ) { + return ""; + } + + args = new Array(l); + while ( l-- ) { + // 97 is 'a' + args[l] = String.fromCharCode(97+l); + } + return " " + args.join( ", " ) + " "; + }, + // object calls it internally, the key part of an item in a map + key: quote, + // function calls it internally, it's the content of the function + functionCode: "[code]", + // node calls it internally, it's an html attribute value + attribute: quote, + string: quote, + date: quote, + regexp: literal, + number: literal, + "boolean": literal + }, + // if true, entities are escaped ( <, >, \t, space and \n ) + HTML: false, + // indentation unit + indentChar: " ", + // if true, items in a collection, are separated by a \n, else just a space. + multiline: true + }; + + return jsDump; +}()); + +// from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" + */ +QUnit.diff = (function() { + /*jshint eqeqeq:false, eqnull:true */ + function diff( o, n ) { + var i, + ns = {}, + os = {}; + + for ( i = 0; i < n.length; i++ ) { + if ( !hasOwn.call( ns, n[i] ) ) { + ns[ n[i] ] = { + rows: [], + o: null + }; + } + ns[ n[i] ].rows.push( i ); + } + + for ( i = 0; i < o.length; i++ ) { + if ( !hasOwn.call( os, o[i] ) ) { + os[ o[i] ] = { + rows: [], + n: null + }; + } + os[ o[i] ].rows.push( i ); + } + + for ( i in ns ) { + if ( !hasOwn.call( ns, i ) ) { + continue; + } + if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) { + n[ ns[i].rows[0] ] = { + text: n[ ns[i].rows[0] ], + row: os[i].rows[0] + }; + o[ os[i].rows[0] ] = { + text: o[ os[i].rows[0] ], + row: ns[i].rows[0] + }; + } + } + + for ( i = 0; i < n.length - 1; i++ ) { + if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && + n[ i + 1 ] == o[ n[i].row + 1 ] ) { + + n[ i + 1 ] = { + text: n[ i + 1 ], + row: n[i].row + 1 + }; + o[ n[i].row + 1 ] = { + text: o[ n[i].row + 1 ], + row: i + 1 + }; + } + } + + for ( i = n.length - 1; i > 0; i-- ) { + if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && + n[ i - 1 ] == o[ n[i].row - 1 ]) { + + n[ i - 1 ] = { + text: n[ i - 1 ], + row: n[i].row - 1 + }; + o[ n[i].row - 1 ] = { + text: o[ n[i].row - 1 ], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function( o, n ) { + o = o.replace( /\s+$/, "" ); + n = n.replace( /\s+$/, "" ); + + var i, pre, + str = "", + out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), + oSpace = o.match(/\s+/g), + nSpace = n.match(/\s+/g); + + if ( oSpace == null ) { + oSpace = [ " " ]; + } + else { + oSpace.push( " " ); + } + + if ( nSpace == null ) { + nSpace = [ " " ]; + } + else { + nSpace.push( " " ); + } + + if ( out.n.length === 0 ) { + for ( i = 0; i < out.o.length; i++ ) { + str += "" + out.o[i] + oSpace[i] + ""; + } + } + else { + if ( out.n[0].text == null ) { + for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { + str += "" + out.o[n] + oSpace[n] + ""; + } + } + + for ( i = 0; i < out.n.length; i++ ) { + if (out.n[i].text == null) { + str += "" + out.n[i] + nSpace[i] + ""; + } + else { + // `pre` initialized at top of scope + pre = ""; + + for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { + pre += "" + out.o[n] + oSpace[n] + ""; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; + }; +}()); + +// for CommonJS enviroments, export everything +if ( typeof exports !== "undefined" ) { + extend( exports, QUnit ); +} + +// get at whatever the global object is, like window in browsers +}( (function() {return this;}.call()) )); diff --git a/public/js/lib/jszip/test/ref/all.7zip.zip b/public/js/lib/jszip/test/ref/all.7zip.zip new file mode 100644 index 0000000000000000000000000000000000000000..a7a6c5f5f5747aaa52cdb20fae9f55a728dbbd35 GIT binary patch literal 367 zcmWIWW@h1H0D+{s|5lHmPTjx*WP>m#5PPKNRFr@j3gP)hIVoHLC|ZE3;D8;- z%FInnPc7C*Rb*rTx=Rx%3Bm#hMa8+9IjMT-nQ88xZWiW=tPHFS4NO33hX3~%bU-vn zgn@~phks)FYOWwg2I~NCMkWyk+ztk5Vqj1JlSs}-*9MgbQy@n}0LW#=Kn(W+s$J-w efM`+xQV|GEa4!XTv$BCyFazN#AiW;MVE_P2tU{as literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/all.windows.zip b/public/js/lib/jszip/test/ref/all.windows.zip new file mode 100644 index 0000000000000000000000000000000000000000..97b8ab9337f93695520adff0a2873a2fe9c1397b GIT binary patch literal 273 zcmWIWW@Zs#0D+{s|5lHmPTjx*WP>m#5PPKNRFr@j3gP)hIVoHLP%Ru_EjISA zyHtTnHGx literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/backslash.zip b/public/js/lib/jszip/test/ref/backslash.zip new file mode 100644 index 0000000000000000000000000000000000000000..a63d7b3b07da30f3b5433ba18f896ac747db0d37 GIT binary patch literal 130 zcmWIWW@h1H0D)^;)SVtbow|Vs$Od7Ms7Go}OisRDNks{em6NX!o?n!c!WH1n$Rx*% eTNh9x7%XW7Q3x{vyjj^mB8)(20i;bp90mZLQW@0% literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/complex_files/AntarcticaTemps.ods b/public/js/lib/jszip/test/ref/complex_files/AntarcticaTemps.ods new file mode 100644 index 0000000000000000000000000000000000000000..77988bda9834bca7e04b39408e2583e30e00e03c GIT binary patch literal 40538 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 literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/complex_files/AntarcticaTemps.xlsx b/public/js/lib/jszip/test/ref/complex_files/AntarcticaTemps.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b592785ce350b2176a060a42cdbc40e1faa2fa30 GIT binary patch literal 31683 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

    yDTI7Mzp=F+T> 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 Y0j`CMJEE{`!EiLY>iSOt2N2jH2 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

  1. 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

    Hv$jC>; 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 literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/data_descriptor.zip b/public/js/lib/jszip/test/ref/data_descriptor.zip new file mode 100644 index 0000000000000000000000000000000000000000..e884181129f845bab40e29e17f55dbd6d5fb2aef GIT binary patch literal 196 zcmWIWW@h1H;9y{2C~H=90#Xb-P|V37!{CvclasGkQc)5b!pXp#&+s?^gi9;985mh! zFf%ZK39urC@cg2j6s`boc8}nS7%XW7QApOYLaalx UD!`kS4Wy6}2>pR{Jcz>p01Ch*F8}}l literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/deflate.zip b/public/js/lib/jszip/test/ref/deflate.zip new file mode 100644 index 0000000000000000000000000000000000000000..a6c7cbc9f3fc14a9f188412cc0360252c45a10ec GIT binary patch literal 189 zcmWIWW@Zs#U|`^2xKcR7X0kuuLr)+t4v0B{*dsM3Ctt6mq9pXhM&1Sk9+m_1H0zky z68OX#emLu>nsw=>)@H5SvpMsDQ+auHz*b>)vBV_`vW`m9ic#9?YX!`UCw_bF^6{ge w+X`v6%{!0ms}1mGWRhdXZ6nZ921X!W(gD0Ad?4QUCw| literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/encrypted.zip b/public/js/lib/jszip/test/ref/encrypted.zip new file mode 100644 index 0000000000000000000000000000000000000000..632a988b756ee264af0859f8ad9959a7a454bb15 GIT binary patch literal 156 zcmWIWW@h1H;ACK6m{ao6>haU58zg{i9v}vZd8Fp#W{1A%6O!IDN01vfsxo0SbDzzBrqK-wR~VE_Oy Cj3kZ# literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/extra_attributes.zip b/public/js/lib/jszip/test/ref/extra_attributes.zip new file mode 100644 index 0000000000000000000000000000000000000000..1bae71204987b82ca38b97a12c83eb2483d72981 GIT binary patch literal 180 zcmWIWW@h1H0D(CrAFUogow|Vs$Od6f1{nsA)SR4ry^@NO&=5`r=8S>_FAy%R;AUWC zdBM!U04BhS6vFe1a#FYgycwC~m~j~>0kQ`SmNbGWB;#2j#-kY>;LXYgQpgB|{y-Xp G85jWi1SP8g literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/folder.zip b/public/js/lib/jszip/test/ref/folder.zip new file mode 100644 index 0000000000000000000000000000000000000000..c06e26a7a0e8e1b99c353b1c6076074f111b3726 GIT binary patch literal 112 zcmWIWW@h1HW&i@_+|O1Z8V1;bjI{iml++^q0B=Sn5oX-VAX)?(-a3Li LngVH65QhN(^WF^5 literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/image.zip b/public/js/lib/jszip/test/ref/image.zip new file mode 100644 index 0000000000000000000000000000000000000000..b5217b98d77c0ee3457e41318d7b96ded7050091 GIT binary patch literal 157 zcmWIWW@h1HW&i@w{8v^s_OH7%fou@w1mfb{%$!uc^vpDOPd5wmL{Gj0<>niv=q8kRJIXt?k>Y(g>p9t_<*IWdjK? s0--sOHU@DR0=&sI451C1N5N(Ti6xC7Yp{76;ut0dCWdmLipO9L0Ck8^5C8xG literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/nested_data_descriptor.zip b/public/js/lib/jszip/test/ref/nested_data_descriptor.zip new file mode 100644 index 0000000000000000000000000000000000000000..b70ba4b0458950e8851b9b87034b991b287129f6 GIT binary patch literal 400 zcmWIWW@h1H;9y{2m@rS#2}m&8HSX^lEnCw)Z*l#%z~2qBE722g3u672IhQ& z#{nQ*TEWf0$nt`jfdNbezzr*Fh8V^JGz^3}frfdc=H%q-l~j~Kj9>s70mNuVfE6i( z=NILqa0Pg?b3A@JbpydtN{kH9$R1`td9g*tjGwm9spaaQj!1w literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/nested_zip64.zip b/public/js/lib/jszip/test/ref/nested_zip64.zip new file mode 100644 index 0000000000000000000000000000000000000000..85860c37fd8abc8c0517607509f21e2bddc4cb9e GIT binary patch literal 564 zcmWIWW@gc40D&!Y6`dT7?tK0a1)K~93{{y0W+r+-GBkvff%%Hw;{XsYt>9*0WO>2N zzyKx~83Y&<7{O-1=>WK~WzC9CkDpH6fNZQsYEDkRUP(m>*w}oA#{nRW#aJGQsSGe0 ztWhC6zbGe#E5MtPNsbxfc9Osx}i6R^i3wQ;fa_o*riUy$L Yu|@$0QqYs;_;RSPV2-~8<>Pid01ISnCIA2c literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/permissions/linux_7z.zip b/public/js/lib/jszip/test/ref/permissions/linux_7z.zip new file mode 100644 index 0000000000000000000000000000000000000000..614b5e13b23ab1fda060b5216eb5fce9510f50ff GIT binary patch literal 666 zcmWIWW@Zs#W&nZ>t3upBGz@S687Y}X@umg_`T+!0nVXstqsrVItcnY4<2o!hre)@& z#+w)zfNUh7%FKi)Rc2;Hm<4oxfHxzPJu~jGfP{-+gM%Z8g$Nm9bO|)PbyS1uf`k-t zy8b)*z;uB_4x|frsDRwXz@XT`&{zbd5g|#8E`^2#jWb}nz#&VVu5FF`;JQE|O`NW` bjZa{@z#-4d2IMlZ17Q^-0|OTjGcW)EaLZa( literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/permissions/linux_ark.zip b/public/js/lib/jszip/test/ref/permissions/linux_ark.zip new file mode 100644 index 0000000000000000000000000000000000000000..98f6acc545add4080565d2ffd252e6582489c1da GIT binary patch literal 1030 zcmWIWW@h1H00GtV3^y}Y$l%}zVj^Of6%xA`p-PNt0t{~*ouH;cVw$jNn6U(N z8zTclV++tUM63f%Bj8iqrZF%qXgmfp4V(ffGwp372hf3Fw}DdwVbd_v0?elZ4F4Uy sfTn?B0g^H(2{#6YZH+xJw}Dd$F1N9=0Rx1A9SD_}7#Pk0^)N610H(mDuK)l5 literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/permissions/linux_file_roller-ubuntu.zip b/public/js/lib/jszip/test/ref/permissions/linux_file_roller-ubuntu.zip new file mode 100644 index 0000000000000000000000000000000000000000..917146c47442ceb751fbba47ffd0f1242298072b GIT binary patch literal 666 zcmWIWW@Zs#W&ncUU1@G08U{FkjFilxcvAxd{Q!ch%uP*+QDtrpR>g(W#PS<}& zADAw1$bod>4i%8Q7#I{A7#fR!G$JI4(WTI^pm7FF7dT{z)3vQ}A6yqGq>0n@w($u} X7dYfu*??RIb|9=`WMJR|Vg?2Pg^pdl literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/permissions/linux_file_roller-xubuntu.zip b/public/js/lib/jszip/test/ref/permissions/linux_file_roller-xubuntu.zip new file mode 100644 index 0000000000000000000000000000000000000000..29b1e885516bbafde0f1085a9d1148cf020a3f40 GIT binary patch literal 1030 zcmWIWW@h1H0D--}8E#+(l;B{HVMxo&NsTu*H4P2nWMG~e^d|&_ODnh;7+H#e%2;ZF zL;ztE%*@OvHNnJyLK933h&16imT*YPEQ&WbH`fQdVHq$C?1J%x15Oi6O(`_N)WCp% z35-l~%(&uH0v^3@8$nD&?6N{)7b9kgGi_U=6U;PlOjBmsg2ooOX`ooA#56_*hQ?zs z)4(Z!uxXgF2Mad=hX0NnKqC>U0caX1HQ)(1e5Sp1^n#fNP8pP#CdlC6*aI~Ul1gxy W#>xf^5C(Q2RAORaI0w|jzyJWYsHPPF literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/permissions/linux_zip.zip b/public/js/lib/jszip/test/ref/permissions/linux_zip.zip new file mode 100644 index 0000000000000000000000000000000000000000..b6f29da2cbc3e8dd40460c4932dd5bbe4a9991af GIT binary patch literal 1030 zcmWIWW@h1H0D*O@LfpU%D8a!X!;qGllNxVgU=SL@$-wL}{douomsW5yFtWU0W?%pl z0dNyGU@;*jvnbx&)KnjAf)7wP2;(#XryI=7%!qRXP7{ERAkG9_zA!Z~px75Cl!m0a zIRQ5?GRZOHicbk>%rY`CG=i9j*ky&pE=If{Ov4Nnm}vqGZylY0rXgY)Xd2d7Mwo^f zOEA+I7`8RGz}yCob;54LXWHAwV=&XeDS)tPxP2@m!ok52 z#6-jd2RtSMyood6t)mW2rKFu-DkSQGv`=DBXK;ccS}%mi?ZBAdX<26P?+I}n}&s;L5E1_l80 C*q$K( literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/permissions/windows_7z.zip b/public/js/lib/jszip/test/ref/permissions/windows_7z.zip new file mode 100644 index 0000000000000000000000000000000000000000..fbb71bb6fef8fed261bc2ad384efe8770635d772 GIT binary patch literal 1082 zcmWIWW@Zs#00B1}UpFuVO0WRwl*}Ui0H6vku$U{F3LdD6f}H#Uy^@L&kV=SI9%w4L zAu8iDGE-7g^Y9ocjH(dXWQZHCSYx^}Ei)$-;YxHBAiF^-pqArS$PQCjl#g2xA3_n_ zKt?8e23%pN0#pwI0uTxuqFf9LU>+lb1ViCk=9We77Z_pmVZ8~4Abx;1$W&b64l@;G zjuH@q;t3X3$fk!H9ccoYhE79F#}!vF(}jR0`#?;G#T>HXTb7u$feeSyKa{Qy3Tki3q+~) z3P4H=h=Bo!87v3`(7g=`7zj`RQqe#R2`1b+Kmi2-Nh(S8A_!8YJP{2WeB9K}J o#9)n}V8m@3C?Fv~8AzQ5VyGs#g{*8Kc{U&nXJlab4&pEX08>*{rvLx| literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/permissions/windows_izarc.zip b/public/js/lib/jszip/test/ref/permissions/windows_izarc.zip new file mode 100644 index 0000000000000000000000000000000000000000..7422401f3c9659f4e33378af8925951592e38720 GIT binary patch literal 612 zcmWIWW@Zs#0D&vkzHVR!lwbkUX_+~x0XS7~Lsi6QWTvE~=HXVz4pUf^k6RHRLJ@|6 zt~RJ{;{mEo$t=<@$jL9zE2$_!n2N4a7@`ttB9aD1CJ_eQ9tY}TU}R7LQ9u9*2HZM8 z0RaMx3`#%}gh4vszQC;!6fhvb$e;)$y@4345fn_gHGu*O1Q;2Vfn)&?Lp5Qs5Is0R v0S5vQzs&)%P=gU+E4oflK!N~7=P@7)s1q|-S=m5}*nlvck%8emh{FH?9065% literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/permissions/windows_winrar.zip b/public/js/lib/jszip/test/ref/permissions/windows_winrar.zip new file mode 100644 index 0000000000000000000000000000000000000000..9439a11264e43cec53717bcdaf2852b46dc7650c GIT binary patch literal 1082 zcmWIWW@h1H0D;TazHVR!lwbkUX_+~x0XS7~Lsi6QWTvE~=HXVz4pUf^k6RHRLJ@|6 zt~Qu%OUW$KN0{b6M0Gr{(_KLh9 zOJFoU!`b16D*_Gnh8bRzkImqE{R=!GgJCp2gZbbFD+3KJKp2e2;fG(G0XrNnOi`vh0%xgCK!VF$fjbZBbccQKoj>tO@+lhvgx5lN18yU zq0`8wW2QZr=|Vu0UqDQUr9@=Iw=6Mh0~rpZe|-0O2Dh1_mdfQ49>&0fg0n*z@qllEbTu@(wR5$vnIz@9=`0%&No7 zfb1Q4k7hJ~m_KQyUP(m>VO3lK-i%Cg%(yKA+64wn8bK6c13}gXc(byBR5Jo$2#`(( GaTowWB1;AU literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/slashes_and_izarc.zip b/public/js/lib/jszip/test/ref/slashes_and_izarc.zip new file mode 100644 index 0000000000000000000000000000000000000000..328b52adf86c8bf2fbaf0eae27be90a970ce8552 GIT binary patch literal 139 zcmWIWW@Zs#0D;{FdQR{AXLR!d*&xgZ#3iZ4CHfwzIXU@yB^4!LhC+FMQBDdkSAaJo mlL!NDtw7xjj0_4O3J5?3#lQ^;@MdKLi82DA4Uo13aTowr=Njbz literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/store.zip b/public/js/lib/jszip/test/ref/store.zip new file mode 100644 index 0000000000000000000000000000000000000000..761b91947a4e3b70a901aa37c43af0ff5570cf75 GIT binary patch literal 210 zcmWIWW@h1H0D&uoGi)aN^F53MvO$;=h&@tsa`N>`DoR2!GK&=w6>{?P^YhXb(lT>W z6|5A>Qx)=3Q&SX5@)e3xQx!@wQWa7%)6!ClQuC5i6_Qd*%2QMGP=reqlJj#5ic*V< yGxPHla#Kq(@>7cSxB|QxndF#pI|JwvFj&$EqTr4S@MdKL2`~boIgoAzaToyF$~Hy- literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/ref/subfolder.zip b/public/js/lib/jszip/test/ref/subfolder.zip new file mode 100644 index 0000000000000000000000000000000000000000..333057e618ac6f446dd72d361fbf00942c9a7362 GIT binary patch literal 222 zcmWIWW@h1HW&i@_+|O1Z8V1;bjI{iml++^q0Jx&ro7Jpg3P7|VLQ!#P5?nbWlL#|z mQy~TjG`w{Lv9M^uW(z`-Dnb*oovdsiB}_nA0;EGg90mX>%boC?BLQz?+o~#AO6Rkb02w7#IMU C_&34; literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/smile.gif b/public/js/lib/jszip/test/smile.gif new file mode 100644 index 0000000000000000000000000000000000000000..dd8c01923a7de8f0d3f7f27d1a0c256e9ee3c673 GIT binary patch literal 41 qcmZ?wbh9u|WMyDwXkcOhg8%mzbU-vngn@~phks)FYOWwg25SJ8G6yCA literal 0 HcmV?d00001 diff --git a/public/js/lib/jszip/test/test.js b/public/js/lib/jszip/test/test.js new file mode 100644 index 0000000..0eb6b9a --- /dev/null +++ b/public/js/lib/jszip/test/test.js @@ -0,0 +1,1529 @@ +'use strict'; +//var JSZip = require('../lib'); +function similar(actual, expected, mistakes) { + // actual is the generated zip, expected is what we got from the xhr. + // Be sure to have a well formatted string + expected = JSZip.utils.string2binary(expected); + + if (actual.length !== expected.length) { + mistakes -= Math.abs((actual.length||0) - (expected.length||0)); + } + + for (var i = 0; i < Math.min(actual.length, expected.length); i++) { + if (actual.charAt(i) !== expected.charAt(i)) { + mistakes--; + } + } + + if (mistakes < 0) + return false; + else + return true; +} + +/** + * bytes -> JSZip -> bytes + */ +function reload(bytesStream) { + return new JSZip(bytesStream, {checkCRC32:true}).generate({type:"string"}); +} + +// cache for files +var refZips = {}; + +function testZipFile(testName, zipName, testFunction) { + test(testName, function () { + if (refZips[zipName]) { + testFunction.call(this, refZips[zipName]); + } else { + stop(); + JSZipTestUtils.loadZipFile(zipName, function (err, file) { + if (QUnit.config.semaphore) { + start(); + } + + if(err) { + ok(false, err); + return; + } + + file = JSZip.utils.transformTo("string", file); + refZips[zipName] = file; + testFunction.call(this, file); + }); + } + }); +} + + + + +test("JSZip", function(){ + ok(JSZip, "JSZip exists"); + + var zip = new JSZip(); + ok(zip instanceof JSZip, "Constructor works"); + + var zipNoNew = JSZip(); + ok(zipNoNew instanceof JSZip, "Constructor adds `new` before itself where necessary"); +}); + +QUnit.module("Essential"); // {{{ + +test("JSZip.utils.transformTo", function () { + var supportedArgs = ['string', 'array']; + if (JSZip.support.arraybuffer) { + supportedArgs.push("arraybuffer"); + } + if (JSZip.support.uint8array) { + supportedArgs.push("uint8array"); + } + if (JSZip.support.nodebuffer) { + supportedArgs.push("nodebuffer"); + } + + var txt = 'test text !'; + + for (var i = 0; i < supportedArgs.length; i++) { + for (var j = 0; j < supportedArgs.length; j++) { + var step1 = JSZip.utils.transformTo(supportedArgs[i], txt); + var step2 = JSZip.utils.transformTo(supportedArgs[j], step1); + var result = JSZip.utils.transformTo("string", step2); + equal(result, txt, "The transformation string -> " + supportedArgs[i] + " -> " + supportedArgs[j] + " -> string works"); + } + } +}); + +testZipFile("Zip text file !", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + /* + Expected differing bytes: + 2 version number + 4 date/time + 4 central dir version numbers + 4 central dir date/time + 4 external file attributes + + 18 Total + */ + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + equal(reload(actual), actual, "Generated ZIP can be parsed"); +}); + +testZipFile("Add a file to overwrite", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "hello ?"); + zip.file("Hello.txt", "Hello World\n"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + /* + Expected differing bytes: + 2 version number + 4 date/time + 4 central dir version numbers + 4 central dir date/time + 4 external file attributes + + 18 Total + */ + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + equal(reload(actual), actual, "Generated ZIP can be parsed"); + }); + +// zip -X -0 utf8.zip amount.txt +testZipFile("Zip text file with UTF-8 characters", "ref/utf8.zip", function(expected) { + var zip = new JSZip(); + zip.file("amount.txt", "€15\n"); + var actual = zip.generate({type:"string"}); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + equal(reload(actual), actual, "Generated ZIP can be parsed"); + }); + +// zip -X -0 utf8_in_name.zip €15.txt +testZipFile("Zip text file with UTF-8 characters in filename", "ref/utf8_in_name.zip", function(expected) { + var zip = new JSZip(); + zip.file("€15.txt", "€15\n"); + var actual = zip.generate({type:"string"}); + + // zip doesn't generate a strange file like us (utf8 flag AND unicode path extra field) + // if one of the files has more data than the other, the bytes are no more aligned and the + // error count goes through the roof. The parsing is checked on a other test so I'll + // comment this one for now. + // ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + equal(reload(actual), actual, "Generated ZIP can be parsed"); + }); + +// zip -X -0 pile_of_poo.zip Iñtërnâtiônàlizætiøn☃💩.txt +testZipFile("Zip text file and UTF-8, Pile Of Poo test", "ref/pile_of_poo.zip", function(expected) { + var zip = new JSZip(); + // this is the string "Iñtërnâtiônàlizætiøn☃💩", + // see http://mathiasbynens.be/notes/javascript-unicode + // but escaped, to avoid troubles + // thanks http://mothereff.in/js-escapes#1I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%C3%A0liz%C3%A6ti%C3%B8n%E2%98%83%F0%9F%92%A9 + var text = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9'; + zip.file(text + ".txt", text + "\n"); + var actual = zip.generate({type:"string"}); + + equal(reload(actual), actual, "Generated ZIP can be parsed"); + + ok(new JSZip(expected).file(text + ".txt"), "JSZip finds the unicode file name on the external file"); + ok(new JSZip(actual).file(text + ".txt"), "JSZip finds the unicode file name on its own file"); + var textFromExpected = new JSZip(expected).file(text + ".txt").asText(); + var textFromActual = new JSZip(actual).file(text + ".txt").asText(); + + equal(textFromExpected, text + "\n", "JSZip can decode the external file"); + equal(textFromActual, text + "\n", "JSZip can decode its own file"); +}); + +testZipFile("Zip text file with date", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n", {date : new Date("July 17, 2009 14:36:57")}); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + /* + Expected differing bytes: + 2 version number + 4 central dir version numbers + 4 external file attributes + + 10 Total + */ + ok(similar(actual, expected, 10) , "Generated ZIP matches reference ZIP"); + equal(reload(actual), actual, "Generated ZIP can be parsed"); +}); + + +testZipFile("Zip image file", "ref/image.zip", function(expected) { + var zip = new JSZip(); + zip.file("smile.gif", "R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=", {base64: true}); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + equal(reload(actual), actual, "Generated ZIP can be parsed"); +}); + +test("Zip folder() shouldn't throw an exception", function(expected) { + var zip = new JSZip(); + try { + zip.folder(); + ok(true, "no exception thrown"); + } catch (e) { + ok(false, e.message||e); + } +}); + +testZipFile("Zip empty folder", "ref/folder.zip", function(expected) { + var zip = new JSZip(); + zip.folder("folder"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + equal(reload(actual), actual, "Generated ZIP can be parsed"); +}); + +testZipFile("Zip text, folder and image", "ref/all.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + zip.folder("images").file("smile.gif", "R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=", {base64: true}); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + /* + Expected differing bytes: + 2 version number + 4 date/time + 4 central dir version numbers + 4 central dir date/time + 4 external file attributes + + 18 * 3 files + 54 Total + */ + + ok(similar(actual, expected, 54) , "Generated ZIP matches reference ZIP"); + equal(reload(actual), actual, "Generated ZIP can be parsed"); +}); + +test("Finding a file", function() { + var zip = new JSZip(); + zip.file("Readme", "Hello World!\n"); + zip.file("Readme.French", "Bonjour tout le monde!\n"); + zip.file("Readme.Pirate", "Ahoy m'hearty!\n"); + + equal(zip.file("Readme.French").asText(), "Bonjour tout le monde!\n", "Exact match found"); + equal(zip.file("Readme.Deutch"), null, "Match exactly nothing"); + equal(zip.file(/Readme\../).length, 2, "Match regex free text"); + equal(zip.file(/pirate/i).length, 1, "Match regex 1 result"); +}); + +testZipFile("Finding a file : modifying the result doesn't alter the zip", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + zip.file("Hello.txt").name = "Hello2.txt"; + zip.file("Hello.txt").dir = true; + // these changes won't be used + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +test("Finding a file (text search) with a relative folder", function() { + var zip = new JSZip(); + zip.folder("files/default").file("Readme", "Hello World!\n"); + zip.folder("files/translation").file("Readme.French", "Bonjour tout le monde!\n"); + zip.folder("files").folder("translation").file("Readme.Pirate", "Ahoy m'hearty!\n"); + + equal(zip.file("files/translation/Readme.French").asText(), "Bonjour tout le monde!\n", "finding file with the full path"); + equal(zip.folder("files").file("translation/Readme.French").asText(), "Bonjour tout le monde!\n", "finding file with a relative path"); + equal(zip.folder("files/translation").file("Readme.French").asText(), "Bonjour tout le monde!\n", "finding file with a relative path"); +}); + +test("Finding files (regex) with a relative folder", function() { + var zip = new JSZip(); + zip.folder("files/default").file("Readme", "Hello World!\n"); + zip.folder("files/translation").file("Readme.French", "Bonjour tout le monde!\n"); + zip.folder("files").folder("translation").file("Readme.Pirate", "Ahoy m'hearty!\n"); + + equal(zip.file(/Readme/).length, 3, "match files in subfolders"); + equal(zip.folder("files/translation").file(/Readme/).length, 2, "regex match only in subfolders"); + equal(zip.folder("files").folder("translation").file(/Readme/).length, 2, "regex match only in subfolders"); + equal(zip.folder("files/translation").file(/pirate/i).length, 1, "regex match only in subfolders"); + equal(zip.folder("files/translation").file(/^readme/i).length, 2, "regex match only with the relative path"); + equal(zip.folder("files/default").file(/pirate/i).length, 0, "regex match only in subfolders"); +}); + +test("Finding folders", function () { + var zip = new JSZip(); + zip.folder("root/").folder("sub1/"); + zip.folder("root/sub2/subsub1"); + + equal(zip.folder(/sub2\/$/).length, 0, "unique result"); + equal(zip.folder(/sub1/).length, 2, "multiple results"); + equal(zip.folder(/root/).length, 3, "match on whole path"); +}); + +test("Finding folders with relative path", function () { + var zip = new JSZip(); + zip.folder("root/").folder("sub1/"); + zip.folder("root/sub2/subsub1"); + var root = zip.folder("root/sub2"); + + equal(root.folder(/sub2\/$/).length, 0, "current folder is not matched"); + equal(root.folder(/sub1/).length, 1, "sub folder is matched"); + equal(root.folder(/^subsub1/).length, 1, "relative folder path is used"); + equal(root.folder(/root/).length, 0, "parent folder is not matched"); +}); + +function zipObjectsAssertions(zipObject) { + var date = new Date("July 17, 2009 14:36:57"); + + equal(zipObject.name, "Hello.txt", "ZipObject#name is here"); + + equal(zipObject.comment, "my comment", "ZipObject#comment is here"); + + // the zip date has a 2s resolution + var delta = Math.abs(zipObject.date.getTime() - date.getTime()); + ok(delta < 2000/* ms */, date, "ZipObject#date is here"); + var deltaOptions = Math.abs(zipObject.options.date.getTime() - date.getTime()); + ok(deltaOptions < 2000/* ms */, date, "ZipObject#options.date is here (deprecated API)"); +} +test("ZipObject attributes", function () { + var date = new Date("July 17, 2009 14:36:57"); + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n", {comment:"my comment", date:date}); + zipObjectsAssertions(zip.file("Hello.txt")); + zipObjectsAssertions(zip.files["Hello.txt"]); + var reloaded = new JSZip(zip.generate({base64:false})); + zipObjectsAssertions(reloaded.file("Hello.txt")); + zipObjectsAssertions(reloaded.files["Hello.txt"]); +}); +test("generate uses updated ZipObject date attribute", function () { + var date = new Date("July 17, 2009 14:36:57"); + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n", {comment:"my comment"}); // date = now + zip.files["Hello.txt"].date = date; + var reloaded = new JSZip(zip.generate({type:"string"})); + zipObjectsAssertions(reloaded.file("Hello.txt")); + zipObjectsAssertions(reloaded.files["Hello.txt"]); +}); +test("generate uses updated ZipObject options.date attribute (deprecated)", function () { + var date = new Date("July 17, 2009 14:36:57"); + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n", {comment:"my comment"}); // date = now + zip.files["Hello.txt"].options.date = date; + var reloaded = new JSZip(zip.generate({type:"string"})); + zipObjectsAssertions(reloaded.file("Hello.txt")); + zipObjectsAssertions(reloaded.files["Hello.txt"]); +}); + +// }}} module Essential + +QUnit.module("More advanced"); // {{{ + +testZipFile("Delete file", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Remove.txt", "This file should be deleted\n"); + zip.file("Hello.txt", "Hello World\n"); + zip.remove("Remove.txt"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + +}); + +testZipFile("Delete file in folder", "ref/folder.zip", function(expected) { + var zip = new JSZip(); + zip.folder("folder").file("Remove.txt", "This folder and file should be deleted\n"); + zip.remove("folder/Remove.txt"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +testZipFile("Delete file in folder, with a relative path", "ref/folder.zip", function(expected) { + var zip = new JSZip(); + var folder = zip.folder("folder"); + folder.file("Remove.txt", "This folder and file should be deleted\n"); + folder.remove("Remove.txt"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +testZipFile("Delete folder", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.folder("remove").file("Remove.txt", "This folder and file should be deleted\n"); + zip.file("Hello.txt", "Hello World\n"); + zip.remove("remove"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +testZipFile("Delete folder with a final /", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.folder("remove").file("Remove.txt", "This folder and file should be deleted\n"); + zip.file("Hello.txt", "Hello World\n"); + zip.remove("remove/"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +testZipFile("Delete unknown path", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + zip.remove("unknown_file"); + zip.remove("unknown_folder/Hello.txt"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +testZipFile("Delete nested folders", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.folder("remove").file("Remove.txt", "This folder and file should be deleted\n"); + zip.folder("remove/second").file("Sub.txt", "This should be removed"); + zip.file("remove/second/another.txt", "Another file"); + zip.file("Hello.txt", "Hello World\n"); + zip.remove("remove"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + +}); + +testZipFile("Delete nested folders from relative path", "ref/folder.zip", function(expected) { + var zip = new JSZip(); + zip.folder("folder"); + zip.folder("folder/1/2/3"); + zip.folder("folder").remove("1"); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + equal(reload(actual), actual, "Generated ZIP can be parsed"); +}); + +testZipFile("add file: from XHR (with bytes > 255)", "ref/text.zip", function(textZip) { + var zip = new JSZip(); + zip.file("text.zip", textZip, {binary:true}); + var actual = zip.generate({base64:false}); + + equal(reload(actual), actual, "high-order byte is discarded and won't mess up the result"); +}); + +function testFileDataGetters (opts) { + if (typeof opts.rawData === "undefined") { + opts.rawData = opts.textData; + } + _actualTestFileDataGetters.asText(opts); + _actualTestFileDataGetters.asBinary(opts); + _actualTestFileDataGetters.asArrayBuffer(opts); + _actualTestFileDataGetters.asUint8Array(opts); + _actualTestFileDataGetters.asNodeBuffer(opts); + + var reload = function () { + return { + name : "reloaded, " + opts.name, + // no check of crc32, we want to test the CompressedObject code. + zip : new JSZip(opts.zip.generate({type:"string"}, {checkCRC32:false})), + textData : opts.textData, + rawData : opts.rawData + }; + }; + + _actualTestFileDataGetters.asText(reload()); + _actualTestFileDataGetters.asBinary(reload()); + _actualTestFileDataGetters.asArrayBuffer(reload()); + _actualTestFileDataGetters.asUint8Array(reload()); + _actualTestFileDataGetters.asNodeBuffer(reload()); +} + +var _actualTestFileDataGetters = { + asText : function (opts) { + equal(opts.zip.file("file.txt").asText(), opts.textData, opts.name + " : asText()"); + }, + asBinary : function (opts) { + equal(opts.zip.file("file.txt").asBinary(), opts.rawData, opts.name + " : asBinary()"); + }, + asArrayBuffer : function (opts) { + if (JSZip.support.arraybuffer) { + var buffer = opts.zip.file("file.txt").asArrayBuffer(); + ok(buffer instanceof ArrayBuffer, opts.name + " : the result is a instance of ArrayBuffer"); + var actual = JSZip.utils.transformTo("string", buffer); + equal(actual, opts.rawData, opts.name + " : asArrayBuffer()"); + } else { + try { + opts.zip.file("file.txt").asArrayBuffer(); + ok(false, "no exception thrown"); + } catch (e) { + ok(e.message.match("not supported by this browser"), opts.name + " : the error message is useful"); + } + } + }, + asUint8Array : function (opts) { + if (JSZip.support.uint8array) { + var bufferView = opts.zip.file("file.txt").asUint8Array(); + ok(bufferView instanceof Uint8Array, opts.name + " : the result is a instance of Uint8Array"); + var actual = JSZip.utils.transformTo("string", bufferView); + equal(actual, opts.rawData, opts.name + " : asUint8Array()"); + } else { + try { + opts.zip.file("file.txt").asUint8Array(); + ok(false, "no exception thrown"); + } catch (e) { + ok(e.message.match("not supported by this browser"), opts.name + " : the error message is useful"); + } + } + }, + asNodeBuffer : function (opts) { + if (JSZip.support.nodebuffer) { + var buffer = opts.zip.file("file.txt").asNodeBuffer(); + ok(buffer instanceof Buffer, opts.name + " : the result is a instance of Buffer"); + var actual = JSZip.utils.transformTo("string", buffer); + equal(actual, opts.rawData, opts.name + " : .asNodeBuffer()"); + } else { + try { + opts.zip.file("file.txt").asNodeBuffer(); + ok(false, "no exception thrown"); + } catch (e) { + ok(e.message.match("not supported by this browser"), opts.name + " : the error message is useful"); + } + } + } +}; + +test("add file: file(name, undefined)", function() { + var zip = new JSZip(), undef; + zip.file("file.txt", undef); + testFileDataGetters({name : "undefined", zip : zip, textData : ""}); + zip = new JSZip(); + zip.file("file.txt", undef, {binary:true}); + testFileDataGetters({name : "undefined", zip : zip, textData : ""}); + zip = new JSZip(); + zip.file("file.txt", undef, {base64:true}); + testFileDataGetters({name : "undefined", zip : zip, textData : ""}); +}); + +test("add file: file(name, null)", function() { + var zip = new JSZip(); + zip.file("file.txt", null); + testFileDataGetters({name : "null", zip : zip, textData : ""}); + zip = new JSZip(); + zip.file("file.txt", null, {binary:true}); + testFileDataGetters({name : "null", zip : zip, textData : ""}); + zip = new JSZip(); + zip.file("file.txt", null, {base64:true}); + testFileDataGetters({name : "null", zip : zip, textData : ""}); +}); + +test("add file: file(name, stringAsText)", function() { + var zip = new JSZip(); + zip.file("file.txt", "€15\n", {binary:false}); + testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); + zip = new JSZip(); + zip.file("file.txt", "test\r\ntest\r\n", {binary:false}); + testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); +}); + +test("add file: file(name, stringAsBinary)", function() { + var zip = new JSZip(); + zip.file("file.txt", "\xE2\x82\xAC15\n", {binary:true}); + testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); + zip = new JSZip(); + zip.file("file.txt", "test\r\ntest\r\n", {binary:true}); + testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); +}); + +test("add file: file(name, base64)", function() { + var zip = new JSZip(); + zip.file("file.txt", "4oKsMTUK", {base64:true}); + testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); + zip = new JSZip(); + zip.file("file.txt", "dGVzdA0KdGVzdA0K", {base64:true}); + testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); +}); + +test("add file: file(name, unsupported)", function() { + var zip = new JSZip(); + try { + zip.file("test.txt", new Date()); + ok(false, "An unsupported object was added, but no exception thrown"); + } catch(e) { + ok(e.message.match("unsupported format"), "the error message is useful"); + } + if (JSZip.support.blob) { + var blob = zip.generate({type:"blob"}); + try { + zip.file("test.txt", blob); + ok(false, "An blob was added, but no exception thrown"); + } catch(e) { + ok(e.message.match("unsupported format"), "the error message is useful"); + } + } +}); + +if (JSZip.support.uint8array) { + test("add file: file(name, Uint8Array)", function() { + var str2array = function (str) { + var array = new Uint8Array(str.length); + for(var i = 0; i < str.length; i++) { + array[i] = str.charCodeAt(i); + } + return array; + }; + var zip = new JSZip(); + zip.file("file.txt", str2array("\xE2\x82\xAC15\n")); + testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); + zip = new JSZip(); + zip.file("file.txt", str2array("test\r\ntest\r\n")); + testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); + zip = new JSZip(); + zip.file("file.txt", str2array("")); + testFileDataGetters({name : "empty content", zip : zip, textData : ""}); + }); +} + +if (JSZip.support.arraybuffer) { + test("add file: file(name, ArrayBuffer)", function() { + var str2buffer = function (str) { + var array = new Uint8Array(str.length); + for(var i = 0; i < str.length; i++) { + array[i] = str.charCodeAt(i); + } + return array.buffer; + }; + var zip = new JSZip(); + zip.file("file.txt", str2buffer("\xE2\x82\xAC15\n")); + testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); + zip = new JSZip(); + zip.file("file.txt", str2buffer("test\r\ntest\r\n")); + testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); + zip = new JSZip(); + zip.file("file.txt", str2buffer("")); + testFileDataGetters({name : "empty content", zip : zip, textData : ""}); + }); +} + +if (JSZip.support.nodebuffer) { + test("add file: file(name, Buffer)", function() { + var str2buffer = function (str) { + var array = new Buffer(str.length); + for(var i = 0; i < str.length; i++) { + array[i] = str.charCodeAt(i); + } + return array; + }; + var zip = new JSZip(); + zip.file("file.txt", str2buffer("\xE2\x82\xAC15\n")); + testFileDataGetters({name : "utf8", zip : zip, textData : "€15\n", rawData : "\xE2\x82\xAC15\n"}); + zip = new JSZip(); + zip.file("file.txt", str2buffer("test\r\ntest\r\n")); + testFileDataGetters({name : "\\r\\n", zip : zip, textData : "test\r\ntest\r\n"}); + zip = new JSZip(); + zip.file("file.txt", str2buffer("")); + testFileDataGetters({name : "empty content", zip : zip, textData : ""}); + }); +} + +testZipFile("generate : base64:false. Deprecated, but it still works", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var actual = zip.generate({base64:false}); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +testZipFile("generate : base64:true. Deprecated, but it still works", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var content = zip.generate({base64:true}); + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +testZipFile("generate : type:string", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var actual = zip.generate({type:"string"}); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +testZipFile("generate : type:base64", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var content = zip.generate({type:"base64"}); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +if (JSZip.support.uint8array) { + testZipFile("generate : type:uint8array", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var array = zip.generate({type:"uint8array"}); + ok(array instanceof Uint8Array, "The result is a instance of Uint8Array"); + equal(array.length, expected.length); + + var actual = JSZip.utils.transformTo("string", array); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + }); +} else { + testZipFile("generate : type:uint8array", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + try { + var blob = zip.generate({type:"uint8array"}); + ok(false, "Uint8Array is not supported, but no exception thrown"); + } catch(e) { + ok(e.message.match("not supported by this browser"), "the error message is useful"); + } + }); +} + +if (JSZip.support.arraybuffer) { + testZipFile("generate : type:arraybuffer", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var buffer = zip.generate({type:"arraybuffer"}); + ok(buffer instanceof ArrayBuffer, "The result is a instance of ArrayBuffer"); + + var actual = JSZip.utils.transformTo("string", buffer); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + }); +} else { + testZipFile("generate : type:arraybuffer", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + try { + var blob = zip.generate({type:"arraybuffer"}); + ok(false, "ArrayBuffer is not supported, but no exception thrown"); + } catch(e) { + ok(e.message.match("not supported by this browser"), "the error message is useful"); + } + }); +} + +if (JSZip.support.nodebuffer) { + testZipFile("generate : type:nodebuffer", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var buffer = zip.generate({type:"nodebuffer"}); + ok(buffer instanceof Buffer, "The result is a instance of ArrayBuffer"); + + var actual = ""; + for (var i = 0; i < buffer.length; i++) { + actual += String.fromCharCode(buffer[i]); + } + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + }); +} else { + testZipFile("generate : type:nodebuffer", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + try { + var blob = zip.generate({type:"nodebuffer"}); + ok(false, "Buffer is not supported, but no exception thrown"); + } catch(e) { + ok(e.message.match("not supported by this browser"), "the error message is useful"); + } + }); +} + +if (JSZip.support.blob) { + testZipFile("generate : type:blob", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var blob = zip.generate({type:"blob"}); + ok(blob instanceof Blob, "The result is a instance of Blob"); + equal(blob.type, "application/zip"); + equal(blob.size, expected.length); + }); +} else { + testZipFile("generate : type:blob", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + try { + var blob = zip.generate({type:"blob"}); + ok(false, "Blob is not supported, but no exception thrown"); + } catch(e) { + ok(e.message.match("not supported by this browser"), "the error message is useful"); + } + }); +} + +if (JSZip.support.blob) { + test("generate : type:blob mimeType:application/ods", function() { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var blob = zip.generate({type:"blob", mimeType: "application/ods"}); + ok(blob instanceof Blob, "The result is a instance of Blob"); + equal(blob.type, "application/ods", "mime-type is application/ods"); + }); +} else { + test("generate : type:blob mimeType:application/ods", function() { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + try { + var blob = zip.generate({type:"blob", mimeType: "application/ods"}); + ok(false, "Blob is not supported, but no exception thrown"); + } catch(e) { + ok(e.message.match("not supported by this browser"), "the error message is useful"); + } + }); +} + +test("Filtering a zip", function() { + var zip = new JSZip(); + zip.file("1.txt", "1\n"); + zip.file("2.txt", "2\n"); + zip.file("3.log", "3\n"); + var result = zip.filter(function (relativeFilename, file){ + return relativeFilename.indexOf(".txt") != -1; + }); + equal(result.length, 2, "filter has filtered"); + ok(result[0].name.indexOf(".txt") != -1, "filter has filtered the good file"); + ok(result[1].name.indexOf(".txt") != -1, "filter has filtered the good file"); +}); + +test("Filtering a zip from a relative path", function() { + var zip = new JSZip(); + zip.file("foo/1.txt", "1\n"); + zip.file("foo/2.txt", "2\n"); + zip.file("foo/3.log", "3\n"); + zip.file("1.txt", "1\n"); + zip.file("2.txt", "2\n"); + zip.file("3.log", "3\n"); + + var result = zip.folder("foo").filter(function (relativeFilename, file) { + return relativeFilename.indexOf("3") != -1; + }); + equal(result.length, 1, "filter has filtered"); + equal(result[0].name, "foo/3.log", "filter has filtered the good file"); +}); + +test("Filtering a zip : the full path is still accessible", function() { + var zip = new JSZip(); + zip.file("foo/1.txt", "1\n"); + zip.file("foo/2.txt", "2\n"); + zip.file("foo/3.log", "3\n"); + zip.file("1.txt", "1\n"); + zip.file("2.txt", "2\n"); + zip.file("3.log", "3\n"); + + var result = zip.folder("foo").filter(function (relativeFilename, file) { + return file.name.indexOf("3") != -1; + }); + equal(result.length, 1, "the filter only match files/folders in the current folder"); + equal(result[0].name, "foo/3.log", "filter has filtered the good file"); +}); + +testZipFile("Filtering a zip : the filter function can't alter the data", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + zip.filter(function (relativeFilename, file) { + file.name = "bye.txt"; + file.data = "good bye"; + file.dir = true; + }); + var content = zip.generate(); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); + +}); + +testZipFile("STORE is the default method", "ref/text.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n"); + var content = zip.generate({compression:'STORE'}); + + var actual = JSZip.base64.decode(content); + + // no difference with the "Zip text file" test. + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +// zip -0 -X store.zip Hello.txt +testZipFile("STORE doesn't compress", "ref/store.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "This a looong file : we need to see the difference between the different compression methods.\n"); + var content = zip.generate({compression:'STORE'}); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +// zip -6 -X deflate.zip Hello.txt +testZipFile("DEFLATE compress", "ref/deflate.zip", function(expected) { + var zip = new JSZip(); + zip.file("Hello.txt", "This a looong file : we need to see the difference between the different compression methods.\n"); + var content = zip.generate({compression:'DEFLATE'}); + + var actual = JSZip.base64.decode(content); + + ok(similar(actual, expected, 18) , "Generated ZIP matches reference ZIP"); +}); + +test("Lazy decompression works", function () { + var zip = new JSZip(); + zip.folder("test/").file("Hello.txt", "hello !"); + + var expected = zip.generate({type:"string", compression:"STORE"}); + + zip = new JSZip(expected); // lazy + equal(zip.generate({type:"string", compression:"STORE"}), expected, "Reloading file, same compression"); + + zip = new JSZip(zip.generate({type:"string", compression:"DEFLATE"})); + zip = new JSZip(zip.generate({type:"string", compression:"STORE"})); + + var zipData = zip.generate({type:"string", compression:"STORE"}); + equal(zipData, expected, "Reloading file, different compression"); + + // check CRC32 + new JSZip(zipData, {checkCRC32:true}).generate({type:"string"}); +}); + +test("Empty files / folders are not compressed", function() { + var zip = new JSZip(); + zip.file("Hello.txt", "This a looong file : we need to see the difference between the different compression methods.\n"); + zip.folder("folder").file("empty", ""); + + var deflateCount = 0, emptyDeflateCount = 0; + var oldDeflateCompress = JSZip.compressions.DEFLATE.compress; + JSZip.compressions.DEFLATE.compress = function (str) { + deflateCount++; + if (!str) { + emptyDeflateCount++; + } + return str; + }; + zip.generate({compression:'DEFLATE'}); + + equal(deflateCount, 1, "The file has been compressed"); + equal(emptyDeflateCount, 0, "The file without content and the folder has not been compressed."); + + JSZip.compressions.DEFLATE.compress = oldDeflateCompress; +}); + +test("DEFLATE level on generate()", function() { + var zip = new JSZip(); + zip.file("Hello.txt", "world"); + + var oldDeflateCompress = JSZip.compressions.DEFLATE.compress; + JSZip.compressions.DEFLATE.compress = function (str, options) { + equal(options.level, 5); + return str; + }; + zip.generate({compression:'DEFLATE', compressionOptions : {level:5}}); + + JSZip.compressions.DEFLATE.compress = oldDeflateCompress; +}); + +test("DEFLATE level on file() takes precedence", function() { + var zip = new JSZip(); + zip.file("Hello.txt", "world", {compressionOptions:{level:9}}); + + var oldDeflateCompress = JSZip.compressions.DEFLATE.compress; + JSZip.compressions.DEFLATE.compress = function (str, options) { + equal(options.level, 9); + return str; + }; + zip.generate({compression:'DEFLATE', compressionOptions : {level:5}}); + + JSZip.compressions.DEFLATE.compress = oldDeflateCompress; +}); + +test("unknown compression throws an exception", function () { + var zip = new JSZip().file("file.txt", "test"); + try { + zip.generate({compression:'MAYBE'}); + ok(false, "no exception"); + } catch (e) { + ok(true, "an exception were thrown"); + } +}); +// }}} More advanced + +QUnit.module("Load file, not supported features"); // {{{ + +// zip -0 -X -e encrypted.zip Hello.txt +testZipFile("basic encryption", "ref/encrypted.zip", function(file) { + try { + var zip = new JSZip(file); + ok(false, "Encryption is not supported, but no exception were thrown"); + } catch(e) { + equal(e.message, "Encrypted zip are not supported", "the error message is useful"); + } +}); +// }}} Load file, not supported features + +QUnit.module("Load file, corrupted zip"); // {{{ + +testZipFile("bad compression method", "ref/invalid/compression.zip", function(file) { + try { + var zip = new JSZip(file); + ok(false, "no exception were thrown"); + } catch(e) { + ok(e.message.match("Corrupted zip"), "the error message is useful"); + } +}); + +testZipFile("invalid crc32 but no check", "ref/invalid/crc32.zip", function(file) { + try { + var zip = new JSZip(file, {checkCRC32:false}); + ok(true, "no exception were thrown"); + } catch(e) { + ok(false, "An exception were thrown but the check should have been disabled."); + } +}); + +testZipFile("invalid crc32", "ref/invalid/crc32.zip", function(file) { + try { + var zip = new JSZip(file, {checkCRC32:true}); + ok(false, "no exception were thrown"); + } catch(e) { + ok(e.message.match("Corrupted zip"), "the error message is useful"); + } +}); + +testZipFile("bad offset", "ref/invalid/bad_offset.zip", function(file) { + try { + var zip = new JSZip(file); + ok(false, "no exception were thrown"); + } catch(e) { + ok(e.message.match("Corrupted zip"), "the error message is useful"); + } +}); + +test("truncated zip file", function() { + try { + var zip = new JSZip("PK\x03\x04\x0A\x00\x00\x00"); + ok(false, "no exception were thrown"); + } catch(e) { + ok(e.message.match("Corrupted zip"), "the error message is useful"); + } +}); + +test("not a zip file", function() { + try { + var zip = new JSZip("I'm not a zip file"); + ok(false, "no exception were thrown"); + } catch(e) { + ok(e.message.match("stuk.github.io/jszip/documentation"), "the error message is useful"); + } +}); +// }}} Load file, corrupted zip + +QUnit.module("Load file"); // {{{ + +testZipFile("load(string) works", "ref/all.zip", function(file) { + ok(typeof file === "string"); + var zip = new JSZip(file); + equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); +}); + +testZipFile("load(string) handles bytes > 255", "ref/all.zip", function(file) { + // the method used to load zip with ajax will remove the extra bits. + // adding extra bits :) + var updatedFile = ""; + for (var i = 0; i < file.length; i++) { + updatedFile += String.fromCharCode((file.charCodeAt(i) & 0xff) + 0x4200); + } + var zip = new JSZip(updatedFile); + + equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); +}); + +if (JSZip.support.arraybuffer) { + testZipFile("load(ArrayBuffer) works", "ref/all.zip", function(fileAsString) { + var file = new ArrayBuffer(fileAsString.length); + var bufferView = new Uint8Array(file); + for( var i = 0; i < fileAsString.length; ++i ) { + bufferView[i] = fileAsString.charCodeAt(i); + } + + ok(file instanceof ArrayBuffer); + + // 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). + equal(new JSZip(file).file("Hello.txt").asArrayBuffer().byteLength, 12, "don't get the original buffer"); + equal(new JSZip(file).file("Hello.txt").asUint8Array().buffer.byteLength, 12, "don't get a view of the original buffer"); + + equal(new JSZip(file).file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); + }); +} + +if (JSZip.support.nodebuffer) { + testZipFile("load(Buffer) works", "ref/all.zip", function(fileAsString) { + var file = new Buffer(fileAsString.length); + for( var i = 0; i < fileAsString.length; ++i ) { + file[i] = fileAsString.charCodeAt(i); + } + + equal(new JSZip(file).file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); + }); +} + +if (JSZip.support.uint8array) { + testZipFile("load(Uint8Array) works", "ref/all.zip", function(fileAsString) { + var file = new Uint8Array(fileAsString.length); + for( var i = 0; i < fileAsString.length; ++i ) { + file[i] = fileAsString.charCodeAt(i); + } + + ok(file instanceof Uint8Array); + + // 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). + equal(new JSZip(file).file("Hello.txt").asArrayBuffer().byteLength, 12, "don't get the original buffer"); + equal(new JSZip(file).file("Hello.txt").asUint8Array().buffer.byteLength, 12, "don't get a view of the original buffer"); + + equal(new JSZip(file).file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); + }); +} + +// zip -6 -X deflate.zip Hello.txt +testZipFile("zip with DEFLATE", "ref/deflate.zip", function(file) { + var zip = new JSZip(file); + equal(zip.file("Hello.txt").asText(), "This a looong file : we need to see the difference between the different compression methods.\n", "the zip was correctly read."); +}); + +// zip -0 -X -z -c archive_comment.zip Hello.txt +testZipFile("read zip with comment", "ref/archive_comment.zip", function(file) { + var zip = new JSZip(file); + equal(zip.comment, "file comment", "the archive comment was correctly read."); + equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); + equal(zip.file("Hello.txt").comment, "entry comment", "the entry comment was correctly read."); +}); +testZipFile("generate zip with comment", "ref/archive_comment.zip", function(file) { + var zip = new JSZip(); + zip.file("Hello.txt", "Hello World\n", {comment:"entry comment"}); + var generated = zip.generate({type:"string", comment:"file comment"}); + ok(similar(generated, file, 18) , "Generated ZIP matches reference ZIP"); + equal(reload(generated), generated, "Generated ZIP can be parsed"); +}); + +// zip -0 extra_attributes.zip Hello.txt +testZipFile("zip with extra attributes", "ref/extra_attributes.zip", function(file) { + var zip = new JSZip(file); + equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); +}); + +// use -fz to force use of Zip64 format +// zip -fz -0 zip64.zip Hello.txt +testZipFile("zip 64", "ref/zip64.zip", function(file) { + var zip = new JSZip(file); + equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); +}); + +// use -fd to force data descriptors as if streaming +// zip -fd -0 data_descriptor.zip Hello.txt +testZipFile("zip with data descriptor", "ref/data_descriptor.zip", function(file) { + var zip = new JSZip(file); + equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); +}); + +// combo of zip64 and data descriptors : +// zip -fz -fd -0 data_descriptor_zip64.zip Hello.txt +// this generate a corrupted zip file :( +// TODO : find how to get the two features + +// zip -0 -X zip_within_zip.zip Hello.txt && zip -0 -X nested.zip Hello.txt zip_within_zip.zip +testZipFile("nested zip", "ref/nested.zip", function(file) { + var zip = new JSZip(file); + equal(zip.file("Hello.txt").asText(), "Hello World\n", "the zip was correctly read."); + var nested = new JSZip(zip.file("zip_within_zip.zip").asBinary()); + equal(nested.file("Hello.txt").asText(), "Hello World\n", "the inner zip was correctly read."); +}); + +// zip -fd -0 nested_data_descriptor.zip data_descriptor.zip +testZipFile("nested zip with data descriptors", "ref/nested_data_descriptor.zip", function(file) { + var zip = new JSZip(file); + var nested = new JSZip(zip.file("data_descriptor.zip").asBinary()); + equal(nested.file("Hello.txt").asText(), "Hello World\n", "the inner zip was correctly read."); +}); + +// zip -fz -0 nested_zip64.zip zip64.zip +testZipFile("nested zip 64", "ref/nested_zip64.zip", function(file) { + var zip = new JSZip(file); + var nested = new JSZip(zip.file("zip64.zip").asBinary()); + equal(nested.file("Hello.txt").asText(), "Hello World\n", "the inner zip was correctly read."); +}); + +// nested zip 64 with data descriptors +// zip -fz -fd -0 nested_data_descriptor_zip64.zip data_descriptor_zip64.zip +// this generate a corrupted zip file :( +// TODO : find how to get the two features + +// zip -X -0 utf8_in_name.zip €15.txt +testZipFile("Zip text file with UTF-8 characters in filename", "ref/utf8_in_name.zip", function(file) { + var zip = new JSZip(file); + ok(zip.file("€15.txt") !== null, "the utf8 file is here."); + equal(zip.file("€15.txt").asText(), "€15\n", "the utf8 content was correctly read (with file().asText)."); + equal(zip.files["€15.txt"].asText(), "€15\n", "the utf8 content was correctly read (with files[].astext)."); +}); + +// Created with winrar +// winrar will replace the euro symbol with a '_' but set the correct unicode path in an extra field. +testZipFile("Zip text file with UTF-8 characters in filename and windows compatibility", "ref/winrar_utf8_in_name.zip", function(file) { + var zip = new JSZip(file); + ok(zip.file("€15.txt") !== null, "the utf8 file is here."); + equal(zip.file("€15.txt").asText(), "€15\n", "the utf8 content was correctly read (with file().asText)."); + equal(zip.files["€15.txt"].asText(), "€15\n", "the utf8 content was correctly read (with files[].astext)."); +}); + +// zip backslash.zip -0 -X Hel\\lo.txt +testZipFile("Zip text file with backslash in filename", "ref/backslash.zip", function(file) { + var zip = new JSZip(file); + equal(zip.file("Hel\\lo.txt").asText(), "Hello World\n", "the utf8 content was correctly read."); +}); + +// use izarc to generate a zip file on windows +testZipFile("Zip text file from windows with \\ in central dir", "ref/slashes_and_izarc.zip", function(file) { + var zip = new JSZip(file); + equal(zip.folder("test").file("Hello.txt").asText(), "Hello world\r\n", "the content was correctly read."); +}); + +test("A folder stays a folder", function () { + var zip = new JSZip(); + zip.folder("folder/"); + ok(zip.files['folder/'].dir, "the folder is marked as a folder"); + ok(zip.files['folder/'].options.dir, "the folder is marked as a folder, deprecated API"); + var reloaded = new JSZip(zip.generate({base64:false})); + ok(reloaded.files['folder/'].dir, "the folder is marked as a folder"); + ok(reloaded.files['folder/'].options.dir, "the folder is marked as a folder, deprecated API"); +}); + +test("file() creates a folder with dir:true", function () { + var zip = new JSZip(); + zip.file("folder", null, { + dir : true + }); + ok(zip.files['folder/'].dir, "the folder with options is marked as a folder"); +}); + +test("file() creates a folder with the right unix permissions", function () { + var zip = new JSZip(); + zip.file("folder", null, { + unixPermissions : parseInt("40500", 8) + }); + ok(zip.files['folder/'].dir, "the folder with options is marked as a folder"); +}); + +test("file() creates a folder with the right dos permissions", function () { + var zip = new JSZip(); + zip.file("folder", null, { + dosPermissions : parseInt("010000", 2) + }); + ok(zip.files['folder/'].dir, "the folder with options is marked as a folder"); +}); + +test("A folder stays a folder when created with file", function () { + var referenceDate = new Date("July 17, 2009 14:36:56"); + var referenceComment = "my comment"; + var zip = new JSZip(); + zip.file("folder", null, { + dir : true, + date : referenceDate, + comment : referenceComment, + unixPermissions : parseInt("40500", 8) + }); + + ok(zip.files['folder/'].dir, "the folder with options is marked as a folder"); + ok(zip.files['folder/'].options.dir, "the folder with options is marked as a folder, deprecated API"); + equal(zip.files['folder/'].date.getMilliseconds(), referenceDate.getMilliseconds(), "the folder with options has the correct date"); + equal(zip.files['folder/'].comment, referenceComment, "the folder with options has the correct comment"); + equal(zip.files['folder/'].unixPermissions.toString(8), "40500", "the folder with options has the correct UNIX permissions"); + + var reloaded = new JSZip(zip.generate({type:"string", platform:"UNIX"})); + + ok(reloaded.files['folder/'].dir, "the folder with options is marked as a folder"); + ok(reloaded.files['folder/'].options.dir, "the folder with options is marked as a folder, deprecated API"); + + ok(reloaded.files['folder/'].dir, "the folder with options is marked as a folder"); + ok(reloaded.files['folder/'].options.dir, "the folder with options is marked as a folder, deprecated API"); + equal(reloaded.files['folder/'].date.getMilliseconds(), referenceDate.getMilliseconds(), "the folder with options has the correct date"); + equal(reloaded.files['folder/'].comment, referenceComment, "the folder with options has the correct comment"); + equal(reloaded.files['folder/'].unixPermissions.toString(8), "40500", "the folder with options has the correct UNIX permissions"); + +}); + +test("file() adds a slash for directories", function () { + var zip = new JSZip(); + zip.file("folder_without_slash", null, { + dir : true + }); + zip.file("folder_with_slash/", null, { + dir : true + }); + ok(zip.files['folder_without_slash/'], "added a slash if not provided"); + ok(zip.files['folder_with_slash/'], "keep the existing slash"); +}); + +test("folder() doesn't overwrite existing entries", function () { + var referenceComment = "my comment"; + var zip = new JSZip(); + zip.file("folder", null, { + dir : true, + comment : referenceComment, + unixPermissions : parseInt("40500", 8) + }); + + // calling folder() doesn't override it + zip.folder("folder"); + + equal(zip.files['folder/'].comment, referenceComment, "the folder with options has the correct comment"); + equal(zip.files['folder/'].unixPermissions.toString(8), "40500", "the folder with options has the correct UNIX permissions"); +}); + +test("createFolders works on a file", function () { + var zip = new JSZip(); + zip.file("false/0/1/2/file", "content", {createFolders:false, unixPermissions:"644"}); + zip.file("true/0/1/2/file", "content", {createFolders:true, unixPermissions:"644"}); + + ok(!zip.files["false/"], "the false/ folder doesn't exist"); + ok(zip.files["true/"], "the true/ folder exists"); + equal(zip.files["true/"].unixPermissions, null, "the options are not propagated"); +}); + +test("createFolders works on a folder", function () { + var zip = new JSZip(); + zip.file("false/0/1/2/folder", null, {createFolders:false, unixPermissions:"777",dir:true}); + zip.file("true/0/1/2/folder", null, {createFolders:true, unixPermissions:"777",dir:true}); + + ok(!zip.files["false/"], "the false/ folder doesn't exist"); + ok(zip.files["true/"], "the true/ folder exists"); + equal(zip.files["true/"].unixPermissions, null, "the options are not propagated"); +}); + + +// touch file_{666,640,400,755} +// mkdir dir_{777,755,500} +// for mode in 777 755 500 666 640 400; do +// chmod $mode *_$mode +// done +// then : +// zip -r linux_zip.zip . +// 7z a -r linux_7z.zip . +// ... +function assertUnixPermissions(file){ + function doAsserts(fileName, dir, octal) { + var mode = parseInt(octal, 8); + equal(zip.files[fileName].dosPermissions, null, fileName + ", no DOS permissions"); + equal(zip.files[fileName].dir, dir, fileName + " dir flag"); + equal(zip.files[fileName].unixPermissions, mode, fileName + " mode " + octal); + } + + var zip = new JSZip(file); + doAsserts("dir_777/", true, "40777"); + doAsserts("dir_755/", true, "40755"); + doAsserts("dir_500/", true, "40500"); + doAsserts("file_666", false, "100666"); + doAsserts("file_640", false, "100640"); + doAsserts("file_400", false, "100400"); + doAsserts("file_755", false, "100755"); +} + +function assertDosPermissions(file){ + function doAsserts(fileName, dir, binary) { + var mode = parseInt(binary, 2); + equal(zip.files[fileName].unixPermissions, null, fileName + ", no UNIX permissions"); + equal(zip.files[fileName].dir, dir, fileName + " dir flag"); + equal(zip.files[fileName].dosPermissions, mode, fileName + " mode " + mode); + } + + var zip = new JSZip(file); + if (zip.files["dir/"]) { + doAsserts("dir/", true, "010000"); + } + if (zip.files["dir_hidden/"]) { + doAsserts("dir_hidden/", true, "010010"); + } + doAsserts("file", false, "100000"); + doAsserts("file_ro", false, "100001"); + doAsserts("file_hidden", false, "100010"); + doAsserts("file_ro_hidden", false, "100011"); +} +function reloadAndAssertUnixPermissions(file){ + var zip = new JSZip(file); + assertUnixPermissions(zip.generate({type:"string", platform:"UNIX"})); +} +function reloadAndAssertDosPermissions(file){ + var zip = new JSZip(file); + assertDosPermissions(zip.generate({type:"string", platform:"DOS"})); +} +testZipFile("permissions on linux : file created by zip", "ref/permissions/linux_zip.zip", assertUnixPermissions); +testZipFile("permissions on linux : file created by zip, reloaded", "ref/permissions/linux_zip.zip", reloadAndAssertUnixPermissions); +testZipFile("permissions on linux : file created by 7z", "ref/permissions/linux_7z.zip", assertUnixPermissions); +testZipFile("permissions on linux : file created by 7z, reloaded", "ref/permissions/linux_7z.zip", reloadAndAssertUnixPermissions); +testZipFile("permissions on linux : file created by file-roller on ubuntu", "ref/permissions/linux_file_roller-ubuntu.zip", assertUnixPermissions); +testZipFile("permissions on linux : file created by file-roller on ubuntu, reloaded", "ref/permissions/linux_file_roller-ubuntu.zip", reloadAndAssertUnixPermissions); +testZipFile("permissions on linux : file created by file-roller on xubuntu", "ref/permissions/linux_file_roller-xubuntu.zip", assertUnixPermissions); +testZipFile("permissions on linux : file created by file-roller on xubuntu, reloaded", "ref/permissions/linux_file_roller-xubuntu.zip", reloadAndAssertUnixPermissions); +testZipFile("permissions on linux : file created by ark", "ref/permissions/linux_ark.zip", assertUnixPermissions); +testZipFile("permissions on linux : file created by ark, reloaded", "ref/permissions/linux_ark.zip", reloadAndAssertUnixPermissions); +testZipFile("permissions on mac : file created by finder", "ref/permissions/mac_finder.zip", assertUnixPermissions); +testZipFile("permissions on mac : file created by finder, reloaded", "ref/permissions/mac_finder.zip", reloadAndAssertUnixPermissions); + + +testZipFile("permissions on windows : file created by the compressed folders feature", "ref/permissions/windows_compressed_folders.zip", assertDosPermissions); +testZipFile("permissions on windows : file created by the compressed folders feature, reloaded", "ref/permissions/windows_compressed_folders.zip", reloadAndAssertDosPermissions); +testZipFile("permissions on windows : file created by 7z", "ref/permissions/windows_7z.zip", assertDosPermissions); +testZipFile("permissions on windows : file created by 7z, reloaded", "ref/permissions/windows_7z.zip", reloadAndAssertDosPermissions); +testZipFile("permissions on windows : file created by izarc", "ref/permissions/windows_izarc.zip", assertDosPermissions); +testZipFile("permissions on windows : file created by izarc, reloaded", "ref/permissions/windows_izarc.zip", reloadAndAssertDosPermissions); +testZipFile("permissions on windows : file created by winrar", "ref/permissions/windows_winrar.zip", assertDosPermissions); +testZipFile("permissions on windows : file created by winrar, reloaded", "ref/permissions/windows_winrar.zip", reloadAndAssertDosPermissions); + +// }}} Load file + +QUnit.module("Load complex files"); // {{{ + +if (QUnit.urlParams.complexfiles) { + + // http://www.feedbooks.com/book/8/the-metamorphosis + testZipFile("Franz Kafka - The Metamorphosis.epub", "ref/complex_files/Franz Kafka - The Metamorphosis.epub", function(file) { + var zip = new JSZip(file); + equal(zip.filter(function(){return true;}).length, 26, "the zip contains the good number of elements."); + equal(zip.file("mimetype").asText(), "application/epub+zip\r\n", "the zip was correctly read."); + // the .ncx file tells us that the first chapter is in the main0.xml file. + ok(zip.file("OPS/main0.xml").asText().indexOf("One morning, as Gregor Samsa was waking up from anxious dreams") !== -1, "the zip was correctly read."); + }); + + // a showcase in http://msdn.microsoft.com/en-us/windows/hardware/gg463429 + testZipFile("Outlook2007_Calendar.xps", "ref/complex_files/Outlook2007_Calendar.xps", function(file) { + var zip = new JSZip(file); + // the zip file contains 15 entries. + equal(zip.filter(function(){return true;}).length, 15, "the zip contains the good number of elements."); + ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.ms-package.xps-fixeddocument+xml") !== -1, "the zip was correctly read."); + }); + + // Same test as above, but with createFolders option set to true + testZipFile("Outlook2007_Calendar.xps", "ref/complex_files/Outlook2007_Calendar.xps", function(file) { + var zip = new JSZip(file, {createFolders: true}); + // the zip file contains 15 entries, but we get 23 when creating all the sub-folders. + equal(zip.filter(function(){return true;}).length, 23, "the zip contains the good number of elements."); + ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.ms-package.xps-fixeddocument+xml") !== -1, "the zip was correctly read."); + }); + + // an example file in http://cheeso.members.winisp.net/srcview.aspx?dir=js-unzip + // the data come from http://www.antarctica.ac.uk/met/READER/upper_air/ + testZipFile("AntarcticaTemps.xlsx", "ref/complex_files/AntarcticaTemps.xlsx", function(file) { + var zip = new JSZip(file); + // the zip file contains 17 entries. + equal(zip.filter(function(){return true;}).length, 17, "the zip contains the good number of elements."); + ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml") !== -1, "the zip was correctly read."); + }); + + // Same test as above, but with createFolders option set to true + testZipFile("AntarcticaTemps.xlsx", "ref/complex_files/AntarcticaTemps.xlsx", function(file) { + var zip = new JSZip(file, {createFolders: true}); + // the zip file contains 16 entries, but we get 27 when creating all the sub-folders. + equal(zip.filter(function(){return true;}).length, 27, "the zip contains the good number of elements."); + ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml") !== -1, "the zip was correctly read."); + }); + + // same as two up, but in the Open Document format + testZipFile("AntarcticaTemps.ods", "ref/complex_files/AntarcticaTemps.ods", function (file) { + var zip = new JSZip(file); + // the zip file contains 20 entries. + equal(zip.filter(function () {return true;}).length, 20, "the zip contains the good number of elements."); + ok(zip.file("META-INF/manifest.xml").asText().indexOf("application/vnd.oasis.opendocument.spreadsheet") !== -1, "the zip was correctly read."); + }); + + // same as above, but in the Open Document format + testZipFile("AntarcticaTemps.ods", "ref/complex_files/AntarcticaTemps.ods", function (file) { + var zip = new JSZip(file, {createFolders: true}); + // the zip file contains 19 entries, but we get 27 when creating all the sub-folders. + equal(zip.filter(function () {return true;}).length, 27, "the zip contains the good number of elements."); + ok(zip.file("META-INF/manifest.xml").asText().indexOf("application/vnd.oasis.opendocument.spreadsheet") !== -1, "the zip was correctly read."); + }); +} +// }}} Load complex files + + +// enforcing Stuk's coding style +// vim: set shiftwidth=3 softtabstop=3: diff --git a/public/js/lib/jszip/vendor/FileSaver.js b/public/js/lib/jszip/vendor/FileSaver.js new file mode 100644 index 0000000..112efb0 --- /dev/null +++ b/public/js/lib/jszip/vendor/FileSaver.js @@ -0,0 +1,247 @@ +/*! FileSaver.js + * A saveAs() FileSaver implementation. + * 2014-01-24 + * + * By Eli Grey, http://eligrey.com + * License: X11/MIT + * See LICENSE.md + */ + +/*global self */ +/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ + +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ + +var saveAs = saveAs + // IE 10+ (native saveAs) + || (typeof navigator !== "undefined" && + navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) + // Everyone else + || (function(view) { + "use strict"; + // IE <10 is explicitly unsupported + if (typeof navigator !== "undefined" && + /MSIE [1-9]\./.test(navigator.userAgent)) { + return; + } + var + doc = view.document + // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet + , get_URL = function() { + return view.URL || view.webkitURL || view; + } + , URL = view.URL || view.webkitURL || view + , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") + , can_use_save_link = !view.externalHost && "download" in save_link + , click = function(node) { + var event = doc.createEvent("MouseEvents"); + event.initMouseEvent( + "click", true, false, view, 0, 0, 0, 0, 0 + , false, false, false, false, 0, null + ); + node.dispatchEvent(event); + } + , webkit_req_fs = view.webkitRequestFileSystem + , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem + , throw_outside = function(ex) { + (view.setImmediate || view.setTimeout)(function() { + throw ex; + }, 0); + } + , force_saveable_type = "application/octet-stream" + , fs_min_size = 0 + , deletion_queue = [] + , process_deletion_queue = function() { + var i = deletion_queue.length; + while (i--) { + var file = deletion_queue[i]; + if (typeof file === "string") { // file is an object URL + URL.revokeObjectURL(file); + } else { // file is a File + file.remove(); + } + } + deletion_queue.length = 0; // clear queue + } + , dispatch = function(filesaver, event_types, event) { + event_types = [].concat(event_types); + var i = event_types.length; + while (i--) { + var listener = filesaver["on" + event_types[i]]; + if (typeof listener === "function") { + try { + listener.call(filesaver, event || filesaver); + } catch (ex) { + throw_outside(ex); + } + } + } + } + , FileSaver = function(blob, name) { + // First try a.download, then web filesystem, then object URLs + var + filesaver = this + , type = blob.type + , blob_changed = false + , object_url + , target_view + , get_object_url = function() { + var object_url = get_URL().createObjectURL(blob); + deletion_queue.push(object_url); + return object_url; + } + , dispatch_all = function() { + dispatch(filesaver, "writestart progress write writeend".split(" ")); + } + // on any filesys errors revert to saving with object URLs + , fs_error = function() { + // don't create more object URLs than needed + if (blob_changed || !object_url) { + object_url = get_object_url(blob); + } + if (target_view) { + target_view.location.href = object_url; + } else { + window.open(object_url, "_blank"); + } + filesaver.readyState = filesaver.DONE; + dispatch_all(); + } + , abortable = function(func) { + return function() { + if (filesaver.readyState !== filesaver.DONE) { + return func.apply(this, arguments); + } + }; + } + , create_if_not_found = {create: true, exclusive: false} + , slice + ; + filesaver.readyState = filesaver.INIT; + if (!name) { + name = "download"; + } + if (can_use_save_link) { + object_url = get_object_url(blob); + // FF for Android has a nasty garbage collection mechanism + // that turns all objects that are not pure javascript into 'deadObject' + // this means `doc` and `save_link` are unusable and need to be recreated + // `view` is usable though: + doc = view.document; + save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); + save_link.href = object_url; + save_link.download = name; + var event = doc.createEvent("MouseEvents"); + event.initMouseEvent( + "click", true, false, view, 0, 0, 0, 0, 0 + , false, false, false, false, 0, null + ); + save_link.dispatchEvent(event); + filesaver.readyState = filesaver.DONE; + dispatch_all(); + return; + } + // Object and web filesystem URLs have a problem saving in Google Chrome when + // viewed in a tab, so I force save with application/octet-stream + // http://code.google.com/p/chromium/issues/detail?id=91158 + if (view.chrome && type && type !== force_saveable_type) { + slice = blob.slice || blob.webkitSlice; + blob = slice.call(blob, 0, blob.size, force_saveable_type); + blob_changed = true; + } + // Since I can't be sure that the guessed media type will trigger a download + // in WebKit, I append .download to the filename. + // https://bugs.webkit.org/show_bug.cgi?id=65440 + if (webkit_req_fs && name !== "download") { + name += ".download"; + } + if (type === force_saveable_type || webkit_req_fs) { + target_view = view; + } + if (!req_fs) { + fs_error(); + return; + } + fs_min_size += blob.size; + req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { + fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { + var save = function() { + dir.getFile(name, create_if_not_found, abortable(function(file) { + file.createWriter(abortable(function(writer) { + writer.onwriteend = function(event) { + target_view.location.href = file.toURL(); + deletion_queue.push(file); + filesaver.readyState = filesaver.DONE; + dispatch(filesaver, "writeend", event); + }; + writer.onerror = function() { + var error = writer.error; + if (error.code !== error.ABORT_ERR) { + fs_error(); + } + }; + "writestart progress write abort".split(" ").forEach(function(event) { + writer["on" + event] = filesaver["on" + event]; + }); + writer.write(blob); + filesaver.abort = function() { + writer.abort(); + filesaver.readyState = filesaver.DONE; + }; + filesaver.readyState = filesaver.WRITING; + }), fs_error); + }), fs_error); + }; + dir.getFile(name, {create: false}, abortable(function(file) { + // delete file if it already exists + file.remove(); + save(); + }), abortable(function(ex) { + if (ex.code === ex.NOT_FOUND_ERR) { + save(); + } else { + fs_error(); + } + })); + }), fs_error); + }), fs_error); + } + , FS_proto = FileSaver.prototype + , saveAs = function(blob, name) { + return new FileSaver(blob, name); + } + ; + FS_proto.abort = function() { + var filesaver = this; + filesaver.readyState = filesaver.DONE; + dispatch(filesaver, "abort"); + }; + FS_proto.readyState = FS_proto.INIT = 0; + FS_proto.WRITING = 1; + FS_proto.DONE = 2; + + FS_proto.error = + FS_proto.onwritestart = + FS_proto.onprogress = + FS_proto.onwrite = + FS_proto.onabort = + FS_proto.onerror = + FS_proto.onwriteend = + null; + + view.addEventListener("unload", process_deletion_queue, false); + saveAs.unload = function() { + process_deletion_queue(); + view.removeEventListener("unload", process_deletion_queue, false); + }; + return saveAs; +}( + typeof self !== "undefined" && self + || typeof window !== "undefined" && window + || this.content +)); +// `self` is undefined in Firefox for Android content script context +// while `this` is nsIContentFrameMessageManager +// with an attribute `content` that corresponds to the window + +if (typeof module !== "undefined") module.exports = saveAs;