├── .babelrc ├── .codeclimate.yml ├── .editorconfig ├── .gitignore ├── .jshintignore ├── .jshintrc ├── .npmignore ├── .prettierrc.yaml ├── .travis.yml ├── CHANGES.md ├── LICENSE.markdown ├── README.markdown ├── _config.yml ├── docs ├── APPNOTE.TXT ├── ZIP spec.txt └── references.txt ├── documentation ├── _layouts │ └── default.html ├── api_pizzip.md ├── api_pizzip │ ├── constructor.md │ ├── constructor_load.md │ ├── file_data.md │ ├── file_name.md │ ├── file_regex.md │ ├── filter.md │ ├── folder_data.md │ ├── folder_regex.md │ ├── generate.md │ ├── load.md │ ├── remove.md │ └── support.md ├── api_zipobject.md ├── contributing.md ├── css │ ├── main.css │ └── pygments.css ├── examples.md ├── examples │ ├── download-zip-file.html │ ├── downloader.html │ ├── downloader.js │ ├── get-binary-files-ajax.html │ └── read-local-file-api.html ├── faq.md ├── howto │ ├── read_zip.md │ └── write_zip.md ├── limitations.md └── upgrade_guide.md ├── es6 ├── arrayReader.js ├── base64.js ├── compressedObject.js ├── compressions.js ├── crc32.js ├── dataReader.js ├── defaults.js ├── deprecatedPublicUtils.js ├── flate.js ├── index.d.ts ├── index.js ├── index.test-d.ts ├── license_header.js ├── load.js ├── nodeBuffer.js ├── nodeBufferReader.js ├── object.js ├── signature.js ├── stringReader.js ├── stringWriter.js ├── support.js ├── uint8ArrayReader.js ├── uint8ArrayWriter.js ├── utf8.js ├── utils.js ├── zipEntries.js └── zipEntry.js ├── eslint.config.mjs ├── index.html ├── package-lock.json ├── package.json ├── symlink.sh ├── test ├── browser-test-utils.js ├── index.html ├── jquery-1.8.3.min.js ├── node.js ├── qunit-1.11.0.css ├── qunit-1.11.0.js ├── ref │ ├── all.7zip.zip │ ├── all.windows.zip │ ├── all.zip │ ├── all_appended_bytes.zip │ ├── all_missing_bytes.zip │ ├── all_prepended_bytes.zip │ ├── archive_comment.zip │ ├── backslash.zip │ ├── complex_files │ │ ├── AntarcticaTemps.ods │ │ ├── AntarcticaTemps.xlsx │ │ ├── Franz Kafka - The Metamorphosis.epub │ │ └── Outlook2007_Calendar.xps │ ├── data_descriptor.zip │ ├── deflate.zip │ ├── encrypted.zip │ ├── extra_attributes.zip │ ├── folder.zip │ ├── image.zip │ ├── invalid │ │ ├── bad_offset.zip │ │ ├── compression.zip │ │ └── crc32.zip │ ├── local_encoding_in_name.zip │ ├── nested.zip │ ├── nested_data_descriptor.zip │ ├── nested_zip64.zip │ ├── permissions │ │ ├── linux_7z.zip │ │ ├── linux_ark.zip │ │ ├── linux_file_roller-ubuntu.zip │ │ ├── linux_file_roller-xubuntu.zip │ │ ├── linux_zip.zip │ │ ├── mac_finder.zip │ │ ├── windows_7z.zip │ │ ├── windows_compressed_folders.zip │ │ ├── windows_izarc.zip │ │ └── windows_winrar.zip │ ├── pile_of_poo.zip │ ├── slashes_and_izarc.zip │ ├── store.zip │ ├── subfolder.zip │ ├── text.zip │ ├── utf8.zip │ ├── utf8_in_name.zip │ ├── winrar_utf8_in_name.zip │ ├── zip64.zip │ ├── zip64_appended_bytes.zip │ ├── zip64_missing_bytes.zip │ └── zip64_prepended_bytes.zip ├── smile.gif └── test.js ├── utils ├── .jshintignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── CHANGES.md ├── Gruntfile.js ├── LICENSE.markdown ├── README.markdown ├── _config.yml ├── documentation │ ├── _layouts │ │ └── default.html │ ├── api.md │ ├── api │ │ └── getbinarycontent.md │ └── css │ │ ├── main.css │ │ └── pygments.css ├── es6 │ ├── index.js │ ├── index_IE.js │ └── license_header.js ├── index.d.ts ├── index.js ├── index.md ├── index.test-d.ts ├── test │ ├── index.html │ ├── ref │ │ ├── amount.txt │ │ └── smile.gif │ └── test.js └── webpack.config.js ├── vendor └── FileSaver.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - javascript 8 | eslint: 9 | enabled: true 10 | fixme: 11 | enabled: true 12 | ratings: 13 | paths: 14 | - "es6/*" 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.js] 8 | charset = utf-8 9 | indent_style = tab 10 | 11 | [{.travis.yml,package.json}] 12 | indent_style = space 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | node_modules 3 | sauce_connect.log 4 | .c9revisionsjs 5 | js/ 6 | dist 7 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "undef": true, 3 | "strict": true, 4 | "sub": true, 5 | 6 | "globals": { 7 | "TextEncoder": false, 8 | "TextDecoder": false 9 | }, 10 | "browser": true, 11 | "node": true 12 | } 13 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | _config.yml 2 | bower.json 3 | component.json 4 | docs 5 | documentation 6 | Gruntfile.js 7 | index.html 8 | test 9 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | trailingComma: es5 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.12' 5 | - '4' 6 | - '6' 7 | - '8' 8 | - '10' 9 | - '12' 10 | - '13' 11 | script: npm run $COMMAND 12 | sudo: false 13 | env: 14 | matrix: 15 | - COMMAND=test-node 16 | - COMMAND=test-browser 17 | global: 18 | - secure: MhA8GHU42X3GWTUMaqdZVvarx4BMjhQCUGNi3kvuD/iCmKVb7gMwj4jbds7AcJdsCRsRk8bBGzZs/E7HidBJMPDa5DhgLKy9EV1s42JlHq8lVzbJeWIGgrtyJvhVUkGRy2OJjnDSgh3U6elkQmvDn74jreSQc6m/yGoPFF1nqq8= 19 | - secure: qREw6aUu2DnB+2reMuHgygSkumRiJvt7Z5Fz4uEVoraqbe65e4PGhtzypr9uIgCN43vxS2D5tAIeDbfid5VQrWFUQnrC9O5Z5qgVPsKN94zZ1tvYurXI4wRlAg58nNjkfGXWhLI3VUjjDTp5gYcMqgfe5hpEFYUPnUQkKGnaqAk= 20 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Changelog 3 | layout: default 4 | section: main 5 | --- 6 | 7 | # v3.2.0 8 | 9 | Add support for `fileOrder` in the `.generate()` function. 10 | 11 | # v3.1.8 12 | 13 | The following message was shown in PizZipUtils.getBinaryContent: 14 | 15 | InvalidStateError: Failed to read the 'responseText' 16 | 17 | This meant that the server didn't respond or that there is a CORS issue. 18 | 19 | The message is now : "Ajax error, status 0 Server not responding or CORS headers missing." 20 | 21 | # v3.1.7 22 | 23 | Change ArrayBuffer check to work correctly with webworkers 24 | 25 | Fixes #36 26 | 27 | # v3.1.6 28 | 29 | Improve typescript support : 30 | 31 | Fixes following error message : 32 | 33 | ``` 34 | error TS1259: Module 'pizzip' can only be default-imported using the 'allowSyntheticDefaultImports' flag 35 | Error - 'tsc' sub task errored after 2.66 s 36 | ``` 37 | 38 | # v3.1.5 39 | 40 | Use pako.min.js instead of pako.js 41 | 42 | # v3.1.4 43 | 44 | Remove @babel from dependencies (moved to devDependencies) 45 | 46 | # v3.1.3 47 | 48 | Update typescript typings to work correctly. 49 | 50 | # v3.1.2 51 | 52 | Add typescript typings 53 | 54 | # v3.1.1 55 | 56 | - Add zip.clone() function to deep clone a zip instance 57 | 58 | - Remove usage of `new Buffer` in favor of `Buffer.from()` or `Buffer.alloc()` 59 | 60 | # v3.1.0 61 | 62 | Update pako to v2 63 | 64 | When using new Pizzip(promise), show specific error message 65 | 66 | # v3.0.5 67 | 68 | Compile to es5 69 | 70 | # v3.0.4 71 | 72 | Add missing built files in dist 73 | 74 | # v3.0.3 75 | 76 | Migrate to babel, eslint, prettier and mocha 77 | 78 | # v3.0.2 79 | 80 | Export window.PizZipUtils in utils generated bundle 81 | 82 | # v3.0.1 83 | 84 | Update export to be able to do require("pizzip/utils"); 85 | 86 | # v3.0.0 87 | 88 | Initial release of Pizzip 89 | 90 | # v2.6.1 2016-07-28 91 | 92 | - update pako to v1.0.2 to fix a DEFLATE bug (see [#322](https://github.com/Stuk/pizzip/pull/322)). 93 | 94 | # v2.6.0 2016-03-23 95 | 96 | - publish `dist/` files in the npm package (see [#225](https://github.com/Stuk/pizzip/pull/225)). 97 | - update pako to v1.0.0 (see [#261](https://github.com/Stuk/pizzip/pull/261)). 98 | - add support of Array in PizZip#load (see [#252](https://github.com/Stuk/pizzip/pull/252)). 99 | - improve file name / comment encoding support (see [#211](https://github.com/Stuk/pizzip/pull/211)). 100 | - handle prepended data (see [#266](https://github.com/Stuk/pizzip/pull/266)). 101 | - improve platform coverage in tests (see [#233](https://github.com/Stuk/pizzip/pull/233) and [#269](https://github.com/Stuk/pizzip/pull/269)). 102 | 103 | # v2.5.0 2015-03-10 104 | 105 | - add support for custom mime-types (see [#199](https://github.com/Stuk/pizzip/issues/199)). 106 | - add an option to set the DEFLATE level (see [#201](https://github.com/Stuk/pizzip/issues/201)). 107 | - improve the error message with corrupted zip (see [#202](https://github.com/Stuk/pizzip/issues/202)). 108 | - add support for UNIX / DOS permissions (see [#200](https://github.com/Stuk/pizzip/issues/200) and [#205](https://github.com/Stuk/pizzip/issues/205)). 109 | 110 | # v2.4.0 2014-07-24 111 | 112 | - update pako to 0.2.5 (see [#156](https://github.com/Stuk/pizzip/issues/156)). 113 | - make PizZip work in a Firefox addon context (see [#151](https://github.com/Stuk/pizzip/issues/151)). 114 | - add an option (`createFolders`) to control the subfolder generation (see [#154](https://github.com/Stuk/pizzip/issues/154)). 115 | - allow `Buffer` polyfill in the browser (see [#139](https://github.com/Stuk/pizzip/issues/139)). 116 | 117 | # v2.3.0 2014-06-18 118 | 119 | - don't generate subfolders (see [#130](https://github.com/Stuk/pizzip/issues/130)). 120 | - add comment support (see [#134](https://github.com/Stuk/pizzip/issues/134)). 121 | - on `ZipObject#options`, the attributes `date` and `dir` have been deprecated and are now on `ZipObject` (see [the upgrade guide](http://stuk.github.io/pizzip/documentation/upgrade_guide.html)). 122 | - on `ZipObject#options`, the attributes `base64` and `binary` have been deprecated (see [the upgrade guide](http://stuk.github.io/pizzip/documentation/upgrade_guide.html)). 123 | - deprecate internal functions exposed in the public API (see [#123](https://github.com/Stuk/pizzip/issues/123)). 124 | - improve UTF-8 support (see [#142](https://github.com/Stuk/pizzip/issues/142)). 125 | 126 | # v2.2.2, 2014-05-01 127 | 128 | - update pako to v0.2.1, fix an error when decompressing some files (see [#126](https://github.com/Stuk/pizzip/issues/126)). 129 | 130 | # v2.2.1, 2014-04-23 131 | 132 | - fix unreadable generated file on Windows 8 (see [#112](https://github.com/Stuk/pizzip/issues/112)). 133 | - replace zlibjs with pako. 134 | 135 | # v2.2.0, 2014-02-25 136 | 137 | - make the `new` operator optional before the `PizZip` constructor (see [#93](https://github.com/Stuk/pizzip/pull/93)). 138 | - update zlibjs to v0.2.0. 139 | 140 | # v2.1.1, 2014-02-13 141 | 142 | - use the npm package for zlib.js instead of the github url. 143 | 144 | # v2.1.0, 2014-02-06 145 | 146 | - split the files and use Browserify to generate the final file (see [#74](https://github.com/Stuk/pizzip/pull/74)) 147 | - packaging change : instead of 4 files (pizzip.js, pizzip-load.js, pizzip-inflate.js, pizzip-deflate.js) we now have 2 files : dist/pizzip.js and dist/pizzip.min.js 148 | - add component/bower support 149 | - rename variable: 'byte' is a reserved word (see [#76](https://github.com/Stuk/pizzip/pull/76)) 150 | - add support for the unicode path extra field (see [#82](https://github.com/Stuk/pizzip/pull/82)) 151 | - ensure that the generated files have a header with the licenses (see [#80](https://github.com/Stuk/pizzip/pull/80)) 152 | 153 | # v2.0.0, 2013-10-20 154 | 155 | - `PizZipBase64` has been renamed to `PizZip.base64`. 156 | - The `data` attribute on the object returned by `zip.file(name)` has been removed. Use `asText()`, `asBinary()`, `asUint8Array()`, `asArrayBuffer()` or `asNodeBuffer()`. 157 | 158 | - [Fix issue with Android browser](https://github.com/Stuk/pizzip/pull/60) 159 | 160 | - The compression/decompression methods now give their input type with the `compressInputType` and `uncompressInputType` attributes. 161 | - Lazily decompress data when needed and [improve performance in general](https://github.com/Stuk/pizzip/pull/56) 162 | - [Add support for `Buffer` in Node.js](https://github.com/Stuk/pizzip/pull/57). 163 | - Package for CommonJS/npm. 164 | 165 | # v1.0.1, 2013-03-04 166 | 167 | - Fixed an issue when generating a compressed zip file with empty files or folders, see #33. 168 | - With bad data (null or undefined), asText/asBinary/asUint8Array/asArrayBuffer methods now return an empty string, see #36. 169 | 170 | # v1.0.0, 2013-02-14 171 | 172 | - First release after a long period without version. 173 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # PizZip 2 | 3 | PizZip is a fork of JSZip version 2.x, because we want a synchronous Zip library. 4 | 5 | A library for creating, reading and editing .zip files with Javascript, with a lovely and simple API. 6 | 7 | ```javascript 8 | var zip = new PizZip(); 9 | 10 | zip.file("Hello.txt", "Hello World\n"); 11 | 12 | var img = zip.folder("images"); 13 | img.file("smile.gif", imgData, { base64: true }); 14 | 15 | var content = zip.generate({ type: "blob" }); 16 | 17 | // see FileSaver.js 18 | saveAs(content, "example.zip"); 19 | 20 | /* 21 | Results in a zip containing 22 | Hello.txt 23 | images/ 24 | smile.gif 25 | */ 26 | ``` 27 | 28 | ## License 29 | 30 | PizZip is dual-licensed. You may use it under the MIT license _or_ the GPLv3 license. See [LICENSE.markdown](LICENSE.markdown). 31 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # will be overwritten by github, see https://help.github.com/articles/using-jekyll-with-pages 2 | lsi: false 3 | safe: true 4 | source: ./ 5 | incremental: false 6 | highlighter: rouge 7 | gist: 8 | noscript: false 9 | # /overwritten 10 | 11 | baseurl: /pizzip 12 | 13 | layouts_dir: ./documentation/_layouts 14 | permalink: none 15 | exclude: ['bin', 'README.md', 'node_modules'] 16 | 17 | 18 | kramdown: 19 | input: GFM 20 | hard_wrap: false 21 | gems: 22 | - jekyll-coffeescript 23 | - jekyll-paginate 24 | 25 | -------------------------------------------------------------------------------- /docs/ZIP spec.txt: -------------------------------------------------------------------------------- 1 | Here are the notes I made while working through the ZIP file specification. 2 | 3 | For each file: 4 | 5 | local file header signature 4 bytes (0x04034b50) 6 | version needed to extract 2 bytes 7 | general purpose bit flag 2 bytes 8 | compression method 2 bytes 9 | last mod file time 2 bytes 10 | last mod file date 2 bytes 11 | crc-32 4 bytes 12 | compressed size 4 bytes 13 | uncompressed size 4 bytes 14 | file name length 2 bytes 15 | extra field length 2 bytes 16 | 17 | |sig |v |g |c |t |d |crc |csz |usz |n |x | 18 | PK.. ## 00 00 ?? ?? xxxx ???? ???? ?? 00 19 | 20 | 21 | Central directory: 22 | 23 | central file header signature 4 bytes (0x02014b50) 24 | version made by 2 bytes 25 | version needed to extract 2 bytes * 26 | general purpose bit flag 2 bytes * 27 | compression method 2 bytes * 28 | last mod file time 2 bytes * 29 | last mod file date 2 bytes * 30 | crc-32 4 bytes * 31 | compressed size 4 bytes * 32 | uncompressed size 4 bytes * 33 | file name length 2 bytes * 34 | extra field length 2 bytes * 35 | file comment length 2 bytes 36 | disk number start 2 bytes 37 | internal file attributes 2 bytes 38 | external file attributes 4 bytes 39 | relative offset of local header 4 bytes 40 | 41 | file name (variable size) 42 | extra field (variable size) 43 | file comment (variable size) 44 | 45 | |sig |vm|vx|g |c |d |t |crc |csz |usz |n |x |cm|dn|ia|xa |roff| 46 | PK.. ## ## 00 00 ?? ?? xxxx ???? ???? ?? 00 00 00 00 xxxx ???? 47 | 48 | End of central directory: 49 | 50 | end of central dir signature 4 bytes (0x06054b50) 51 | number of this disk 2 bytes 52 | number of the disk with the 53 | start of the central directory 2 bytes 54 | total number of entries in the 55 | central directory on this disk 2 bytes 56 | total number of entries in 57 | the central directory 2 bytes 58 | size of the central directory 4 bytes 59 | offset of start of central 60 | directory with respect to 61 | the starting disk number 4 bytes 62 | .ZIP file comment length 2 bytes 63 | .ZIP file comment (variable size) 64 | 65 | |sig |n1|n2|e |ne|size|off |cm| 66 | PK.. 00 00 ?? ?? ???? ???? 00 67 | -------------------------------------------------------------------------------- /docs/references.txt: -------------------------------------------------------------------------------- 1 | Zip format 2 | ---------- 3 | http://www.pkware.com/support/zip-application-note 4 | http://www.xxcopy.com/xxcopy06.htm 5 | 6 | Data URL 7 | -------- 8 | https://developer.mozilla.org/en/The_data_URL_scheme 9 | http://msdn.microsoft.com/en-us/library/cc848897(VS.85).aspx 10 | http://www.phpied.com/mhtml-when-you-need-data-uris-in-ie7-and-under/ 11 | 12 | http://www.motobit.com/util/base64-decoder-encoder.asp 13 | 14 | Saving files 15 | ------------ 16 | http://msdn.microsoft.com/en-us/library/ms536676(VS.85).aspx 17 | http://msdn.microsoft.com/en-us/library/ms536419(VS.85).aspx 18 | http://msdn.microsoft.com/en-us/library/ms537418(VS.85).aspx 19 | -------------------------------------------------------------------------------- /documentation/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{page.title}} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | 57 | {% if page.section and page.fullpage != true %} 58 |
59 | 115 | {% endif %} 116 |
117 |

{{page.title}}

