Account for Dropbox bug (#833)
* Account for Dropbox bug * Breaking: deprecate dropbox backup * Drop: dropbox and zipjs-browserify * Breaking: remove dropbox backup * Fix: remove href from the command Co-authored-by: eight <eight04@gmail.com>
This commit is contained in:
parent
1f12d50aaf
commit
ff6e941958
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,7 +2,6 @@
|
||||||
pull_locales_login.rb
|
pull_locales_login.rb
|
||||||
.vscode
|
.vscode
|
||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
|
||||||
yarn.lock
|
yarn.lock
|
||||||
*.zip
|
*.zip
|
||||||
.eslintcache
|
.eslintcache
|
||||||
|
|
|
@ -445,6 +445,10 @@
|
||||||
"message": "Press a hotkey",
|
"message": "Press a hotkey",
|
||||||
"description": "Placeholder text of inputbox in keymap help popup on the edit style page. Must be very short"
|
"description": "Placeholder text of inputbox in keymap help popup on the edit style page. Must be very short"
|
||||||
},
|
},
|
||||||
|
"hostDisabled": {
|
||||||
|
"message": "This host has been disabled due to a bug in the current version of the browser being used",
|
||||||
|
"description": "Tooltip for cloud host disabled"
|
||||||
|
},
|
||||||
"importAppendLabel": {
|
"importAppendLabel": {
|
||||||
"message": "Append to style",
|
"message": "Append to style",
|
||||||
"description": "Label for the button to import a style and append to the existing sections"
|
"description": "Label for the button to import a style and append to the existing sections"
|
||||||
|
@ -1540,6 +1544,9 @@
|
||||||
"syncDropboxStyles": {
|
"syncDropboxStyles": {
|
||||||
"message": "Dropbox Export"
|
"message": "Dropbox Export"
|
||||||
},
|
},
|
||||||
|
"syncDropboxDeprecated": {
|
||||||
|
"message": "Dropbox import/export is replaced by a more advanced style sync in the options page."
|
||||||
|
},
|
||||||
"retrieveDropboxSync": {
|
"retrieveDropboxSync": {
|
||||||
"message": "Dropbox Import"
|
"message": "Dropbox Import"
|
||||||
},
|
},
|
||||||
|
|
10
manage.html
10
manage.html
|
@ -170,12 +170,6 @@
|
||||||
<script src="msgbox/msgbox.js"></script>
|
<script src="msgbox/msgbox.js"></script>
|
||||||
<script src="js/sections-util.js"></script>
|
<script src="js/sections-util.js"></script>
|
||||||
<script src="js/storage-util.js"></script>
|
<script src="js/storage-util.js"></script>
|
||||||
|
|
||||||
<script src="vendor/dropbox/dropbox-sdk.js" async></script>
|
|
||||||
<script src="vendor/zipjs-browserify/zip.js" defer></script>
|
|
||||||
<script src="sync/compress-text.js" defer></script>
|
|
||||||
<script src="sync/cross-browser-functions.js" defer></script>
|
|
||||||
<script src="sync/import-export-dropbox.js" async></script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body id="stylus-manage" i18n-dragndrop-hint="dragDropMessage">
|
<body id="stylus-manage" i18n-dragndrop-hint="dragDropMessage">
|
||||||
|
@ -383,7 +377,7 @@
|
||||||
|
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<a href="#" id="file-all-styles" i18n-text="bckpInstStyles"></a>
|
<a href="#" id="file-all-styles" i18n-text="bckpInstStyles"></a>
|
||||||
<a href="#" id="sync-dropbox-export" i18n-text="syncDropboxStyles"></a>
|
<a id="sync-dropbox-export" i18n-text="syncDropboxStyles" i18n-title="syncDropboxDeprecated"></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -395,7 +389,7 @@
|
||||||
|
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<a href="#" id="unfile-all-styles" i18n-text="retrieveBckp"></a>
|
<a href="#" id="unfile-all-styles" i18n-text="retrieveBckp"></a>
|
||||||
<a href="#" id="sync-dropbox-import" i18n-text="retrieveDropboxSync"></a>
|
<a id="sync-dropbox-import" i18n-text="retrieveDropboxSync" i18n-title="syncDropboxDeprecated"></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1302,3 +1302,14 @@ input[id^="manage.newUI"] {
|
||||||
margin-left: -2px;
|
margin-left: -2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Deprecated dropbox backup (dropbox-sync) */
|
||||||
|
#sync-dropbox-export,
|
||||||
|
#sync-dropbox-import {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
#backup-buttons .dropdown-content #sync-dropbox-export:hover,
|
||||||
|
#backup-buttons .dropdown-content #sync-dropbox-import:hover {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,13 @@ setupRadioButtons();
|
||||||
enforceInputRange($('#popupWidth'));
|
enforceInputRange($('#popupWidth'));
|
||||||
setTimeout(splitLongTooltips);
|
setTimeout(splitLongTooltips);
|
||||||
|
|
||||||
|
// TODO: add max version to re-enable once crbug.com/996859 is resolved
|
||||||
|
if (!FIREFOX && CHROME >= 3809) {
|
||||||
|
const dropboxOption = $('option[value="dropbox"]');
|
||||||
|
dropboxOption.disabled = true;
|
||||||
|
dropboxOption.setAttribute('title', t('hostDisabled'));
|
||||||
|
}
|
||||||
|
|
||||||
if (CHROME_HAS_BORDER_BUG) {
|
if (CHROME_HAS_BORDER_BUG) {
|
||||||
const borderOption = $('.chrome-no-popup-border');
|
const borderOption = $('.chrome-no-popup-border');
|
||||||
if (borderOption) {
|
if (borderOption) {
|
||||||
|
|
9819
package-lock.json
generated
Normal file
9819
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -9,7 +9,6 @@
|
||||||
"archiver": "^3.1.1",
|
"archiver": "^3.1.1",
|
||||||
"codemirror": "^5.48.4",
|
"codemirror": "^5.48.4",
|
||||||
"db-to-cloud": "^0.4.5",
|
"db-to-cloud": "^0.4.5",
|
||||||
"dropbox": "^4.0.30",
|
|
||||||
"endent": "^1.3.0",
|
"endent": "^1.3.0",
|
||||||
"eslint": "^6.3.0",
|
"eslint": "^6.3.0",
|
||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
|
@ -23,8 +22,7 @@
|
||||||
"updates": "^9.0.0",
|
"updates": "^9.0.0",
|
||||||
"usercss-meta": "^0.9.0",
|
"usercss-meta": "^0.9.0",
|
||||||
"web-ext": "^3.1.1",
|
"web-ext": "^3.1.1",
|
||||||
"webext-tx-fix": "^0.3.2",
|
"webext-tx-fix": "^0.3.2"
|
||||||
"zipjs-browserify": "^1.0.1"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint **/*.js --cache || exit 0",
|
"lint": "eslint **/*.js --cache || exit 0",
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
/* global zip onDOMready */
|
|
||||||
/* exported createZipFileFromText readZipFileFromBlob */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
onDOMready().then(() => {
|
|
||||||
zip.workerScriptsPath = '../vendor/zipjs-browserify/';
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {String} filename
|
|
||||||
* @param {String} text content of the file as text
|
|
||||||
* @returns {Promise<Blob>} resolves to a blob object representing the zip file
|
|
||||||
*/
|
|
||||||
function createZipFileFromText(filename, text) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
zip.createWriter(new zip.BlobWriter('application/zip'), writer => {
|
|
||||||
writer.add(filename, new zip.TextReader(text), function () {
|
|
||||||
writer.close(blob => {
|
|
||||||
resolve(blob);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} blob object of zip file
|
|
||||||
* @returns {Promise<String>} resolves to a string the content of the first file of the zip
|
|
||||||
*/
|
|
||||||
function readZipFileFromBlob(blob) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
zip.createReader(new zip.BlobReader(blob), zipReader => {
|
|
||||||
zipReader.getEntries(entries => {
|
|
||||||
entries[0].getData(new zip.BlobWriter('text/plain'), data => {
|
|
||||||
zipReader.close();
|
|
||||||
resolve(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, reject);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* exported getRedirectUrlAuthFlow launchWebAuthFlow */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {String} returns a redirect URL to be used in |launchWebAuthFlow|
|
|
||||||
*/
|
|
||||||
function getRedirectUrlAuthFlow() {
|
|
||||||
const browserApi = typeof browser === 'undefined' ? chrome : browser;
|
|
||||||
return browserApi.identity.getRedirectURL();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} details based on chrome api
|
|
||||||
* @param {string} details.url url that initiates the auth flow
|
|
||||||
* @param {boolean} details.interactive if it is true a window will be displayed
|
|
||||||
* @return {Promise} returns the url containing the token for extraction
|
|
||||||
*/
|
|
||||||
function launchWebAuthFlow(details) {
|
|
||||||
if (typeof browser === 'undefined') {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
chrome.identity.launchWebAuthFlow(details, resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return browser.identity.launchWebAuthFlow(details);
|
|
||||||
}
|
|
|
@ -1,178 +0,0 @@
|
||||||
/* global messageBox Dropbox createZipFileFromText readZipFileFromBlob
|
|
||||||
launchWebAuthFlow getRedirectUrlAuthFlow importFromString resolve
|
|
||||||
$ $create t chromeLocal API getOwnTab */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const DROPBOX_API_KEY = 'zg52vphuapvpng9';
|
|
||||||
const FILENAME_ZIP_FILE = 'stylus.json';
|
|
||||||
const DROPBOX_FILE = 'stylus.zip';
|
|
||||||
const API_ERROR_STATUS_FILE_NOT_FOUND = 409;
|
|
||||||
const HTTP_STATUS_CANCEL = 499;
|
|
||||||
|
|
||||||
function messageProgressBar(data) {
|
|
||||||
return messageBox({
|
|
||||||
title: `${data.title}`,
|
|
||||||
className: 'config-dialog',
|
|
||||||
contents: [
|
|
||||||
$create('p', data.text)
|
|
||||||
],
|
|
||||||
buttons: [{
|
|
||||||
textContent: t('confirmClose'),
|
|
||||||
dataset: {cmd: 'close'},
|
|
||||||
}],
|
|
||||||
}).then(() => {
|
|
||||||
document.body.style.minWidth = '';
|
|
||||||
document.body.style.minHeight = '';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasDropboxAccessToken() {
|
|
||||||
return chromeLocal.getValue('dropbox_access_token');
|
|
||||||
}
|
|
||||||
|
|
||||||
function requestDropboxAccessToken() {
|
|
||||||
const client = new Dropbox.Dropbox({
|
|
||||||
clientId: DROPBOX_API_KEY,
|
|
||||||
fetch
|
|
||||||
});
|
|
||||||
const authUrl = client.getAuthenticationUrl(getRedirectUrlAuthFlow());
|
|
||||||
return launchWebAuthFlow({url: authUrl, interactive: true})
|
|
||||||
.then(urlReturned => {
|
|
||||||
const params = new URLSearchParams(new URL(urlReturned).hash.replace('#', ''));
|
|
||||||
chromeLocal.setValue('dropbox_access_token', params.get('access_token'));
|
|
||||||
return params.get('access_token');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function uploadFileDropbox(client, stylesText) {
|
|
||||||
return client.filesUpload({path: '/' + DROPBOX_FILE, contents: stylesText});
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#sync-dropbox-export').onclick = event => {
|
|
||||||
event.preventDefault();
|
|
||||||
const mode = localStorage.installType;
|
|
||||||
const title = t('syncDropboxStyles');
|
|
||||||
const text = mode === 'normal' ? t('connectingDropbox') : t('connectingDropboxNotAllowed');
|
|
||||||
messageProgressBar({title, text});
|
|
||||||
if (mode !== 'normal') return;
|
|
||||||
|
|
||||||
hasDropboxAccessToken()
|
|
||||||
.then(token => token || requestDropboxAccessToken())
|
|
||||||
.then(token => {
|
|
||||||
const client = new Dropbox.Dropbox({
|
|
||||||
clientId: DROPBOX_API_KEY,
|
|
||||||
accessToken: token,
|
|
||||||
fetch
|
|
||||||
});
|
|
||||||
return client.filesDownload({path: '/' + DROPBOX_FILE})
|
|
||||||
.then(() => messageBox.confirm(t('overwriteFileExport')))
|
|
||||||
.then(ok => {
|
|
||||||
// deletes file if user want to
|
|
||||||
if (!ok) {
|
|
||||||
return Promise.reject({status: HTTP_STATUS_CANCEL});
|
|
||||||
}
|
|
||||||
return client.filesDelete({path: '/' + DROPBOX_FILE});
|
|
||||||
})
|
|
||||||
// file deleted with success, get styles and create a file
|
|
||||||
.then(() => {
|
|
||||||
messageProgressBar({title: title, text: t('gettingStyles')});
|
|
||||||
return API.getAllStyles().then(styles => JSON.stringify(styles, null, '\t'));
|
|
||||||
})
|
|
||||||
// create zip file
|
|
||||||
.then(stylesText => {
|
|
||||||
messageProgressBar({title: title, text: t('zipStyles')});
|
|
||||||
return createZipFileFromText(FILENAME_ZIP_FILE, stylesText);
|
|
||||||
})
|
|
||||||
// create file dropbox
|
|
||||||
.then(zipedText => {
|
|
||||||
messageProgressBar({title: title, text: t('uploadingFile')});
|
|
||||||
return uploadFileDropbox(client, zipedText);
|
|
||||||
})
|
|
||||||
// gives feedback to user
|
|
||||||
.then(() => messageProgressBar({title: title, text: t('exportSavedSuccess')}))
|
|
||||||
// handle not found cases and cancel action
|
|
||||||
.catch(error => {
|
|
||||||
console.log(error);
|
|
||||||
// saving file first time
|
|
||||||
if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
|
|
||||||
API.getAllStyles()
|
|
||||||
.then(styles => {
|
|
||||||
messageProgressBar({title: title, text: t('gettingStyles')});
|
|
||||||
return JSON.stringify(styles, null, '\t');
|
|
||||||
})
|
|
||||||
.then(stylesText => {
|
|
||||||
messageProgressBar({title: title, text: t('zipStyles')});
|
|
||||||
return createZipFileFromText(FILENAME_ZIP_FILE, stylesText);
|
|
||||||
})
|
|
||||||
.then(zipedText => {
|
|
||||||
messageProgressBar({title: title, text: t('uploadingFile')});
|
|
||||||
return uploadFileDropbox(client, zipedText);
|
|
||||||
})
|
|
||||||
.then(() => messageProgressBar({title: title, text: t('exportSavedSuccess')}))
|
|
||||||
.catch(err => messageBox.alert(err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// user cancelled the flow
|
|
||||||
if (error.status === HTTP_STATUS_CANCEL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$('#sync-dropbox-import').onclick = event => {
|
|
||||||
event.preventDefault();
|
|
||||||
const mode = localStorage.installType;
|
|
||||||
const title = t('retrieveDropboxSync');
|
|
||||||
const text = mode === 'normal' ? t('connectingDropbox') : t('connectingDropboxNotAllowed');
|
|
||||||
messageProgressBar({title, text});
|
|
||||||
if (mode !== 'normal') return;
|
|
||||||
|
|
||||||
hasDropboxAccessToken()
|
|
||||||
.then(token => token || requestDropboxAccessToken())
|
|
||||||
.then(token => {
|
|
||||||
const client = new Dropbox.Dropbox({
|
|
||||||
clientId: DROPBOX_API_KEY,
|
|
||||||
accessToken: token,
|
|
||||||
fetch
|
|
||||||
});
|
|
||||||
return client.filesDownload({path: '/' + DROPBOX_FILE})
|
|
||||||
.then(response => {
|
|
||||||
messageProgressBar({title: title, text: t('unzipStyles')});
|
|
||||||
return readZipFileFromBlob(response.fileBlob);
|
|
||||||
})
|
|
||||||
.then(zipedFileBlob => {
|
|
||||||
messageProgressBar({title: title, text: t('readingStyles')});
|
|
||||||
document.body.style.cursor = 'wait';
|
|
||||||
const fReader = new FileReader();
|
|
||||||
fReader.onloadend = event => {
|
|
||||||
const text = event.target.result;
|
|
||||||
const maybeUsercss = !/^[\s\r\n]*\[/.test(text) &&
|
|
||||||
(text.includes('==UserStyle==') || /==UserStyle==/i.test(text));
|
|
||||||
(!maybeUsercss ?
|
|
||||||
importFromString(text) :
|
|
||||||
getOwnTab().then(tab => {
|
|
||||||
tab.url = URL.createObjectURL(new Blob([text], {type: 'text/css'}));
|
|
||||||
return API.openUsercssInstallPage({direct: true, tab})
|
|
||||||
.then(() => URL.revokeObjectURL(tab.url));
|
|
||||||
})
|
|
||||||
).then(numStyles => {
|
|
||||||
document.body.style.cursor = '';
|
|
||||||
resolve(numStyles);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
fReader.readAsText(zipedFileBlob, 'utf-8');
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
// no file
|
|
||||||
if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
|
|
||||||
messageBox.alert(t('noFileToImport'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
messageBox.alert(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -11,9 +11,6 @@ const files = {
|
||||||
'*', // only update existing vendor files
|
'*', // only update existing vendor files
|
||||||
'theme' // update all theme files
|
'theme' // update all theme files
|
||||||
],
|
],
|
||||||
'dropbox': [
|
|
||||||
'dist/Dropbox-sdk.js → dropbox-sdk.js'
|
|
||||||
],
|
|
||||||
'jsonlint': [
|
'jsonlint': [
|
||||||
'lib/jsonlint.js → jsonlint.js'
|
'lib/jsonlint.js → jsonlint.js'
|
||||||
],
|
],
|
||||||
|
@ -35,12 +32,6 @@ const files = {
|
||||||
'usercss-meta': [
|
'usercss-meta': [
|
||||||
'dist/usercss-meta.min.js → usercss-meta.min.js'
|
'dist/usercss-meta.min.js → usercss-meta.min.js'
|
||||||
],
|
],
|
||||||
'zipjs-browserify': [
|
|
||||||
'vendor/deflate.js → deflate.js',
|
|
||||||
'vendor/inflate.js → inflate.js',
|
|
||||||
'vendor/z-worker.js → z-worker.js',
|
|
||||||
'vendor/zip.js → zip.js'
|
|
||||||
],
|
|
||||||
'db-to-cloud': [
|
'db-to-cloud': [
|
||||||
'dist/db-to-cloud.min.js → db-to-cloud.min.js'
|
'dist/db-to-cloud.min.js → db-to-cloud.min.js'
|
||||||
]
|
]
|
||||||
|
|
20
vendor/dropbox/LICENSE
vendored
20
vendor/dropbox/LICENSE
vendored
|
@ -1,20 +0,0 @@
|
||||||
Copyright (c) 2016 Dropbox Inc., http://www.dropbox.com/
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
12
vendor/dropbox/README.md
vendored
12
vendor/dropbox/README.md
vendored
|
@ -1,12 +0,0 @@
|
||||||
## Dropbox SDK v4.0.30
|
|
||||||
|
|
||||||
Dropbox SDK JS installed via npm - source repo:
|
|
||||||
|
|
||||||
https://github.com/dropbox/dropbox-sdk-js/tree/v4.0.30
|
|
||||||
|
|
||||||
The source repo **does not** include the `dist` folder with the generated `dropbox-sdk.js`
|
|
||||||
distribution file. It can only be obtained from the npm `node_modules` folder after installing
|
|
||||||
the module.
|
|
||||||
|
|
||||||
- https://www.npmjs.com/package/dropbox
|
|
||||||
- https://github.com/dropbox/dropbox-sdk-js/releases
|
|
5434
vendor/dropbox/dropbox-sdk.js
vendored
5434
vendor/dropbox/dropbox-sdk.js
vendored
File diff suppressed because it is too large
Load Diff
22
vendor/zipjs-browserify/LICENSE
vendored
22
vendor/zipjs-browserify/LICENSE
vendored
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (c) 2013 Gildas Lormeau. All rights reserved.
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in
|
|
||||||
the documentation and/or other materials provided with the distribution.
|
|
||||||
3. The names of the authors may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
||||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
||||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
8
vendor/zipjs-browserify/README.md
vendored
8
vendor/zipjs-browserify/README.md
vendored
|
@ -1,8 +0,0 @@
|
||||||
## zipjs-browserify v1.0.1
|
|
||||||
|
|
||||||
zipjs installed via npm - source repo:
|
|
||||||
|
|
||||||
- https://github.com/juliangruber/zipjs-browserify/tree/v1.0.1/vendor/deflate.js
|
|
||||||
- https://github.com/juliangruber/zipjs-browserify/tree/v1.0.1/vendor/inflate.js
|
|
||||||
- https://github.com/juliangruber/zipjs-browserify/tree/v1.0.1/vendor/z-worker.js
|
|
||||||
- https://github.com/juliangruber/zipjs-browserify/tree/v1.0.1/vendor/zip.js
|
|
2060
vendor/zipjs-browserify/deflate.js
vendored
2060
vendor/zipjs-browserify/deflate.js
vendored
File diff suppressed because it is too large
Load Diff
2155
vendor/zipjs-browserify/inflate.js
vendored
2155
vendor/zipjs-browserify/inflate.js
vendored
File diff suppressed because it is too large
Load Diff
153
vendor/zipjs-browserify/z-worker.js
vendored
153
vendor/zipjs-browserify/z-worker.js
vendored
|
@ -1,153 +0,0 @@
|
||||||
/* jshint worker:true */
|
|
||||||
(function main(global) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
if (global.zWorkerInitialized)
|
|
||||||
throw new Error('z-worker.js should be run only once');
|
|
||||||
global.zWorkerInitialized = true;
|
|
||||||
|
|
||||||
addEventListener("message", function(event) {
|
|
||||||
var message = event.data, type = message.type, sn = message.sn;
|
|
||||||
var handler = handlers[type];
|
|
||||||
if (handler) {
|
|
||||||
try {
|
|
||||||
handler(message);
|
|
||||||
} catch (e) {
|
|
||||||
onError(type, sn, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//for debug
|
|
||||||
//postMessage({type: 'echo', originalType: type, sn: sn});
|
|
||||||
});
|
|
||||||
|
|
||||||
var handlers = {
|
|
||||||
importScripts: doImportScripts,
|
|
||||||
newTask: newTask,
|
|
||||||
append: processData,
|
|
||||||
flush: processData,
|
|
||||||
};
|
|
||||||
|
|
||||||
// deflater/inflater tasks indexed by serial numbers
|
|
||||||
var tasks = {};
|
|
||||||
|
|
||||||
function doImportScripts(msg) {
|
|
||||||
if (msg.scripts && msg.scripts.length > 0)
|
|
||||||
importScripts.apply(undefined, msg.scripts);
|
|
||||||
postMessage({type: 'importScripts'});
|
|
||||||
}
|
|
||||||
|
|
||||||
function newTask(msg) {
|
|
||||||
var CodecClass = global[msg.codecClass];
|
|
||||||
var sn = msg.sn;
|
|
||||||
if (tasks[sn])
|
|
||||||
throw Error('duplicated sn');
|
|
||||||
tasks[sn] = {
|
|
||||||
codec: new CodecClass(msg.options),
|
|
||||||
crcInput: msg.crcType === 'input',
|
|
||||||
crcOutput: msg.crcType === 'output',
|
|
||||||
crc: new Crc32(),
|
|
||||||
};
|
|
||||||
postMessage({type: 'newTask', sn: sn});
|
|
||||||
}
|
|
||||||
|
|
||||||
// performance may not be supported
|
|
||||||
var now = global.performance ? global.performance.now.bind(global.performance) : Date.now;
|
|
||||||
|
|
||||||
function processData(msg) {
|
|
||||||
var sn = msg.sn, type = msg.type, input = msg.data;
|
|
||||||
var task = tasks[sn];
|
|
||||||
// allow creating codec on first append
|
|
||||||
if (!task && msg.codecClass) {
|
|
||||||
newTask(msg);
|
|
||||||
task = tasks[sn];
|
|
||||||
}
|
|
||||||
var isAppend = type === 'append';
|
|
||||||
var start = now();
|
|
||||||
var output;
|
|
||||||
if (isAppend) {
|
|
||||||
try {
|
|
||||||
output = task.codec.append(input, function onprogress(loaded) {
|
|
||||||
postMessage({type: 'progress', sn: sn, loaded: loaded});
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
delete tasks[sn];
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
delete tasks[sn];
|
|
||||||
output = task.codec.flush();
|
|
||||||
}
|
|
||||||
var codecTime = now() - start;
|
|
||||||
|
|
||||||
start = now();
|
|
||||||
if (input && task.crcInput)
|
|
||||||
task.crc.append(input);
|
|
||||||
if (output && task.crcOutput)
|
|
||||||
task.crc.append(output);
|
|
||||||
var crcTime = now() - start;
|
|
||||||
|
|
||||||
var rmsg = {type: type, sn: sn, codecTime: codecTime, crcTime: crcTime};
|
|
||||||
var transferables = [];
|
|
||||||
if (output) {
|
|
||||||
rmsg.data = output;
|
|
||||||
transferables.push(output.buffer);
|
|
||||||
}
|
|
||||||
if (!isAppend && (task.crcInput || task.crcOutput))
|
|
||||||
rmsg.crc = task.crc.get();
|
|
||||||
|
|
||||||
// posting a message with transferables will fail on IE10
|
|
||||||
try {
|
|
||||||
postMessage(rmsg, transferables);
|
|
||||||
} catch(ex) {
|
|
||||||
postMessage(rmsg); // retry without transferables
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onError(type, sn, e) {
|
|
||||||
var msg = {
|
|
||||||
type: type,
|
|
||||||
sn: sn,
|
|
||||||
error: formatError(e)
|
|
||||||
};
|
|
||||||
postMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatError(e) {
|
|
||||||
return { message: e.message, stack: e.stack };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crc32 code copied from file zip.js
|
|
||||||
function Crc32() {
|
|
||||||
this.crc = -1;
|
|
||||||
}
|
|
||||||
Crc32.prototype.append = function append(data) {
|
|
||||||
var crc = this.crc | 0, table = this.table;
|
|
||||||
for (var offset = 0, len = data.length | 0; offset < len; offset++)
|
|
||||||
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
|
|
||||||
this.crc = crc;
|
|
||||||
};
|
|
||||||
Crc32.prototype.get = function get() {
|
|
||||||
return ~this.crc;
|
|
||||||
};
|
|
||||||
Crc32.prototype.table = (function() {
|
|
||||||
var i, j, t, table = []; // Uint32Array is actually slower than []
|
|
||||||
for (i = 0; i < 256; i++) {
|
|
||||||
t = i;
|
|
||||||
for (j = 0; j < 8; j++)
|
|
||||||
if (t & 1)
|
|
||||||
t = (t >>> 1) ^ 0xEDB88320;
|
|
||||||
else
|
|
||||||
t = t >>> 1;
|
|
||||||
table[i] = t;
|
|
||||||
}
|
|
||||||
return table;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// "no-op" codec
|
|
||||||
function NOOP() {}
|
|
||||||
global.NOOP = NOOP;
|
|
||||||
NOOP.prototype.append = function append(bytes, onprogress) {
|
|
||||||
return bytes;
|
|
||||||
};
|
|
||||||
NOOP.prototype.flush = function flush() {};
|
|
||||||
})(this);
|
|
966
vendor/zipjs-browserify/zip.js
vendored
966
vendor/zipjs-browserify/zip.js
vendored
|
@ -1,966 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (c) 2013 Gildas Lormeau. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in
|
|
||||||
the documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. The names of the authors may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
||||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
||||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function(obj) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var ERR_BAD_FORMAT = "File format is not recognized.";
|
|
||||||
var ERR_CRC = "CRC failed.";
|
|
||||||
var ERR_ENCRYPTED = "File contains encrypted entry.";
|
|
||||||
var ERR_ZIP64 = "File is using Zip64 (4gb+ file size).";
|
|
||||||
var ERR_READ = "Error while reading zip file.";
|
|
||||||
var ERR_WRITE = "Error while writing zip file.";
|
|
||||||
var ERR_WRITE_DATA = "Error while writing file data.";
|
|
||||||
var ERR_READ_DATA = "Error while reading file data.";
|
|
||||||
var ERR_DUPLICATED_NAME = "File already exists.";
|
|
||||||
var CHUNK_SIZE = 512 * 1024;
|
|
||||||
|
|
||||||
var TEXT_PLAIN = "text/plain";
|
|
||||||
|
|
||||||
var appendABViewSupported;
|
|
||||||
try {
|
|
||||||
appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0;
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
function Crc32() {
|
|
||||||
this.crc = -1;
|
|
||||||
}
|
|
||||||
Crc32.prototype.append = function append(data) {
|
|
||||||
var crc = this.crc | 0, table = this.table;
|
|
||||||
for (var offset = 0, len = data.length | 0; offset < len; offset++)
|
|
||||||
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
|
|
||||||
this.crc = crc;
|
|
||||||
};
|
|
||||||
Crc32.prototype.get = function get() {
|
|
||||||
return ~this.crc;
|
|
||||||
};
|
|
||||||
Crc32.prototype.table = (function() {
|
|
||||||
var i, j, t, table = []; // Uint32Array is actually slower than []
|
|
||||||
for (i = 0; i < 256; i++) {
|
|
||||||
t = i;
|
|
||||||
for (j = 0; j < 8; j++)
|
|
||||||
if (t & 1)
|
|
||||||
t = (t >>> 1) ^ 0xEDB88320;
|
|
||||||
else
|
|
||||||
t = t >>> 1;
|
|
||||||
table[i] = t;
|
|
||||||
}
|
|
||||||
return table;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// "no-op" codec
|
|
||||||
function NOOP() {}
|
|
||||||
NOOP.prototype.append = function append(bytes, onprogress) {
|
|
||||||
return bytes;
|
|
||||||
};
|
|
||||||
NOOP.prototype.flush = function flush() {};
|
|
||||||
|
|
||||||
function blobSlice(blob, index, length) {
|
|
||||||
if (index < 0 || length < 0 || index + length > blob.size)
|
|
||||||
throw new RangeError('offset:' + index + ', length:' + length + ', size:' + blob.size);
|
|
||||||
if (blob.slice)
|
|
||||||
return blob.slice(index, index + length);
|
|
||||||
else if (blob.webkitSlice)
|
|
||||||
return blob.webkitSlice(index, index + length);
|
|
||||||
else if (blob.mozSlice)
|
|
||||||
return blob.mozSlice(index, index + length);
|
|
||||||
else if (blob.msSlice)
|
|
||||||
return blob.msSlice(index, index + length);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDataHelper(byteLength, bytes) {
|
|
||||||
var dataBuffer, dataArray;
|
|
||||||
dataBuffer = new ArrayBuffer(byteLength);
|
|
||||||
dataArray = new Uint8Array(dataBuffer);
|
|
||||||
if (bytes)
|
|
||||||
dataArray.set(bytes, 0);
|
|
||||||
return {
|
|
||||||
buffer : dataBuffer,
|
|
||||||
array : dataArray,
|
|
||||||
view : new DataView(dataBuffer)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Readers
|
|
||||||
function Reader() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function TextReader(text) {
|
|
||||||
var that = this, blobReader;
|
|
||||||
|
|
||||||
function init(callback, onerror) {
|
|
||||||
var blob = new Blob([ text ], {
|
|
||||||
type : TEXT_PLAIN
|
|
||||||
});
|
|
||||||
blobReader = new BlobReader(blob);
|
|
||||||
blobReader.init(function() {
|
|
||||||
that.size = blobReader.size;
|
|
||||||
callback();
|
|
||||||
}, onerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
function readUint8Array(index, length, callback, onerror) {
|
|
||||||
blobReader.readUint8Array(index, length, callback, onerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
that.size = 0;
|
|
||||||
that.init = init;
|
|
||||||
that.readUint8Array = readUint8Array;
|
|
||||||
}
|
|
||||||
TextReader.prototype = new Reader();
|
|
||||||
TextReader.prototype.constructor = TextReader;
|
|
||||||
|
|
||||||
function Data64URIReader(dataURI) {
|
|
||||||
var that = this, dataStart;
|
|
||||||
|
|
||||||
function init(callback) {
|
|
||||||
var dataEnd = dataURI.length;
|
|
||||||
while (dataURI.charAt(dataEnd - 1) == "=")
|
|
||||||
dataEnd--;
|
|
||||||
dataStart = dataURI.indexOf(",") + 1;
|
|
||||||
that.size = Math.floor((dataEnd - dataStart) * 0.75);
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function readUint8Array(index, length, callback) {
|
|
||||||
var i, data = getDataHelper(length);
|
|
||||||
var start = Math.floor(index / 3) * 4;
|
|
||||||
var end = Math.ceil((index + length) / 3) * 4;
|
|
||||||
var bytes = obj.atob(dataURI.substring(start + dataStart, end + dataStart));
|
|
||||||
var delta = index - Math.floor(start / 4) * 3;
|
|
||||||
for (i = delta; i < delta + length; i++)
|
|
||||||
data.array[i - delta] = bytes.charCodeAt(i);
|
|
||||||
callback(data.array);
|
|
||||||
}
|
|
||||||
|
|
||||||
that.size = 0;
|
|
||||||
that.init = init;
|
|
||||||
that.readUint8Array = readUint8Array;
|
|
||||||
}
|
|
||||||
Data64URIReader.prototype = new Reader();
|
|
||||||
Data64URIReader.prototype.constructor = Data64URIReader;
|
|
||||||
|
|
||||||
function BlobReader(blob) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
function init(callback) {
|
|
||||||
that.size = blob.size;
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function readUint8Array(index, length, callback, onerror) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.onload = function(e) {
|
|
||||||
callback(new Uint8Array(e.target.result));
|
|
||||||
};
|
|
||||||
reader.onerror = onerror;
|
|
||||||
try {
|
|
||||||
reader.readAsArrayBuffer(blobSlice(blob, index, length));
|
|
||||||
} catch (e) {
|
|
||||||
onerror(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
that.size = 0;
|
|
||||||
that.init = init;
|
|
||||||
that.readUint8Array = readUint8Array;
|
|
||||||
}
|
|
||||||
BlobReader.prototype = new Reader();
|
|
||||||
BlobReader.prototype.constructor = BlobReader;
|
|
||||||
|
|
||||||
// Writers
|
|
||||||
|
|
||||||
function Writer() {
|
|
||||||
}
|
|
||||||
Writer.prototype.getData = function(callback) {
|
|
||||||
callback(this.data);
|
|
||||||
};
|
|
||||||
|
|
||||||
function TextWriter(encoding) {
|
|
||||||
var that = this, blob;
|
|
||||||
|
|
||||||
function init(callback) {
|
|
||||||
blob = new Blob([], {
|
|
||||||
type : TEXT_PLAIN
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeUint8Array(array, callback) {
|
|
||||||
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
|
|
||||||
type : TEXT_PLAIN
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getData(callback, onerror) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.onload = function(e) {
|
|
||||||
callback(e.target.result);
|
|
||||||
};
|
|
||||||
reader.onerror = onerror;
|
|
||||||
reader.readAsText(blob, encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
that.init = init;
|
|
||||||
that.writeUint8Array = writeUint8Array;
|
|
||||||
that.getData = getData;
|
|
||||||
}
|
|
||||||
TextWriter.prototype = new Writer();
|
|
||||||
TextWriter.prototype.constructor = TextWriter;
|
|
||||||
|
|
||||||
function Data64URIWriter(contentType) {
|
|
||||||
var that = this, data = "", pending = "";
|
|
||||||
|
|
||||||
function init(callback) {
|
|
||||||
data += "data:" + (contentType || "") + ";base64,";
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeUint8Array(array, callback) {
|
|
||||||
var i, delta = pending.length, dataString = pending;
|
|
||||||
pending = "";
|
|
||||||
for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++)
|
|
||||||
dataString += String.fromCharCode(array[i]);
|
|
||||||
for (; i < array.length; i++)
|
|
||||||
pending += String.fromCharCode(array[i]);
|
|
||||||
if (dataString.length > 2)
|
|
||||||
data += obj.btoa(dataString);
|
|
||||||
else
|
|
||||||
pending = dataString;
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getData(callback) {
|
|
||||||
callback(data + obj.btoa(pending));
|
|
||||||
}
|
|
||||||
|
|
||||||
that.init = init;
|
|
||||||
that.writeUint8Array = writeUint8Array;
|
|
||||||
that.getData = getData;
|
|
||||||
}
|
|
||||||
Data64URIWriter.prototype = new Writer();
|
|
||||||
Data64URIWriter.prototype.constructor = Data64URIWriter;
|
|
||||||
|
|
||||||
function BlobWriter(contentType) {
|
|
||||||
var blob, that = this;
|
|
||||||
|
|
||||||
function init(callback) {
|
|
||||||
blob = new Blob([], {
|
|
||||||
type : contentType
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeUint8Array(array, callback) {
|
|
||||||
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
|
|
||||||
type : contentType
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getData(callback) {
|
|
||||||
callback(blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
that.init = init;
|
|
||||||
that.writeUint8Array = writeUint8Array;
|
|
||||||
that.getData = getData;
|
|
||||||
}
|
|
||||||
BlobWriter.prototype = new Writer();
|
|
||||||
BlobWriter.prototype.constructor = BlobWriter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* inflate/deflate core functions
|
|
||||||
* @param worker {Worker} web worker for the task.
|
|
||||||
* @param initialMessage {Object} initial message to be sent to the worker. should contain
|
|
||||||
* sn(serial number for distinguishing multiple tasks sent to the worker), and codecClass.
|
|
||||||
* This function may add more properties before sending.
|
|
||||||
*/
|
|
||||||
function launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror) {
|
|
||||||
var chunkIndex = 0, index, outputSize, sn = initialMessage.sn, crc;
|
|
||||||
|
|
||||||
function onflush() {
|
|
||||||
worker.removeEventListener('message', onmessage, false);
|
|
||||||
onend(outputSize, crc);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onmessage(event) {
|
|
||||||
var message = event.data, data = message.data, err = message.error;
|
|
||||||
if (err) {
|
|
||||||
err.toString = function () { return 'Error: ' + this.message; };
|
|
||||||
onreaderror(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (message.sn !== sn)
|
|
||||||
return;
|
|
||||||
if (typeof message.codecTime === 'number')
|
|
||||||
worker.codecTime += message.codecTime; // should be before onflush()
|
|
||||||
if (typeof message.crcTime === 'number')
|
|
||||||
worker.crcTime += message.crcTime;
|
|
||||||
|
|
||||||
switch (message.type) {
|
|
||||||
case 'append':
|
|
||||||
if (data) {
|
|
||||||
outputSize += data.length;
|
|
||||||
writer.writeUint8Array(data, function() {
|
|
||||||
step();
|
|
||||||
}, onwriteerror);
|
|
||||||
} else
|
|
||||||
step();
|
|
||||||
break;
|
|
||||||
case 'flush':
|
|
||||||
crc = message.crc;
|
|
||||||
if (data) {
|
|
||||||
outputSize += data.length;
|
|
||||||
writer.writeUint8Array(data, function() {
|
|
||||||
onflush();
|
|
||||||
}, onwriteerror);
|
|
||||||
} else
|
|
||||||
onflush();
|
|
||||||
break;
|
|
||||||
case 'progress':
|
|
||||||
if (onprogress)
|
|
||||||
onprogress(index + message.loaded, size);
|
|
||||||
break;
|
|
||||||
case 'importScripts': //no need to handle here
|
|
||||||
case 'newTask':
|
|
||||||
case 'echo':
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.warn('zip.js:launchWorkerProcess: unknown message: ', message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function step() {
|
|
||||||
index = chunkIndex * CHUNK_SIZE;
|
|
||||||
// use `<=` instead of `<`, because `size` may be 0.
|
|
||||||
if (index <= size) {
|
|
||||||
reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
|
|
||||||
if (onprogress)
|
|
||||||
onprogress(index, size);
|
|
||||||
var msg = index === 0 ? initialMessage : {sn : sn};
|
|
||||||
msg.type = 'append';
|
|
||||||
msg.data = array;
|
|
||||||
|
|
||||||
// posting a message with transferables will fail on IE10
|
|
||||||
try {
|
|
||||||
worker.postMessage(msg, [array.buffer]);
|
|
||||||
} catch(ex) {
|
|
||||||
worker.postMessage(msg); // retry without transferables
|
|
||||||
}
|
|
||||||
chunkIndex++;
|
|
||||||
}, onreaderror);
|
|
||||||
} else {
|
|
||||||
worker.postMessage({
|
|
||||||
sn: sn,
|
|
||||||
type: 'flush'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outputSize = 0;
|
|
||||||
worker.addEventListener('message', onmessage, false);
|
|
||||||
step();
|
|
||||||
}
|
|
||||||
|
|
||||||
function launchProcess(process, reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror) {
|
|
||||||
var chunkIndex = 0, index, outputSize = 0,
|
|
||||||
crcInput = crcType === 'input',
|
|
||||||
crcOutput = crcType === 'output',
|
|
||||||
crc = new Crc32();
|
|
||||||
function step() {
|
|
||||||
var outputData;
|
|
||||||
index = chunkIndex * CHUNK_SIZE;
|
|
||||||
if (index < size)
|
|
||||||
reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(inputData) {
|
|
||||||
var outputData;
|
|
||||||
try {
|
|
||||||
outputData = process.append(inputData, function(loaded) {
|
|
||||||
if (onprogress)
|
|
||||||
onprogress(index + loaded, size);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
onreaderror(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (outputData) {
|
|
||||||
outputSize += outputData.length;
|
|
||||||
writer.writeUint8Array(outputData, function() {
|
|
||||||
chunkIndex++;
|
|
||||||
setTimeout(step, 1);
|
|
||||||
}, onwriteerror);
|
|
||||||
if (crcOutput)
|
|
||||||
crc.append(outputData);
|
|
||||||
} else {
|
|
||||||
chunkIndex++;
|
|
||||||
setTimeout(step, 1);
|
|
||||||
}
|
|
||||||
if (crcInput)
|
|
||||||
crc.append(inputData);
|
|
||||||
if (onprogress)
|
|
||||||
onprogress(index, size);
|
|
||||||
}, onreaderror);
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
outputData = process.flush();
|
|
||||||
} catch (e) {
|
|
||||||
onreaderror(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (outputData) {
|
|
||||||
if (crcOutput)
|
|
||||||
crc.append(outputData);
|
|
||||||
outputSize += outputData.length;
|
|
||||||
writer.writeUint8Array(outputData, function() {
|
|
||||||
onend(outputSize, crc.get());
|
|
||||||
}, onwriteerror);
|
|
||||||
} else
|
|
||||||
onend(outputSize, crc.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
step();
|
|
||||||
}
|
|
||||||
|
|
||||||
function inflate(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
|
|
||||||
var crcType = computeCrc32 ? 'output' : 'none';
|
|
||||||
if (obj.zip.useWebWorkers) {
|
|
||||||
var initialMessage = {
|
|
||||||
sn: sn,
|
|
||||||
codecClass: 'Inflater',
|
|
||||||
crcType: crcType,
|
|
||||||
};
|
|
||||||
launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror);
|
|
||||||
} else
|
|
||||||
launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
function deflate(worker, sn, reader, writer, level, onend, onprogress, onreaderror, onwriteerror) {
|
|
||||||
var crcType = 'input';
|
|
||||||
if (obj.zip.useWebWorkers) {
|
|
||||||
var initialMessage = {
|
|
||||||
sn: sn,
|
|
||||||
options: {level: level},
|
|
||||||
codecClass: 'Deflater',
|
|
||||||
crcType: crcType,
|
|
||||||
};
|
|
||||||
launchWorkerProcess(worker, initialMessage, reader, writer, 0, reader.size, onprogress, onend, onreaderror, onwriteerror);
|
|
||||||
} else
|
|
||||||
launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, crcType, onprogress, onend, onreaderror, onwriteerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
function copy(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
|
|
||||||
var crcType = 'input';
|
|
||||||
if (obj.zip.useWebWorkers && computeCrc32) {
|
|
||||||
var initialMessage = {
|
|
||||||
sn: sn,
|
|
||||||
codecClass: 'NOOP',
|
|
||||||
crcType: crcType,
|
|
||||||
};
|
|
||||||
launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror);
|
|
||||||
} else
|
|
||||||
launchProcess(new NOOP(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ZipReader
|
|
||||||
|
|
||||||
function decodeASCII(str) {
|
|
||||||
var i, out = "", charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB',
|
|
||||||
'\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9',
|
|
||||||
'\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1',
|
|
||||||
'\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6',
|
|
||||||
'\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3',
|
|
||||||
'\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE',
|
|
||||||
'\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE',
|
|
||||||
'\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7',
|
|
||||||
'\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ' ];
|
|
||||||
for (i = 0; i < str.length; i++) {
|
|
||||||
charCode = str.charCodeAt(i) & 0xFF;
|
|
||||||
if (charCode > 127)
|
|
||||||
out += extendedASCII[charCode - 128];
|
|
||||||
else
|
|
||||||
out += String.fromCharCode(charCode);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
function decodeUTF8(string) {
|
|
||||||
return decodeURIComponent(escape(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getString(bytes) {
|
|
||||||
var i, str = "";
|
|
||||||
for (i = 0; i < bytes.length; i++)
|
|
||||||
str += String.fromCharCode(bytes[i]);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDate(timeRaw) {
|
|
||||||
var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff;
|
|
||||||
try {
|
|
||||||
return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5,
|
|
||||||
(time & 0x001F) * 2, 0);
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function readCommonHeader(entry, data, index, centralDirectory, onerror) {
|
|
||||||
entry.version = data.view.getUint16(index, true);
|
|
||||||
entry.bitFlag = data.view.getUint16(index + 2, true);
|
|
||||||
entry.compressionMethod = data.view.getUint16(index + 4, true);
|
|
||||||
entry.lastModDateRaw = data.view.getUint32(index + 6, true);
|
|
||||||
entry.lastModDate = getDate(entry.lastModDateRaw);
|
|
||||||
if ((entry.bitFlag & 0x01) === 0x01) {
|
|
||||||
onerror(ERR_ENCRYPTED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) {
|
|
||||||
entry.crc32 = data.view.getUint32(index + 10, true);
|
|
||||||
entry.compressedSize = data.view.getUint32(index + 14, true);
|
|
||||||
entry.uncompressedSize = data.view.getUint32(index + 18, true);
|
|
||||||
}
|
|
||||||
if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) {
|
|
||||||
onerror(ERR_ZIP64);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entry.filenameLength = data.view.getUint16(index + 22, true);
|
|
||||||
entry.extraFieldLength = data.view.getUint16(index + 24, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createZipReader(reader, callback, onerror) {
|
|
||||||
var inflateSN = 0;
|
|
||||||
|
|
||||||
function Entry() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Entry.prototype.getData = function(writer, onend, onprogress, checkCrc32) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
function testCrc32(crc32) {
|
|
||||||
var dataCrc32 = getDataHelper(4);
|
|
||||||
dataCrc32.view.setUint32(0, crc32);
|
|
||||||
return that.crc32 == dataCrc32.view.getUint32(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWriterData(uncompressedSize, crc32) {
|
|
||||||
if (checkCrc32 && !testCrc32(crc32))
|
|
||||||
onerror(ERR_CRC);
|
|
||||||
else
|
|
||||||
writer.getData(function(data) {
|
|
||||||
onend(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function onreaderror(err) {
|
|
||||||
onerror(err || ERR_READ_DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onwriteerror(err) {
|
|
||||||
onerror(err || ERR_WRITE_DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.readUint8Array(that.offset, 30, function(bytes) {
|
|
||||||
var data = getDataHelper(bytes.length, bytes), dataOffset;
|
|
||||||
if (data.view.getUint32(0) != 0x504b0304) {
|
|
||||||
onerror(ERR_BAD_FORMAT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
readCommonHeader(that, data, 4, false, onerror);
|
|
||||||
dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength;
|
|
||||||
writer.init(function() {
|
|
||||||
if (that.compressionMethod === 0)
|
|
||||||
copy(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
|
|
||||||
else
|
|
||||||
inflate(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
|
|
||||||
}, onwriteerror);
|
|
||||||
}, onreaderror);
|
|
||||||
};
|
|
||||||
|
|
||||||
function seekEOCDR(eocdrCallback) {
|
|
||||||
// "End of central directory record" is the last part of a zip archive, and is at least 22 bytes long.
|
|
||||||
// Zip file comment is the last part of EOCDR and has max length of 64KB,
|
|
||||||
// so we only have to search the last 64K + 22 bytes of a archive for EOCDR signature (0x06054b50).
|
|
||||||
var EOCDR_MIN = 22;
|
|
||||||
if (reader.size < EOCDR_MIN) {
|
|
||||||
onerror(ERR_BAD_FORMAT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var ZIP_COMMENT_MAX = 256 * 256, EOCDR_MAX = EOCDR_MIN + ZIP_COMMENT_MAX;
|
|
||||||
|
|
||||||
// In most cases, the EOCDR is EOCDR_MIN bytes long
|
|
||||||
doSeek(EOCDR_MIN, function() {
|
|
||||||
// If not found, try within EOCDR_MAX bytes
|
|
||||||
doSeek(Math.min(EOCDR_MAX, reader.size), function() {
|
|
||||||
onerror(ERR_BAD_FORMAT);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// seek last length bytes of file for EOCDR
|
|
||||||
function doSeek(length, eocdrNotFoundCallback) {
|
|
||||||
reader.readUint8Array(reader.size - length, length, function(bytes) {
|
|
||||||
for (var i = bytes.length - EOCDR_MIN; i >= 0; i--) {
|
|
||||||
if (bytes[i] === 0x50 && bytes[i + 1] === 0x4b && bytes[i + 2] === 0x05 && bytes[i + 3] === 0x06) {
|
|
||||||
eocdrCallback(new DataView(bytes.buffer, i, EOCDR_MIN));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eocdrNotFoundCallback();
|
|
||||||
}, function() {
|
|
||||||
onerror(ERR_READ);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var zipReader = {
|
|
||||||
getEntries : function(callback) {
|
|
||||||
var worker = this._worker;
|
|
||||||
// look for End of central directory record
|
|
||||||
seekEOCDR(function(dataView) {
|
|
||||||
var datalength, fileslength;
|
|
||||||
datalength = dataView.getUint32(16, true);
|
|
||||||
fileslength = dataView.getUint16(8, true);
|
|
||||||
if (datalength < 0 || datalength >= reader.size) {
|
|
||||||
onerror(ERR_BAD_FORMAT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reader.readUint8Array(datalength, reader.size - datalength, function(bytes) {
|
|
||||||
var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes);
|
|
||||||
for (i = 0; i < fileslength; i++) {
|
|
||||||
entry = new Entry();
|
|
||||||
entry._worker = worker;
|
|
||||||
if (data.view.getUint32(index) != 0x504b0102) {
|
|
||||||
onerror(ERR_BAD_FORMAT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
readCommonHeader(entry, data, index + 6, true, onerror);
|
|
||||||
entry.commentLength = data.view.getUint16(index + 32, true);
|
|
||||||
entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10);
|
|
||||||
entry.offset = data.view.getUint32(index + 42, true);
|
|
||||||
filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength));
|
|
||||||
entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename);
|
|
||||||
if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/")
|
|
||||||
entry.directory = true;
|
|
||||||
comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46
|
|
||||||
+ entry.filenameLength + entry.extraFieldLength + entry.commentLength));
|
|
||||||
entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment);
|
|
||||||
entries.push(entry);
|
|
||||||
index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength;
|
|
||||||
}
|
|
||||||
callback(entries);
|
|
||||||
}, function() {
|
|
||||||
onerror(ERR_READ);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
close : function(callback) {
|
|
||||||
if (this._worker) {
|
|
||||||
this._worker.terminate();
|
|
||||||
this._worker = null;
|
|
||||||
}
|
|
||||||
if (callback)
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
_worker: null
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!obj.zip.useWebWorkers)
|
|
||||||
callback(zipReader);
|
|
||||||
else {
|
|
||||||
createWorker('inflater',
|
|
||||||
function(worker) {
|
|
||||||
zipReader._worker = worker;
|
|
||||||
callback(zipReader);
|
|
||||||
},
|
|
||||||
function(err) {
|
|
||||||
onerror(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ZipWriter
|
|
||||||
|
|
||||||
function encodeUTF8(string) {
|
|
||||||
return unescape(encodeURIComponent(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBytes(str) {
|
|
||||||
var i, array = [];
|
|
||||||
for (i = 0; i < str.length; i++)
|
|
||||||
array.push(str.charCodeAt(i));
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createZipWriter(writer, callback, onerror, dontDeflate) {
|
|
||||||
var files = {}, filenames = [], datalength = 0;
|
|
||||||
var deflateSN = 0;
|
|
||||||
|
|
||||||
function onwriteerror(err) {
|
|
||||||
onerror(err || ERR_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onreaderror(err) {
|
|
||||||
onerror(err || ERR_READ_DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
var zipWriter = {
|
|
||||||
add : function(name, reader, onend, onprogress, options) {
|
|
||||||
var header, filename, date;
|
|
||||||
var worker = this._worker;
|
|
||||||
|
|
||||||
function writeHeader(callback) {
|
|
||||||
var data;
|
|
||||||
date = options.lastModDate || new Date();
|
|
||||||
header = getDataHelper(26);
|
|
||||||
files[name] = {
|
|
||||||
headerArray : header.array,
|
|
||||||
directory : options.directory,
|
|
||||||
filename : filename,
|
|
||||||
offset : datalength,
|
|
||||||
comment : getBytes(encodeUTF8(options.comment || ""))
|
|
||||||
};
|
|
||||||
header.view.setUint32(0, 0x14000808);
|
|
||||||
if (options.version)
|
|
||||||
header.view.setUint8(0, options.version);
|
|
||||||
if (!dontDeflate && options.level !== 0 && !options.directory)
|
|
||||||
header.view.setUint16(4, 0x0800);
|
|
||||||
header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true);
|
|
||||||
header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true);
|
|
||||||
header.view.setUint16(22, filename.length, true);
|
|
||||||
data = getDataHelper(30 + filename.length);
|
|
||||||
data.view.setUint32(0, 0x504b0304);
|
|
||||||
data.array.set(header.array, 4);
|
|
||||||
data.array.set(filename, 30);
|
|
||||||
datalength += data.array.length;
|
|
||||||
writer.writeUint8Array(data.array, callback, onwriteerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeFooter(compressedLength, crc32) {
|
|
||||||
var footer = getDataHelper(16);
|
|
||||||
datalength += compressedLength || 0;
|
|
||||||
footer.view.setUint32(0, 0x504b0708);
|
|
||||||
if (typeof crc32 != "undefined") {
|
|
||||||
header.view.setUint32(10, crc32, true);
|
|
||||||
footer.view.setUint32(4, crc32, true);
|
|
||||||
}
|
|
||||||
if (reader) {
|
|
||||||
footer.view.setUint32(8, compressedLength, true);
|
|
||||||
header.view.setUint32(14, compressedLength, true);
|
|
||||||
footer.view.setUint32(12, reader.size, true);
|
|
||||||
header.view.setUint32(18, reader.size, true);
|
|
||||||
}
|
|
||||||
writer.writeUint8Array(footer.array, function() {
|
|
||||||
datalength += 16;
|
|
||||||
onend();
|
|
||||||
}, onwriteerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeFile() {
|
|
||||||
options = options || {};
|
|
||||||
name = name.trim();
|
|
||||||
if (options.directory && name.charAt(name.length - 1) != "/")
|
|
||||||
name += "/";
|
|
||||||
if (files.hasOwnProperty(name)) {
|
|
||||||
onerror(ERR_DUPLICATED_NAME);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
filename = getBytes(encodeUTF8(name));
|
|
||||||
filenames.push(name);
|
|
||||||
writeHeader(function() {
|
|
||||||
if (reader)
|
|
||||||
if (dontDeflate || options.level === 0)
|
|
||||||
copy(worker, deflateSN++, reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror);
|
|
||||||
else
|
|
||||||
deflate(worker, deflateSN++, reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror);
|
|
||||||
else
|
|
||||||
writeFooter();
|
|
||||||
}, onwriteerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reader)
|
|
||||||
reader.init(writeFile, onreaderror);
|
|
||||||
else
|
|
||||||
writeFile();
|
|
||||||
},
|
|
||||||
close : function(callback) {
|
|
||||||
if (this._worker) {
|
|
||||||
this._worker.terminate();
|
|
||||||
this._worker = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var data, length = 0, index = 0, indexFilename, file;
|
|
||||||
for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
|
|
||||||
file = files[filenames[indexFilename]];
|
|
||||||
length += 46 + file.filename.length + file.comment.length;
|
|
||||||
}
|
|
||||||
data = getDataHelper(length + 22);
|
|
||||||
for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
|
|
||||||
file = files[filenames[indexFilename]];
|
|
||||||
data.view.setUint32(index, 0x504b0102);
|
|
||||||
data.view.setUint16(index + 4, 0x1400);
|
|
||||||
data.array.set(file.headerArray, index + 6);
|
|
||||||
data.view.setUint16(index + 32, file.comment.length, true);
|
|
||||||
if (file.directory)
|
|
||||||
data.view.setUint8(index + 38, 0x10);
|
|
||||||
data.view.setUint32(index + 42, file.offset, true);
|
|
||||||
data.array.set(file.filename, index + 46);
|
|
||||||
data.array.set(file.comment, index + 46 + file.filename.length);
|
|
||||||
index += 46 + file.filename.length + file.comment.length;
|
|
||||||
}
|
|
||||||
data.view.setUint32(index, 0x504b0506);
|
|
||||||
data.view.setUint16(index + 8, filenames.length, true);
|
|
||||||
data.view.setUint16(index + 10, filenames.length, true);
|
|
||||||
data.view.setUint32(index + 12, length, true);
|
|
||||||
data.view.setUint32(index + 16, datalength, true);
|
|
||||||
writer.writeUint8Array(data.array, function() {
|
|
||||||
writer.getData(callback);
|
|
||||||
}, onwriteerror);
|
|
||||||
},
|
|
||||||
_worker: null
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!obj.zip.useWebWorkers)
|
|
||||||
callback(zipWriter);
|
|
||||||
else {
|
|
||||||
createWorker('deflater',
|
|
||||||
function(worker) {
|
|
||||||
zipWriter._worker = worker;
|
|
||||||
callback(zipWriter);
|
|
||||||
},
|
|
||||||
function(err) {
|
|
||||||
onerror(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveURLs(urls) {
|
|
||||||
var a = document.createElement('a');
|
|
||||||
return urls.map(function(url) {
|
|
||||||
a.href = url;
|
|
||||||
return a.href;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var DEFAULT_WORKER_SCRIPTS = {
|
|
||||||
deflater: ['z-worker.js', 'deflate.js'],
|
|
||||||
inflater: ['z-worker.js', 'inflate.js']
|
|
||||||
};
|
|
||||||
function createWorker(type, callback, onerror) {
|
|
||||||
if (obj.zip.workerScripts !== null && obj.zip.workerScriptsPath !== null) {
|
|
||||||
onerror(new Error('Either zip.workerScripts or zip.workerScriptsPath may be set, not both.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var scripts;
|
|
||||||
if (obj.zip.workerScripts) {
|
|
||||||
scripts = obj.zip.workerScripts[type];
|
|
||||||
if (!Array.isArray(scripts)) {
|
|
||||||
onerror(new Error('zip.workerScripts.' + type + ' is not an array!'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scripts = resolveURLs(scripts);
|
|
||||||
} else {
|
|
||||||
scripts = DEFAULT_WORKER_SCRIPTS[type].slice(0);
|
|
||||||
scripts[0] = (obj.zip.workerScriptsPath || '') + scripts[0];
|
|
||||||
}
|
|
||||||
var worker = new Worker(scripts[0]);
|
|
||||||
// record total consumed time by inflater/deflater/crc32 in this worker
|
|
||||||
worker.codecTime = worker.crcTime = 0;
|
|
||||||
worker.postMessage({ type: 'importScripts', scripts: scripts.slice(1) });
|
|
||||||
worker.addEventListener('message', onmessage);
|
|
||||||
function onmessage(ev) {
|
|
||||||
var msg = ev.data;
|
|
||||||
if (msg.error) {
|
|
||||||
worker.terminate(); // should before onerror(), because onerror() may throw.
|
|
||||||
onerror(msg.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (msg.type === 'importScripts') {
|
|
||||||
worker.removeEventListener('message', onmessage);
|
|
||||||
worker.removeEventListener('error', errorHandler);
|
|
||||||
callback(worker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// catch entry script loading error and other unhandled errors
|
|
||||||
worker.addEventListener('error', errorHandler);
|
|
||||||
function errorHandler(err) {
|
|
||||||
worker.terminate();
|
|
||||||
onerror(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onerror_default(error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
obj.zip = {
|
|
||||||
Reader : Reader,
|
|
||||||
Writer : Writer,
|
|
||||||
BlobReader : BlobReader,
|
|
||||||
Data64URIReader : Data64URIReader,
|
|
||||||
TextReader : TextReader,
|
|
||||||
BlobWriter : BlobWriter,
|
|
||||||
Data64URIWriter : Data64URIWriter,
|
|
||||||
TextWriter : TextWriter,
|
|
||||||
createReader : function(reader, callback, onerror) {
|
|
||||||
onerror = onerror || onerror_default;
|
|
||||||
|
|
||||||
reader.init(function() {
|
|
||||||
createZipReader(reader, callback, onerror);
|
|
||||||
}, onerror);
|
|
||||||
},
|
|
||||||
createWriter : function(writer, callback, onerror, dontDeflate) {
|
|
||||||
onerror = onerror || onerror_default;
|
|
||||||
dontDeflate = !!dontDeflate;
|
|
||||||
|
|
||||||
writer.init(function() {
|
|
||||||
createZipWriter(writer, callback, onerror, dontDeflate);
|
|
||||||
}, onerror);
|
|
||||||
},
|
|
||||||
useWebWorkers : true,
|
|
||||||
/**
|
|
||||||
* Directory containing the default worker scripts (z-worker.js, deflate.js, and inflate.js), relative to current base url.
|
|
||||||
* E.g.: zip.workerScripts = './';
|
|
||||||
*/
|
|
||||||
workerScriptsPath : null,
|
|
||||||
/**
|
|
||||||
* Advanced option to control which scripts are loaded in the Web worker. If this option is specified, then workerScriptsPath must not be set.
|
|
||||||
* workerScripts.deflater/workerScripts.inflater should be arrays of urls to scripts for deflater/inflater, respectively.
|
|
||||||
* Scripts in the array are executed in order, and the first one should be z-worker.js, which is used to start the worker.
|
|
||||||
* All urls are relative to current base url.
|
|
||||||
* E.g.:
|
|
||||||
* zip.workerScripts = {
|
|
||||||
* deflater: ['z-worker.js', 'deflate.js'],
|
|
||||||
* inflater: ['z-worker.js', 'inflate.js']
|
|
||||||
* };
|
|
||||||
*/
|
|
||||||
workerScripts : null,
|
|
||||||
};
|
|
||||||
|
|
||||||
})(this);
|
|
Loading…
Reference in New Issue
Block a user