Update JSON API
[src/app-framework-demo.git] / afm-client / bower_components / jszip / lib / zipEntries.js
1 'use strict';
2 var StringReader = require('./stringReader');
3 var NodeBufferReader = require('./nodeBufferReader');
4 var Uint8ArrayReader = require('./uint8ArrayReader');
5 var utils = require('./utils');
6 var sig = require('./signature');
7 var ZipEntry = require('./zipEntry');
8 var support = require('./support');
9 var jszipProto = require('./object');
10 //  class ZipEntries {{{
11 /**
12  * All the entries in the zip file.
13  * @constructor
14  * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load.
15  * @param {Object} loadOptions Options for loading the stream.
16  */
17 function ZipEntries(data, loadOptions) {
18     this.files = [];
19     this.loadOptions = loadOptions;
20     if (data) {
21         this.load(data);
22     }
23 }
24 ZipEntries.prototype = {
25     /**
26      * Check that the reader is on the speficied signature.
27      * @param {string} expectedSignature the expected signature.
28      * @throws {Error} if it is an other signature.
29      */
30     checkSignature: function(expectedSignature) {
31         var signature = this.reader.readString(4);
32         if (signature !== expectedSignature) {
33             throw new Error("Corrupted zip or bug : unexpected signature " + "(" + utils.pretty(signature) + ", expected " + utils.pretty(expectedSignature) + ")");
34         }
35     },
36     /**
37      * Read the end of the central directory.
38      */
39     readBlockEndOfCentral: function() {
40         this.diskNumber = this.reader.readInt(2);
41         this.diskWithCentralDirStart = this.reader.readInt(2);
42         this.centralDirRecordsOnThisDisk = this.reader.readInt(2);
43         this.centralDirRecords = this.reader.readInt(2);
44         this.centralDirSize = this.reader.readInt(4);
45         this.centralDirOffset = this.reader.readInt(4);
46
47         this.zipCommentLength = this.reader.readInt(2);
48         // warning : the encoding depends of the system locale
49         // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded.
50         // On a windows machine, this field is encoded with the localized windows code page.
51         this.zipComment = this.reader.readString(this.zipCommentLength);
52         // To get consistent behavior with the generation part, we will assume that
53         // this is utf8 encoded.
54         this.zipComment = jszipProto.utf8decode(this.zipComment);
55     },
56     /**
57      * Read the end of the Zip 64 central directory.
58      * Not merged with the method readEndOfCentral :
59      * The end of central can coexist with its Zip64 brother,
60      * I don't want to read the wrong number of bytes !
61      */
62     readBlockZip64EndOfCentral: function() {
63         this.zip64EndOfCentralSize = this.reader.readInt(8);
64         this.versionMadeBy = this.reader.readString(2);
65         this.versionNeeded = this.reader.readInt(2);
66         this.diskNumber = this.reader.readInt(4);
67         this.diskWithCentralDirStart = this.reader.readInt(4);
68         this.centralDirRecordsOnThisDisk = this.reader.readInt(8);
69         this.centralDirRecords = this.reader.readInt(8);
70         this.centralDirSize = this.reader.readInt(8);
71         this.centralDirOffset = this.reader.readInt(8);
72
73         this.zip64ExtensibleData = {};
74         var extraDataSize = this.zip64EndOfCentralSize - 44,
75             index = 0,
76             extraFieldId,
77             extraFieldLength,
78             extraFieldValue;
79         while (index < extraDataSize) {
80             extraFieldId = this.reader.readInt(2);
81             extraFieldLength = this.reader.readInt(4);
82             extraFieldValue = this.reader.readString(extraFieldLength);
83             this.zip64ExtensibleData[extraFieldId] = {
84                 id: extraFieldId,
85                 length: extraFieldLength,
86                 value: extraFieldValue
87             };
88         }
89     },
90     /**
91      * Read the end of the Zip 64 central directory locator.
92      */
93     readBlockZip64EndOfCentralLocator: function() {
94         this.diskWithZip64CentralDirStart = this.reader.readInt(4);
95         this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8);
96         this.disksCount = this.reader.readInt(4);
97         if (this.disksCount > 1) {
98             throw new Error("Multi-volumes zip are not supported");
99         }
100     },
101     /**
102      * Read the local files, based on the offset read in the central part.
103      */
104     readLocalFiles: function() {
105         var i, file;
106         for (i = 0; i < this.files.length; i++) {
107             file = this.files[i];
108             this.reader.setIndex(file.localHeaderOffset);
109             this.checkSignature(sig.LOCAL_FILE_HEADER);
110             file.readLocalPart(this.reader);
111             file.handleUTF8();
112             file.processAttributes();
113         }
114     },
115     /**
116      * Read the central directory.
117      */
118     readCentralDir: function() {
119         var file;
120
121         this.reader.setIndex(this.centralDirOffset);
122         while (this.reader.readString(4) === sig.CENTRAL_FILE_HEADER) {
123             file = new ZipEntry({
124                 zip64: this.zip64
125             }, this.loadOptions);
126             file.readCentralPart(this.reader);
127             this.files.push(file);
128         }
129     },
130     /**
131      * Read the end of central directory.
132      */
133     readEndOfCentral: function() {
134         var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END);
135         if (offset === -1) {
136             // Check if the content is a truncated zip or complete garbage.
137             // A "LOCAL_FILE_HEADER" is not required at the beginning (auto
138             // extractible zip for example) but it can give a good hint.
139             // If an ajax request was used without responseType, we will also
140             // get unreadable data.
141             var isGarbage = true;
142             try {
143                 this.reader.setIndex(0);
144                 this.checkSignature(sig.LOCAL_FILE_HEADER);
145                 isGarbage = false;
146             } catch (e) {}
147
148             if (isGarbage) {
149                 throw new Error("Can't find end of central directory : is this a zip file ? " +
150                                 "If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html");
151             } else {
152                 throw new Error("Corrupted zip : can't find end of central directory");
153             }
154         }
155         this.reader.setIndex(offset);
156         this.checkSignature(sig.CENTRAL_DIRECTORY_END);
157         this.readBlockEndOfCentral();
158
159
160         /* extract from the zip spec :
161             4)  If one of the fields in the end of central directory
162                 record is too small to hold required data, the field
163                 should be set to -1 (0xFFFF or 0xFFFFFFFF) and the
164                 ZIP64 format record should be created.
165             5)  The end of central directory record and the
166                 Zip64 end of central directory locator record must
167                 reside on the same disk when splitting or spanning
168                 an archive.
169          */
170         if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) {
171             this.zip64 = true;
172
173             /*
174             Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from
175             the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents
176             all numbers as 64-bit double precision IEEE 754 floating point numbers.
177             So, we have 53bits for integers and bitwise operations treat everything as 32bits.
178             see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators
179             and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5
180             */
181
182             // should look for a zip64 EOCD locator
183             offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
184             if (offset === -1) {
185                 throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator");
186             }
187             this.reader.setIndex(offset);
188             this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
189             this.readBlockZip64EndOfCentralLocator();
190
191             // now the zip64 EOCD record
192             this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir);
193             this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);
194             this.readBlockZip64EndOfCentral();
195         }
196     },
197     prepareReader: function(data) {
198         var type = utils.getTypeOf(data);
199         if (type === "string" && !support.uint8array) {
200             this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString);
201         }
202         else if (type === "nodebuffer") {
203             this.reader = new NodeBufferReader(data);
204         }
205         else {
206             this.reader = new Uint8ArrayReader(utils.transformTo("uint8array", data));
207         }
208     },
209     /**
210      * Read a zip file and create ZipEntries.
211      * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file.
212      */
213     load: function(data) {
214         this.prepareReader(data);
215         this.readEndOfCentral();
216         this.readCentralDir();
217         this.readLocalFiles();
218     }
219 };
220 // }}} end of ZipEntries
221 module.exports = ZipEntries;