118 | 119 | 120 | 121 | 122 | {{content}} 123 | 124 | 125 | 126 | 127 |
128 |
129 |
130 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /documentation/api_pizzip.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "PizZip API" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | An instance of PizZip represents a set of files. You can add them, remove them, 8 | modify them. You can also import an existing zip file or generate one. 9 | 10 | ### Attributes 11 | 12 | | attribute name | type | description | 13 | | -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 14 | | `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_pizzip/file_name.html). | 15 | | `comment` | string | the comment of the zip file. | 16 | -------------------------------------------------------------------------------- /documentation/api_pizzip/constructor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "new PizZip() or PizZip()" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Create a new PizZip instance. 8 | 9 | **Arguments** : None 10 | 11 | **Returns** : A new PizZip. 12 | 13 | **Throws** : Nothing. 14 | 15 | 16 | 17 | **Example** 18 | 19 | ```js 20 | var zip = new PizZip(); 21 | // same as 22 | var zip = PizZip(); 23 | ``` 24 | -------------------------------------------------------------------------------- /documentation/api_pizzip/constructor_load.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "new PizZip(data [,options]) or PizZip(data [,options])" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | This is a shortcut for 8 | 9 | ```js 10 | var zip = new PizZip(); 11 | zip.load(data, options); 12 | ``` 13 | 14 | Please see the documentation of [load]({{site.baseurl}}/documentation/api_pizzip/load.html). 15 | 16 | **Example** 17 | 18 | ```js 19 | var zip = new PizZip(data, options); 20 | // same as 21 | var zip = PizZip(data, options); 22 | ``` 23 | -------------------------------------------------------------------------------- /documentation/api_pizzip/file_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "file(name, data [,options])" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Add (or update) a file to the zip file. 8 | 9 | **Arguments** 10 | 11 | | name | type | description | 12 | | ------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------- | 13 | | name | string | the name of the file. You can specify folders in the name : the folder separator is a forward slash ("/"). | 14 | | data | String/ArrayBuffer/Uint8Array/Buffer | the content of the file. | 15 | | options | object | the options. | 16 | 17 | Content of `options` : 18 | 19 | | name | type | default | description | 20 | | --------------------- | -------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 21 | | 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. | 22 | | 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`. | 23 | | date | date | the current date | the last modification date. | 24 | | 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_pizzip/generate.html). | 25 | | compressionOptions | object | `null` | the options to use when compressing the file, see [generate(options)]({{site.baseurl}}/documentation/api_pizzip/generate.html). | 26 | | comment | string | null | The comment for this file. | 27 | | 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. | 28 | | 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. | 29 | | unixPermissions | 16 bits number | null | The UNIX permissions of the file, if any. | 30 | | dosPermissions | 6 bits number | null | The DOS permissions of the file, if any. | 31 | | dir | boolean | false | Set to true if this is a directory and content should be ignored. | 32 | 33 | You shouldn't update the data given to this method : it is kept as it so any 34 | update will impact the stored data. 35 | 36 | **For the permissions** : 37 | 38 | The field `unixPermissions` also accepts a string representing the octal value : 39 | "644", "755", etc. On nodejs you can use the `mode` attribute of 40 | [nodejs' fs.Stats](http://nodejs.org/api/fs.html#fs_class_fs_stats). 41 | 42 | See also [the platform option of generate()]({{site.baseurl}}/documentation/api_pizzip/generate.html). 43 | 44 | **About `dir`** : 45 | 46 | If `dir` is true or if a permission says it's a folder, this entry be flagged 47 | as a folder and the content will be ignored. 48 | 49 | **Returns** : The current PizZip object, for chaining. 50 | 51 | **Throws** : An exception if the data is not in a supported format. 52 | 53 | 59 | 60 | **Example** 61 | 62 | ```js 63 | zip.file("Hello.txt", "Hello World\n"); 64 | 65 | // base64 66 | zip.file( 67 | "smile.gif", 68 | "R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=", 69 | { base64: true } 70 | ); 71 | // from an ajax call with xhr.responseType = 'arraybuffer' 72 | zip.file("smile.gif", arraybufferFromXhr); 73 | // or on nodejs 74 | zip.file("smile.gif", fs.readFileSync("smile.gif")); 75 | 76 | zip.file("Xmas.txt", "Ho ho ho !", { 77 | date: new Date("December 25, 2007 00:00:01"), 78 | }); 79 | zip.file("folder/file.txt", "file in folder"); 80 | 81 | zip 82 | .file("animals.txt", "dog,platypus\n") 83 | .file("people.txt", "james,sebastian\n"); 84 | 85 | // result : Hello.txt, smile.gif, Xmas.txt, animals.txt, people.txt, 86 | // folder/, folder/file.txt 87 | // In the above case, the "folder" folder will not have a 'D'irectory attribute or Method property. The 88 | // folder only exists as part of the path to "file.txt". 89 | 90 | zip.file("folder/file.txt", "file in folder", { createFolders: true }); 91 | // In this case, the "folder" folder WILL have a 'D'irectory attribute and a Method property of "store". 92 | // It will exist whether or not "file.txt" is present. 93 | 94 | zip.file("script.sh", "echo 'hello world'", { 95 | unixPermissions: "755", 96 | }); 97 | // when generated with platform:UNIX, the script.sh file will be executable 98 | ``` 99 | -------------------------------------------------------------------------------- /documentation/api_pizzip/file_name.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "file(name)" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Get a file with the specified name. You can specify folders 8 | in the name : the folder separator is a forward slash ("/"). 9 | 10 | **Arguments** 11 | 12 | | name | type | description | 13 | | ---- | ------ | --------------------- | 14 | | name | string | the name of the file. | 15 | 16 | **Returns** : An instance of [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html) representing 17 | the file if any, `null` otherwise. 18 | 19 | **Throws** : Nothing. 20 | 21 | 22 | 23 | **Examples** 24 | 25 | ```js 26 | var zip = new PizZip(); 27 | zip.file("file.txt", "content"); 28 | 29 | zip.file("file.txt").name; // "file.txt" 30 | zip.file("file.txt").asText(); // "content" 31 | zip.file("file.txt").options.dir; // false 32 | 33 | // utf8 example 34 | var zip = new PizZip(zipFromAjaxWithUTF8); 35 | zip.file("amount.txt").asText(); // "€15" 36 | zip.file("amount.txt").asArrayBuffer(); // an ArrayBuffer containing €15 encoded as utf8 37 | zip.file("amount.txt").asUint8Array(); // an Uint8Array containing €15 encoded as utf8 38 | 39 | // with folders 40 | zip.folder("sub").file("file.txt", "content"); 41 | zip.file("sub/file.txt"); // the file 42 | // or 43 | zip.folder("sub").file("file.txt"); // the file 44 | ``` 45 | -------------------------------------------------------------------------------- /documentation/api_pizzip/file_regex.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "file(regex)" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Search a file in the current folder and subfolders with a 8 | [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions). 9 | The regex is tested against the relative filename. 10 | 11 | **Arguments** 12 | 13 | | name | type | description | 14 | | ----- | ------ | ----------------- | 15 | | regex | RegExp | the regex to use. | 16 | 17 | **Returns** : An array of matching files (an empty array if none matched). Each 18 | maching file is an instance of [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html). 19 | 20 | **Throws** : Nothing. 21 | 22 | 26 | 27 | **Example** 28 | 29 | ```js 30 | var zip = new PizZip(); 31 | zip.file("file1.txt", "content"); 32 | zip.file("file2.txt", "content"); 33 | 34 | zip.file(/file/); // array of size 2 35 | 36 | // example with a relative path : 37 | var folder = zip.folder("sub"); 38 | folder 39 | .file("file3.txt", "content") // relative path from folder : file3.txt 40 | .file("file4.txt", "content"); // relative path from folder : file4.txt 41 | 42 | folder.file(/file/); // array of size 2 43 | folder.file(/^file/); // array of size 2, the relative paths start with file 44 | 45 | // arrays contain objects in the form: 46 | // {name: "file2.txt", dir: false, asText : function () {...}, ...} 47 | ``` 48 | -------------------------------------------------------------------------------- /documentation/api_pizzip/filter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "filter(predicate)" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Filter nested files/folders with the specified function. 8 | 9 | **Arguments** 10 | 11 | | name | type | description | 12 | | --------- | -------- | --------------------- | 13 | | predicate | function | the predicate to use. | 14 | 15 | The predicate has the following signature : `function (relativePath, file) {...}` : 16 | 17 | | name | type | description | 18 | | ------------ | --------- | ------------------------------------------------------------------------------------------ | 19 | | relativePath | string | the filename and its path, reliatively to the current folder. | 20 | | file | ZipObject | the file being tested. See [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html). | 21 | 22 | The predicate must return true if the file should be included, false otherwise. 23 | 24 | **Returns** : An array of matching ZipObject. 25 | 26 | **Throws** : Nothing. 27 | 28 | 29 | 30 | **Example** 31 | 32 | ```js 33 | var zip = new PizZip().folder("dir"); 34 | zip.file("readme.txt", "content"); 35 | zip.filter(function (relativePath, file) { 36 | // relativePath == "readme.txt" 37 | // file = {name:"dir/readme.txt",options:{...},asText:function} 38 | return true / false; 39 | }); 40 | ``` 41 | -------------------------------------------------------------------------------- /documentation/api_pizzip/folder_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "folder(name)" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Create a directory if it doesn't exist, return a new PizZip 8 | object with the new folder as root. 9 | 10 | See also [the `dir` option of file()]({{site.baseurl}}/documentation/api_pizzip/file_data.html). 11 | 12 | **Arguments** 13 | 14 | | name | type | description | 15 | | ---- | ------ | -------------------------- | 16 | | name | string | the name of the directory. | 17 | 18 | **Returns** : A new PizZip (for chaining), with the new folder as root. 19 | 20 | **Throws** : Nothing. 21 | 22 | 23 | 24 | **Example** 25 | 26 | ```js 27 | zip.folder("images"); 28 | zip.folder("css").file("style.css", "body {background: #FF0000}"); 29 | // or specify an absolute path (using forward slashes) 30 | zip.file("css/font.css", "body {font-family: sans-serif}"); 31 | 32 | // result : images/, css/, css/style.css, css/font.css 33 | ``` 34 | -------------------------------------------------------------------------------- /documentation/api_pizzip/folder_regex.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "folder(regex)" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Search a subdirectory in the current directory with a 8 | [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions). 9 | The regex is tested against the relative path. 10 | 11 | **Arguments** 12 | 13 | | name | type | description | 14 | | ----- | ------ | ----------------- | 15 | | regex | RegExp | the regex to use. | 16 | 17 | **Returns** : An array of matching folders (an empty array if none matched). 18 | Each maching folder is an instance of [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html). 19 | 20 | **Throws** : Nothing. 21 | 22 | 26 | 27 | **Example** 28 | 29 | ```js 30 | var zip = new PizZip(); 31 | zip.folder("home/Pierre/videos"); 32 | zip.folder("home/Pierre/photos"); 33 | zip.folder("home/Jean/videos"); 34 | zip.folder("home/Jean/photos"); 35 | 36 | zip.folder(/videos/); // array of size 2 37 | 38 | zip.folder("home/Jean").folder(/^vid/); // array of 1 39 | ``` 40 | -------------------------------------------------------------------------------- /documentation/api_pizzip/generate.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "generate(options)" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Generates the complete zip file. 8 | 9 | **Arguments** 10 | 11 | | name | type | default | description | 12 | | -------------------------- | -------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | 13 | | options | object | | the options to generate the zip file : | 14 | | 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. | 15 | | 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. | 16 | | options.compressionOptions | object | `null` | the options to use when compressing the file, see below. | 17 | | options.type | string | `base64` | The type of zip to return, see below for the other types. | 18 | | options.comment | string | | The comment to use for the zip file. | 19 | | 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". | 20 | | options.platform | string | `DOS` | The platform to use when generating the zip file. | 21 | | options.encodeFileName | function | encode with UTF-8 | the function to encode the file name / comment. | 22 | | options.fileOrder | function | | the function to specify the order of the files in the generated zip file. | 23 | 24 | Possible values for `type` : 25 | 26 | - `base64` (default) : the result will be a string, the binary in a base64 form. 27 | - `string` : the result will be a string in "binary" form, using 1 byte per char (2 bytes). 28 | - `uint8array` : the result will be a Uint8Array containing the zip. This requires a compatible browser. 29 | - `arraybuffer` : the result will be a ArrayBuffer containing the zip. This requires a compatible browser. 30 | - `blob` : the result will be a Blob containing the zip. This requires a compatible browser. 31 | - `nodebuffer` : the result will be a nodejs Buffer containing the zip. This requires nodejs. 32 | 33 | Note : when using type = "uint8array", "arraybuffer" or "blob", be sure to 34 | check if the browser supports it (you can use [`PizZip.support`]({{site.baseurl}}/documentation/api_pizzip/support.html)). 35 | 36 | The `compressionOptions` parameter depends on the compression type. With 37 | `STORE` (no compression), this parameter is ignored. With `DEFLATE`, you can 38 | give the compression level with `compressionOptions : {level:6}` (or any level 39 | between 1 (best speed) and 9 (best compression)). 40 | 41 | Note : if the entry is _already_ compressed (coming from a compressed zip file), 42 | calling `generate()` with a different compression level won't update the entry. 43 | The reason is simple : PizZip doesn't know how compressed the content was and 44 | how to match the compression level with the implementation we use. 45 | 46 | Note for the `comment` option : the zip format has no flag or field to give the 47 | encoding of this field and PizZip will use UTF-8. With non ASCII characters you 48 | might get encoding issues if the file archiver doesn't use UTF-8 to decode the 49 | comment. 50 | 51 | If not set, PizZip will use the field `comment` on its `options`. 52 | 53 | Possible values for `platform` : `DOS` and `UNIX`. It also accepts nodejs 54 | `process.platform` values. 55 | When using `DOS`, the attribute `dosPermissions` of each file is used. 56 | When using `UNIX`, the attribute `unixPermissions` of each file is used. 57 | 58 | If you set the platform value on nodejs, be sure to use `process.platform`. 59 | `fs.stats` returns a non executable mode for folders on windows, if you 60 | force the platform to `UNIX` the generated zip file will have a strange 61 | behavior on UNIX platforms. 62 | 63 | **About `encodeFileName`** : 64 | 65 | By default, PizZip uses UTF-8 to encode the file names / comments. You can use 66 | this method to force an other encoding. Note : the encoding used is not stored 67 | in a zip file, not using UTF-8 may lead to encoding issues. 68 | The function takes a string and returns a bytes array (Uint8Array or Array). 69 | 70 | **About `fileOrder`** : 71 | 72 | By default, PizZip will keep the order of the files of the input, and if you change a file, that file will be put at the end of the archive. If you need to specify the order of the zip files, you can use the `fileOrder` function and return the files in the order that you want them. All files present in the zip archive but not present in the `fileOrder` array will be put after the files in `fileOrder`. 73 | 74 | **Returns** : The generated zip file. 75 | 76 | **Throws** : An exception if the asked `type` is not available in the browser, 77 | see [PizZip.support]({{site.baseurl}}/documentation/api_pizzip/support.html). 78 | 79 | 80 | 81 | **Example** 82 | 83 | ```js 84 | var content = zip.generate({ type: "blob" }); 85 | // see FileSaver.js 86 | saveAs(content, "hello.zip"); 87 | ``` 88 | 89 | ```js 90 | var content = zip.generate({ type: "base64" }); 91 | location.href = "data:application/zip;base64," + content; 92 | ``` 93 | 94 | ```js 95 | var content = zip.generate({ type: "nodebuffer" }); 96 | require("fs").writeFile("hello.zip", content, function (err) { 97 | /*...*/ 98 | }); 99 | ``` 100 | 101 | ```js 102 | // on nodejs 103 | zip.file(pathname, content, { 104 | date: stat.mtime, 105 | unixPermissions: stat.mode, 106 | }); 107 | 108 | // ... 109 | 110 | zip.generate({ 111 | type: "nodebuffer", 112 | platform: process.platform, 113 | }); 114 | ``` 115 | 116 | ```js 117 | //This example will Generate a Open Document Spreasheet, with the correct mime type 118 | var zip = new PizZip(); 119 | zip.file("mimetype", "application/vnd.oasis.opendocument.spreadsheet"); 120 | var conf2 = zip.folder("Configurations2"); 121 | conf2.folder("acceleator"); 122 | conf2.folder("images"); 123 | conf2.folder("popupmenu"); 124 | conf2.folder("statusbar"); 125 | conf2.folder("floater"); 126 | conf2.folder("menubar"); 127 | conf2.folder("progressbar"); 128 | conf2.folder("toolbar"); 129 | 130 | var manifest = "<..."; //xml containing manifest.xml 131 | var styles = "<..."; //xml containing styles.xml 132 | var settings = "<..."; //xml containing settings.xml 133 | var meta = "<..."; //xml containing meta.xml 134 | var content = "<..."; //xml containing content.xml 135 | 136 | var metaInf = zip.folder("META-INF"); 137 | metaInf.file("manifest.xml", manifest); 138 | zip.file("styles.xml", styles); 139 | zip.file("settings.xml", settings); 140 | zip.file("meta.xml", meta); 141 | zip.file("content.xml", content); 142 | 143 | //Generate the file 144 | var odsFile = zip.generate({ 145 | type: "blob", 146 | mimeType: "application/ods", 147 | compression: "DEFLATE", 148 | }); 149 | 150 | var url = window.URL.createObjectURL(odsFile); 151 | var link = document.getElementById("link"); //I suppose you'll have a link with this id :) 152 | link.download = "testjs.ods"; 153 | link.href = url; 154 | ``` 155 | 156 | Using a custom charset : 157 | 158 | ```js 159 | // using iconv-lite for example 160 | var iconv = require("iconv-lite"); 161 | 162 | zip.generate({ 163 | type: "uint8array", 164 | encodeFileName: function (string) { 165 | return iconv.encode(string, "your-encoding"); 166 | }, 167 | }); 168 | ``` 169 | -------------------------------------------------------------------------------- /documentation/api_pizzip/load.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "load(data [, options])" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Read an existing zip and merge the data in the current PizZip 8 | object at the current folder level. This technique has some limitations, see 9 | [here]({{site.baseurl}}/documentation/limitations.html). 10 | 11 | **Arguments** 12 | 13 | | name | type | description | 14 | | ------- | --------------------------------------------------- | -------------------------------- | 15 | | data | String/Array of bytes/ArrayBuffer/Uint8Array/Buffer | the zip file | 16 | | options | object | the options to load the zip file | 17 | 18 | Content of `options` : 19 | 20 | | name | type | default | description | 21 | | ----------------------------- | -------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 22 | | options.base64 | boolean | false | set to `true` if the data is base64 encoded, `false` for binary. | 23 | | options.checkCRC32 | boolean | false | set to `true` if the read data should be checked against its CRC32. | 24 | | 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. | 25 | | 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. | 26 | | options.decodeFileName | function | decode from UTF-8 | the function to decode the file name / comment. | 27 | 28 | You shouldn't update the data given to this method : it is kept as it so any 29 | update will impact the stored data. 30 | 31 | Zip features supported by this method : 32 | 33 | - Compression (DEFLATE supported) 34 | - zip with data descriptor 35 | - ZIP64 36 | - UTF8 in file name, UTF8 in file content 37 | 38 | Zip features not (yet) supported : 39 | 40 | - password protected zip 41 | - multi-volume zip 42 | 43 | **About `decodeFileName`** : 44 | 45 | A zip file has a flag to say if the filename and comment are encoded with UTF-8. 46 | If it's not set, PizZip has **no way** to know the encoding used. It usually 47 | is the default encoding of the operating system. 48 | 49 | The function takes the bytes array (Uint8Array or Array) and returns the 50 | decoded string. 51 | 52 | **Returns** : The current PizZip object. 53 | 54 | **Throws** : An exception if the loaded data is not valid zip data or if it 55 | uses features (multi volume, password protected, etc). 56 | 57 | 68 | 69 | **Example** 70 | 71 | ```js 72 | var zip = new PizZip(); 73 | zip.load(zipDataFromXHR); 74 | ``` 75 | 76 | ```js 77 | require("fs").readFile("hello.zip", function (err, data) { 78 | if (err) throw err; 79 | var zip = new PizZip(); 80 | zip.load(data); 81 | } 82 | ``` 83 | 84 | Using sub folders : 85 | 86 | ```js 87 | var zip = new PizZip(); 88 | zip.folder("subfolder").load(data); 89 | // the content of data will be loaded in subfolder/ 90 | ``` 91 | 92 | Using a custom charset : 93 | 94 | ```js 95 | // using iconv-lite for example 96 | var iconv = require("iconv-lite"); 97 | 98 | zip.load(content, { 99 | decodeFileName: function (bytes) { 100 | return iconv.decode(bytes, "your-encoding"); 101 | }, 102 | }); 103 | ``` 104 | -------------------------------------------------------------------------------- /documentation/api_pizzip/remove.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "remove(name)" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | **Description** : Delete a file or folder (recursively). 8 | 9 | **Arguments** 10 | 11 | | name | type | description | 12 | | ---- | ------ | -------------------------------------- | 13 | | name | string | the name of the file/folder to delete. | 14 | 15 | **Returns** : The current PizZip object. 16 | 17 | **Throws** : Nothing. 18 | 19 | 23 | 24 | **Example** 25 | 26 | ```js 27 | var zip = new PizZip(); 28 | zip.file("Hello.txt", "Hello World\n"); 29 | zip.file("temp.txt", "nothing").remove("temp.txt"); 30 | // result : Hello.txt 31 | 32 | zip.folder("css").file("style.css", "body {background: #FF0000}"); 33 | zip.remove("css"); 34 | //result : empty zip 35 | ``` 36 | -------------------------------------------------------------------------------- /documentation/api_pizzip/support.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "PizZip.support" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | If the browser supports them, PizZip can take advantage of some "new" features : 8 | ArrayBuffer, Blob, Uint8Array. To know if PizZip can use them, you can check the 9 | PizZip.support object. It contains the following boolean properties : 10 | 11 | - `arraybuffer` : true if PizZip can read and generate ArrayBuffer, false otherwise. 12 | - `uint8array` : true if PizZip can read and generate Uint8Array, false otherwise. 13 | - `blob` : true if PizZip can generate Blob, false otherwise. 14 | - `nodebuffer` : true if PizZip can read and generate nodejs Buffer, false otherwise. 15 | -------------------------------------------------------------------------------- /documentation/api_zipobject.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "ZipObject API" 3 | layout: default 4 | section: api 5 | --- 6 | 7 | This represents an entry in the zip file. If the entry comes from an existing 8 | archive previously [loaded]({{site.baseurl}}/documentation/api_pizzip/load.html), the content 9 | will be automatically decompressed/converted first. 10 | 11 | ### Attributes 12 | 13 | | attribute name | type | description | 14 | | --------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- | 15 | | `name` | string | the absolute path of the file | 16 | | `dir` | boolean | true if this is a directory | 17 | | `date` | date | the last modification date | 18 | | `comment` | string | the comment for this file | 19 | | `unixPermissions` | 16 bits number | The UNIX permissions of the file, if any. | 20 | | `dosPermissions` | 6 bits number | The DOS permissions of the file, if any. | 21 | | `options` | object | the options of the file. The available options are : | 22 | | `options.base64` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_pizzip/file_data.html) | 23 | | `options.binary` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_pizzip/file_data.html) | 24 | | `options.dir` | boolean | **Deprecated**, use `dir`. True if this is a directory | 25 | | `options.date` | date | **Deprecated**, use `date`. See [file(name, data [,options])]({{site.baseurl}}/documentation/api_pizzip/file_data.html) | 26 | | `options.compression` | compression | see [file(name, data [,options])]({{site.baseurl}}/documentation/api_pizzip/file_data.html) | 27 | 28 | ### Getters 29 | 30 | | method | return type | description | 31 | | ----------------- | ------------- | ------------------------------------------------------------------------------------ | 32 | | `asText()` | string | the content as an unicode string. | 33 | | `asBinary()` | string | the content as binary string. | 34 | | `asArrayBuffer()` | ArrayBuffer | need a [compatible browser]({{site.baseurl}}/documentation/api_pizzip/support.html). | 35 | | `asUint8Array()` | Uint8Array | need a [compatible browser]({{site.baseurl}}/documentation/api_pizzip/support.html). | 36 | | `asNodeBuffer()` | nodejs Buffer | need [nodejs]({{site.baseurl}}/documentation/api_pizzip/support.html). | 37 | -------------------------------------------------------------------------------- /documentation/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Contributing layout: default 4 | 5 | section: main 6 | --- 7 | 8 | --- 9 | 10 | ### Download the sources 11 | 12 | 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). 13 | 14 | If you just want the get the source code, you can use git and do `git clone https://github.com/open-xml-templating/pizzip.git` to get the sources. You can also download the latest sources [here](https://github.com/open-xml-templating/pizzip/archive/master.zip). 15 | 16 | ### Building the project 17 | 18 | #### Code 19 | 20 | The dependencies are handled by npm, the first step is to run `npm install` to get the dependencies. PizZip uses Grunt to handle the build, [see here to install its CLI](http://gruntjs.com/getting-started). 21 | 22 | Here are the interesting build commands : 23 | 24 | - `grunt` will generate the final js file in dist/ and the minified version. 25 | - `npm run test-node` will run the tests in nodejs. 26 | - `npm run test-browser` will the tests in some browsers using SauceLabs, see below. 27 | - `npm run test` will run the tests in nodejs and in the browser. 28 | 29 | #### Documentation 30 | 31 | 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 ''`. 32 | 33 | ### Testing the project 34 | 35 | To test PizZip in nodejs, use `npm run test-node`. 36 | 37 | To test PizZip 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`. 38 | 39 | You can also test PizZip 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 40 | 41 | ```bash 42 | export SAUCE_USERNAME=your-saucelabs-username 43 | export SAUCE_ACCESS_KEY=your-saucelabs-access-key 44 | ``` 45 | 46 | before running the `npm run test-browser` command. 47 | 48 | ### Merging the changes 49 | 50 | 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. 51 | -------------------------------------------------------------------------------- /documentation/css/main.css: -------------------------------------------------------------------------------- 1 | ul.nav ul { 2 | list-style:none; 3 | margin: 0; 4 | padding: 0 0 0 25px; 5 | } 6 | 7 | #downloader_application form { 8 | margin-bottom: 10px; 9 | } 10 | 11 | #downloader_application ul { 12 | list-style-type: none; 13 | } 14 | 15 | .browser_support th { 16 | border-bottom-width: 3px !important; 17 | } 18 | 19 | .support_ie {border-bottom-color: #0275BA !important;} 20 | .support_ff {border-bottom-color: #DF7215 !important;} 21 | .support_sf {border-bottom-color: #43B3E9 !important;} 22 | .support_cr {border-bottom-color: #39B642 !important;} 23 | .support_op {border-bottom-color: #C42122 !important;} 24 | .support_nd {border-bottom-color: #8CC84B !important;} 25 | -------------------------------------------------------------------------------- /documentation/css/pygments.css: -------------------------------------------------------------------------------- 1 | /* Generated with : 2 | * pygmentize -S default -f html > pygments.css 3 | */ 4 | .hll { background-color: #ffffcc } 5 | .c { color: #408080; font-style: italic } /* Comment */ 6 | .err { border: 1px solid #FF0000 } /* Error */ 7 | .k { color: #008000; font-weight: bold } /* Keyword */ 8 | .o { color: #666666 } /* Operator */ 9 | .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 10 | .cp { color: #BC7A00 } /* Comment.Preproc */ 11 | .c1 { color: #408080; font-style: italic } /* Comment.Single */ 12 | .cs { color: #408080; font-style: italic } /* Comment.Special */ 13 | .gd { color: #A00000 } /* Generic.Deleted */ 14 | .ge { font-style: italic } /* Generic.Emph */ 15 | .gr { color: #FF0000 } /* Generic.Error */ 16 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 17 | .gi { color: #00A000 } /* Generic.Inserted */ 18 | .go { color: #888888 } /* Generic.Output */ 19 | .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 20 | .gs { font-weight: bold } /* Generic.Strong */ 21 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 22 | .gt { color: #0044DD } /* Generic.Traceback */ 23 | .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 24 | .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 25 | .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 26 | .kp { color: #008000 } /* Keyword.Pseudo */ 27 | .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 28 | .kt { color: #B00040 } /* Keyword.Type */ 29 | .m { color: #666666 } /* Literal.Number */ 30 | .s { color: #BA2121 } /* Literal.String */ 31 | .na { color: #7D9029 } /* Name.Attribute */ 32 | .nb { color: #008000 } /* Name.Builtin */ 33 | .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 34 | .no { color: #880000 } /* Name.Constant */ 35 | .nd { color: #AA22FF } /* Name.Decorator */ 36 | .ni { color: #999999; font-weight: bold } /* Name.Entity */ 37 | .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 38 | .nf { color: #0000FF } /* Name.Function */ 39 | .nl { color: #A0A000 } /* Name.Label */ 40 | .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 41 | .nt { color: #008000; font-weight: bold } /* Name.Tag */ 42 | .nv { color: #19177C } /* Name.Variable */ 43 | .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 44 | .w { color: #bbbbbb } /* Text.Whitespace */ 45 | .mf { color: #666666 } /* Literal.Number.Float */ 46 | .mh { color: #666666 } /* Literal.Number.Hex */ 47 | .mi { color: #666666 } /* Literal.Number.Integer */ 48 | .mo { color: #666666 } /* Literal.Number.Oct */ 49 | .sb { color: #BA2121 } /* Literal.String.Backtick */ 50 | .sc { color: #BA2121 } /* Literal.String.Char */ 51 | .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 52 | .s2 { color: #BA2121 } /* Literal.String.Double */ 53 | .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 54 | .sh { color: #BA2121 } /* Literal.String.Heredoc */ 55 | .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 56 | .sx { color: #008000 } /* Literal.String.Other */ 57 | .sr { color: #BB6688 } /* Literal.String.Regex */ 58 | .s1 { color: #BA2121 } /* Literal.String.Single */ 59 | .ss { color: #19177C } /* Literal.String.Symbol */ 60 | .bp { color: #008000 } /* Name.Builtin.Pseudo */ 61 | .vc { color: #19177C } /* Name.Variable.Class */ 62 | .vg { color: #19177C } /* Name.Variable.Global */ 63 | .vi { color: #19177C } /* Name.Variable.Instance */ 64 | .il { color: #666666 } /* Literal.Number.Integer.Long */ 65 | -------------------------------------------------------------------------------- /documentation/examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "How to use PizZip" 3 | layout: default 4 | section: example 5 | --- 6 | 7 | An instance of PizZip represents a set of files. You can add them, remove them, 8 | modify them. You can also import an existing zip file or generate one. 9 | 10 | ### Getting the object 11 | 12 | #### In a browser 13 | 14 | For a browser, there are two interesting files : `dist/pizzip.js` and 15 | `dist/pizzip.min.js` (include just one). 16 | 17 | If you use an AMD loader (RequireJS for example) PizZip will register itself : 18 | you just have to put the js file at the right place, or configure the loader 19 | (see [here for RequireJS](http://requirejs.org/docs/api.html#config-paths)). 20 | 21 | Without any loader, PizZip will declare in the global scope a variable named `PizZip`. 22 | 23 | #### In nodejs 24 | 25 | In nodejs, you can `require` it : 26 | 27 | ```js 28 | var PizZip = require("pizzip"); 29 | ``` 30 | 31 | ### Basic manipulations 32 | 33 | The first step is to create an instance of PizZip : 34 | 35 | ```js 36 | var zip = new PizZip(); 37 | ``` 38 | 39 | On this instance, we can add (and update) files and folders with 40 | `.file(name, content)` and `.folder(name)`. 41 | They return the current PizZip instance so you can chain the calls. 42 | 43 | ```js 44 | // create a file 45 | zip.file("hello.txt", "Hello[p my)6cxsw2q"); 46 | // oops, cat on keyboard. Fixing ! 47 | zip.file("hello.txt", "Hello World\n"); 48 | 49 | // create a file and a folder 50 | zip.file("nested/hello.txt", "Hello World\n"); 51 | // same as 52 | zip.folder("nested").file("hello.txt", "Hello World\n"); 53 | ``` 54 | 55 | With `.folder(name)`, the returned object has a different root : if you add files 56 | on this object, you will put them in the created subfolder. This is just a 57 | view, the added files will also be in the "root" object. 58 | 59 | ```js 60 | var photoZip = zip.folder("photos"); 61 | // this call will create photos/README 62 | photoZip.file("README", "a folder with photos"); 63 | ``` 64 | 65 | You can access the file content with `.file(name)` and 66 | [its getters]({{site.baseurl}}/documentation/api_zipobject.html) : 67 | 68 | ```js 69 | zip.file("hello.txt").asText(); // "Hello World\n" 70 | 71 | if (PizZip.support.uint8array) { 72 | zip.file("hello.txt").asUint8Array(); // Uint8Array { 0=72, 1=101, 2=108, more...} 73 | } 74 | ``` 75 | 76 | You can also remove files or folders with `.remove(name)` : 77 | 78 | ```js 79 | zip.remove("photos/README"); 80 | zip.remove("photos"); 81 | // same as 82 | zip.remove("photos"); // by removing the folder, you also remove its content. 83 | ``` 84 | 85 | ### Generate a zip file 86 | 87 | With `.generate(options)` you can generate a zip file (not a real file but its 88 | representation in memory). Check 89 | [this page]({{site.baseurl}}/documentation/howto/write_zip.html) for more 90 | informations on how to write / give the file to the user. 91 | 92 | ```js 93 | var content = null; 94 | if (PizZip.support.uint8array) { 95 | content = zip.generate({ type: "uint8array" }); 96 | } else { 97 | content = zip.generate({ type: "string" }); 98 | } 99 | ``` 100 | 101 | ### Read a zip file 102 | 103 | With `.load(data)` you can load a zip file. Check 104 | [this page]({{site.baseurl}}/documentation/howto/read_zip.html) to see how to 105 | do properly (it's more tricky that it seems). 106 | 107 | ```js 108 | var new_zip = new PizZip(); 109 | // more files ! 110 | new_zip.load(content); 111 | 112 | // you now have every files contained in the loaded zip 113 | new_zip.file("hello.txt").asText(); // "Hello World\n" 114 | ``` 115 | -------------------------------------------------------------------------------- /documentation/examples/download-zip-file.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Download the generated zip file" 3 | layout: default 4 | section: example 5 | --- 6 | 7 |

