mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-18 14:27:34 +09:00
79 lines
3.2 KiB
JavaScript
79 lines
3.2 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
// base: relative or absolute path (http[s] or file, untested with ftp)
|
|
// files: array of file names relative to base to include at the zip
|
|
// callbacks: object with optional functions:
|
|
// onsuccess(result), onerror(exception), onprogress(percentage)
|
|
function createXpiDataUri(base, files, callbacks) {
|
|
|
|
// Synchronous XHR for http[s]/file (untested ftp), throws on any error
|
|
// Note that on firefox, file:// XHR can't access files outside base dir
|
|
function readBinFile(url) {
|
|
// The DOM will qualify the URI for us if it's relative (not IE6)
|
|
function isFileUri(uri) {
|
|
var a = document.createElement("a");
|
|
a.href = uri;
|
|
return a.href.toLowerCase().indexOf("file://") == 0;
|
|
}
|
|
|
|
var r = new XMLHttpRequest();
|
|
r.open("GET", url, false);
|
|
r.requestType = "arraybuffer";
|
|
r.overrideMimeType("text/plain; charset=x-user-defined");
|
|
try { r.send(); }
|
|
catch (e) { throw "FileNotRetrieved: " + url + " - " + e; }
|
|
// For 'file://' Firefox sets status=0 on success or throws otherwise
|
|
// In Firefox 34-ish onwards, success status is 200.
|
|
if (!(r.readyState == 4 && (r.status == 0 || r.status == 200)))
|
|
throw ("FileNotRetrieved: " + url + " - " + r.status + " " + r.statusText);
|
|
|
|
return r.response;
|
|
}
|
|
|
|
// Create base64 string for a binary array (btoa fails on arbitrary binary data)
|
|
function base64EncArr(aBytes) {
|
|
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
|
|
"use strict;"
|
|
function uint6ToB64(nUint6) {
|
|
return nUint6 < 26 ? nUint6 + 65 : nUint6 < 52 ? nUint6 + 71 : nUint6 < 62 ?
|
|
nUint6 - 4 : nUint6 === 62 ? 43 : nUint6 === 63 ? 47 : 65;
|
|
}
|
|
|
|
var nMod3 = 2, sB64Enc = "";
|
|
for (var nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
|
|
nMod3 = nIdx % 3;
|
|
if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) { sB64Enc += "\r\n"; }
|
|
nUint24 |= aBytes[nIdx] << (16 >>> nMod3 & 24);
|
|
if (nMod3 === 2 || aBytes.length - nIdx === 1) {
|
|
sB64Enc += String.fromCharCode(uint6ToB64(nUint24 >>> 18 & 63), uint6ToB64(nUint24 >>> 12 & 63),
|
|
uint6ToB64(nUint24 >>> 6 & 63), uint6ToB64(nUint24 & 63));
|
|
nUint24 = 0;
|
|
}
|
|
}
|
|
|
|
return sB64Enc.substr(0, sB64Enc.length - 2 + nMod3) + (nMod3 === 2 ? '' : nMod3 === 1 ? '=' : '==');
|
|
}
|
|
|
|
// Create the zip/xpi
|
|
try {
|
|
function dummy() {}
|
|
var onsuccess = callbacks.onsuccess || dummy;
|
|
var onerror = callbacks.onerror || dummy;
|
|
var onprogress = callbacks.onprogress || dummy;
|
|
|
|
var zip = new JSZip();
|
|
for (var i = 0; i < files.length; i++) {
|
|
zip.file(files[i], readBinFile(base + files[i]),
|
|
{binary: true, compression: "deflate"});
|
|
onprogress(100 * (i + 1) / (files.length + 1));
|
|
}
|
|
zip = zip.generate({type: "uint8array"});
|
|
onprogress(100);
|
|
setTimeout(onsuccess, 0, "data:application/x-xpinstall;base64," + base64EncArr(zip));
|
|
|
|
} catch (e) {
|
|
setTimeout(onerror, 0, e);
|
|
}
|
|
}
|