2 var support = require('./support');
3 var compressions = require('./compressions');
4 var nodeBuffer = require('./nodeBuffer');
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.
10 exports.string2binary = function(str) {
12 for (var i = 0; i < str.length; i++) {
13 result += String.fromCharCode(str.charCodeAt(i) & 0xff);
17 exports.arrayBuffer2Blob = function(buffer, mimeType) {
18 exports.checkSupport("blob");
19 mimeType = mimeType || 'application/zip';
23 return new Blob([buffer], {
30 // deprecated, browser only, old way
31 var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
32 var builder = new Builder();
33 builder.append(buffer);
34 return builder.getBlob(mimeType);
39 throw new Error("Bug : can't construct the Blob.");
46 * The identity function.
47 * @param {Object} input the input.
48 * @return {Object} the same input.
50 function identity(input) {
55 * Fill in an array with a string.
56 * @param {String} str the string to use.
57 * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated).
58 * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array.
60 function stringToArrayLike(str, array) {
61 for (var i = 0; i < str.length; ++i) {
62 array[i] = str.charCodeAt(i) & 0xFF;
68 * Transform an array-like object to a string.
69 * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform.
70 * @return {String} the result.
72 function arrayLikeToString(array) {
73 // Performances notes :
74 // --------------------
75 // String.fromCharCode.apply(null, array) is the fastest, see
76 // see http://jsperf.com/converting-a-uint8array-to-a-string/2
77 // but the stack is limited (and we can get huge arrays !).
79 // result += String.fromCharCode(array[i]); generate too many strings !
81 // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2
85 type = exports.getTypeOf(array),
91 String.fromCharCode.apply(null, new Uint8Array(0));
94 String.fromCharCode.apply(null, nodeBuffer(0));
101 // no apply : slow and painful algorithm
102 // default browser on android 4.*
105 for(var i = 0; i < array.length;i++) {
106 resultStr += String.fromCharCode(array[i]);
110 while (k < len && chunk > 1) {
112 if (type === "array" || type === "nodebuffer") {
113 result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len))));
116 result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len))));
121 chunk = Math.floor(chunk / 2);
124 return result.join("");
127 exports.applyFromCharCode = arrayLikeToString;
131 * Copy the data from an array-like to an other array-like.
132 * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array.
133 * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated.
134 * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array.
136 function arrayLikeToArrayLike(arrayFrom, arrayTo) {
137 for (var i = 0; i < arrayFrom.length; i++) {
138 arrayTo[i] = arrayFrom[i];
143 // a matrix containing functions to transform everything into everything.
147 transform["string"] = {
149 "array": function(input) {
150 return stringToArrayLike(input, new Array(input.length));
152 "arraybuffer": function(input) {
153 return transform["string"]["uint8array"](input).buffer;
155 "uint8array": function(input) {
156 return stringToArrayLike(input, new Uint8Array(input.length));
158 "nodebuffer": function(input) {
159 return stringToArrayLike(input, nodeBuffer(input.length));
164 transform["array"] = {
165 "string": arrayLikeToString,
167 "arraybuffer": function(input) {
168 return (new Uint8Array(input)).buffer;
170 "uint8array": function(input) {
171 return new Uint8Array(input);
173 "nodebuffer": function(input) {
174 return nodeBuffer(input);
179 transform["arraybuffer"] = {
180 "string": function(input) {
181 return arrayLikeToString(new Uint8Array(input));
183 "array": function(input) {
184 return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength));
186 "arraybuffer": identity,
187 "uint8array": function(input) {
188 return new Uint8Array(input);
190 "nodebuffer": function(input) {
191 return nodeBuffer(new Uint8Array(input));
196 transform["uint8array"] = {
197 "string": arrayLikeToString,
198 "array": function(input) {
199 return arrayLikeToArrayLike(input, new Array(input.length));
201 "arraybuffer": function(input) {
204 "uint8array": identity,
205 "nodebuffer": function(input) {
206 return nodeBuffer(input);
211 transform["nodebuffer"] = {
212 "string": arrayLikeToString,
213 "array": function(input) {
214 return arrayLikeToArrayLike(input, new Array(input.length));
216 "arraybuffer": function(input) {
217 return transform["nodebuffer"]["uint8array"](input).buffer;
219 "uint8array": function(input) {
220 return arrayLikeToArrayLike(input, new Uint8Array(input.length));
222 "nodebuffer": identity
226 * Transform an input into any type.
227 * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer.
228 * If no output type is specified, the unmodified input will be returned.
229 * @param {String} outputType the output type.
230 * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert.
231 * @throws {Error} an Error if the browser doesn't support the requested output type.
233 exports.transformTo = function(outputType, input) {
235 // undefined, null, etc
236 // an empty string won't harm.
242 exports.checkSupport(outputType);
243 var inputType = exports.getTypeOf(input);
244 var result = transform[inputType][outputType](input);
249 * Return the type of the input.
250 * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer.
251 * @param {Object} input the input to identify.
252 * @return {String} the (lowercase) type of the input.
254 exports.getTypeOf = function(input) {
255 if (typeof input === "string") {
258 if (Object.prototype.toString.call(input) === "[object Array]") {
261 if (support.nodebuffer && nodeBuffer.test(input)) {
264 if (support.uint8array && input instanceof Uint8Array) {
267 if (support.arraybuffer && input instanceof ArrayBuffer) {
268 return "arraybuffer";
273 * Throw an exception if the type is not supported.
274 * @param {String} type the type to check.
275 * @throws {Error} an Error if the browser doesn't support the requested type.
277 exports.checkSupport = function(type) {
278 var supported = support[type.toLowerCase()];
280 throw new Error(type + " is not supported by this browser");
283 exports.MAX_VALUE_16BITS = 65535;
284 exports.MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1
287 * Prettify a string read as binary.
288 * @param {string} str the string to prettify.
289 * @return {string} a pretty string.
291 exports.pretty = function(str) {
294 for (i = 0; i < (str || "").length; i++) {
295 code = str.charCodeAt(i);
296 res += '\\x' + (code < 16 ? "0" : "") + code.toString(16).toUpperCase();
302 * Find a compression registered in JSZip.
303 * @param {string} compressionMethod the method magic to find.
304 * @return {Object|null} the JSZip compression object, null if none found.
306 exports.findCompression = function(compressionMethod) {
307 for (var method in compressions) {
308 if (!compressions.hasOwnProperty(method)) {
311 if (compressions[method].magic === compressionMethod) {
312 return compressions[method];
318 * Cross-window, cross-Node-context regular expression detection
319 * @param {Object} object Anything
320 * @return {Boolean} true if the object is a regular expression,
323 exports.isRegExp = function (object) {
324 return Object.prototype.toString.call(object) === "[object RegExp]";