Tip : check the source of the page !

8 |

The FileSaver API

9 |
10 | Works on firefox, chrome , opera >= 15 and IE >= 10 (but NOT in compatibility view).
11 | 12 |
13 |

The data URL

14 |
15 | Does not work in IE, has restrictions on the length.
16 | 17 |
18 | 60 | -------------------------------------------------------------------------------- /documentation/examples/downloader.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Mini app : Downloader" 3 | layout: default 4 | section: example 5 | --- 6 | 7 |

Tip : check the source of the page !

8 | 9 |

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

13 |

14 | This demo requires a recent browser, see 15 | the howto. 16 |

17 | 18 | 19 | 20 |
21 |

Please select your files

22 |
23 |
    24 |
  • 25 | 29 |
  • 30 |
  • 31 | 35 |
  • 36 |
  • 37 | 41 |
  • 42 |
  • 43 | 47 |
  • 48 |
49 | 50 | 51 |
52 | 53 |

54 | 55 | 56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /documentation/examples/downloader.js: -------------------------------------------------------------------------------- 1 | jQuery(function ($) { 2 | "use strict"; 3 | 4 | /** 5 | * Reset the message. 6 | */ 7 | function resetMessage () { 8 | $("#result") 9 | .removeClass() 10 | .text(""); 11 | } 12 | /** 13 | * show a successful message. 14 | * @param {String} text the text to show. 15 | */ 16 | function showMessage(text) { 17 | resetMessage(); 18 | $("#result") 19 | .addClass("alert alert-success") 20 | .text(text); 21 | } 22 | /** 23 | * show an error message. 24 | * @param {String} text the text to show. 25 | */ 26 | function showError(text) { 27 | resetMessage(); 28 | $("#result") 29 | .addClass("alert alert-danger") 30 | .text(text); 31 | } 32 | 33 | /** 34 | * Fetch the content, add it to the PizZip object 35 | * and use a jQuery deferred to hold the result. 36 | * @param {String} url the url of the content to fetch. 37 | * @param {String} filename the filename to use in the PizZip object. 38 | * @param {PizZip} zip the PizZip instance. 39 | * @return {jQuery.Deferred} the deferred containing the data. 40 | */ 41 | function deferredAddZip(url, filename, zip) { 42 | const deferred = $.Deferred(); 43 | PizZipUtils.getBinaryContent(url, function (err, data) { 44 | if(err) { 45 | deferred.reject(err); 46 | } else { 47 | zip.file(filename, data, {binary: true}); 48 | deferred.resolve(data); 49 | } 50 | }); 51 | return deferred; 52 | } 53 | 54 | if(!PizZip.support.blob) { 55 | showError("This demo works only with a recent browser !"); 56 | return; 57 | } 58 | 59 | const $form = $("#download_form").on("submit", function () { 60 | resetMessage(); 61 | 62 | const zip = new PizZip(); 63 | const deferreds = []; 64 | 65 | // find every checked item 66 | $(this).find(":checked").each(function () { 67 | const $this = $(this); 68 | const url = $this.data("url"); 69 | const filename = url.replace(/.*\//g, ""); 70 | deferreds.push(deferredAddZip(url, filename, zip)); 71 | }); 72 | 73 | // when everything has been downloaded, we can trigger the dl 74 | $.when.apply($, deferreds).done(function () { 75 | const blob = zip.generate({type: "blob"}); 76 | 77 | // see FileSaver.js 78 | saveAs(blob, "example.zip"); 79 | 80 | showMessage("done !"); 81 | }).fail(function (err) { 82 | showError(err); 83 | }); 84 | return false; 85 | }); 86 | }); 87 | 88 | -------------------------------------------------------------------------------- /documentation/examples/get-binary-files-ajax.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Get a file with an ajax call" 3 | layout: default 4 | section: example 5 | --- 6 | 7 |

Tip : check the source of the page !

8 | 9 |

With PizZipUtils

10 |
11 | 12 | 44 | -------------------------------------------------------------------------------- /documentation/examples/read-local-file-api.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Reading a local file with the File API" 3 | layout: default 4 | section: example 5 | --- 6 | 7 |

Choose the local(s) zip file(s)

8 |

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

9 |
10 | 11 | 14 | 15 | 19 | 20 | 88 | -------------------------------------------------------------------------------- /documentation/faq.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Frequently Asked Questions" 3 | layout: default 4 | section: main 5 | --- 6 | 7 | ### "Corrupted zip or bug : unexpected signature" 8 | 9 | If you are sure that the zip file is correct, that error often comes from a 10 | corrupted content. An ajax request, if not prepared correctly, will try to 11 | decode the binary content as a text and corrupt it. See 12 | [this page]({{site.baseurl}}/documentation/howto/read_zip.html). 13 | 14 | ### My browser crashes / becomes unresponsive / never finish the execution 15 | 16 | That happens if you try to handle to much data. If possible, try again with a 17 | small (some KB) zip file to see if your code is correct. See 18 | [this page]({{site.baseurl}}/documentation/limitations.html) for more 19 | informations. 20 | -------------------------------------------------------------------------------- /documentation/howto/read_zip.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: "How to read a file" layout: default 4 | 5 | ## section: example 6 | 7 | This page explains how to read an existing zip file or add a existing file into the zip file. 8 | 9 | ### In the browser 10 | 11 | #### AJAX request 12 | 13 | Getting binary data with an ajax request is hard (mainly because of IE <= 9). The easy way is to use [PizZipUtils.getBinaryContent](https://github.com/open-xml-templating/pizzip-utils). With PizZipUtils.getBinaryContent, you can do the following (see the documentation for more examples) : 14 | 15 | ```js 16 | PizZipUtils.getBinaryContent("path/to/content.zip", function (err, data) { 17 | if (err) { 18 | throw err; // or handle err 19 | } 20 | 21 | var zip = new PizZip(data); 22 | }); 23 | ``` 24 | 25 |
26 | 27 | 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. 28 | 29 | 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. 30 | 31 | #### Local files 32 | 33 | If the browser supports the [FileReader API](http://caniuse.com/filereader), you can use it to read a zip file. PizZip can read ArrayBuffer, so you can use `FileReader.readAsArrayBuffer(Blob)`, see this [example]({{site.baseurl}}/documentation/examples/read-local-file-api.html). 34 | 35 | ### In nodejs 36 | 37 | PizZip can read Buffers so you can do the following : 38 | 39 | #### Local file 40 | 41 | ```js 42 | "use strict"; 43 | 44 | var fs = require("fs"); 45 | var PizZip = require("pizzip"); 46 | 47 | // read a zip file 48 | fs.readFile("test.zip", function (err, data) { 49 | if (err) throw err; 50 | var zip = new PizZip(data); 51 | }); 52 | 53 | // read a file and add it to a zip 54 | fs.readFile("picture.png", function (err, data) { 55 | if (err) throw err; 56 | var zip = new PizZip(); 57 | zip.file("picture.png", data); 58 | }); 59 | ``` 60 | 61 | #### Remote file 62 | 63 | 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"`). 64 | 65 | ##### With http : 66 | 67 | ```js 68 | "use strict"; 69 | 70 | var http = require("http"); 71 | var url = require("url"); 72 | var PizZip = require("pizzip"); 73 | 74 | var req = http.get(url.parse("http://localhost/.../file.zip"), function (res) { 75 | if (res.statusCode !== 200) { 76 | console.log(res.statusCode); 77 | // handle error 78 | return; 79 | } 80 | var data = [], 81 | dataLen = 0; 82 | 83 | // don't set the encoding, it will break everything ! 84 | // or, if you must, set it to null. In that case the chunk will be a string. 85 | 86 | res.on("data", function (chunk) { 87 | data.push(chunk); 88 | dataLen += chunk.length; 89 | }); 90 | 91 | res.on("end", function () { 92 | var buf = Buffer.alloc(dataLen); 93 | for (var i = 0, len = data.length, pos = 0; i < len; i++) { 94 | data[i].copy(buf, pos); 95 | pos += data[i].length; 96 | } 97 | 98 | // here we go ! 99 | var zip = new PizZip(buf); 100 | console.log(zip.file("content.txt").asText()); 101 | }); 102 | }); 103 | 104 | req.on("error", function (err) { 105 | // handle error 106 | }); 107 | ``` 108 | 109 | ##### With request : 110 | 111 | ```js 112 | "use strict"; 113 | 114 | var request = require("request"); 115 | var PizZip = require("pizzip"); 116 | 117 | request( 118 | { 119 | method: "GET", 120 | url: "http://localhost/.../file.zip", 121 | encoding: null, // <- this one is important ! 122 | }, 123 | function (error, response, body) { 124 | if (error || response.statusCode !== 200) { 125 | // handle error 126 | return; 127 | } 128 | var zip = new PizZip(body); 129 | console.log(zip.file("content.txt").asText()); 130 | } 131 | ); 132 | ``` 133 | -------------------------------------------------------------------------------- /documentation/howto/write_zip.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "How to write a file / give it to the user" 3 | layout: default 4 | section: example 5 | --- 6 | 7 | ### In the browser 8 | 9 | With only javascript, this part won't work in old browsers, including IE < 10. 10 | For those browsers, you can use a flash polyfill, see below. 11 | 12 | You can also see this 13 | [example]({{site.baseurl}}/documentation/examples/download-zip-file.html). 14 | 15 | #### Blob URL / FileSaver 16 | 17 | With recent browsers, the easiest way is to use `saveAs` or a polyfill, see 18 | [FileSaver.js](https://github.com/eligrey/FileSaver.js) : 19 | 20 | ```js 21 | var blob = zip.generate({ type: "blob" }); 22 | saveAs(blob, "hello.zip"); 23 | ``` 24 | 25 | Under the hood, the polyfill uses the native `saveAs` from the 26 | [FileSaver](http://www.w3.org/TR/file-writer-api/#the-filesaver-interface) API 27 | (on Chrome and IE10+) or use a [Blob URL](http://updates.html5rocks.com/2011/08/Downloading-resources-in-HTML5-a-download) 28 | (on Firefox). 29 | 30 | #### Data URI 31 | 32 | For older browsers that support [data URI](http://caniuse.com/datauri), you can also 33 | do the following : 34 | 35 | ```js 36 | location.href = 37 | "data:application/zip;base64," + zip.generate({ type: "base64" }); 38 | ``` 39 | 40 | The biggest issue here is that the filenames are very awkward, Firefox 41 | generates filenames such as `a5sZQRsx.zip.part` (see bugs 42 | [367231](https://bugzilla.mozilla.org/show_bug.cgi?id=367231) and 43 | [532230](https://bugzilla.mozilla.org/show_bug.cgi?id=532230), and Safari 44 | isn't much better with just `Unknown`. 45 | 46 | Browser support and resulting filename : 47 | 48 | | Opera | Firefox | Safari | Chrome | Internet Explorer | 49 | | ------------- | ------------------------------------------ | ------------------------ | ----------------------------------------------------------- | ----------------- | 50 | | "default.zip" | random alphanumeric with ".part" extension | "Unknown" (no extension) | "download.zip" on OSX and Linux, just "download" on Windows | No | 51 | 52 | #### Downloadify 53 | 54 | [Downloadify](https://github.com/dcneiner/downloadify) uses a small Flash SWF 55 | to download files to a user's computer with a filename that you can choose. 56 | Doug Neiner has added the `dataType` option to allow you to pass a zip for 57 | downloading. Follow the [Downloadify demo](http://pixelgraphics.us/downloadify/test.html) 58 | with the following changes: 59 | 60 | ```js 61 | zip = new PizZip(); 62 | zip.file("Hello.", "hello.txt"); 63 | Downloadify.create('downloadify',{ 64 | ... 65 | data: function(){ 66 | return zip.generate({type:"base64"}); 67 | }, 68 | ... 69 | dataType: 'base64' 70 | }); 71 | ``` 72 | 73 | 76 | 77 | #### Deprecated google gears 78 | 79 | [Franz Buchinger](http://www.picurl.org/blog/author/franz/) has written a 80 | brilliant tutorial on [using PizZip with Google Gears](http://www.picurl.org/blog/2009/11/22/creating-zip-archives-with-gears) 81 | ([part 2](http://www.picurl.org/blog/2009/11/29/gearszipper-part2-adding-support-for-real-files-and-canvas-elements/)). 82 | If you want to let your Gears users download several files at once I really 83 | recommend having a look at some of his [examples](http://picurl.org/gears/zipper/). 84 | 85 | ### In nodejs 86 | 87 | PizZip can generate Buffers so you can do the following : 88 | 89 | ```js 90 | var fs = require("fs"); 91 | var PizZip = require("pizzip"); 92 | 93 | var zip = new PizZip(); 94 | // zip.file("file", content); 95 | // ... and other manipulations 96 | 97 | var buffer = zip.generate({ type: "nodebuffer" }); 98 | 99 | fs.writeFile("test.zip", buffer, function (err) { 100 | if (err) throw err; 101 | }); 102 | ``` 103 | -------------------------------------------------------------------------------- /documentation/limitations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Limitations of PizZip" 3 | layout: default 4 | section: limitations 5 | fullpage: true 6 | --- 7 | 8 | ### Not supported features 9 | 10 | All the features of zip files are not supported. Classic zip files will work 11 | but encrypted zip, multi-volume, etc are not supported and the load() method 12 | will throw an `Error`. 13 | 14 | ### ZIP64 and 32bit integers 15 | 16 | ZIP64 files can be loaded, but only if the zip file is not "too big". ZIP64 uses 64bits integers 17 | but Javascript represents all numbers as 18 | [64-bit double precision IEEE 754 floating point numbers](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf) 19 | (see section 8.5). So, we have 53bits for integers and 20 | [bitwise operations treat everything as 32bits](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators). 21 | So if all the 64bits integers can fit into 32 bits integers, everything will be 22 | fine. If it's not the case, you will have other problems anyway (see next 23 | limitation). 24 | 25 | ### Performance issues 26 | 27 | An other limitation comes from the browser (and the machine running the 28 | browser). A compressed zip file of 10MB is "easily" opened by firefox / chrome 29 | / opera / IE10+ but will crash older IE. Also keep in mind that strings in 30 | javascript are encoded in UTF-16 : a 10MB ascii text file will take 20MB of 31 | memory. 32 | 33 | If you're having performance issues, please consider the following : 34 | 35 | - Don't use IE <= 9. Everything is better with typed arrays. 36 | - Use typed arrays (Uint8Array, ArrayBuffer, etc) if possible : 37 | - If you generate a zip file, you should use `type:"uint8array"` 38 | (or blob, arraybuffer, nodebuffer). 39 | - If you load the file from an ajax call, ask your XHR an ArrayBuffer. 40 | Loading a string is asking for troubles. 41 | - Don't use compression (see below). 42 | - If you want to get the content of an ASCII file as a string, consider using 43 | `asBinary()` instead of `asText()`. The transformation 44 | "binary string" -> "unicode string" is a consuming process. 45 | 46 | Note about compression : 47 | When reading a file, PizZip will store the content without decompressing it. 48 | When generating a compressed file, PizZip will reuse if possible compressed 49 | content : 50 | 51 | - If you read a zip file compressed with DEFLATE and call `generate` with the 52 | DEFLATE compression, PizZip won't call the compression algorithms (same with 53 | STORE everywhere.) 54 | - If you read a zip file compressed with DEFLATE and call `generate` with the 55 | STORE compression, PizZip will have to decompress everything. 56 | 57 | On IE <=9, typed arrays are not supported and the compression algorithm 58 | will fallback on arrays. In that case, PizZip needs to convert the binary string 59 | into an array, DEFLATE it and convert the result into a binary string. 60 | You don't want that to happen. 61 | 62 | ### The output zip will differ from the input zip 63 | 64 | Reading and generating a zip file won't give you back the same file. 65 | Some data are discarded (file metadata) and other are added (subfolders). 66 | 67 | ### Encodings support 68 | 69 | PizZip only supports UTF-8 natively. A zip file doesn't contain the name of the 70 | encoding used, you need to know it before doing anything. 71 | 72 | #### File name 73 | 74 | If the name of a file inside the zip is encoded with UTF-8 then PizZip can 75 | detect it (Language encoding flag, Unicode Path Extra Field). If not, PizZip 76 | can't detect the encoding used and will generate [Mojibake](https://en.wikipedia.org/wiki/Mojibake). 77 | You can use the [encodeFileName]({{site.baseurl}}/documentation/api_pizzip/generate.html) 78 | option and the [decodeFileName]({{site.baseurl}}/documentation/api_pizzip/load.html) 79 | option to encode/decode using a custom encoding. 80 | 81 | #### File content 82 | 83 | The `asText()` method uses UTF-8 to decode the content. If you have a text in 84 | a different encoding, you can get the bytes array with `asUint8Array()` and 85 | decode it with a lib (iconv, iconv-lite, etc) on your side. 86 | To save a text using a non-UTF-8 encoding, do the same : encode it into a 87 | Uint8Array before adding it to PizZip. 88 | -------------------------------------------------------------------------------- /documentation/upgrade_guide.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrade Guide 3 | layout: default 4 | section: main 5 | --- 6 | 7 | ### From 2.2.2 to 2.3.0 8 | 9 | - On `ZipObject#options`, the attributes `date` and `dir` have been 10 | deprecated and are now on `ZipObject`. 11 | - On `ZipObject#options`, the attributes `base64` and `binary` have been 12 | deprecated. 13 | - `PizZip.base64`, `PizZip.prototype.crc32`, `PizZip.prototype.utf8decode`, 14 | `PizZip.prototype.utf8encode` and `PizZip.utils` have been deprecated. 15 | 16 | ```js 17 | // deprecated 18 | zip.file("test.txt").options.date; 19 | zip.file("test.txt").options.dir; 20 | // new API 21 | zip.file("test.txt").date; 22 | zip.file("test.txt").dir; 23 | ``` 24 | 25 | ### From 2.0.0 to 2.1.0 26 | 27 | - The packaging changed : instead of loading pizzip.js, pizzip-load.js, 28 | pizzip-inflate.js, pizzip-deflate.js, just include dist/pizzip.js or 29 | dist/pizzip.min.js. 30 | For AMD loader users : PizZip now registers itself. You just have to put the 31 | file at the right place or configure your loader. 32 | 33 | ### From 1.x to 2.x 34 | 35 | - `PizZipBase64` has been renamed to `PizZip.base64`. 36 | - The `data` attribute doesn't exist anymore : 37 | use the getters `asText()`, `asBinary()`, etc 38 | - The compression/decompression methods now give their input type with the 39 | `compressInputType` and `uncompressInputType` attributes. 40 | 41 | Example for the data attribute : 42 | 43 | ```js 44 | // before 45 | zip.file("test.txt").data; 46 | zip.files["test.txt"].data; 47 | zip.file("image.png").data; 48 | zip.files["image.png"].data; 49 | 50 | // after 51 | zip.file("test.txt").asText(); 52 | zip.files["test.txt"].asText(); 53 | zip.file("image.png").asBinary(); 54 | zip.files["image.png"].asBinary(); 55 | ``` 56 | -------------------------------------------------------------------------------- /es6/arrayReader.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const DataReader = require("./dataReader.js"); 3 | 4 | function ArrayReader(data) { 5 | if (data) { 6 | this.data = data; 7 | this.length = this.data.length; 8 | this.index = 0; 9 | this.zero = 0; 10 | 11 | for (let i = 0; i < this.data.length; i++) { 12 | data[i] &= data[i]; 13 | } 14 | } 15 | } 16 | ArrayReader.prototype = new DataReader(); 17 | /** 18 | * @see DataReader.byteAt 19 | */ 20 | ArrayReader.prototype.byteAt = function (i) { 21 | return this.data[this.zero + i]; 22 | }; 23 | /** 24 | * @see DataReader.lastIndexOfSignature 25 | */ 26 | ArrayReader.prototype.lastIndexOfSignature = function (sig) { 27 | const sig0 = sig.charCodeAt(0), 28 | sig1 = sig.charCodeAt(1), 29 | sig2 = sig.charCodeAt(2), 30 | sig3 = sig.charCodeAt(3); 31 | for (let i = this.length - 4; i >= 0; --i) { 32 | if ( 33 | this.data[i] === sig0 && 34 | this.data[i + 1] === sig1 && 35 | this.data[i + 2] === sig2 && 36 | this.data[i + 3] === sig3 37 | ) { 38 | return i - this.zero; 39 | } 40 | } 41 | 42 | return -1; 43 | }; 44 | /** 45 | * @see DataReader.readData 46 | */ 47 | ArrayReader.prototype.readData = function (size) { 48 | this.checkOffset(size); 49 | if (size === 0) { 50 | return []; 51 | } 52 | const result = this.data.slice( 53 | this.zero + this.index, 54 | this.zero + this.index + size 55 | ); 56 | this.index += size; 57 | return result; 58 | }; 59 | module.exports = ArrayReader; 60 | -------------------------------------------------------------------------------- /es6/base64.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // private property 3 | const _keyStr = 4 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 5 | 6 | // public method for encoding 7 | exports.encode = function (input) { 8 | let output = ""; 9 | let chr1, chr2, chr3, enc1, enc2, enc3, enc4; 10 | let i = 0; 11 | 12 | while (i < input.length) { 13 | chr1 = input.charCodeAt(i++); 14 | chr2 = input.charCodeAt(i++); 15 | chr3 = input.charCodeAt(i++); 16 | 17 | enc1 = chr1 >> 2; 18 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 19 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 20 | enc4 = chr3 & 63; 21 | 22 | if (isNaN(chr2)) { 23 | enc3 = enc4 = 64; 24 | } else if (isNaN(chr3)) { 25 | enc4 = 64; 26 | } 27 | 28 | output = 29 | output + 30 | _keyStr.charAt(enc1) + 31 | _keyStr.charAt(enc2) + 32 | _keyStr.charAt(enc3) + 33 | _keyStr.charAt(enc4); 34 | } 35 | 36 | return output; 37 | }; 38 | 39 | // public method for decoding 40 | exports.decode = function (input) { 41 | let output = ""; 42 | let chr1, chr2, chr3; 43 | let enc1, enc2, enc3, enc4; 44 | let i = 0; 45 | 46 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 47 | 48 | while (i < input.length) { 49 | enc1 = _keyStr.indexOf(input.charAt(i++)); 50 | enc2 = _keyStr.indexOf(input.charAt(i++)); 51 | enc3 = _keyStr.indexOf(input.charAt(i++)); 52 | enc4 = _keyStr.indexOf(input.charAt(i++)); 53 | 54 | chr1 = (enc1 << 2) | (enc2 >> 4); 55 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 56 | chr3 = ((enc3 & 3) << 6) | enc4; 57 | 58 | output += String.fromCharCode(chr1); 59 | 60 | if (enc3 !== 64) { 61 | output += String.fromCharCode(chr2); 62 | } 63 | if (enc4 !== 64) { 64 | output += String.fromCharCode(chr3); 65 | } 66 | } 67 | 68 | return output; 69 | }; 70 | -------------------------------------------------------------------------------- /es6/compressedObject.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function CompressedObject() { 3 | this.compressedSize = 0; 4 | this.uncompressedSize = 0; 5 | this.crc32 = 0; 6 | this.compressionMethod = null; 7 | this.compressedContent = null; 8 | } 9 | 10 | CompressedObject.prototype = { 11 | /** 12 | * Return the decompressed content in an unspecified format. 13 | * The format will depend on the decompressor. 14 | * @return {Object} the decompressed content. 15 | */ 16 | getContent() { 17 | return null; // see implementation 18 | }, 19 | /** 20 | * Return the compressed content in an unspecified format. 21 | * The format will depend on the compressed conten source. 22 | * @return {Object} the compressed content. 23 | */ 24 | getCompressedContent() { 25 | return null; // see implementation 26 | }, 27 | }; 28 | module.exports = CompressedObject; 29 | -------------------------------------------------------------------------------- /es6/compressions.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.STORE = { 3 | magic: "\x00\x00", 4 | compress(content) { 5 | return content; // no compression 6 | }, 7 | uncompress(content) { 8 | return content; // no compression 9 | }, 10 | compressInputType: null, 11 | uncompressInputType: null, 12 | }; 13 | exports.DEFLATE = require("./flate.js"); 14 | -------------------------------------------------------------------------------- /es6/crc32.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("./utils.js"); 4 | 5 | // prettier-ignore 6 | const table = [ 7 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 8 | 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 9 | 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 10 | 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 11 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 12 | 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 13 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 14 | 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 15 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 16 | 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 17 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 18 | 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 19 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 20 | 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 21 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 22 | 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 23 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 24 | 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 25 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 26 | 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 27 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 28 | 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 29 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 30 | 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 31 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 32 | 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 33 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 34 | 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 35 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 36 | 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 37 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 38 | 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 39 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 40 | 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 41 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 42 | 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 43 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 44 | 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 45 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 46 | 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 47 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 48 | 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 49 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 50 | 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 51 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 52 | 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 53 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 54 | 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 55 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 56 | 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 57 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 58 | 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 59 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 60 | 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 61 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 62 | 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 63 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 64 | 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 65 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 66 | 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 67 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 68 | 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 69 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 70 | 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, 71 | ]; 72 | 73 | /** 74 | * 75 | * Javascript crc32 76 | * http://www.webtoolkit.info/ 77 | * 78 | */ 79 | module.exports = function crc32(input, crc) { 80 | if (typeof input === "undefined" || !input.length) { 81 | return 0; 82 | } 83 | 84 | const isArray = utils.getTypeOf(input) !== "string"; 85 | 86 | if (typeof crc == "undefined") { 87 | crc = 0; 88 | } 89 | let x = 0; 90 | let y = 0; 91 | let b = 0; 92 | 93 | crc ^= -1; 94 | for (let i = 0, iTop = input.length; i < iTop; i++) { 95 | b = isArray ? input[i] : input.charCodeAt(i); 96 | y = (crc ^ b) & 0xff; 97 | x = table[y]; 98 | crc = (crc >>> 8) ^ x; 99 | } 100 | 101 | return crc ^ -1; 102 | }; 103 | -------------------------------------------------------------------------------- /es6/dataReader.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const utils = require("./utils.js"); 3 | 4 | function DataReader() { 5 | this.data = null; // type : see implementation 6 | this.length = 0; 7 | this.index = 0; 8 | this.zero = 0; 9 | } 10 | DataReader.prototype = { 11 | /** 12 | * Check that the offset will not go too far. 13 | * @param {string} offset the additional offset to check. 14 | * @throws {Error} an Error if the offset is out of bounds. 15 | */ 16 | checkOffset(offset) { 17 | this.checkIndex(this.index + offset); 18 | }, 19 | /** 20 | * Check that the specifed index will not be too far. 21 | * @param {string} newIndex the index to check. 22 | * @throws {Error} an Error if the index is out of bounds. 23 | */ 24 | checkIndex(newIndex) { 25 | if (this.length < this.zero + newIndex || newIndex < 0) { 26 | throw new Error( 27 | "End of data reached (data length = " + 28 | this.length + 29 | ", asked index = " + 30 | newIndex + 31 | "). Corrupted zip ?" 32 | ); 33 | } 34 | }, 35 | /** 36 | * Change the index. 37 | * @param {number} newIndex The new index. 38 | * @throws {Error} if the new index is out of the data. 39 | */ 40 | setIndex(newIndex) { 41 | this.checkIndex(newIndex); 42 | this.index = newIndex; 43 | }, 44 | /** 45 | * Skip the next n bytes. 46 | * @param {number} n the number of bytes to skip. 47 | * @throws {Error} if the new index is out of the data. 48 | */ 49 | skip(n) { 50 | this.setIndex(this.index + n); 51 | }, 52 | /** 53 | * Get the byte at the specified index. 54 | * @param {number} i the index to use. 55 | * @return {number} a byte. 56 | */ 57 | byteAt() { 58 | // see implementations 59 | }, 60 | /** 61 | * Get the next number with a given byte size. 62 | * @param {number} size the number of bytes to read. 63 | * @return {number} the corresponding number. 64 | */ 65 | readInt(size) { 66 | let result = 0, 67 | i; 68 | this.checkOffset(size); 69 | for (i = this.index + size - 1; i >= this.index; i--) { 70 | result = (result << 8) + this.byteAt(i); 71 | } 72 | this.index += size; 73 | return result; 74 | }, 75 | /** 76 | * Get the next string with a given byte size. 77 | * @param {number} size the number of bytes to read. 78 | * @return {string} the corresponding string. 79 | */ 80 | readString(size) { 81 | return utils.transformTo("string", this.readData(size)); 82 | }, 83 | /** 84 | * Get raw data without conversion, bytes. 85 | * @param {number} size the number of bytes to read. 86 | * @return {Object} the raw data, implementation specific. 87 | */ 88 | readData() { 89 | // see implementations 90 | }, 91 | /** 92 | * Find the last occurence of a zip signature (4 bytes). 93 | * @param {string} sig the signature to find. 94 | * @return {number} the index of the last occurence, -1 if not found. 95 | */ 96 | lastIndexOfSignature() { 97 | // see implementations 98 | }, 99 | /** 100 | * Get the next date. 101 | * @return {Date} the date. 102 | */ 103 | readDate() { 104 | const dostime = this.readInt(4); 105 | return new Date( 106 | ((dostime >> 25) & 0x7f) + 1980, // year 107 | ((dostime >> 21) & 0x0f) - 1, // month 108 | (dostime >> 16) & 0x1f, // day 109 | (dostime >> 11) & 0x1f, // hour 110 | (dostime >> 5) & 0x3f, // minute 111 | (dostime & 0x1f) << 1 112 | ); // second 113 | }, 114 | }; 115 | module.exports = DataReader; 116 | -------------------------------------------------------------------------------- /es6/defaults.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.base64 = false; 3 | exports.binary = false; 4 | exports.dir = false; 5 | exports.createFolders = false; 6 | exports.date = null; 7 | exports.compression = null; 8 | exports.compressionOptions = null; 9 | exports.comment = null; 10 | exports.unixPermissions = null; 11 | exports.dosPermissions = null; 12 | -------------------------------------------------------------------------------- /es6/deprecatedPublicUtils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const utils = require("./utils.js"); 3 | 4 | /** 5 | * @deprecated 6 | * This function will be removed in a future version without replacement. 7 | */ 8 | exports.string2binary = function (str) { 9 | return utils.string2binary(str); 10 | }; 11 | 12 | /** 13 | * @deprecated 14 | * This function will be removed in a future version without replacement. 15 | */ 16 | exports.string2Uint8Array = function (str) { 17 | return utils.transformTo("uint8array", str); 18 | }; 19 | 20 | /** 21 | * @deprecated 22 | * This function will be removed in a future version without replacement. 23 | */ 24 | exports.uint8Array2String = function (array) { 25 | return utils.transformTo("string", array); 26 | }; 27 | 28 | /** 29 | * @deprecated 30 | * This function will be removed in a future version without replacement. 31 | */ 32 | exports.string2Blob = function (str) { 33 | const buffer = utils.transformTo("arraybuffer", str); 34 | return utils.arrayBuffer2Blob(buffer); 35 | }; 36 | 37 | /** 38 | * @deprecated 39 | * This function will be removed in a future version without replacement. 40 | */ 41 | exports.arrayBuffer2Blob = function (buffer) { 42 | return utils.arrayBuffer2Blob(buffer); 43 | }; 44 | 45 | /** 46 | * @deprecated 47 | * This function will be removed in a future version without replacement. 48 | */ 49 | exports.transformTo = function (outputType, input) { 50 | return utils.transformTo(outputType, input); 51 | }; 52 | 53 | /** 54 | * @deprecated 55 | * This function will be removed in a future version without replacement. 56 | */ 57 | exports.getTypeOf = function (input) { 58 | return utils.getTypeOf(input); 59 | }; 60 | 61 | /** 62 | * @deprecated 63 | * This function will be removed in a future version without replacement. 64 | */ 65 | exports.checkSupport = function (type) { 66 | return utils.checkSupport(type); 67 | }; 68 | 69 | /** 70 | * @deprecated 71 | * This value will be removed in a future version without replacement. 72 | */ 73 | exports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS; 74 | 75 | /** 76 | * @deprecated 77 | * This value will be removed in a future version without replacement. 78 | */ 79 | exports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS; 80 | 81 | /** 82 | * @deprecated 83 | * This function will be removed in a future version without replacement. 84 | */ 85 | exports.pretty = function (str) { 86 | return utils.pretty(str); 87 | }; 88 | 89 | /** 90 | * @deprecated 91 | * This function will be removed in a future version without replacement. 92 | */ 93 | exports.findCompression = function (compressionMethod) { 94 | return utils.findCompression(compressionMethod); 95 | }; 96 | 97 | /** 98 | * @deprecated 99 | * This function will be removed in a future version without replacement. 100 | */ 101 | exports.isRegExp = function (object) { 102 | return utils.isRegExp(object); 103 | }; 104 | -------------------------------------------------------------------------------- /es6/flate.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const USE_TYPEDARRAY = 3 | typeof Uint8Array !== "undefined" && 4 | typeof Uint16Array !== "undefined" && 5 | typeof Uint32Array !== "undefined"; 6 | 7 | const pako = require("pako/dist/pako.es5.min.js"); 8 | exports.uncompressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; 9 | exports.compressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; 10 | 11 | exports.magic = "\x08\x00"; 12 | exports.compress = function (input, compressionOptions) { 13 | return pako.deflateRaw(input, { 14 | level: compressionOptions.level || -1, // default compression 15 | }); 16 | }; 17 | exports.uncompress = function (input) { 18 | return pako.inflateRaw(input); 19 | }; 20 | -------------------------------------------------------------------------------- /es6/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const base64 = require("./base64.js"); 4 | 5 | /** 6 | Usage: 7 | zip = new PizZip(); 8 | zip.file("hello.txt", "Hello, World!").file("tempfile", "nothing"); 9 | zip.folder("images").file("smile.gif", base64Data, {base64: true}); 10 | zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")}); 11 | zip.remove("tempfile"); 12 | 13 | base64zip = zip.generate(); 14 | 15 | **/ 16 | 17 | /** 18 | * Representation a of zip file in js 19 | * @constructor 20 | * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional). 21 | * @param {Object=} options the options for creating this objects (optional). 22 | */ 23 | function PizZip(data, options) { 24 | // if this constructor is used without `new`, it adds `new` before itself: 25 | if (!(this instanceof PizZip)) { 26 | return new PizZip(data, options); 27 | } 28 | 29 | // object containing the files : 30 | // { 31 | // "folder/" : {...}, 32 | // "folder/data.txt" : {...} 33 | // } 34 | this.files = {}; 35 | 36 | this.comment = null; 37 | 38 | // Where we are in the hierarchy 39 | this.root = ""; 40 | if (data) { 41 | this.load(data, options); 42 | } 43 | this.clone = function () { 44 | const newObj = new PizZip(); 45 | Object.keys(this.files).forEach((file) => { 46 | newObj.file(file, this.files[file].asUint8Array()); 47 | }); 48 | return newObj; 49 | }; 50 | this.shallowClone = function () { 51 | const newObj = new PizZip(); 52 | for (const i in this) { 53 | if (typeof this[i] !== "function") { 54 | newObj[i] = this[i]; 55 | } 56 | } 57 | return newObj; 58 | }; 59 | } 60 | PizZip.prototype = require("./object.js"); 61 | PizZip.prototype.load = require("./load.js"); 62 | PizZip.support = require("./support.js"); 63 | PizZip.defaults = require("./defaults.js"); 64 | 65 | /** 66 | * @deprecated 67 | * This namespace will be removed in a future version without replacement. 68 | */ 69 | PizZip.utils = require("./deprecatedPublicUtils.js"); 70 | 71 | PizZip.base64 = { 72 | /** 73 | * @deprecated 74 | * This method will be removed in a future version without replacement. 75 | */ 76 | encode(input) { 77 | return base64.encode(input); 78 | }, 79 | /** 80 | * @deprecated 81 | * This method will be removed in a future version without replacement. 82 | */ 83 | decode(input) { 84 | return base64.decode(input); 85 | }, 86 | }; 87 | PizZip.compressions = require("./compressions.js"); 88 | module.exports = PizZip; 89 | module.exports.default = PizZip; 90 | -------------------------------------------------------------------------------- /es6/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import PizZip from "./index.js"; 2 | import { expectType, expectError } from "tsd"; 3 | import * as fs from "fs"; 4 | 5 | const zip1 = new PizZip(); 6 | 7 | zip1.file( 8 | "smile.gif", 9 | "R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=", 10 | { base64: true } 11 | ); 12 | 13 | expectError(zip1.foo("xxx")); 14 | 15 | var zip3 = new PizZip(); 16 | expectError(zip3.load()); 17 | 18 | var zip2 = new PizZip(); 19 | zip2.load("foobar"); 20 | 21 | const output = zip1.generate({ 22 | type: "blob", 23 | mimeType: 24 | "application/vnd.openxmlformats-officedocument.wordprocessingml.document", 25 | compression: "DEFLATE", 26 | }); 27 | 28 | expectError(zip1.generate({ optionXYZ: true })); 29 | 30 | const zip = new PizZip(); 31 | 32 | if (PizZip.support.blob) { 33 | /* amazing */ 34 | } 35 | 36 | new PizZip("data", { 37 | base64: true, 38 | checkCRC32: true, 39 | createFolders: true, 40 | optimizedBinaryString: true, 41 | decodeFileName: (a) => "", 42 | }); 43 | 44 | zip 45 | .file("Hello.txt", "Hello World\n") 46 | .file( 47 | "smile.gif", 48 | "R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=", 49 | { base64: true } 50 | ) 51 | .file("smile.gif", fs.readFileSync("smile.gif")) 52 | .file("Xmas.txt", "Ho ho ho !", { 53 | date: new Date("December 25, 2007 00:00:01"), 54 | }) 55 | .file("folder/file.txt", "file in folder", { createFolders: true }) 56 | .file("script.sh", "echo 'hello world'", { unixPermissions: "755" }) 57 | .folder("css") 58 | .remove("css"); 59 | 60 | zip.load("content", { decodeFileName: (bytes) => "encoding" }); 61 | zip.file(/file/).map((z) => z); 62 | zip.folder(/^vid/).map((z) => z); 63 | zip.filter((relativePath, file) => true).map((z) => z); 64 | zip.folder("subfolder").load("data"); 65 | 66 | const file = zip.file(""); 67 | 68 | if (file) { 69 | const nameTest: string = file.name; 70 | const textTest: string = file.asText(); 71 | const binaryTest: string = file.asBinary(); 72 | const arrBufTest: ArrayBuffer = file.asArrayBuffer(); 73 | const uint8Test: Uint8Array = file.asUint8Array(); 74 | const bufTest: Buffer = file.asNodeBuffer(); 75 | } 76 | 77 | const noOptionsTest: string = zip.generate(); 78 | const noTypeTest: string = zip.generate({ base64: true }); 79 | const b64Test: string = zip.generate({ 80 | type: "base64", 81 | compression: "DEFLATE", 82 | }); 83 | const stringTest: string = zip.generate({ 84 | type: "string", 85 | encodeFileName: (s) => new Buffer(s), 86 | }); 87 | const arrBufTest: ArrayBuffer = zip.generate({ 88 | type: "arraybuffer", 89 | mimeType: "", 90 | }); 91 | const blobTest: Blob = zip.generate({ 92 | type: "blob", 93 | compressionOptions: { level: 1 }, 94 | }); 95 | const bufTest: Buffer = zip.generate({ type: "nodebuffer", platform: "DOS" }); 96 | const unit8Test: Uint8Array = zip.generate({ 97 | type: "uint8array", 98 | base64: true, 99 | }); 100 | 101 | zip.generate({ 102 | type: "nodebuffer", 103 | fileOrder: function (files) { 104 | return []; 105 | }, 106 | }); 107 | -------------------------------------------------------------------------------- /es6/license_header.js: -------------------------------------------------------------------------------- 1 | /* ! 2 | 3 | PizZip - A Javascript class for generating and reading zip files 4 | 5 | 6 | (c) 2009-2014 Stuart Knightley 7 | Dual licenced under the MIT license or GPLv3. See https://raw.github.com/open-xml-templating/pizzip/master/LICENSE.markdown 8 | 9 | PizZip uses the library pako released under the MIT license : 10 | https://github.com/nodeca/pako/blob/master/LICENSE 11 | */ 12 | -------------------------------------------------------------------------------- /es6/load.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const base64 = require("./base64.js"); 3 | const utf8 = require("./utf8.js"); 4 | const utils = require("./utils.js"); 5 | const ZipEntries = require("./zipEntries.js"); 6 | module.exports = function (data, options) { 7 | let i, input; 8 | options = utils.extend(options || {}, { 9 | base64: false, 10 | checkCRC32: false, 11 | optimizedBinaryString: false, 12 | createFolders: false, 13 | decodeFileName: utf8.utf8decode, 14 | }); 15 | if (options.base64) { 16 | data = base64.decode(data); 17 | } 18 | 19 | const zipEntries = new ZipEntries(data, options); 20 | const files = zipEntries.files; 21 | for (i = 0; i < files.length; i++) { 22 | input = files[i]; 23 | this.file(input.fileNameStr, input.decompressed, { 24 | binary: true, 25 | optimizedBinaryString: true, 26 | date: input.date, 27 | dir: input.dir, 28 | comment: input.fileCommentStr.length ? input.fileCommentStr : null, 29 | unixPermissions: input.unixPermissions, 30 | dosPermissions: input.dosPermissions, 31 | createFolders: options.createFolders, 32 | }); 33 | } 34 | if (zipEntries.zipComment.length) { 35 | this.comment = zipEntries.zipComment; 36 | } 37 | 38 | return this; 39 | }; 40 | -------------------------------------------------------------------------------- /es6/nodeBuffer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = function (data, encoding) { 3 | if (typeof data === "number") { 4 | return Buffer.alloc(data); 5 | } 6 | return Buffer.from(data, encoding); 7 | }; 8 | module.exports.test = function (b) { 9 | return Buffer.isBuffer(b); 10 | }; 11 | -------------------------------------------------------------------------------- /es6/nodeBufferReader.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const Uint8ArrayReader = require("./uint8ArrayReader.js"); 3 | 4 | function NodeBufferReader(data) { 5 | this.data = data; 6 | this.length = this.data.length; 7 | this.index = 0; 8 | this.zero = 0; 9 | } 10 | NodeBufferReader.prototype = new Uint8ArrayReader(); 11 | 12 | /** 13 | * @see DataReader.readData 14 | */ 15 | NodeBufferReader.prototype.readData = function (size) { 16 | this.checkOffset(size); 17 | const result = this.data.slice( 18 | this.zero + this.index, 19 | this.zero + this.index + size 20 | ); 21 | this.index += size; 22 | return result; 23 | }; 24 | module.exports = NodeBufferReader; 25 | -------------------------------------------------------------------------------- /es6/signature.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.LOCAL_FILE_HEADER = "PK\x03\x04"; 3 | exports.CENTRAL_FILE_HEADER = "PK\x01\x02"; 4 | exports.CENTRAL_DIRECTORY_END = "PK\x05\x06"; 5 | exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07"; 6 | exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06"; 7 | exports.DATA_DESCRIPTOR = "PK\x07\x08"; 8 | -------------------------------------------------------------------------------- /es6/stringReader.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const DataReader = require("./dataReader.js"); 3 | const utils = require("./utils.js"); 4 | 5 | function StringReader(data, optimizedBinaryString) { 6 | this.data = data; 7 | if (!optimizedBinaryString) { 8 | this.data = utils.string2binary(this.data); 9 | } 10 | this.length = this.data.length; 11 | this.index = 0; 12 | this.zero = 0; 13 | } 14 | StringReader.prototype = new DataReader(); 15 | /** 16 | * @see DataReader.byteAt 17 | */ 18 | StringReader.prototype.byteAt = function (i) { 19 | return this.data.charCodeAt(this.zero + i); 20 | }; 21 | /** 22 | * @see DataReader.lastIndexOfSignature 23 | */ 24 | StringReader.prototype.lastIndexOfSignature = function (sig) { 25 | return this.data.lastIndexOf(sig) - this.zero; 26 | }; 27 | /** 28 | * @see DataReader.readData 29 | */ 30 | StringReader.prototype.readData = function (size) { 31 | this.checkOffset(size); 32 | // this will work because the constructor applied the "& 0xff" mask. 33 | const result = this.data.slice( 34 | this.zero + this.index, 35 | this.zero + this.index + size 36 | ); 37 | this.index += size; 38 | return result; 39 | }; 40 | module.exports = StringReader; 41 | -------------------------------------------------------------------------------- /es6/stringWriter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("./utils.js"); 4 | 5 | /** 6 | * An object to write any content to a string. 7 | * @constructor 8 | */ 9 | function StringWriter() { 10 | this.data = []; 11 | } 12 | StringWriter.prototype = { 13 | /** 14 | * Append any content to the current string. 15 | * @param {Object} input the content to add. 16 | */ 17 | append(input) { 18 | input = utils.transformTo("string", input); 19 | this.data.push(input); 20 | }, 21 | /** 22 | * Finalize the construction an return the result. 23 | * @return {string} the generated string. 24 | */ 25 | finalize() { 26 | return this.data.join(""); 27 | }, 28 | }; 29 | 30 | module.exports = StringWriter; 31 | -------------------------------------------------------------------------------- /es6/support.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.base64 = true; 3 | exports.array = true; 4 | exports.string = true; 5 | exports.arraybuffer = 6 | typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined"; 7 | // contains true if PizZip can read/generate nodejs Buffer, false otherwise. 8 | // Browserify will provide a Buffer implementation for browsers, which is 9 | // an augmented Uint8Array (i.e., can be used as either Buffer or U8). 10 | exports.nodebuffer = typeof Buffer !== "undefined"; 11 | // contains true if PizZip can read/generate Uint8Array, false otherwise. 12 | exports.uint8array = typeof Uint8Array !== "undefined"; 13 | 14 | if (typeof ArrayBuffer === "undefined") { 15 | exports.blob = false; 16 | } else { 17 | const buffer = new ArrayBuffer(0); 18 | try { 19 | exports.blob = 20 | new Blob([buffer], { 21 | type: "application/zip", 22 | }).size === 0; 23 | } catch { 24 | try { 25 | const Builder = 26 | window.BlobBuilder || 27 | window.WebKitBlobBuilder || 28 | window.MozBlobBuilder || 29 | window.MSBlobBuilder; 30 | const builder = new Builder(); 31 | builder.append(buffer); 32 | exports.blob = builder.getBlob("application/zip").size === 0; 33 | } catch { 34 | exports.blob = false; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /es6/uint8ArrayReader.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const ArrayReader = require("./arrayReader.js"); 3 | 4 | function Uint8ArrayReader(data) { 5 | if (data) { 6 | this.data = data; 7 | this.length = this.data.length; 8 | this.index = 0; 9 | this.zero = 0; 10 | } 11 | } 12 | Uint8ArrayReader.prototype = new ArrayReader(); 13 | /** 14 | * @see DataReader.readData 15 | */ 16 | Uint8ArrayReader.prototype.readData = function (size) { 17 | this.checkOffset(size); 18 | if (size === 0) { 19 | // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of []. 20 | return new Uint8Array(0); 21 | } 22 | const result = this.data.subarray( 23 | this.zero + this.index, 24 | this.zero + this.index + size 25 | ); 26 | this.index += size; 27 | return result; 28 | }; 29 | module.exports = Uint8ArrayReader; 30 | -------------------------------------------------------------------------------- /es6/uint8ArrayWriter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("./utils.js"); 4 | 5 | /** 6 | * An object to write any content to an Uint8Array. 7 | * @constructor 8 | * @param {number} length The length of the array. 9 | */ 10 | function Uint8ArrayWriter(length) { 11 | this.data = new Uint8Array(length); 12 | this.index = 0; 13 | } 14 | Uint8ArrayWriter.prototype = { 15 | /** 16 | * Append any content to the current array. 17 | * @param {Object} input the content to add. 18 | */ 19 | append(input) { 20 | if (input.length !== 0) { 21 | // with an empty Uint8Array, Opera fails with a "Offset larger than array size" 22 | input = utils.transformTo("uint8array", input); 23 | this.data.set(input, this.index); 24 | this.index += input.length; 25 | } 26 | }, 27 | /** 28 | * Finalize the construction an return the result. 29 | * @return {Uint8Array} the generated array. 30 | */ 31 | finalize() { 32 | return this.data; 33 | }, 34 | }; 35 | 36 | module.exports = Uint8ArrayWriter; 37 | -------------------------------------------------------------------------------- /es6/utf8.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("./utils.js"); 4 | const support = require("./support.js"); 5 | const nodeBuffer = require("./nodeBuffer.js"); 6 | 7 | /** 8 | * The following functions come from pako, from pako/lib/utils/strings 9 | * released under the MIT license, see pako https://github.com/nodeca/pako/ 10 | */ 11 | 12 | // Table with utf8 lengths (calculated by first byte of sequence) 13 | // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, 14 | // because max possible codepoint is 0x10ffff 15 | const _utf8len = new Array(256); 16 | for (let i = 0; i < 256; i++) { 17 | _utf8len[i] = 18 | i >= 252 19 | ? 6 20 | : i >= 248 21 | ? 5 22 | : i >= 240 23 | ? 4 24 | : i >= 224 25 | ? 3 26 | : i >= 192 27 | ? 2 28 | : 1; 29 | } 30 | _utf8len[254] = _utf8len[254] = 1; // Invalid sequence start 31 | 32 | // convert string to array (typed, when possible) 33 | function string2buf(str) { 34 | let buf, 35 | c, 36 | c2, 37 | mPos, 38 | i, 39 | bufLen = 0; 40 | 41 | const strLen = str.length; 42 | 43 | // count binary size 44 | for (mPos = 0; mPos < strLen; mPos++) { 45 | c = str.charCodeAt(mPos); 46 | if ((c & 0xfc00) === 0xd800 && mPos + 1 < strLen) { 47 | c2 = str.charCodeAt(mPos + 1); 48 | if ((c2 & 0xfc00) === 0xdc00) { 49 | c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); 50 | mPos++; 51 | } 52 | } 53 | bufLen += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; 54 | } 55 | 56 | // allocate buffer 57 | if (support.uint8array) { 58 | buf = new Uint8Array(bufLen); 59 | } else { 60 | buf = new Array(bufLen); 61 | } 62 | 63 | // convert 64 | for (i = 0, mPos = 0; i < bufLen; mPos++) { 65 | c = str.charCodeAt(mPos); 66 | if ((c & 0xfc00) === 0xd800 && mPos + 1 < strLen) { 67 | c2 = str.charCodeAt(mPos + 1); 68 | if ((c2 & 0xfc00) === 0xdc00) { 69 | c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); 70 | mPos++; 71 | } 72 | } 73 | if (c < 0x80) { 74 | /* one byte */ 75 | buf[i++] = c; 76 | } else if (c < 0x800) { 77 | /* two bytes */ 78 | buf[i++] = 0xc0 | (c >>> 6); 79 | buf[i++] = 0x80 | (c & 0x3f); 80 | } else if (c < 0x10000) { 81 | /* three bytes */ 82 | buf[i++] = 0xe0 | (c >>> 12); 83 | buf[i++] = 0x80 | ((c >>> 6) & 0x3f); 84 | buf[i++] = 0x80 | (c & 0x3f); 85 | } else { 86 | /* four bytes */ 87 | buf[i++] = 0xf0 | (c >>> 18); 88 | buf[i++] = 0x80 | ((c >>> 12) & 0x3f); 89 | buf[i++] = 0x80 | ((c >>> 6) & 0x3f); 90 | buf[i++] = 0x80 | (c & 0x3f); 91 | } 92 | } 93 | 94 | return buf; 95 | } 96 | 97 | // Calculate max possible position in utf8 buffer, 98 | // that will not break sequence. If that's not possible 99 | // - (very small limits) return max size as is. 100 | // 101 | // buf[] - utf8 bytes array 102 | // max - length limit (mandatory); 103 | function utf8border(buf, max) { 104 | let pos; 105 | 106 | max = max || buf.length; 107 | if (max > buf.length) { 108 | max = buf.length; 109 | } 110 | 111 | // go back from last position, until start of sequence found 112 | pos = max - 1; 113 | while (pos >= 0 && (buf[pos] & 0xc0) === 0x80) { 114 | pos--; 115 | } 116 | 117 | // Fuckup - very small and broken sequence, 118 | // return max, because we should return something anyway. 119 | if (pos < 0) { 120 | return max; 121 | } 122 | 123 | // If we came to start of buffer - that means vuffer is too small, 124 | // return max too. 125 | if (pos === 0) { 126 | return max; 127 | } 128 | 129 | return pos + _utf8len[buf[pos]] > max ? pos : max; 130 | } 131 | 132 | // convert array to string 133 | function buf2string(buf) { 134 | let i, out, c, cLen; 135 | const len = buf.length; 136 | 137 | // Reserve max possible length (2 words per char) 138 | // NB: by unknown reasons, Array is significantly faster for 139 | // String.fromCharCode.apply than Uint16Array. 140 | let utf16buf = new Array(len * 2); 141 | 142 | for (out = 0, i = 0; i < len; ) { 143 | c = buf[i++]; 144 | // quick process ascii 145 | if (c < 0x80) { 146 | utf16buf[out++] = c; 147 | continue; 148 | } 149 | 150 | cLen = _utf8len[c]; 151 | // skip 5 & 6 byte codes 152 | if (cLen > 4) { 153 | utf16buf[out++] = 0xfffd; 154 | i += cLen - 1; 155 | continue; 156 | } 157 | 158 | // apply mask on first byte 159 | c &= cLen === 2 ? 0x1f : cLen === 3 ? 0x0f : 0x07; 160 | // join the rest 161 | while (cLen > 1 && i < len) { 162 | c = (c << 6) | (buf[i++] & 0x3f); 163 | cLen--; 164 | } 165 | 166 | // terminated by end of string? 167 | if (cLen > 1) { 168 | utf16buf[out++] = 0xfffd; 169 | continue; 170 | } 171 | 172 | if (c < 0x10000) { 173 | utf16buf[out++] = c; 174 | } else { 175 | c -= 0x10000; 176 | utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); 177 | utf16buf[out++] = 0xdc00 | (c & 0x3ff); 178 | } 179 | } 180 | 181 | // shrinkBuf(utf16buf, out) 182 | if (utf16buf.length !== out) { 183 | if (utf16buf.subarray) { 184 | utf16buf = utf16buf.subarray(0, out); 185 | } else { 186 | utf16buf.length = out; 187 | } 188 | } 189 | 190 | // return String.fromCharCode.apply(null, utf16buf); 191 | return utils.applyFromCharCode(utf16buf); 192 | } 193 | 194 | // That's all for the pako functions. 195 | 196 | /** 197 | * Transform a javascript string into an array (typed if possible) of bytes, 198 | * UTF-8 encoded. 199 | * @param {String} str the string to encode 200 | * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string. 201 | */ 202 | exports.utf8encode = function utf8encode(str) { 203 | if (support.nodebuffer) { 204 | return nodeBuffer(str, "utf-8"); 205 | } 206 | 207 | return string2buf(str); 208 | }; 209 | 210 | /** 211 | * Transform a bytes array (or a representation) representing an UTF-8 encoded 212 | * string into a javascript string. 213 | * @param {Array|Uint8Array|Buffer} buf the data de decode 214 | * @return {String} the decoded string. 215 | */ 216 | exports.utf8decode = function utf8decode(buf) { 217 | if (support.nodebuffer) { 218 | return utils.transformTo("nodebuffer", buf).toString("utf-8"); 219 | } 220 | 221 | buf = utils.transformTo(support.uint8array ? "uint8array" : "array", buf); 222 | 223 | // return buf2string(buf); 224 | // Chrome prefers to work with "small" chunks of data 225 | // for the method buf2string. 226 | // Firefox and Chrome has their own shortcut, IE doesn't seem to really care. 227 | const result = [], 228 | len = buf.length, 229 | chunk = 65536; 230 | let k = 0; 231 | while (k < len) { 232 | const nextBoundary = utf8border(buf, Math.min(k + chunk, len)); 233 | if (support.uint8array) { 234 | result.push(buf2string(buf.subarray(k, nextBoundary))); 235 | } else { 236 | result.push(buf2string(buf.slice(k, nextBoundary))); 237 | } 238 | k = nextBoundary; 239 | } 240 | return result.join(""); 241 | }; 242 | -------------------------------------------------------------------------------- /es6/utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const support = require("./support.js"); 3 | const compressions = require("./compressions.js"); 4 | const nodeBuffer = require("./nodeBuffer.js"); 5 | /** 6 | * Convert a string to a "binary string" : a string containing only char codes between 0 and 255. 7 | * @param {string} str the string to transform. 8 | * @return {String} the binary string. 9 | */ 10 | exports.string2binary = function (str) { 11 | let result = ""; 12 | for (let i = 0; i < str.length; i++) { 13 | result += String.fromCharCode(str.charCodeAt(i) & 0xff); 14 | } 15 | return result; 16 | }; 17 | exports.arrayBuffer2Blob = function (buffer, mimeType) { 18 | exports.checkSupport("blob"); 19 | mimeType = mimeType || "application/zip"; 20 | 21 | try { 22 | // Blob constructor 23 | return new Blob([buffer], { 24 | type: mimeType, 25 | }); 26 | } catch { 27 | try { 28 | // deprecated, browser only, old way 29 | const Builder = 30 | window.BlobBuilder || 31 | window.WebKitBlobBuilder || 32 | window.MozBlobBuilder || 33 | window.MSBlobBuilder; 34 | const builder = new Builder(); 35 | builder.append(buffer); 36 | return builder.getBlob(mimeType); 37 | } catch { 38 | // well, fuck ?! 39 | throw new Error("Bug : can't construct the Blob."); 40 | } 41 | } 42 | }; 43 | /** 44 | * The identity function. 45 | * @param {Object} input the input. 46 | * @return {Object} the same input. 47 | */ 48 | function identity(input) { 49 | return input; 50 | } 51 | 52 | /** 53 | * Fill in an array with a string. 54 | * @param {String} str the string to use. 55 | * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated). 56 | * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array. 57 | */ 58 | function stringToArrayLike(str, array) { 59 | for (let i = 0; i < str.length; ++i) { 60 | array[i] = str.charCodeAt(i) & 0xff; 61 | } 62 | return array; 63 | } 64 | 65 | /** 66 | * Transform an array-like object to a string. 67 | * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform. 68 | * @return {String} the result. 69 | */ 70 | function arrayLikeToString(array) { 71 | // Performances notes : 72 | // -------------------- 73 | // String.fromCharCode.apply(null, array) is the fastest, see 74 | // see http://jsperf.com/converting-a-uint8array-to-a-string/2 75 | // but the stack is limited (and we can get huge arrays !). 76 | // 77 | // result += String.fromCharCode(array[i]); generate too many strings ! 78 | // 79 | // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2 80 | let chunk = 65536; 81 | const result = [], 82 | len = array.length, 83 | type = exports.getTypeOf(array); 84 | let k = 0, 85 | canUseApply = true; 86 | try { 87 | switch (type) { 88 | case "uint8array": 89 | String.fromCharCode.apply(null, new Uint8Array(0)); 90 | break; 91 | case "nodebuffer": 92 | String.fromCharCode.apply(null, nodeBuffer(0)); 93 | break; 94 | } 95 | } catch { 96 | canUseApply = false; 97 | } 98 | 99 | // no apply : slow and painful algorithm 100 | // default browser on android 4.* 101 | if (!canUseApply) { 102 | let resultStr = ""; 103 | for (let i = 0; i < array.length; i++) { 104 | resultStr += String.fromCharCode(array[i]); 105 | } 106 | return resultStr; 107 | } 108 | while (k < len && chunk > 1) { 109 | try { 110 | if (type === "array" || type === "nodebuffer") { 111 | result.push( 112 | String.fromCharCode.apply( 113 | null, 114 | array.slice(k, Math.min(k + chunk, len)) 115 | ) 116 | ); 117 | } else { 118 | result.push( 119 | String.fromCharCode.apply( 120 | null, 121 | array.subarray(k, Math.min(k + chunk, len)) 122 | ) 123 | ); 124 | } 125 | k += chunk; 126 | } catch { 127 | chunk = Math.floor(chunk / 2); 128 | } 129 | } 130 | return result.join(""); 131 | } 132 | 133 | exports.applyFromCharCode = arrayLikeToString; 134 | 135 | /** 136 | * Copy the data from an array-like to an other array-like. 137 | * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array. 138 | * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated. 139 | * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array. 140 | */ 141 | function arrayLikeToArrayLike(arrayFrom, arrayTo) { 142 | for (let i = 0; i < arrayFrom.length; i++) { 143 | arrayTo[i] = arrayFrom[i]; 144 | } 145 | return arrayTo; 146 | } 147 | 148 | // a matrix containing functions to transform everything into everything. 149 | const transform = {}; 150 | 151 | // string to ? 152 | transform.string = { 153 | string: identity, 154 | array(input) { 155 | return stringToArrayLike(input, new Array(input.length)); 156 | }, 157 | arraybuffer(input) { 158 | return transform.string.uint8array(input).buffer; 159 | }, 160 | uint8array(input) { 161 | return stringToArrayLike(input, new Uint8Array(input.length)); 162 | }, 163 | nodebuffer(input) { 164 | return stringToArrayLike(input, nodeBuffer(input.length)); 165 | }, 166 | }; 167 | 168 | // array to ? 169 | transform.array = { 170 | string: arrayLikeToString, 171 | array: identity, 172 | arraybuffer(input) { 173 | return new Uint8Array(input).buffer; 174 | }, 175 | uint8array(input) { 176 | return new Uint8Array(input); 177 | }, 178 | nodebuffer(input) { 179 | return nodeBuffer(input); 180 | }, 181 | }; 182 | 183 | // arraybuffer to ? 184 | transform.arraybuffer = { 185 | string(input) { 186 | return arrayLikeToString(new Uint8Array(input)); 187 | }, 188 | array(input) { 189 | return arrayLikeToArrayLike( 190 | new Uint8Array(input), 191 | new Array(input.byteLength) 192 | ); 193 | }, 194 | arraybuffer: identity, 195 | uint8array(input) { 196 | return new Uint8Array(input); 197 | }, 198 | nodebuffer(input) { 199 | return nodeBuffer(new Uint8Array(input)); 200 | }, 201 | }; 202 | 203 | // uint8array to ? 204 | transform.uint8array = { 205 | string: arrayLikeToString, 206 | array(input) { 207 | return arrayLikeToArrayLike(input, new Array(input.length)); 208 | }, 209 | arraybuffer(input) { 210 | return input.buffer; 211 | }, 212 | uint8array: identity, 213 | nodebuffer(input) { 214 | return nodeBuffer(input); 215 | }, 216 | }; 217 | 218 | // nodebuffer to ? 219 | transform.nodebuffer = { 220 | string: arrayLikeToString, 221 | array(input) { 222 | return arrayLikeToArrayLike(input, new Array(input.length)); 223 | }, 224 | arraybuffer(input) { 225 | return transform.nodebuffer.uint8array(input).buffer; 226 | }, 227 | uint8array(input) { 228 | return arrayLikeToArrayLike(input, new Uint8Array(input.length)); 229 | }, 230 | nodebuffer: identity, 231 | }; 232 | 233 | /** 234 | * Transform an input into any type. 235 | * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer. 236 | * If no output type is specified, the unmodified input will be returned. 237 | * @param {String} outputType the output type. 238 | * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert. 239 | * @throws {Error} an Error if the browser doesn't support the requested output type. 240 | */ 241 | exports.transformTo = function (outputType, input) { 242 | if (!input) { 243 | // undefined, null, etc 244 | // an empty string won't harm. 245 | input = ""; 246 | } 247 | if (!outputType) { 248 | return input; 249 | } 250 | exports.checkSupport(outputType); 251 | const inputType = exports.getTypeOf(input); 252 | const result = transform[inputType][outputType](input); 253 | return result; 254 | }; 255 | 256 | /** 257 | * Return the type of the input. 258 | * The type will be in a format valid for PizZip.utils.transformTo : string, array, uint8array, arraybuffer. 259 | * @param {Object} input the input to identify. 260 | * @return {String} the (lowercase) type of the input. 261 | */ 262 | exports.getTypeOf = function (input) { 263 | if (input == null) { 264 | return; 265 | } 266 | if (typeof input === "string") { 267 | return "string"; 268 | } 269 | const protoResult = Object.prototype.toString.call(input); 270 | if (protoResult === "[object Array]") { 271 | return "array"; 272 | } 273 | if (support.nodebuffer && nodeBuffer.test(input)) { 274 | return "nodebuffer"; 275 | } 276 | if (support.uint8array && protoResult === "[object Uint8Array]") { 277 | return "uint8array"; 278 | } 279 | if (support.arraybuffer && protoResult === "[object ArrayBuffer]") { 280 | return "arraybuffer"; 281 | } 282 | if (protoResult === "[object Promise]") { 283 | throw new Error( 284 | "Cannot read data from a promise, you probably are running new PizZip(data) with a promise" 285 | ); 286 | } 287 | if (typeof input === "object" && typeof input.file === "function") { 288 | throw new Error( 289 | "Cannot read data from a pizzip instance, you probably are running new PizZip(zip) with a zipinstance" 290 | ); 291 | } 292 | if (protoResult === "[object Date]") { 293 | throw new Error( 294 | "Cannot read data from a Date, you probably are running new PizZip(data) with a date" 295 | ); 296 | } 297 | if (typeof input === "object" && input.crc32 == null) { 298 | throw new Error( 299 | "Unsupported data given to new PizZip(data) (object given)" 300 | ); 301 | } 302 | }; 303 | 304 | /** 305 | * Throw an exception if the type is not supported. 306 | * @param {String} type the type to check. 307 | * @throws {Error} an Error if the browser doesn't support the requested type. 308 | */ 309 | exports.checkSupport = function (type) { 310 | const supported = support[type.toLowerCase()]; 311 | if (!supported) { 312 | throw new Error(type + " is not supported by this browser"); 313 | } 314 | }; 315 | exports.MAX_VALUE_16BITS = 65535; 316 | exports.MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1 317 | 318 | /** 319 | * Prettify a string read as binary. 320 | * @param {string} str the string to prettify. 321 | * @return {string} a pretty string. 322 | */ 323 | exports.pretty = function (str) { 324 | let res = "", 325 | code, 326 | i; 327 | for (i = 0; i < (str || "").length; i++) { 328 | code = str.charCodeAt(i); 329 | res += "\\x" + (code < 16 ? "0" : "") + code.toString(16).toUpperCase(); 330 | } 331 | return res; 332 | }; 333 | 334 | /** 335 | * Find a compression registered in PizZip. 336 | * @param {string} compressionMethod the method magic to find. 337 | * @return {Object|null} the PizZip compression object, null if none found. 338 | */ 339 | exports.findCompression = function (compressionMethod) { 340 | for (const method in compressions) { 341 | if (!compressions.hasOwnProperty(method)) { 342 | continue; 343 | } 344 | if (compressions[method].magic === compressionMethod) { 345 | return compressions[method]; 346 | } 347 | } 348 | return null; 349 | }; 350 | /** 351 | * Cross-window, cross-Node-context regular expression detection 352 | * @param {Object} object Anything 353 | * @return {Boolean} true if the object is a regular expression, 354 | * false otherwise 355 | */ 356 | exports.isRegExp = function (object) { 357 | return Object.prototype.toString.call(object) === "[object RegExp]"; 358 | }; 359 | 360 | /** 361 | * Merge the objects passed as parameters into a new one. 362 | * @private 363 | * @param {...Object} var_args All objects to merge. 364 | * @return {Object} a new object with the data of the others. 365 | */ 366 | exports.extend = function () { 367 | const result = {}; 368 | let i, attr; 369 | for (i = 0; i < arguments.length; i++) { 370 | // arguments is not enumerable in some browsers 371 | for (attr in arguments[i]) { 372 | if ( 373 | arguments[i].hasOwnProperty(attr) && 374 | typeof result[attr] === "undefined" 375 | ) { 376 | result[attr] = arguments[i][attr]; 377 | } 378 | } 379 | } 380 | return result; 381 | }; 382 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import globals from "globals"; 2 | import parser from "@babel/eslint-parser"; 3 | import importPlugin from "eslint-plugin-import"; 4 | // import specificSortPlugin from "eslint-plugin-specific-sort"; 5 | // import sortClassMembers from "eslint-plugin-sort-class-members"; 6 | // import stylisticJs from "@stylistic/eslint-plugin-js"; 7 | 8 | export default [ 9 | { 10 | ignores: [ 11 | "**/.edb-*", 12 | "*.sublime-project", 13 | "*.sublime-workspace", 14 | "npm-debug.log", 15 | "node_modules/", 16 | "**/node_modules/**", 17 | ".eslint-rules/", 18 | "node_modules/**", 19 | ".idea", 20 | "test/spec/output.docx", 21 | "/output.docx", 22 | "tags", 23 | "/docs/build", 24 | "*.spec.js", 25 | "*.spec.map", 26 | "*.log", 27 | "/js", 28 | "es6/tests/filenames.js", 29 | "es6/tests/__snapshots.js", 30 | "/build", 31 | "/browser", 32 | "/browser-demo", 33 | "examples/index.html", 34 | "*.es5", 35 | ".babel.json", 36 | "browser/", 37 | "build/", 38 | "vendor/", 39 | "js/", 40 | "test/", 41 | "coverage/", 42 | "prof/", 43 | ".git", 44 | "text.js", 45 | ], 46 | }, 47 | { 48 | languageOptions: { 49 | parserOptions: { 50 | ecmaVersion: 7, 51 | }, 52 | parser, 53 | globals: { 54 | Uint8Array: true, 55 | saveAs: true, 56 | Promise: true, 57 | Proxy: true, 58 | PizZipUtils: true, 59 | ArrayBuffer: true, 60 | ...globals.node, 61 | ...globals.browser, 62 | ...globals.mocha, 63 | }, 64 | }, 65 | plugins: { 66 | import: importPlugin, 67 | }, 68 | rules: { 69 | "accessor-pairs": 2, 70 | "array-bracket-spacing": [2, "never"], 71 | "arrow-parens": 0, 72 | "arrow-spacing": [2, { before: true, after: true }], 73 | "block-scoped-var": 2, 74 | "block-spacing": [2, "always"], 75 | "brace-style": 0, 76 | "callback-return": 2, 77 | camelcase: [2, { properties: "never" }], 78 | "comma-dangle": [ 79 | 2, 80 | { 81 | functions: "never", 82 | arrays: "only-multiline", 83 | objects: "only-multiline", 84 | imports: "only-multiline", 85 | exports: "only-multiline", 86 | }, 87 | ], 88 | "comma-spacing": [2, { before: false, after: true }], 89 | "comma-style": [2, "last"], 90 | complexity: [2, 50], 91 | "computed-property-spacing": [2, "never"], 92 | "consistent-return": 0, 93 | "consistent-this": [2, "self"], 94 | "constructor-super": 2, 95 | curly: [2, "all"], 96 | "default-case": 0, 97 | "import/no-cycle": 2, 98 | "import/no-unresolved": 2, 99 | "import/extensions": [2, "always"], 100 | "dot-location": [2, "property"], 101 | "dot-notation": 2, 102 | "eol-last": 2, 103 | eqeqeq: [2, "smart"], 104 | "func-names": 0, 105 | "func-style": [2, "declaration"], 106 | "generator-star-spacing": [2, { before: false, after: true }], 107 | "global-require": 0, 108 | "guard-for-in": 2, 109 | "handle-callback-err": 2, 110 | "id-length": 0, 111 | "id-match": 0, 112 | "init-declarations": 0, 113 | "key-spacing": [ 114 | 2, 115 | { beforeColon: false, afterColon: true, mode: "strict" }, 116 | ], 117 | "linebreak-style": 0, 118 | "lines-around-comment": 0, 119 | "max-nested-callbacks": 0, 120 | "new-cap": [ 121 | 2, 122 | { 123 | newIsCapExceptions: [ 124 | "Boom.badRequest", 125 | "Boom.forbidden", 126 | "Boom.unauthorized", 127 | "Boom.wrap", 128 | ], 129 | capIsNewExceptions: ["squeeze.Squeeze"], 130 | }, 131 | ], 132 | "new-parens": 2, 133 | "newline-after-var": 0, 134 | "no-alert": 2, 135 | "no-array-constructor": 2, 136 | "no-caller": 2, 137 | "no-catch-shadow": 0, 138 | "no-class-assign": 2, 139 | "no-console": 2, 140 | "no-const-assign": 2, 141 | "no-constant-condition": [2, { checkLoops: false }], 142 | "no-continue": 0, 143 | "no-control-regex": 0, 144 | "no-debugger": 2, 145 | "no-delete-var": 2, 146 | "no-div-regex": 2, 147 | "no-dupe-args": 2, 148 | "no-dupe-class-members": 2, 149 | "no-dupe-keys": 2, 150 | "no-duplicate-case": 2, 151 | "no-else-return": 2, 152 | "no-empty": 2, 153 | "no-empty-character-class": 2, 154 | "no-eval": 2, 155 | "no-ex-assign": 2, 156 | "no-extend-native": 2, 157 | "no-extra-bind": 2, 158 | "no-extra-boolean-cast": 2, 159 | "no-extra-parens": [2, "functions"], 160 | "no-extra-semi": 2, 161 | "no-fallthrough": 2, 162 | "no-floating-decimal": 2, 163 | "no-func-assign": 2, 164 | "no-implicit-coercion": 0, 165 | "no-implied-eval": 2, 166 | "no-inline-comments": 0, 167 | "no-inner-declarations": 2, 168 | "no-invalid-regexp": 2, 169 | "no-iterator": 2, 170 | "no-label-var": 2, 171 | "no-labels": 0, 172 | "no-lone-blocks": 2, 173 | "no-lonely-if": 2, 174 | "no-loop-func": 2, 175 | "no-mixed-requires": 2, 176 | "no-multi-str": 2, 177 | "no-multiple-empty-lines": [2, { max: 1 }], 178 | "no-native-reassign": 2, 179 | "no-negated-in-lhs": 2, 180 | "no-new": 2, 181 | "no-new-func": 2, 182 | "no-new-object": 2, 183 | "no-new-require": 2, 184 | "no-new-wrappers": 2, 185 | "no-obj-calls": 2, 186 | "no-octal": 2, 187 | "no-octal-escape": 2, 188 | "no-param-reassign": 0, 189 | "no-path-concat": 2, 190 | "no-process-env": 2, 191 | "no-process-exit": 2, 192 | "no-proto": 2, 193 | "no-redeclare": 2, 194 | "no-restricted-modules": 0, 195 | "no-restricted-syntax": 0, 196 | "no-return-assign": 0, 197 | "no-script-url": 2, 198 | "no-self-compare": 2, 199 | "no-sequences": 2, 200 | "no-shadow": 0, 201 | "no-shadow-restricted-names": 2, 202 | "no-sparse-arrays": 2, 203 | "no-ternary": 0, 204 | "no-this-before-super": 2, 205 | "no-throw-literal": 2, 206 | "no-undef": 2, 207 | "no-undef-init": 0, 208 | "no-undefined": 0, 209 | "no-underscore-dangle": 0, 210 | "no-unexpected-multiline": 2, 211 | "no-unneeded-ternary": 2, 212 | "no-unreachable": 2, 213 | "no-unused-expressions": 2, 214 | "no-unused-vars": 2, 215 | "no-use-before-define": [2, "nofunc"], 216 | "no-useless-call": 2, 217 | "no-useless-concat": 2, 218 | "no-var": 2, 219 | "no-void": 2, 220 | "no-warning-comments": [ 221 | 2, 222 | { terms: ["todo", "fixme"], location: "anywhere" }, 223 | ], 224 | "no-with": 2, 225 | "object-curly-spacing": 0, 226 | "object-shorthand": 2, 227 | "one-var": 0, 228 | "operator-assignment": [2, "always"], 229 | "operator-linebreak": 0, 230 | "padded-blocks": [2, "never"], 231 | "prefer-arrow-callback": 0, 232 | "prefer-const": 2, 233 | "prefer-destructuring": [ 234 | 2, 235 | { 236 | AssignmentExpression: { 237 | array: true, 238 | object: false, 239 | }, 240 | }, 241 | ], 242 | "prefer-reflect": 0, 243 | "prefer-spread": 0, 244 | "prefer-template": 0, 245 | quotes: [2, "double", { avoidEscape: true }], 246 | "quote-props": [2, "as-needed"], 247 | radix: 2, 248 | "require-jsdoc": 0, 249 | "require-yield": 2, 250 | semi: [2, "always"], 251 | "semi-spacing": [2, { before: false, after: true }], 252 | "sort-vars": 0, 253 | "use-isnan": 2, 254 | "valid-jsdoc": 0, 255 | "valid-typeof": 2, 256 | "vars-on-top": 0, 257 | "wrap-iife": [2, "inside"], 258 | "wrap-regex": 0, 259 | yoda: [2, "never"], 260 | }, 261 | }, 262 | ]; 263 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pizzip 3 | layout: default 4 | section: main 5 | --- 6 | 7 |
8 |
9 | 10 | PizZip is a javascript library for creating, reading and editing .zip files, with a 11 | lovely and simple API. 12 | 13 |
14 |
15 |

16 | Current version : v2.6.1 17 |

18 |

19 | License : PizZip is dual-licensed. You may use it under the 20 | MIT license or the GPLv3 license. See 21 | LICENSE.markdown. 22 |

23 |
24 | 25 |
26 |
27 | 28 |

Example

29 | 30 | 57 | 65 | 66 | 67 | 71 |
72 |
73 | 74 |

Installation

75 | 76 |

77 | With npm : npm install pizzip 78 |

79 |

80 | Manually : download PizZip 81 | and include the file dist/pizzip.js or dist/pizzip.min.js 82 |

83 |
84 |

85 | Installed ? Great ! You can now check our 86 | guides and examples ! 87 |

88 |
89 |
90 | 91 |

Support

92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 |
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
119 | 120 |

Getting help

121 | 122 |

123 | Having trouble ? We'd like to help ! 124 |

125 |
    126 |
  • 127 | Try the FAQ, it has 128 | answers to common questions. 129 |
  • 130 |
  • 131 | If you're looking for informations about a specific method, try the 132 | documentation. 133 |
  • 134 |
  • 135 | Check the 136 | examples. 137 |
  • 138 |
  • 139 | Report bugs in our 140 | Bug tracker. 141 |
  • 142 |
143 | 144 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pizzip", 3 | "version": "3.2.0", 4 | "author": "Edgar Hipp", 5 | "description": "Create, read and edit .zip files synchronously with Javascript", 6 | "scripts": { 7 | "lint:fix": "npm run prettier:fix && npm run eslint:fix", 8 | "eslint:fix": "eslint --cache 'es6/**/*.js' --fix", 9 | "prettier:fix": "prettier --cache --write '*.js' 'es6/**/*.js' 'test/test.js' test/node.js 'utils/*.js' 'utils/es6/**/*.js' 'documentation/**.md'", 10 | "browserify:lib": "webpack", 11 | "babel": "babel es6 --out-dir js", 12 | "babel:watch": "npm run babel -- --watch", 13 | "build": "npm run browserify:lib && npm run browserify:lib:min", 14 | "browserify:lib:min": "cross-env MIN=true webpack", 15 | "preversion": "npm run babel && npm run build && npm test && npm run utils:build && cp utils/dist/* dist && npm run test:typings", 16 | "test": "mocha test/test.js", 17 | "test:watch": "mocha test/test.js --watch", 18 | "test:typings": "cp es6/*.ts js && tsd js && tsd utils", 19 | "utils:build": "cd utils && cross-env MIN=true ../node_modules/.bin/webpack && ../node_modules/.bin/webpack && IE=true cross-env MIN=true ../node_modules/.bin/webpack && IE=true ../node_modules/.bin/webpack" 20 | }, 21 | "contributors": [ 22 | { 23 | "name": "Stuart Knightley" 24 | }, 25 | { 26 | "name": "Franz Buchinger" 27 | }, 28 | { 29 | "name": "António Afonso" 30 | }, 31 | { 32 | "name": "David Duponchel" 33 | }, 34 | { 35 | "name": "yiminghe" 36 | }, 37 | { 38 | "name": "Edgar Hipp" 39 | } 40 | ], 41 | "main": "./js/index.js", 42 | "repository": { 43 | "type": "git", 44 | "url": "https://github.com/open-xml-templating/pizzip" 45 | }, 46 | "keywords": [ 47 | "zip", 48 | "deflate", 49 | "inflate" 50 | ], 51 | "devDependencies": { 52 | "@babel/cli": "^7.27.1", 53 | "@babel/core": "^7.27.1", 54 | "@babel/eslint-parser": "^7.27.1", 55 | "@babel/plugin-proposal-object-rest-spread": "^7.20.7", 56 | "@babel/preset-env": "^7.27.1", 57 | "acorn": "^8.14.1", 58 | "babel-loader": "^10.0.0", 59 | "chai": "^5.2.0", 60 | "cross-env": "^7.0.3", 61 | "eslint": "^9.26.0", 62 | "eslint_d": "^14.3.0", 63 | "eslint-plugin-import": "^2.31.0", 64 | "globals": "^16.0.0", 65 | "mocha": "^11.2.2", 66 | "prettier": "^3.5.3", 67 | "tsd": "^0.32.0", 68 | "webpack": "^5.99.7", 69 | "webpack-cli": "^6.0.1" 70 | }, 71 | "dependencies": { 72 | "pako": "^2.1.0" 73 | }, 74 | "license": "(MIT OR GPL-3.0)" 75 | } 76 | -------------------------------------------------------------------------------- /symlink.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | rm -rf utils/node_modules 4 | cp -r node_modules utils/node_modules 5 | -------------------------------------------------------------------------------- /test/browser-test-utils.js: -------------------------------------------------------------------------------- 1 | const PizZipTestUtils = { 2 | loadZipFile (name, callback) { 3 | PizZipUtils.getBinaryContent(name + "?_=" + (new Date()).getTime(), callback); 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PizZip Testing 6 | 7 | 8 | 9 | 10 | 11 | 47 | 48 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
63 |
64 | 65 | 66 | -------------------------------------------------------------------------------- /test/node.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | global.PizZip = require("../es6/index"); 4 | 5 | global.PizZipTestUtils = { 6 | loadZipFile(name, callback) { 7 | fs.readFile(name, "binary", callback); 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /test/qunit-1.11.0.css: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit v1.11.0 - A JavaScript Unit Testing Framework 3 | * 4 | * http://qunitjs.com 5 | * 6 | * Copyright 2012 jQuery Foundation and other contributors 7 | * Released under the MIT license. 8 | * http://jquery.org/license 9 | */ 10 | 11 | /** Font Family and Sizes */ 12 | 13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 15 | } 16 | 17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 18 | #qunit-tests { font-size: smaller; } 19 | 20 | 21 | /** Resets */ 22 | 23 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { 24 | margin: 0; 25 | padding: 0; 26 | } 27 | 28 | 29 | /** Header */ 30 | 31 | #qunit-header { 32 | padding: 0.5em 0 0.5em 1em; 33 | 34 | color: #8699a4; 35 | background-color: #0d3349; 36 | 37 | font-size: 1.5em; 38 | line-height: 1em; 39 | font-weight: normal; 40 | 41 | border-radius: 5px 5px 0 0; 42 | -moz-border-radius: 5px 5px 0 0; 43 | -webkit-border-top-right-radius: 5px; 44 | -webkit-border-top-left-radius: 5px; 45 | } 46 | 47 | #qunit-header a { 48 | text-decoration: none; 49 | color: #c2ccd1; 50 | } 51 | 52 | #qunit-header a:hover, 53 | #qunit-header a:focus { 54 | color: #fff; 55 | } 56 | 57 | #qunit-testrunner-toolbar label { 58 | display: inline-block; 59 | padding: 0 .5em 0 .1em; 60 | } 61 | 62 | #qunit-banner { 63 | height: 5px; 64 | } 65 | 66 | #qunit-testrunner-toolbar { 67 | padding: 0.5em 0 0.5em 2em; 68 | color: #5E740B; 69 | background-color: #eee; 70 | overflow: hidden; 71 | } 72 | 73 | #qunit-userAgent { 74 | padding: 0.5em 0 0.5em 2.5em; 75 | background-color: #2b81af; 76 | color: #fff; 77 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 78 | } 79 | 80 | #qunit-modulefilter-container { 81 | float: right; 82 | } 83 | 84 | /** Tests: Pass/Fail */ 85 | 86 | #qunit-tests { 87 | list-style-position: inside; 88 | } 89 | 90 | #qunit-tests li { 91 | padding: 0.4em 0.5em 0.4em 2.5em; 92 | border-bottom: 1px solid #fff; 93 | list-style-position: inside; 94 | } 95 | 96 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 97 | display: none; 98 | } 99 | 100 | #qunit-tests li strong { 101 | cursor: pointer; 102 | } 103 | 104 | #qunit-tests li a { 105 | padding: 0.5em; 106 | color: #c2ccd1; 107 | text-decoration: none; 108 | } 109 | #qunit-tests li a:hover, 110 | #qunit-tests li a:focus { 111 | color: #000; 112 | } 113 | 114 | #qunit-tests li .runtime { 115 | float: right; 116 | font-size: smaller; 117 | } 118 | 119 | .qunit-assert-list { 120 | margin-top: 0.5em; 121 | padding: 0.5em; 122 | 123 | background-color: #fff; 124 | 125 | border-radius: 5px; 126 | -moz-border-radius: 5px; 127 | -webkit-border-radius: 5px; 128 | } 129 | 130 | .qunit-collapsed { 131 | display: none; 132 | } 133 | 134 | #qunit-tests table { 135 | border-collapse: collapse; 136 | margin-top: .2em; 137 | } 138 | 139 | #qunit-tests th { 140 | text-align: right; 141 | vertical-align: top; 142 | padding: 0 .5em 0 0; 143 | } 144 | 145 | #qunit-tests td { 146 | vertical-align: top; 147 | } 148 | 149 | #qunit-tests pre { 150 | margin: 0; 151 | white-space: pre-wrap; 152 | word-wrap: break-word; 153 | } 154 | 155 | #qunit-tests del { 156 | background-color: #e0f2be; 157 | color: #374e0c; 158 | text-decoration: none; 159 | } 160 | 161 | #qunit-tests ins { 162 | background-color: #ffcaca; 163 | color: #500; 164 | text-decoration: none; 165 | } 166 | 167 | /*** Test Counts */ 168 | 169 | #qunit-tests b.counts { color: black; } 170 | #qunit-tests b.passed { color: #5E740B; } 171 | #qunit-tests b.failed { color: #710909; } 172 | 173 | #qunit-tests li li { 174 | padding: 5px; 175 | background-color: #fff; 176 | border-bottom: none; 177 | list-style-position: inside; 178 | } 179 | 180 | /*** Passing Styles */ 181 | 182 | #qunit-tests li li.pass { 183 | color: #3c510c; 184 | background-color: #fff; 185 | border-left: 10px solid #C6E746; 186 | } 187 | 188 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 189 | #qunit-tests .pass .test-name { color: #366097; } 190 | 191 | #qunit-tests .pass .test-actual, 192 | #qunit-tests .pass .test-expected { color: #999999; } 193 | 194 | #qunit-banner.qunit-pass { background-color: #C6E746; } 195 | 196 | /*** Failing Styles */ 197 | 198 | #qunit-tests li li.fail { 199 | color: #710909; 200 | background-color: #fff; 201 | border-left: 10px solid #EE5757; 202 | white-space: pre; 203 | } 204 | 205 | #qunit-tests > li:last-child { 206 | border-radius: 0 0 5px 5px; 207 | -moz-border-radius: 0 0 5px 5px; 208 | -webkit-border-bottom-right-radius: 5px; 209 | -webkit-border-bottom-left-radius: 5px; 210 | } 211 | 212 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 213 | #qunit-tests .fail .test-name, 214 | #qunit-tests .fail .module-name { color: #000000; } 215 | 216 | #qunit-tests .fail .test-actual { color: #EE5757; } 217 | #qunit-tests .fail .test-expected { color: green; } 218 | 219 | #qunit-banner.qunit-fail { background-color: #EE5757; } 220 | 221 | 222 | /** Result */ 223 | 224 | #qunit-testresult { 225 | padding: 0.5em 0.5em 0.5em 2.5em; 226 | 227 | color: #2b81af; 228 | background-color: #D2E0E6; 229 | 230 | border-bottom: 1px solid white; 231 | } 232 | #qunit-testresult .module-name { 233 | font-weight: bold; 234 | } 235 | 236 | /** Fixture */ 237 | 238 | #qunit-fixture { 239 | position: absolute; 240 | top: -10000px; 241 | left: -10000px; 242 | width: 1000px; 243 | height: 1000px; 244 | } 245 | -------------------------------------------------------------------------------- /test/ref/all.7zip.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/all.7zip.zip -------------------------------------------------------------------------------- /test/ref/all.windows.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/all.windows.zip -------------------------------------------------------------------------------- /test/ref/all.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/all.zip -------------------------------------------------------------------------------- /test/ref/all_appended_bytes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/all_appended_bytes.zip -------------------------------------------------------------------------------- /test/ref/all_missing_bytes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/all_missing_bytes.zip -------------------------------------------------------------------------------- /test/ref/all_prepended_bytes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/all_prepended_bytes.zip -------------------------------------------------------------------------------- /test/ref/archive_comment.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/archive_comment.zip -------------------------------------------------------------------------------- /test/ref/backslash.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/backslash.zip -------------------------------------------------------------------------------- /test/ref/complex_files/AntarcticaTemps.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/complex_files/AntarcticaTemps.ods -------------------------------------------------------------------------------- /test/ref/complex_files/AntarcticaTemps.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/complex_files/AntarcticaTemps.xlsx -------------------------------------------------------------------------------- /test/ref/complex_files/Franz Kafka - The Metamorphosis.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/complex_files/Franz Kafka - The Metamorphosis.epub -------------------------------------------------------------------------------- /test/ref/complex_files/Outlook2007_Calendar.xps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/complex_files/Outlook2007_Calendar.xps -------------------------------------------------------------------------------- /test/ref/data_descriptor.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/data_descriptor.zip -------------------------------------------------------------------------------- /test/ref/deflate.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/deflate.zip -------------------------------------------------------------------------------- /test/ref/encrypted.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/encrypted.zip -------------------------------------------------------------------------------- /test/ref/extra_attributes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/extra_attributes.zip -------------------------------------------------------------------------------- /test/ref/folder.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/folder.zip -------------------------------------------------------------------------------- /test/ref/image.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/image.zip -------------------------------------------------------------------------------- /test/ref/invalid/bad_offset.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/invalid/bad_offset.zip -------------------------------------------------------------------------------- /test/ref/invalid/compression.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/invalid/compression.zip -------------------------------------------------------------------------------- /test/ref/invalid/crc32.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/invalid/crc32.zip -------------------------------------------------------------------------------- /test/ref/local_encoding_in_name.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/local_encoding_in_name.zip -------------------------------------------------------------------------------- /test/ref/nested.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/nested.zip -------------------------------------------------------------------------------- /test/ref/nested_data_descriptor.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/nested_data_descriptor.zip -------------------------------------------------------------------------------- /test/ref/nested_zip64.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/nested_zip64.zip -------------------------------------------------------------------------------- /test/ref/permissions/linux_7z.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/linux_7z.zip -------------------------------------------------------------------------------- /test/ref/permissions/linux_ark.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/linux_ark.zip -------------------------------------------------------------------------------- /test/ref/permissions/linux_file_roller-ubuntu.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/linux_file_roller-ubuntu.zip -------------------------------------------------------------------------------- /test/ref/permissions/linux_file_roller-xubuntu.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/linux_file_roller-xubuntu.zip -------------------------------------------------------------------------------- /test/ref/permissions/linux_zip.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/linux_zip.zip -------------------------------------------------------------------------------- /test/ref/permissions/mac_finder.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/mac_finder.zip -------------------------------------------------------------------------------- /test/ref/permissions/windows_7z.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/windows_7z.zip -------------------------------------------------------------------------------- /test/ref/permissions/windows_compressed_folders.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/windows_compressed_folders.zip -------------------------------------------------------------------------------- /test/ref/permissions/windows_izarc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/windows_izarc.zip -------------------------------------------------------------------------------- /test/ref/permissions/windows_winrar.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/permissions/windows_winrar.zip -------------------------------------------------------------------------------- /test/ref/pile_of_poo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/pile_of_poo.zip -------------------------------------------------------------------------------- /test/ref/slashes_and_izarc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/slashes_and_izarc.zip -------------------------------------------------------------------------------- /test/ref/store.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/store.zip -------------------------------------------------------------------------------- /test/ref/subfolder.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/subfolder.zip -------------------------------------------------------------------------------- /test/ref/text.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/text.zip -------------------------------------------------------------------------------- /test/ref/utf8.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/utf8.zip -------------------------------------------------------------------------------- /test/ref/utf8_in_name.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/utf8_in_name.zip -------------------------------------------------------------------------------- /test/ref/winrar_utf8_in_name.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/winrar_utf8_in_name.zip -------------------------------------------------------------------------------- /test/ref/zip64.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/zip64.zip -------------------------------------------------------------------------------- /test/ref/zip64_appended_bytes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/zip64_appended_bytes.zip -------------------------------------------------------------------------------- /test/ref/zip64_missing_bytes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/zip64_missing_bytes.zip -------------------------------------------------------------------------------- /test/ref/zip64_prepended_bytes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/ref/zip64_prepended_bytes.zip -------------------------------------------------------------------------------- /test/smile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/test/smile.gif -------------------------------------------------------------------------------- /utils/.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test 3 | -------------------------------------------------------------------------------- /utils/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "undef": true, 3 | "strict": true, 4 | "sub": true, 5 | 6 | "globals": { 7 | "TextEncoder": false, 8 | "TextDecoder": false 9 | }, 10 | "browser": true, 11 | "node": true, 12 | "es3": true 13 | } 14 | -------------------------------------------------------------------------------- /utils/.npmignore: -------------------------------------------------------------------------------- 1 | *~ 2 | node_modules 3 | sauce_connect.log 4 | _site 5 | -------------------------------------------------------------------------------- /utils/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | script: npm run $COMMAND 5 | env: 6 | matrix: 7 | - COMMAND=test-browser 8 | global: 9 | - secure: MhA8GHU42X3GWTUMaqdZVvarx4BMjhQCUGNi3kvuD/iCmKVb7gMwj4jbds7AcJdsCRsRk8bBGzZs/E7HidBJMPDa5DhgLKy9EV1s42JlHq8lVzbJeWIGgrtyJvhVUkGRy2OJjnDSgh3U6elkQmvDn74jreSQc6m/yGoPFF1nqq8= 10 | - secure: qREw6aUu2DnB+2reMuHgygSkumRiJvt7Z5Fz4uEVoraqbe65e4PGhtzypr9uIgCN43vxS2D5tAIeDbfid5VQrWFUQnrC9O5Z5qgVPsKN94zZ1tvYurXI4wRlAg58nNjkfGXWhLI3VUjjDTp5gYcMqgfe5hpEFYUPnUQkKGnaqAk= 11 | -------------------------------------------------------------------------------- /utils/CHANGES.md: -------------------------------------------------------------------------------- 1 | v0.0.2 2014-05-19 2 | ================= 3 | 4 | - Drop the code for xhr on `file://` and fix an issue with `file://` to `http://` requests 5 | 6 | v0.0.1 2014-04-27 7 | ================= 8 | 9 | - First release. 10 | -------------------------------------------------------------------------------- /utils/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | const browsers = [ 3 | { 4 | browserName: "iphone", 5 | platform: "OS X 10.8", 6 | version: "6", 7 | }, 8 | { 9 | browserName: "android", 10 | platform: "Linux", 11 | version: "4.0", 12 | }, 13 | { 14 | browserName: "firefox", 15 | platform: "XP", 16 | }, 17 | { 18 | browserName: "chrome", 19 | platform: "XP", 20 | }, 21 | { 22 | browserName: "internet explorer", 23 | platform: "WIN8", 24 | version: "10", 25 | }, 26 | { 27 | browserName: "internet explorer", 28 | platform: "VISTA", 29 | version: "9", 30 | }, 31 | { 32 | browserName: "internet explorer", 33 | platform: "Windows 7", 34 | version: "8", 35 | }, 36 | { 37 | browserName: "internet explorer", 38 | platform: "XP", 39 | version: "7", 40 | }, 41 | { 42 | browserName: "opera", 43 | platform: "Windows 2008", 44 | version: "12", 45 | }, 46 | { 47 | browserName: "safari", 48 | platform: "OS X 10.8", 49 | version: "6", 50 | }, 51 | ]; 52 | 53 | const tags = []; 54 | if ( 55 | process.env.TRAVIS_PULL_REQUEST && 56 | process.env.TRAVIS_PULL_REQUEST != "false" 57 | ) { 58 | tags.push("pr" + process.env.TRAVIS_PULL_REQUEST); 59 | } else if (process.env.TRAVIS_BRANCH) { 60 | tags.push(process.env.TRAVIS_BRANCH); 61 | } 62 | 63 | grunt.initConfig({ 64 | connect: { 65 | server: { 66 | options: { 67 | base: "", 68 | port: 9999, 69 | }, 70 | }, 71 | }, 72 | "saucelabs-qunit": { 73 | all: { 74 | options: { 75 | urls: ["http://127.0.0.1:9999/test/index.html"], 76 | tunnelTimeout: 5, 77 | build: process.env.TRAVIS_JOB_ID, 78 | concurrency: 3, 79 | browsers, 80 | testname: "qunit tests", 81 | tags, 82 | }, 83 | }, 84 | }, 85 | }); 86 | 87 | grunt.loadNpmTasks("grunt-saucelabs"); 88 | grunt.loadNpmTasks("grunt-contrib-connect"); 89 | 90 | if (process.env.SAUCE_USERNAME && process.env.SAUCE_ACCESS_KEY) { 91 | grunt.registerTask("test", ["connect", "saucelabs-qunit"]); 92 | } else { 93 | grunt.registerTask("test", []); 94 | } 95 | }; 96 | -------------------------------------------------------------------------------- /utils/README.markdown: -------------------------------------------------------------------------------- 1 | PizZipUtils 2 | =========== 3 | 4 | A collection of cross-browser utilities to go along with PizZip 5 | 6 | It has two parts, one for every browsers and one for IE < 10. To use it : 7 | 8 | ```html 9 | 10 | 13 | 16 | ``` 17 | 18 | License 19 | ------- 20 | 21 | PizZipUtils is dual-licensed. You may use it under the MIT license *or* the GPLv3 license. See LICENSE.markdown. 22 | -------------------------------------------------------------------------------- /utils/_config.yml: -------------------------------------------------------------------------------- 1 | # will be overwritten by github, see https://help.github.com/articles/using-jekyll-with-pages 2 | safe: true 3 | lsi: false 4 | pygments: true 5 | source: ./ 6 | # /overwritten 7 | 8 | baseurl: /pizzip-utils 9 | 10 | layouts: ./documentation/_layouts 11 | permalink: none 12 | exclude: ['bin', 'README.md', 'node_modules'] 13 | 14 | markdown: redcarpet 15 | redcarpet: 16 | extensions: [ 17 | 'no_intra_emphasis', 18 | 'fenced_code_blocks', 19 | 'autolink', 20 | 'strikethrough', 21 | 'superscript', 22 | 'with_toc_data', 23 | 'tables', 24 | 'hardwrap' 25 | ] 26 | -------------------------------------------------------------------------------- /utils/documentation/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{page.title}} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 29 | 30 | 31 |
32 | 49 |
50 | 62 |
63 |

{{page.title}}

64 | 65 | 66 | 67 | 68 | {{content}} 69 | 70 | 71 | 72 | 73 |
74 |
75 |
76 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /utils/documentation/api.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "PizZipUtils" 3 | layout: default 4 | section: api 5 | --- 6 | This section contains the documentation of the different functions. 7 | -------------------------------------------------------------------------------- /utils/documentation/api/getbinarycontent.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: "getBinaryContent(path, callback)" layout: default 4 | 5 | section: api 6 | ------------ 7 | 8 | **Description** : Use an AJAX call to fetch a file (HTTP GET) on the server that served the file. Cross domain requests will work if the browser support [them](http://caniuse.com/cors) but only if the server send the [right headers](https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS). This function doesn't follow redirects : currently only `200 OK` are accepted. 9 | 10 | **Arguments** 11 | 12 | | name | type | description | 13 | |----------|----------|----------------------------------| 14 | | path | String | the path to the resource to GET. | 15 | | callback | function | the callback function. | 16 | 17 | The callback function has the following signature : `function (err, data) {...}` : 18 | 19 | | name | type | description | 20 | |------|--------------------|-------------------------------------------| 21 | | err | Error | the error, if any. | 22 | | data | ArrayBuffer/String | the data in a format suitable for PizZip. | 23 | 24 | The data can be parsed by PizZip#load or used with PizZip#file to add a new file. With `PizZip#file` use `{binary:true}` as options. 25 | 26 | **Returns** : Nothing. 27 | 28 | **Throws** : Nothing. 29 | 30 | 34 | 35 | **Example** 36 | 37 | ```js 38 | // loading a zip file 39 | PizZipUtils.getBinaryContent("path/to/file.zip", function (err, data) { 40 | if(err) { 41 | throw err; // or handle the error 42 | } 43 | var zip = new PizZip(data); 44 | }); 45 | 46 | // loading a file and add it in a zip file 47 | PizZipUtils.getBinaryContent("path/to/picture.png", function (err, data) { 48 | if(err) { 49 | throw err; // or handle the error 50 | } 51 | var zip = new PizZip(); 52 | zip.file("picture.png", data, {binary:true}); 53 | }); 54 | ``` 55 | -------------------------------------------------------------------------------- /utils/documentation/css/main.css: -------------------------------------------------------------------------------- 1 | ul.nav ul { 2 | list-style:none; 3 | margin: 0; 4 | padding: 0 0 0 25px; 5 | } 6 | 7 | 8 | -------------------------------------------------------------------------------- /utils/documentation/css/pygments.css: -------------------------------------------------------------------------------- 1 | /* Generated with : 2 | * pygmentize -S default -f html > pygments.css 3 | */ 4 | .hll { background-color: #ffffcc } 5 | .c { color: #408080; font-style: italic } /* Comment */ 6 | .err { border: 1px solid #FF0000 } /* Error */ 7 | .k { color: #008000; font-weight: bold } /* Keyword */ 8 | .o { color: #666666 } /* Operator */ 9 | .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 10 | .cp { color: #BC7A00 } /* Comment.Preproc */ 11 | .c1 { color: #408080; font-style: italic } /* Comment.Single */ 12 | .cs { color: #408080; font-style: italic } /* Comment.Special */ 13 | .gd { color: #A00000 } /* Generic.Deleted */ 14 | .ge { font-style: italic } /* Generic.Emph */ 15 | .gr { color: #FF0000 } /* Generic.Error */ 16 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 17 | .gi { color: #00A000 } /* Generic.Inserted */ 18 | .go { color: #888888 } /* Generic.Output */ 19 | .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 20 | .gs { font-weight: bold } /* Generic.Strong */ 21 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 22 | .gt { color: #0044DD } /* Generic.Traceback */ 23 | .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 24 | .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 25 | .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 26 | .kp { color: #008000 } /* Keyword.Pseudo */ 27 | .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 28 | .kt { color: #B00040 } /* Keyword.Type */ 29 | .m { color: #666666 } /* Literal.Number */ 30 | .s { color: #BA2121 } /* Literal.String */ 31 | .na { color: #7D9029 } /* Name.Attribute */ 32 | .nb { color: #008000 } /* Name.Builtin */ 33 | .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 34 | .no { color: #880000 } /* Name.Constant */ 35 | .nd { color: #AA22FF } /* Name.Decorator */ 36 | .ni { color: #999999; font-weight: bold } /* Name.Entity */ 37 | .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 38 | .nf { color: #0000FF } /* Name.Function */ 39 | .nl { color: #A0A000 } /* Name.Label */ 40 | .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 41 | .nt { color: #008000; font-weight: bold } /* Name.Tag */ 42 | .nv { color: #19177C } /* Name.Variable */ 43 | .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 44 | .w { color: #bbbbbb } /* Text.Whitespace */ 45 | .mf { color: #666666 } /* Literal.Number.Float */ 46 | .mh { color: #666666 } /* Literal.Number.Hex */ 47 | .mi { color: #666666 } /* Literal.Number.Integer */ 48 | .mo { color: #666666 } /* Literal.Number.Oct */ 49 | .sb { color: #BA2121 } /* Literal.String.Backtick */ 50 | .sc { color: #BA2121 } /* Literal.String.Char */ 51 | .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 52 | .s2 { color: #BA2121 } /* Literal.String.Double */ 53 | .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 54 | .sh { color: #BA2121 } /* Literal.String.Heredoc */ 55 | .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 56 | .sx { color: #008000 } /* Literal.String.Other */ 57 | .sr { color: #BB6688 } /* Literal.String.Regex */ 58 | .s1 { color: #BA2121 } /* Literal.String.Single */ 59 | .ss { color: #19177C } /* Literal.String.Symbol */ 60 | .bp { color: #008000 } /* Name.Builtin.Pseudo */ 61 | .vc { color: #19177C } /* Name.Variable.Class */ 62 | .vg { color: #19177C } /* Name.Variable.Global */ 63 | .vi { color: #19177C } /* Name.Variable.Instance */ 64 | .il { color: #666666 } /* Literal.Number.Integer.Long */ 65 | -------------------------------------------------------------------------------- /utils/es6/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const PizZipUtils = {}; 4 | // just use the responseText with xhr1, response with xhr2. 5 | // The transformation doesn't throw away high-order byte (with responseText) 6 | // because PizZip handles that case. If not used with PizZip, you may need to 7 | // do it, see https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data 8 | PizZipUtils._getBinaryFromXHR = function (xhr) { 9 | // for xhr.responseText, the 0xFF mask is applied by PizZip 10 | return xhr.response || xhr.responseText; 11 | }; 12 | 13 | // taken from jQuery 14 | function createStandardXHR() { 15 | try { 16 | return new window.XMLHttpRequest(); 17 | } catch (e) {} 18 | } 19 | 20 | function createActiveXHR() { 21 | try { 22 | return new window.ActiveXObject("Microsoft.XMLHTTP"); 23 | } catch (e) {} 24 | } 25 | 26 | // Create the request object 27 | const createXHR = window.ActiveXObject 28 | ? /* Microsoft failed to properly 29 | * implement the XMLHttpRequest in IE7 (can't request local files), 30 | * so we use the ActiveXObject when it is available 31 | * Additionally XMLHttpRequest can be disabled in IE7/IE8 so 32 | * we need a fallback. 33 | */ 34 | function () { 35 | return createStandardXHR() || createActiveXHR(); 36 | } 37 | : // For all other browsers, use the standard XMLHttpRequest object 38 | createStandardXHR; 39 | 40 | function isFileProtocol(path) { 41 | return ( 42 | path.startsWith("file://") || 43 | (typeof window !== "undefined" && window.location.protocol === "file:") 44 | ); 45 | } 46 | 47 | PizZipUtils.getBinaryContent = function (path, callback) { 48 | /* 49 | * Here is the tricky part : getting the data. 50 | * In firefox/chrome/opera/... setting the mimeType to 'text/plain; charset=x-user-defined' 51 | * is enough, the result is in the standard xhr.responseText. 52 | * cf https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest#Receiving_binary_data_in_older_browsers 53 | * In IE <= 9, we must use (the IE only) attribute responseBody 54 | * (for binary data, its content is different from responseText). 55 | * In IE 10, the 'charset=x-user-defined' trick doesn't work, only the 56 | * responseType will work : 57 | * http://msdn.microsoft.com/en-us/library/ie/hh673569%28v=vs.85%29.aspx#Binary_Object_upload_and_download 58 | * 59 | * I'd like to use jQuery to avoid this XHR madness, but it doesn't support 60 | * the responseType attribute : http://bugs.jquery.com/ticket/11461 61 | */ 62 | try { 63 | const xhr = createXHR(); 64 | 65 | xhr.open("GET", path, true); 66 | const isLocalFile = isFileProtocol(path); 67 | 68 | // recent browsers 69 | if ("responseType" in xhr) { 70 | xhr.responseType = "arraybuffer"; 71 | } 72 | 73 | // older browser 74 | if (xhr.overrideMimeType) { 75 | xhr.overrideMimeType("text/plain; charset=x-user-defined"); 76 | } 77 | 78 | xhr.onreadystatechange = function (evt) { 79 | let file, err; 80 | // use `xhr` and not `this`... thanks IE 81 | if (xhr.readyState === 4) { 82 | if (xhr.status === 200 || (isLocalFile && xhr.status === 0)) { 83 | try { 84 | const file = PizZipUtils._getBinaryFromXHR(xhr); 85 | callback(null, file); 86 | } catch (e) { 87 | callback(new Error(e), null); 88 | } 89 | } else { 90 | const errorDescription = 91 | xhr.status === 0 92 | ? "Server not responding or CORS headers missing. " 93 | : ""; 94 | callback( 95 | new Error( 96 | `Ajax error for ${path}: status ${xhr.status} ${errorDescription}${xhr.statusText}` 97 | ), 98 | null 99 | ); 100 | } 101 | } 102 | }; 103 | 104 | xhr.send(); 105 | } catch (e) { 106 | callback(new Error(e), null); 107 | } 108 | }; 109 | 110 | module.exports = PizZipUtils; 111 | -------------------------------------------------------------------------------- /utils/es6/index_IE.js: -------------------------------------------------------------------------------- 1 | /* global IEBinaryToArray_ByteStr, IEBinaryToArray_ByteStr_Last */ 2 | "use strict"; 3 | 4 | // Adapted from http://stackoverflow.com/questions/1095102/how-do-i-load-binary-image-data-using-javascript-and-xmlhttprequest 5 | const IEBinaryToArray_ByteStr_Script = 6 | "\r\n" + 7 | "\r\n"; 23 | 24 | // inject VBScript 25 | document.write(IEBinaryToArray_ByteStr_Script); 26 | 27 | global.PizZipUtils._getBinaryFromXHR = function (xhr) { 28 | const binary = xhr.responseBody; 29 | const byteMapping = {}; 30 | for (let i = 0; i < 256; i++) { 31 | for (let j = 0; j < 256; j++) { 32 | byteMapping[String.fromCharCode(i + (j << 8))] = 33 | String.fromCharCode(i) + String.fromCharCode(j); 34 | } 35 | } 36 | const rawBytes = IEBinaryToArray_ByteStr(binary); 37 | const lastChr = IEBinaryToArray_ByteStr_Last(binary); 38 | return ( 39 | rawBytes.replace(/[\s\S]/g, function (match) { 40 | return byteMapping[match]; 41 | }) + lastChr 42 | ); 43 | }; 44 | -------------------------------------------------------------------------------- /utils/es6/license_header.js: -------------------------------------------------------------------------------- 1 | /* ! 2 | 3 | PizZipUtils - A collection of cross-browser utilities to go along with PizZip. 4 | 5 | (c) 2014 Stuart Knightley, David Duponchel 6 | Dual licenced under the MIT license or GPLv3. See https://raw.github.com/open-xml-templating/pizzip/master/LICENSE.markdown. 7 | 8 | */ 9 | -------------------------------------------------------------------------------- /utils/index.d.ts: -------------------------------------------------------------------------------- 1 | declare var PizZipUtils : { 2 | getBinaryContent(path: string, callback: (err: Error, data: string) => void) : void 3 | } 4 | 5 | export default PizZipUtils; 6 | -------------------------------------------------------------------------------- /utils/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./es6/index.js"); 2 | -------------------------------------------------------------------------------- /utils/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: PizZipUtils 4 | 5 | layout: default 6 | --------------- 7 | 8 | A collection of cross-browser utilities to go along with PizZip 9 | 10 | It has two parts, one for every browsers and one for IE < 10. To use it : 11 | 12 | ```html 13 | 14 | 17 | 20 | ``` 21 | 22 | License 23 | ------- 24 | 25 | PizZipUtils is dual-licensed. You may use it under the MIT license *or* the GPLv3 license. See LICENSE.markdown. 26 | -------------------------------------------------------------------------------- /utils/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import PizZipUtils from "./index.js"; 2 | import { expectType, expectError } from "tsd"; 3 | 4 | const url = "https://www.google.com/content.png"; 5 | 6 | PizZipUtils.getBinaryContent(url, function (err: Error, data: string) { 7 | if (err) { 8 | console.log(err.message); 9 | console.log(err.stack); 10 | } 11 | console.log(data.length); 12 | expectType(data); 13 | }); 14 | 15 | expectError(PizZipUtils.getFooBar()); 16 | -------------------------------------------------------------------------------- /utils/test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PizZip Testing 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 22 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /utils/test/ref/amount.txt: -------------------------------------------------------------------------------- 1 | €15 2 | -------------------------------------------------------------------------------- /utils/test/ref/smile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-xml-templating/pizzip/3423fe98d3e6afb8fff08a68a008116fafa3fecb/utils/test/ref/smile.gif -------------------------------------------------------------------------------- /utils/test/test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * This is an helper function to transform the input into a binary string. 5 | * The transformation is normaly handled by PizZip. 6 | * @param {String|ArrayBuffer} input the input to convert. 7 | * @return {String} the binary string. 8 | */ 9 | function toString(input) { 10 | const isArray = typeof input !== "string"; 11 | let result = "", 12 | i, 13 | len; 14 | 15 | if (isArray) { 16 | input = new Uint8Array(input); 17 | } 18 | 19 | for (i = 0, len = input.length; i < len; i++) { 20 | result += String.fromCharCode( 21 | (isArray ? input[i] : input.charCodeAt(i)) % 0xff 22 | ); 23 | } 24 | 25 | return result; 26 | } 27 | 28 | test("PizZipUtils.getBinaryContent, text, 200 OK", function () { 29 | stop(); 30 | PizZipUtils.getBinaryContent("ref/amount.txt", function (err, data) { 31 | equal(err, null, "no error"); 32 | equal( 33 | toString(data), 34 | "\xe2\x82\xac\x31\x35\x0a", 35 | "The content has been fetched" 36 | ); 37 | start(); 38 | }); 39 | }); 40 | 41 | test("PizZipUtils.getBinaryContent, image, 200 OK", function () { 42 | stop(); 43 | PizZipUtils.getBinaryContent("ref/smile.gif", function (err, data) { 44 | equal(err, null, "no error"); 45 | equal( 46 | toString(data).indexOf("\x47\x49\x46\x38\x37\x61"), 47 | 0, 48 | "The content has been fetched" 49 | ); 50 | start(); 51 | }); 52 | }); 53 | 54 | test("PizZipUtils.getBinaryContent, 404 NOT FOUND", function () { 55 | stop(); 56 | PizZipUtils.getBinaryContent("ref/nothing", function (err, data) { 57 | equal(data, null, "no error"); 58 | ok(err instanceof Error, "The error is an Error"); 59 | start(); 60 | }); 61 | }); 62 | 63 | test("PizZipUtils.getBinaryContent, incorrect domain", function () { 64 | stop(); 65 | PizZipUtils.getBinaryContent("http://test.local", function (err, data) { 66 | console.log(err); 67 | equal(data, null, "no error"); 68 | ok(err instanceof Error, "The error is an Error"); 69 | ok(err.message.indexOf("Ajax error") !== -1, "The error is an Ajax error"); 70 | ok( 71 | err.message.indexOf( 72 | "Server not responding or CORS headers missing. " 73 | ) !== -1, 74 | "The error contains the CORS description" 75 | ); 76 | start(); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /utils/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | /* eslint-disable no-process-env */ 3 | const min = process.env.MIN === "true"; 4 | const IE = process.env.IE === "true"; 5 | 6 | const outputFilename = `pizzip-utils${IE ? "-ie" : ""}.${min ? "min." : ""}js`; 7 | 8 | const outputPath = path.resolve(__dirname, "dist"); 9 | console.log(outputPath); 10 | const entry = `./es6/index${IE ? "_IE" : ""}.js`; 11 | 12 | const output = { 13 | path: outputPath, 14 | filename: outputFilename, 15 | }; 16 | 17 | if (!IE) { 18 | output.library = "PizZipUtils"; 19 | output.libraryTarget = "window"; 20 | } 21 | console.log(output); 22 | 23 | module.exports = { 24 | entry, 25 | output, 26 | module: { 27 | rules: [ 28 | { 29 | test: [/\.js$/], 30 | exclude: [/node_modules/], 31 | loader: "babel-loader", 32 | }, 33 | ], 34 | }, 35 | mode: min ? "production" : "development", 36 | optimization: { 37 | minimize: min, 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /vendor/FileSaver.js: -------------------------------------------------------------------------------- 1 | /* ! FileSaver.js 2 | * A saveAs() FileSaver implementation. 3 | * 2014-01-24 4 | * 5 | * By Eli Grey, http://eligrey.com 6 | * License: X11/MIT 7 | * See LICENSE.md 8 | */ 9 | 10 | /* global self */ 11 | /* jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 12 | 13 | /* ! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 14 | 15 | var saveAs = saveAs 16 | // IE 10+ (native saveAs) 17 | || (typeof navigator !== "undefined" && 18 | navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) 19 | // Everyone else 20 | || (function(view) { 21 | "use strict"; 22 | // IE <10 is explicitly unsupported 23 | if (typeof navigator !== "undefined" && 24 | /MSIE [1-9]\./.test(navigator.userAgent)) { 25 | return; 26 | } 27 | let 28 | doc = view.document, 29 | // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet 30 | get_URL = function() { 31 | return view.URL || view.webkitURL || view; 32 | }, 33 | URL = view.URL || view.webkitURL || view, 34 | save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"), 35 | can_use_save_link = !view.externalHost && "download" in save_link, 36 | click = function(node) { 37 | const event = doc.createEvent("MouseEvents"); 38 | event.initMouseEvent( 39 | "click", true, false, view, 0, 0, 0, 0, 0 40 | , false, false, false, false, 0, null 41 | ); 42 | node.dispatchEvent(event); 43 | }, 44 | webkit_req_fs = view.webkitRequestFileSystem, 45 | req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem, 46 | throw_outside = function(ex) { 47 | (view.setImmediate || view.setTimeout)(function() { 48 | throw ex; 49 | }, 0); 50 | }, 51 | force_saveable_type = "application/octet-stream", 52 | fs_min_size = 0, 53 | deletion_queue = [], 54 | process_deletion_queue = function() { 55 | let i = deletion_queue.length; 56 | while (i--) { 57 | const file = deletion_queue[i]; 58 | if (typeof file === "string") { // file is an object URL 59 | URL.revokeObjectURL(file); 60 | } else { // file is a File 61 | file.remove(); 62 | } 63 | } 64 | deletion_queue.length = 0; // clear queue 65 | }, 66 | dispatch = function(filesaver, event_types, event) { 67 | event_types = [].concat(event_types); 68 | let i = event_types.length; 69 | while (i--) { 70 | const listener = filesaver["on" + event_types[i]]; 71 | if (typeof listener === "function") { 72 | try { 73 | listener.call(filesaver, event || filesaver); 74 | } catch (ex) { 75 | throw_outside(ex); 76 | } 77 | } 78 | } 79 | }, 80 | FileSaver = function(blob, name) { 81 | // First try a.download, then web filesystem, then object URLs 82 | let 83 | filesaver = this, 84 | type = blob.type, 85 | blob_changed = false, 86 | object_url, 87 | target_view, 88 | get_object_url = function() { 89 | const object_url = get_URL().createObjectURL(blob); 90 | deletion_queue.push(object_url); 91 | return object_url; 92 | }, 93 | dispatch_all = function() { 94 | dispatch(filesaver, "writestart progress write writeend".split(" ")); 95 | }, 96 | // on any filesys errors revert to saving with object URLs 97 | fs_error = function() { 98 | // don't create more object URLs than needed 99 | if (blob_changed || !object_url) { 100 | object_url = get_object_url(blob); 101 | } 102 | if (target_view) { 103 | target_view.location.href = object_url; 104 | } else { 105 | window.open(object_url, "_blank"); 106 | } 107 | filesaver.readyState = filesaver.DONE; 108 | dispatch_all(); 109 | }, 110 | abortable = function(func) { 111 | return function() { 112 | if (filesaver.readyState !== filesaver.DONE) { 113 | return func.apply(this, arguments); 114 | } 115 | }; 116 | }, 117 | create_if_not_found = {create: true, exclusive: false}, 118 | slice 119 | ; 120 | filesaver.readyState = filesaver.INIT; 121 | if (!name) { 122 | name = "download"; 123 | } 124 | if (can_use_save_link) { 125 | object_url = get_object_url(blob); 126 | // FF for Android has a nasty garbage collection mechanism 127 | // that turns all objects that are not pure javascript into 'deadObject' 128 | // this means `doc` and `save_link` are unusable and need to be recreated 129 | // `view` is usable though: 130 | doc = view.document; 131 | save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); 132 | save_link.href = object_url; 133 | save_link.download = name; 134 | const event = doc.createEvent("MouseEvents"); 135 | event.initMouseEvent( 136 | "click", true, false, view, 0, 0, 0, 0, 0 137 | , false, false, false, false, 0, null 138 | ); 139 | save_link.dispatchEvent(event); 140 | filesaver.readyState = filesaver.DONE; 141 | dispatch_all(); 142 | return; 143 | } 144 | // Object and web filesystem URLs have a problem saving in Google Chrome when 145 | // viewed in a tab, so I force save with application/octet-stream 146 | // http://code.google.com/p/chromium/issues/detail?id=91158 147 | if (view.chrome && type && type !== force_saveable_type) { 148 | slice = blob.slice || blob.webkitSlice; 149 | blob = slice.call(blob, 0, blob.size, force_saveable_type); 150 | blob_changed = true; 151 | } 152 | // Since I can't be sure that the guessed media type will trigger a download 153 | // in WebKit, I append .download to the filename. 154 | // https://bugs.webkit.org/show_bug.cgi?id=65440 155 | if (webkit_req_fs && name !== "download") { 156 | name += ".download"; 157 | } 158 | if (type === force_saveable_type || webkit_req_fs) { 159 | target_view = view; 160 | } 161 | if (!req_fs) { 162 | fs_error(); 163 | return; 164 | } 165 | fs_min_size += blob.size; 166 | req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { 167 | fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { 168 | const save = function() { 169 | dir.getFile(name, create_if_not_found, abortable(function(file) { 170 | file.createWriter(abortable(function(writer) { 171 | writer.onwriteend = function(event) { 172 | target_view.location.href = file.toURL(); 173 | deletion_queue.push(file); 174 | filesaver.readyState = filesaver.DONE; 175 | dispatch(filesaver, "writeend", event); 176 | }; 177 | writer.onerror = function() { 178 | const error = writer.error; 179 | if (error.code !== error.ABORT_ERR) { 180 | fs_error(); 181 | } 182 | }; 183 | "writestart progress write abort".split(" ").forEach(function(event) { 184 | writer["on" + event] = filesaver["on" + event]; 185 | }); 186 | writer.write(blob); 187 | filesaver.abort = function() { 188 | writer.abort(); 189 | filesaver.readyState = filesaver.DONE; 190 | }; 191 | filesaver.readyState = filesaver.WRITING; 192 | }), fs_error); 193 | }), fs_error); 194 | }; 195 | dir.getFile(name, {create: false}, abortable(function(file) { 196 | // delete file if it already exists 197 | file.remove(); 198 | save(); 199 | }), abortable(function(ex) { 200 | if (ex.code === ex.NOT_FOUND_ERR) { 201 | save(); 202 | } else { 203 | fs_error(); 204 | } 205 | })); 206 | }), fs_error); 207 | }), fs_error); 208 | }, 209 | FS_proto = FileSaver.prototype, 210 | saveAs = function(blob, name) { 211 | return new FileSaver(blob, name); 212 | } 213 | ; 214 | FS_proto.abort = function() { 215 | const filesaver = this; 216 | filesaver.readyState = filesaver.DONE; 217 | dispatch(filesaver, "abort"); 218 | }; 219 | FS_proto.readyState = FS_proto.INIT = 0; 220 | FS_proto.WRITING = 1; 221 | FS_proto.DONE = 2; 222 | 223 | FS_proto.error = 224 | FS_proto.onwritestart = 225 | FS_proto.onprogress = 226 | FS_proto.onwrite = 227 | FS_proto.onabort = 228 | FS_proto.onerror = 229 | FS_proto.onwriteend = 230 | null; 231 | 232 | view.addEventListener("unload", process_deletion_queue, false); 233 | saveAs.unload = function() { 234 | process_deletion_queue(); 235 | view.removeEventListener("unload", process_deletion_queue, false); 236 | }; 237 | return saveAs; 238 | })( 239 | typeof self !== "undefined" && self 240 | || typeof window !== "undefined" && window 241 | || this.content 242 | ); 243 | // `self` is undefined in Firefox for Android content script context 244 | // while `this` is nsIContentFrameMessageManager 245 | // with an attribute `content` that corresponds to the window 246 | 247 | if (typeof module !== "undefined") { module.exports = saveAs; } 248 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | /* eslint-disable no-process-env */ 3 | const min = process.env.MIN === "true"; 4 | const outputFilename = `pizzip.${min ? "min." : ""}js`; 5 | 6 | const outputPath = path.resolve(__dirname, "dist"); 7 | const entry = "./es6/index.js"; 8 | 9 | module.exports = { 10 | entry, 11 | output: { 12 | path: outputPath, 13 | filename: outputFilename, 14 | library: "PizZip", 15 | libraryTarget: "window", 16 | }, 17 | module: { 18 | rules: [ 19 | { 20 | test: [/\.js$/], 21 | exclude: [/node_modules/], 22 | loader: "babel-loader", 23 | }, 24 | ], 25 | }, 26 | mode: min ? "production" : "development", 27 | optimization: { 28 | minimize: min, 29 | }, 30 | }; 31 | --------------------------------------------------------------------------------