diff --git a/o2web/source/o2_core/o2/lp/zh-cn.js b/o2web/source/o2_core/o2/lp/zh-cn.js index 6e6def930823b755d0e2861a51e70cda791f5223..54212caa903b5d30c9c1246ecdac29368d5a4cb2 100644 --- a/o2web/source/o2_core/o2/lp/zh-cn.js +++ b/o2web/source/o2_core/o2/lp/zh-cn.js @@ -305,6 +305,7 @@ o2.LP.widget = { "uploadTitle": "上传文件", "uploadInfor": "请选择要上传的文件", "delete": "删除", + "previewAtt" : "预览", "replace": "替换", "select": "选择", diff --git a/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt.png b/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt.png new file mode 100644 index 0000000000000000000000000000000000000000..3eed2902e1789d04fb0a1092296ad1a1d2048c5d Binary files /dev/null and b/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt.png differ diff --git a/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt_gray.png b/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8e633789e2eb8abd41bb2a9d46edf20bcc467d Binary files /dev/null and b/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt_gray.png differ diff --git a/o2web/source/o2_core/o2/widget/AttachmentController.js b/o2web/source/o2_core/o2/widget/AttachmentController.js index 95d64e9d9f14e65644b5e169417a5d5687b9d4fd..a2bbc4f885e0af1baff4cc4fa22ba1d2387515f1 100644 --- a/o2web/source/o2_core/o2/widget/AttachmentController.js +++ b/o2web/source/o2_core/o2/widget/AttachmentController.js @@ -13,6 +13,7 @@ o2.widget.AttachmentController = o2.widget.ATTER = new Class({ "isDelete": true, "isReplace": true, "isDownload": true, + "isPreviewAtt": true, "isSizeChange": true, "readonly": false, "availableListStyles" : ["list","seq","icon","preview"], @@ -1116,9 +1117,11 @@ o2.widget.AttachmentController = o2.widget.ATTER = new Class({ this.doFormDataUploadAttachment(obj, action, invokeUrl, parameter, callback, multiple, accept, accept, size); } }, - - - + previewAttachment: function(e, node){ + if (this.selectedAttachments.length){ + if (this.module) this.module.previewAttachment(this.selectedAttachments); + } + }, downloadAttachment: function(e, node){ if (this.selectedAttachments.length){ if (this.module) this.module.downloadAttachment(e, node, this.selectedAttachments); diff --git a/o2web/source/o2_lib/viewer/viewer.css b/o2web/source/o2_lib/viewer/viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ec0653bd18e5dd0d6644bb72bef51b54ecfdea37 --- /dev/null +++ b/o2web/source/o2_lib/viewer/viewer.css @@ -0,0 +1,456 @@ +/*! + * Viewer.js v1.3.5 + * https://fengyuanchen.github.io/viewerjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2019-07-04T11:00:13.705Z + */ + +.viewer-zoom-in::before, +.viewer-zoom-out::before, +.viewer-one-to-one::before, +.viewer-reset::before, +.viewer-prev::before, +.viewer-play::before, +.viewer-next::before, +.viewer-rotate-left::before, +.viewer-rotate-right::before, +.viewer-flip-horizontal::before, +.viewer-flip-vertical::before, +.viewer-fullscreen::before, +.viewer-fullscreen-exit::before, +.viewer-close::before { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC'); + background-repeat: no-repeat; + background-size: 280px; + color: transparent; + display: block; + font-size: 0; + height: 20px; + line-height: 0; + width: 20px; +} + +.viewer-zoom-in::before { + background-position: 0 0; + content: 'Zoom In'; +} + +.viewer-zoom-out::before { + background-position: -20px 0; + content: 'Zoom Out'; +} + +.viewer-one-to-one::before { + background-position: -40px 0; + content: 'One to One'; +} + +.viewer-reset::before { + background-position: -60px 0; + content: 'Reset'; +} + +.viewer-prev::before { + background-position: -80px 0; + content: 'Previous'; +} + +.viewer-play::before { + background-position: -100px 0; + content: 'Play'; +} + +.viewer-next::before { + background-position: -120px 0; + content: 'Next'; +} + +.viewer-rotate-left::before { + background-position: -140px 0; + content: 'Rotate Left'; +} + +.viewer-rotate-right::before { + background-position: -160px 0; + content: 'Rotate Right'; +} + +.viewer-flip-horizontal::before { + background-position: -180px 0; + content: 'Flip Horizontal'; +} + +.viewer-flip-vertical::before { + background-position: -200px 0; + content: 'Flip Vertical'; +} + +.viewer-fullscreen::before { + background-position: -220px 0; + content: 'Enter Full Screen'; +} + +.viewer-fullscreen-exit::before { + background-position: -240px 0; + content: 'Exit Full Screen'; +} + +.viewer-close::before { + background-position: -260px 0; + content: 'Close'; +} + +.viewer-container { + bottom: 0; + direction: ltr; + font-size: 0; + left: 0; + line-height: 0; + overflow: hidden; + position: absolute; + right: 0; + -webkit-tap-highlight-color: transparent; + top: 0; + -ms-touch-action: none; + touch-action: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.viewer-container::-moz-selection, +.viewer-container *::-moz-selection { + background-color: transparent; +} + +.viewer-container::selection, +.viewer-container *::selection { + background-color: transparent; +} + +.viewer-container img { + display: block; + height: auto; + max-height: none !important; + max-width: none !important; + min-height: 0 !important; + min-width: 0 !important; + width: 100%; +} + +.viewer-canvas { + bottom: 0; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + top: 0; +} + +.viewer-canvas > img { + height: auto; + margin: 15px auto; + max-width: 90% !important; + width: auto; +} + +.viewer-footer { + bottom: 0; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + text-align: center; +} + +.viewer-navbar { + background-color: rgba(0, 0, 0, 0.5); + overflow: hidden; +} + +.viewer-list { + -webkit-box-sizing: content-box; + box-sizing: content-box; + height: 50px; + margin: 0; + overflow: hidden; + padding: 1px 0; +} + +.viewer-list > li { + color: transparent; + cursor: pointer; + float: left; + font-size: 0; + height: 50px; + line-height: 0; + opacity: 0.5; + overflow: hidden; + -webkit-transition: opacity 0.15s; + transition: opacity 0.15s; + width: 30px; +} + +.viewer-list > li:hover { + opacity: 0.75; +} + +.viewer-list > li + li { + margin-left: 1px; +} + +.viewer-list > .viewer-loading { + position: relative; +} + +.viewer-list > .viewer-loading::after { + border-width: 2px; + height: 20px; + margin-left: -10px; + margin-top: -10px; + width: 20px; +} + +.viewer-list > .viewer-active, +.viewer-list > .viewer-active:hover { + opacity: 1; +} + +.viewer-player { + background-color: #000; + bottom: 0; + cursor: none; + display: none; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.viewer-player > img { + left: 0; + position: absolute; + top: 0; +} + +.viewer-toolbar > ul { + display: inline-block; + margin: 0 auto 5px; + overflow: hidden; + padding: 3px 0; +} + +.viewer-toolbar > ul > li { + background-color: rgba(0, 0, 0, 0.5); + border-radius: 50%; + cursor: pointer; + float: left; + height: 24px; + overflow: hidden; + -webkit-transition: background-color 0.15s; + transition: background-color 0.15s; + width: 24px; +} + +.viewer-toolbar > ul > li:hover { + background-color: rgba(0, 0, 0, 0.8); +} + +.viewer-toolbar > ul > li::before { + margin: 2px; +} + +.viewer-toolbar > ul > li + li { + margin-left: 1px; +} + +.viewer-toolbar > ul > .viewer-small { + height: 18px; + margin-bottom: 3px; + margin-top: 3px; + width: 18px; +} + +.viewer-toolbar > ul > .viewer-small::before { + margin: -1px; +} + +.viewer-toolbar > ul > .viewer-large { + height: 30px; + margin-bottom: -3px; + margin-top: -3px; + width: 30px; +} + +.viewer-toolbar > ul > .viewer-large::before { + margin: 5px; +} + +.viewer-tooltip { + background-color: rgba(0, 0, 0, 0.8); + border-radius: 10px; + color: #fff; + display: none; + font-size: 12px; + height: 20px; + left: 50%; + line-height: 20px; + margin-left: -25px; + margin-top: -10px; + position: absolute; + text-align: center; + top: 50%; + width: 50px; +} + +.viewer-title { + color: #ccc; + display: inline-block; + font-size: 12px; + line-height: 1; + margin: 0 5% 5px; + max-width: 90%; + opacity: 0.8; + overflow: hidden; + text-overflow: ellipsis; + -webkit-transition: opacity 0.15s; + transition: opacity 0.15s; + white-space: nowrap; +} + +.viewer-title:hover { + opacity: 1; +} + +.viewer-button { + background-color: rgba(0, 0, 0, 0.5); + border-radius: 50%; + cursor: pointer; + height: 80px; + overflow: hidden; + position: absolute; + right: -40px; + top: -40px; + -webkit-transition: background-color 0.15s; + transition: background-color 0.15s; + width: 80px; +} + +.viewer-button:focus, +.viewer-button:hover { + background-color: rgba(0, 0, 0, 0.8); +} + +.viewer-button::before { + bottom: 15px; + left: 15px; + position: absolute; +} + +.viewer-fixed { + position: fixed; +} + +.viewer-open { + overflow: hidden; +} + +.viewer-show { + display: block; +} + +.viewer-hide { + display: none; +} + +.viewer-backdrop { + background-color: rgba(0, 0, 0, 0.5); +} + +.viewer-invisible { + visibility: hidden; +} + +.viewer-move { + cursor: move; + cursor: -webkit-grab; + cursor: grab; +} + +.viewer-fade { + opacity: 0; +} + +.viewer-in { + opacity: 1; +} + +.viewer-transition { + -webkit-transition: all 0.3s; + transition: all 0.3s; +} + +@-webkit-keyframes viewer-spinner { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes viewer-spinner { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.viewer-loading::after { + -webkit-animation: viewer-spinner 1s linear infinite; + animation: viewer-spinner 1s linear infinite; + border: 4px solid rgba(255, 255, 255, 0.1); + border-left-color: rgba(255, 255, 255, 0.5); + border-radius: 50%; + content: ''; + display: inline-block; + height: 40px; + left: 50%; + margin-left: -20px; + margin-top: -20px; + position: absolute; + top: 50%; + width: 40px; + z-index: 1; +} + +@media (max-width: 767px) { + .viewer-hide-xs-down { + display: none; + } +} + +@media (max-width: 991px) { + .viewer-hide-sm-down { + display: none; + } +} + +@media (max-width: 1199px) { + .viewer-hide-md-down { + display: none; + } +} \ No newline at end of file diff --git a/o2web/source/o2_lib/viewer/viewer.js b/o2web/source/o2_lib/viewer/viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..a410d3ab90a29c88765d51865fc6cc13ac413d27 --- /dev/null +++ b/o2web/source/o2_lib/viewer/viewer.js @@ -0,0 +1,3043 @@ +/*! + * Viewer.js v1.3.5 + * https://fengyuanchen.github.io/viewerjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2019-07-04T11:00:16.790Z + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.Viewer = factory()); +}(this, function () { 'use strict'; + + function _typeof(obj) { + if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { + _typeof = function (obj) { + return typeof obj; + }; + } else { + _typeof = function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + } + + return _typeof(obj); + } + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; + } + + var DEFAULTS = { + /** + * Enable a modal backdrop, specify `static` for a backdrop + * which doesn't close the modal on click. + * @type {boolean} + */ + backdrop: true, + + /** + * Show the button on the top-right of the viewer. + * @type {boolean} + */ + button: true, + + /** + * Show the navbar. + * @type {boolean | number} + */ + navbar: true, + + /** + * Specify the visibility and the content of the title. + * @type {boolean | number | Function | Array} + */ + title: true, + + /** + * Show the toolbar. + * @type {boolean | number | Object} + */ + toolbar: true, + + /** + * Custom class name(s) to add to the viewer's root element. + * @type {string} + */ + className: '', + + /** + * Define where to put the viewer in modal mode. + * @type {string | Element} + */ + container: 'body', + + /** + * Filter the images for viewing. Return true if the image is viewable. + * @type {Function} + */ + filter: null, + + /** + * Enable to request fullscreen when play. + * @type {boolean} + */ + fullscreen: true, + + /** + * Define the initial index of image for viewing. + * @type {number} + */ + initialViewIndex: 0, + + /** + * Enable inline mode. + * @type {boolean} + */ + inline: false, + + /** + * The amount of time to delay between automatically cycling an image when playing. + * @type {number} + */ + interval: 5000, + + /** + * Enable keyboard support. + * @type {boolean} + */ + keyboard: true, + + /** + * Indicate if show a loading spinner when load image or not. + * @type {boolean} + */ + loading: true, + + /** + * Indicate if enable loop viewing or not. + * @type {boolean} + */ + loop: true, + + /** + * Min width of the viewer in inline mode. + * @type {number} + */ + minWidth: 200, + + /** + * Min height of the viewer in inline mode. + * @type {number} + */ + minHeight: 100, + + /** + * Enable to move the image. + * @type {boolean} + */ + movable: true, + + /** + * Enable to zoom the image. + * @type {boolean} + */ + zoomable: true, + + /** + * Enable to rotate the image. + * @type {boolean} + */ + rotatable: true, + + /** + * Enable to scale the image. + * @type {boolean} + */ + scalable: true, + + /** + * Indicate if toggle the image size between its natural size + * and initial size when double click on the image or not. + * @type {boolean} + */ + toggleOnDblclick: true, + + /** + * Show the tooltip with image ratio (percentage) when zoom in or zoom out. + * @type {boolean} + */ + tooltip: true, + + /** + * Enable CSS3 Transition for some special elements. + * @type {boolean} + */ + transition: true, + + /** + * Define the CSS `z-index` value of viewer in modal mode. + * @type {number} + */ + zIndex: 2015, + + /** + * Define the CSS `z-index` value of viewer in inline mode. + * @type {number} + */ + zIndexInline: 0, + + /** + * Define the ratio when zoom the image by wheeling mouse. + * @type {number} + */ + zoomRatio: 0.1, + + /** + * Define the min ratio of the image when zoom out. + * @type {number} + */ + minZoomRatio: 0.01, + + /** + * Define the max ratio of the image when zoom in. + * @type {number} + */ + maxZoomRatio: 100, + + /** + * Define where to get the original image URL for viewing. + * @type {string | Function} + */ + url: 'src', + + /** + * Event shortcuts. + * @type {Function} + */ + ready: null, + show: null, + shown: null, + hide: null, + hidden: null, + view: null, + viewed: null, + zoom: null, + zoomed: null + }; + + var TEMPLATE = '
>>16-Q,Q+=i-16):(N|=t<=8&&(Z(255&N),N>>>=8,Q-=8);}function at(e,n){let i,a,r;if(t.pending_buf[K+2*P]=e>>>8&255,t.pending_buf[K+2*P+1]=255&e,t.pending_buf[D+P]=255&n,P++,0===e?M[2*n]++:(G++,e--,M[2*(R._length_code[n]+256+1)]++,B[2*R.d_code(e)]++),0==(8191&P)&&z>2){for(i=8*P,a=m-p,r=0;r<30;r++)i+=B[2*r]*(5+R.extra_dbits[r]);if(i>>>=3,G8?$(N):Q>0&&Z(255&N),N=0,Q=0;}function ot(e,n,i){tt(0+(i?1:0),3),function(e,n,i){st(),J=8,$(n),$(~n),t.pending_buf.set(l.subarray(e,e+n),t.pending),t.pending+=n;}(e,n);}function lt(e,n,i){let a,r,s=0;z>0?(H.build_tree(t),V.build_tree(t),s=function(){let e;for(Y(M,H.max_code),Y(B,V.max_code),O.build_tree(t),e=18;e>=3&&0===j[2*R.bl_order[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}(),a=t.opt_len+3+7>>>3,r=t.static_len+3+7>>>3,r<=a&&(a=r)):a=r=n+5,n+4<=a&&-1!=e?ot(e,n,i):r==a?(tt(2+(i?1:0),3),rt(W.static_ltree,W.static_dtree)):(tt(4+(i?1:0),3),function(t,e,n){let i;for(tt(t-257,5),tt(e-1,5),tt(n-4,4),i=0;i =0?p:-1,m-p,t),p=m,e.flush_pending();}function dt(){let t,n,i,a;do{if(a=_-v-m,0===a&&0===m&&0===v)a=r;else if(-1==a)a--;else if(m>=r+r-262){l.set(l.subarray(r,r+r),0),k-=r,m-=r,p-=r,t=u,i=t;do{n=65535&c[--i],c[i]=n>=r?n-r:0;}while(0!=--t);t=r,i=t;do{n=65535&d[--i],d[i]=n>=r?n-r:0;}while(0!=--t);a+=r;}if(0===e.avail_in)return;t=e.read_buf(l,m+v,a),v+=t,v>=3&&(f=255&l[m],f=(f< r-262?m-(r-262):0;let c=C;const f=o,u=m+258;let h=l[a+s-1],b=l[a+s];A>=E&&(i>>=2),c>v&&(c=v);do{if(e=t,l[e+s]==b&&l[e+s-1]==h&&l[e]==l[a]&&l[++e]==l[a+1]){a+=2,e++;do{}while(l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&as){if(k=t,s=n,n>=c)break;h=l[a+s-1],b=l[a+s];}}}while((t=65535&d[t&f])>_&&0!=--i);return s<=v?s:v}function ft(e){return e.total_in=e.total_out=0,e.msg=null,t.pending=0,t.pending_out=0,n=113,a=0,H.dyn_tree=M,H.stat_desc=W.static_l_desc,V.dyn_tree=B,V.stat_desc=W.static_d_desc,O.dyn_tree=j,O.stat_desc=W.static_bl_desc,N=0,Q=0,J=8,X(),function(){_=2*r,c[u-1]=0;for(let t=0;t 9||8!=_||a<9||a>15||n<0||n>9||p<0||p>2?-2:(e.dstate=t,s=a,r=1< 9||n<0||n>2?-2:(T[z].func!=T[e].func&&0!==t.total_in&&(i=t.deflate(1)),z!=e&&(z=e,S=T[z].max_lazy,E=T[z].good_length,C=T[z].nice_length,U=T[z].max_chain),I=n,i)},t.deflateSetDictionary=function(t,e,i){let a,s=i,_=0;if(!e||42!=n)return -2;if(s<3)return 0;for(s>r-262&&(s=r-262,_=i-s),l.set(e.subarray(_,_+s),0),m=s,p=s,f=255&l[0],f=(f<4||h<0)return -2;if(!_.next_out||!_.next_in&&0!==_.avail_in||666==n&&4!=h)return _.msg=q[4],-2;if(0===_.avail_out)return _.msg=q[7],-5;var j;if(e=_,M=a,a=h,42==n&&(E=8+(s-8<<4)<<8,C=(z-1&255)>>1,C>3&&(C=3),E|=C<<6,0!==m&&(E|=32),E+=31-E%31,n=113,Z((j=E)>>8&255),Z(255&j)),0!==t.pending){if(e.flush_pending(),0===e.avail_out)return a=-1,0}else if(0===e.avail_in&&h<=M&&4!=h)return e.msg=q[7],-5;if(666==n&&0!==e.avail_in)return _.msg=q[7],-5;if(0!==e.avail_in||0!==v||0!=h&&666!=n){switch(B=-1,T[z].func){case 0:B=function(t){let n,a=65535;for(a>i-5&&(a=i-5);;){if(v<=1){if(dt(),0===v&&0==t)return 0;if(0===v)break}if(m+=v,v=0,n=p+a,(0===m||m>=n)&&(v=m-n,m=n,_t(!1),0===e.avail_out))return 0;if(m-p>=r-262&&(_t(!1),0===e.avail_out))return 0}return _t(4==t),0===e.avail_out?4==t?2:0:4==t?3:1}(h);break;case 1:B=function(t){let n,i=0;for(;;){if(v<262){if(dt(),v<262&&0==t)return 0;if(0===v)break}if(v>=3&&(f=(f< =3)if(n=at(m-k,x-3),v-=x,x<=S&&v>=3){x--;do{m++,f=(f< =3&&(f=(f< 4096)&&(x=2)),A>=3&&x<=A){i=m+v-3,n=at(m-1-g,A-3),v-=A-1,A-=2;do{++m<=i&&(f=(f< 0&&e.next_in_index!=o&&(a(e.next_in_index),o=e.next_in_index);}while(e.avail_in>0||0===e.avail_out);return d.length>1?(s=new Uint8Array(_),d.forEach((function(t){s.set(t,l),l+=t.length;}))):s=d[0]||new Uint8Array(0),s}},this.flush=function(){let t,a,r=0,s=0;const o=[];do{if(e.next_out_index=0,e.avail_out=n,t=e.deflate(4),1!=t&&0!=t)throw new Error("deflating: "+e.msg);n-e.avail_out>0&&o.push(i.slice(0,e.next_out_index)),s+=e.next_out_index;}while(e.avail_in>0||0===e.avail_out);return e.deflateEnd(),a=new Uint8Array(s),o.forEach((function(t){a.set(t,r),r+=t.length;})),a};}N.prototype={deflateInit:function(t,e){const n=this;return n.dstate=new J,e||(e=15),n.dstate.deflateInit(n,t,e)},deflate:function(t){const e=this;return e.dstate?e.dstate.deflate(e,t):-2},deflateEnd:function(){const t=this;if(!t.dstate)return -2;const e=t.dstate.deflateEnd();return t.dstate=null,e},deflateParams:function(t,e){const n=this;return n.dstate?n.dstate.deflateParams(n,t,e):-2},deflateSetDictionary:function(t,e){const n=this;return n.dstate?n.dstate.deflateSetDictionary(n,t,e):-2},read_buf:function(t,e,n){const i=this;let a=i.avail_in;return a>n&&(a=n),0===a?0:(i.avail_in-=a,t.set(i.next_in.subarray(i.next_in_index,i.next_in_index+a),e),i.next_in_index+=a,i.total_in+=a,a)},flush_pending:function(){const t=this;let e=t.dstate.pending;e>t.avail_out&&(e=t.avail_out),0!==e&&(t.next_out.set(t.dstate.pending_buf.subarray(t.dstate.pending_out,t.dstate.pending_out+e),t.next_out_index),t.next_out_index+=e,t.dstate.pending_out+=e,t.total_out+=e,t.avail_out-=e,t.dstate.pending-=e,0===t.dstate.pending&&(t.dstate.pending_out=0));}};const X=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],Y=[96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,192,80,7,10,0,8,96,0,8,32,0,9,160,0,8,0,0,8,128,0,8,64,0,9,224,80,7,6,0,8,88,0,8,24,0,9,144,83,7,59,0,8,120,0,8,56,0,9,208,81,7,17,0,8,104,0,8,40,0,9,176,0,8,8,0,8,136,0,8,72,0,9,240,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,200,81,7,13,0,8,100,0,8,36,0,9,168,0,8,4,0,8,132,0,8,68,0,9,232,80,7,8,0,8,92,0,8,28,0,9,152,84,7,83,0,8,124,0,8,60,0,9,216,82,7,23,0,8,108,0,8,44,0,9,184,0,8,12,0,8,140,0,8,76,0,9,248,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,196,81,7,11,0,8,98,0,8,34,0,9,164,0,8,2,0,8,130,0,8,66,0,9,228,80,7,7,0,8,90,0,8,26,0,9,148,84,7,67,0,8,122,0,8,58,0,9,212,82,7,19,0,8,106,0,8,42,0,9,180,0,8,10,0,8,138,0,8,74,0,9,244,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,204,81,7,15,0,8,102,0,8,38,0,9,172,0,8,6,0,8,134,0,8,70,0,9,236,80,7,9,0,8,94,0,8,30,0,9,156,84,7,99,0,8,126,0,8,62,0,9,220,82,7,27,0,8,110,0,8,46,0,9,188,0,8,14,0,8,142,0,8,78,0,9,252,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,194,80,7,10,0,8,97,0,8,33,0,9,162,0,8,1,0,8,129,0,8,65,0,9,226,80,7,6,0,8,89,0,8,25,0,9,146,83,7,59,0,8,121,0,8,57,0,9,210,81,7,17,0,8,105,0,8,41,0,9,178,0,8,9,0,8,137,0,8,73,0,9,242,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,202,81,7,13,0,8,101,0,8,37,0,9,170,0,8,5,0,8,133,0,8,69,0,9,234,80,7,8,0,8,93,0,8,29,0,9,154,84,7,83,0,8,125,0,8,61,0,9,218,82,7,23,0,8,109,0,8,45,0,9,186,0,8,13,0,8,141,0,8,77,0,9,250,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,198,81,7,11,0,8,99,0,8,35,0,9,166,0,8,3,0,8,131,0,8,67,0,9,230,80,7,7,0,8,91,0,8,27,0,9,150,84,7,67,0,8,123,0,8,59,0,9,214,82,7,19,0,8,107,0,8,43,0,9,182,0,8,11,0,8,139,0,8,75,0,9,246,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,206,81,7,15,0,8,103,0,8,39,0,9,174,0,8,7,0,8,135,0,8,71,0,9,238,80,7,9,0,8,95,0,8,31,0,9,158,84,7,99,0,8,127,0,8,63,0,9,222,82,7,27,0,8,111,0,8,47,0,9,190,0,8,15,0,8,143,0,8,79,0,9,254,96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,193,80,7,10,0,8,96,0,8,32,0,9,161,0,8,0,0,8,128,0,8,64,0,9,225,80,7,6,0,8,88,0,8,24,0,9,145,83,7,59,0,8,120,0,8,56,0,9,209,81,7,17,0,8,104,0,8,40,0,9,177,0,8,8,0,8,136,0,8,72,0,9,241,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,201,81,7,13,0,8,100,0,8,36,0,9,169,0,8,4,0,8,132,0,8,68,0,9,233,80,7,8,0,8,92,0,8,28,0,9,153,84,7,83,0,8,124,0,8,60,0,9,217,82,7,23,0,8,108,0,8,44,0,9,185,0,8,12,0,8,140,0,8,76,0,9,249,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,197,81,7,11,0,8,98,0,8,34,0,9,165,0,8,2,0,8,130,0,8,66,0,9,229,80,7,7,0,8,90,0,8,26,0,9,149,84,7,67,0,8,122,0,8,58,0,9,213,82,7,19,0,8,106,0,8,42,0,9,181,0,8,10,0,8,138,0,8,74,0,9,245,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,205,81,7,15,0,8,102,0,8,38,0,9,173,0,8,6,0,8,134,0,8,70,0,9,237,80,7,9,0,8,94,0,8,30,0,9,157,84,7,99,0,8,126,0,8,62,0,9,221,82,7,27,0,8,110,0,8,46,0,9,189,0,8,14,0,8,142,0,8,78,0,9,253,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,195,80,7,10,0,8,97,0,8,33,0,9,163,0,8,1,0,8,129,0,8,65,0,9,227,80,7,6,0,8,89,0,8,25,0,9,147,83,7,59,0,8,121,0,8,57,0,9,211,81,7,17,0,8,105,0,8,41,0,9,179,0,8,9,0,8,137,0,8,73,0,9,243,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,203,81,7,13,0,8,101,0,8,37,0,9,171,0,8,5,0,8,133,0,8,69,0,9,235,80,7,8,0,8,93,0,8,29,0,9,155,84,7,83,0,8,125,0,8,61,0,9,219,82,7,23,0,8,109,0,8,45,0,9,187,0,8,13,0,8,141,0,8,77,0,9,251,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,199,81,7,11,0,8,99,0,8,35,0,9,167,0,8,3,0,8,131,0,8,67,0,9,231,80,7,7,0,8,91,0,8,27,0,9,151,84,7,67,0,8,123,0,8,59,0,9,215,82,7,19,0,8,107,0,8,43,0,9,183,0,8,11,0,8,139,0,8,75,0,9,247,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,207,81,7,15,0,8,103,0,8,39,0,9,175,0,8,7,0,8,135,0,8,71,0,9,239,80,7,9,0,8,95,0,8,31,0,9,159,84,7,99,0,8,127,0,8,63,0,9,223,82,7,27,0,8,111,0,8,47,0,9,191,0,8,15,0,8,143,0,8,79,0,9,255],Z=[80,5,1,87,5,257,83,5,17,91,5,4097,81,5,5,89,5,1025,85,5,65,93,5,16385,80,5,3,88,5,513,84,5,33,92,5,8193,82,5,9,90,5,2049,86,5,129,192,5,24577,80,5,2,87,5,385,83,5,25,91,5,6145,81,5,7,89,5,1537,85,5,97,93,5,24577,80,5,4,88,5,769,84,5,49,92,5,12289,82,5,13,90,5,3073,86,5,193,192,5,24577],$=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],tt=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,112,112],et=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],nt=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];function it(){let t,e,n,i,a,r;function s(t,e,s,o,l,_,d,c,f,u,h){let b,w,p,x,g,y,m,k,v,A,U,S,z,I,E;A=0,g=s;do{n[t[e+A]]++,A++,g--;}while(0!==g);if(n[0]==s)return d[0]=-1,c[0]=0,0;for(k=c[0],y=1;y<=15&&0===n[y];y++);for(m=y,k g&&(k=g),c[0]=k,I=1< S+k;){if(x++,S+=k,E=p-S,E=E>k?k:E,(w=1<<(y=m-S))>b+1&&(w-=b+1,z=m,y 1440)return -3;a[x]=U=u[0],u[0]+=E,0!==x?(r[x]=g,i[0]=y,i[1]=k,y=g>>>S-k,i[2]=U-a[x-1]-y,f.set(i,3*(a[x-1]+y))):d[0]=U;}for(i[1]=m-S,A>=s?i[0]=192:h[A] >>S;y >>=1)g^=y;for(g^=y,v=(1< 257?(-3==u?f.msg="oversubscribed distance tree":-5==u?(f.msg="incomplete distance tree",u=-3):-4!=u&&(f.msg="empty distance tree with lengths",u=-3),u):0)};}function at(){const t=this;let e,n,i,a,r=0,s=0,o=0,l=0,_=0,d=0,c=0,f=0,u=0,h=0;function b(t,e,n,i,a,r,s,o){let l,_,d,c,f,u,h,b,w,p,x,g,y,m,k,v;h=o.next_in_index,b=o.avail_in,f=s.bitb,u=s.bitk,w=s.write,p=w>=_[v+1],u-=_[v+1],0!=(16&c)){for(c&=15,y=_[v+2]+(f&X[c]),f>>=c,u-=c;u<15;)b--,f|=(255&o.read_byte(h++))<>=_[v+1],u-=_[v+1],0!=(16&c)){for(c&=15;u >=c,u-=c,p-=y,w>=m)k=w-m,w-k>0&&2>w-k?(s.window[w++]=s.window[k++],s.window[w++]=s.window[k++],y-=2):(s.window.set(s.window.subarray(k,k+2),w),w+=2,k+=2,y-=2);else {k=w-m;do{k+=s.end;}while(k<0);if(c=s.end-k,y>c){if(y-=c,w-k>0&&c>w-k)do{s.window[w++]=s.window[k++];}while(0!=--c);else s.window.set(s.window.subarray(k,k+c),w),w+=c,k+=c,c=0;k=0;}}if(w-k>0&&y>w-k)do{s.window[w++]=s.window[k++];}while(0!=--y);else s.window.set(s.window.subarray(k,k+y),w),w+=y,k+=y,y=0;break}if(0!=(64&c))return o.msg="invalid distance code",y=o.avail_in-b,y=u>>3 >3:y,b+=y,h-=y,u-=y<<3,s.bitb=f,s.bitk=u,o.avail_in=b,o.total_in+=h-o.next_in_index,o.next_in_index=h,s.write=w,-3;l+=_[v+2],l+=f&X[c],v=3*(d+l),c=_[v];}break}if(0!=(64&c))return 0!=(32&c)?(y=o.avail_in-b,y=u>>3 >3:y,b+=y,h-=y,u-=y<<3,s.bitb=f,s.bitk=u,o.avail_in=b,o.total_in+=h-o.next_in_index,o.next_in_index=h,s.write=w,1):(o.msg="invalid literal/length code",y=o.avail_in-b,y=u>>3 >3:y,b+=y,h-=y,u-=y<<3,s.bitb=f,s.bitk=u,o.avail_in=b,o.total_in+=h-o.next_in_index,o.next_in_index=h,s.write=w,-3);if(l+=_[v+2],l+=f&X[c],v=3*(d+l),0===(c=_[v])){f>>=_[v+1],u-=_[v+1],s.window[w++]=_[v+2],p--;break}}else f>>=_[v+1],u-=_[v+1],s.window[w++]=_[v+2],p--;}while(p>=258&&b>=10);return y=o.avail_in-b,y=u>>3 >3:y,b+=y,h-=y,u-=y<<3,s.bitb=f,s.bitk=u,o.avail_in=b,o.total_in+=h-o.next_in_index,o.next_in_index=h,s.write=w,0}t.init=function(t,r,s,o,l,_){e=0,c=t,f=r,i=s,u=o,a=l,h=_,n=null;},t.proc=function(t,w,p){let x,g,y,m,k,v,A,U=0,S=0,z=0;for(z=w.next_in_index,m=w.avail_in,U=t.bitb,S=t.bitk,k=t.write,v=k =258&&m>=10&&(t.bitb=U,t.bitk=S,w.avail_in=m,w.total_in+=z-w.next_in_index,w.next_in_index=z,t.write=k,p=b(c,f,i,u,a,h,t,w),z=w.next_in_index,m=w.avail_in,U=t.bitb,S=t.bitk,k=t.write,v=k >>=n[g+1],S-=n[g+1],y=n[g],0===y){l=n[g+2],e=6;break}if(0!=(16&y)){_=15&y,r=n[g+2],e=2;break}if(0==(64&y)){o=y,s=g/3+n[g+2];break}if(0!=(32&y)){e=7;break}return e=9,w.msg="invalid literal/length code",p=-3,t.bitb=U,t.bitk=S,w.avail_in=m,w.total_in+=z-w.next_in_index,w.next_in_index=z,t.write=k,t.inflate_flush(w,p);case 2:for(x=_;S >=x,S-=x,o=f,n=a,s=h,e=3;case 3:for(x=o;S >=n[g+1],S-=n[g+1],y=n[g],0!=(16&y)){_=15&y,d=n[g+2],e=4;break}if(0==(64&y)){o=y,s=g/3+n[g+2];break}return e=9,w.msg="invalid distance code",p=-3,t.bitb=U,t.bitk=S,w.avail_in=m,w.total_in+=z-w.next_in_index,w.next_in_index=z,t.write=k,t.inflate_flush(w,p);case 4:for(x=_;S >=x,S-=x,e=5;case 5:for(A=k-d;A<0;)A+=t.end;for(;0!==r;){if(0===v&&(k==t.end&&0!==t.read&&(k=0,v=k 7&&(S-=8,m++,z--),t.write=k,p=t.inflate_flush(w,p),k=t.write,v=k t.avail_out&&(i=t.avail_out),0!==i&&-5==e&&(e=0),t.avail_out-=i,t.total_out+=i,t.next_out.set(n.window.subarray(r,r+i),a),a+=i,r+=i,r==n.end&&(r=0,n.write==n.end&&(n.write=0),i=n.write-r,i>t.avail_out&&(i=t.avail_out),0!==i&&-5==e&&(e=0),t.avail_out-=i,t.total_out+=i,t.next_out.set(n.window.subarray(r,r+i),a),a+=i,r+=i),t.next_out_index=a,n.read=r,e},n.proc=function(t,e){let h,b,w,p,x,g,y,m;for(p=t.next_in_index,x=t.avail_in,b=n.bitb,w=n.bitk,g=n.write,y=g >>1){case 0:b>>>=3,w-=3,h=7&w,b>>>=h,w-=h,a=1;break;case 1:k=[],v=[],A=[[]],U=[[]],it.inflate_trees_fixed(k,v,A,U),d.init(k[0],v[0],A[0],0,U[0],0),b>>>=3,w-=3,a=6;break;case 2:b>>>=3,w-=3,a=3;break;case 3:return b>>>=3,w-=3,a=9,t.msg="invalid block type",e=-3,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e)}break;case 1:for(;w<32;){if(0===x)return n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);e=0,x--,b|=(255&t.read_byte(p++))< >>16&65535)!=(65535&b))return a=9,t.msg="invalid stored block lengths",e=-3,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);r=65535&b,b=w=0,a=0!==r?2:0!==c?7:0;break;case 2:if(0===x)return n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);if(0===y&&(g==n.end&&0!==n.read&&(g=0,y=g x&&(h=x),h>y&&(h=y),n.window.set(t.read_buf(p,h),g),p+=h,x-=h,g+=h,y-=h,0!=(r-=h))break;a=0!==c?7:0;break;case 3:for(;w<14;){if(0===x)return n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);e=0,x--,b|=(255&t.read_byte(p++))< 29||(h>>5&31)>29)return a=9,t.msg="too many length or distance symbols",e=-3,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);if(h=258+(31&h)+(h>>5&31),!i||i.length >>=14,w-=14,o=0,a=4;case 4:for(;o<4+(s>>>10);){for(;w<3;){if(0===x)return n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);e=0,x--,b|=(255&t.read_byte(p++))< >>=3,w-=3;}for(;o<19;)i[rt[o++]]=0;if(l[0]=7,h=u.inflate_trees_bits(i,l,_,f,t),0!=h)return -3==(e=h)&&(i=null,a=9),n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);o=0,a=5;case 5:for(;h=s,!(o>=258+(31&h)+(h>>5&31));){let r,d;for(h=l[0];w >>=h,w-=h,i[o++]=d;else {for(m=18==d?7:d-14,r=18==d?11:3;w >>=h,w-=h,r+=b&X[m],b>>>=m,w-=m,m=o,h=s,m+r>258+(31&h)+(h>>5&31)||16==d&&m<1)return i=null,a=9,t.msg="invalid bit length repeat",e=-3,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);d=16==d?i[m-1]:0;do{i[m++]=d;}while(0!=--r);o=m;}}if(_[0]=-1,S=[],z=[],I=[],E=[],S[0]=9,z[0]=6,h=s,h=u.inflate_trees_dynamic(257+(31&h),1+(h>>5&31),i,S,z,I,E,f,t),0!=h)return -3==h&&(i=null,a=9),e=h,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);d.init(S[0],z[0],f,I[0],f,E[0]),a=6;case 6:if(n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,1!=(e=d.proc(n,t,e)))return n.inflate_flush(t,e);if(e=0,d.free(t),p=t.next_in_index,x=t.avail_in,b=n.bitb,w=n.bitk,g=n.write,y=g 15?(t.inflateEnd(n),-2):(t.wbits=i,n.istate.blocks=new st(n,1<>4)>a.wbits){a.mode=13,t.msg="invalid window size",a.marker=5;break}a.mode=1;case 1:if(0===t.avail_in)return n;if(n=e,t.avail_in--,t.total_in++,i=255&t.read_byte(t.next_in_index++),((a.method<<8)+i)%31!=0){a.mode=13,t.msg="incorrect header check",a.marker=5;break}if(0==(32&i)){a.mode=7;break}a.mode=2;case 2:if(0===t.avail_in)return n;n=e,t.avail_in--,t.total_in++,a.need=(255&t.read_byte(t.next_in_index++))<<24&4278190080,a.mode=3;case 3:if(0===t.avail_in)return n;n=e,t.avail_in--,t.total_in++,a.need+=(255&t.read_byte(t.next_in_index++))<<16&16711680,a.mode=4;case 4:if(0===t.avail_in)return n;n=e,t.avail_in--,t.total_in++,a.need+=(255&t.read_byte(t.next_in_index++))<<8&65280,a.mode=5;case 5:return 0===t.avail_in?n:(n=e,t.avail_in--,t.total_in++,a.need+=255&t.read_byte(t.next_in_index++),a.mode=6,2);case 6:return a.mode=13,t.msg="need dictionary",a.marker=0,-2;case 7:if(n=a.blocks.proc(t,n),-3==n){a.mode=13,a.marker=0;break}if(0==n&&(n=e),1!=n)return n;n=e,a.blocks.reset(t,a.was),a.mode=12;case 12:return 1;case 13:return -3;default:return -2}},t.inflateSetDictionary=function(t,e,n){let i=0,a=n;if(!t||!t.istate||6!=t.istate.mode)return -2;const r=t.istate;return a>=1< 0&&e.next_in_index!=_&&(r(e.next_in_index),_=e.next_in_index);}while(e.avail_in>0||0===e.avail_out);return s.length>1?(l=new Uint8Array(c),s.forEach((function(t){l.set(t,d),d+=t.length;}))):l=s[0]||new Uint8Array(0),l}},this.flush=function(){e.inflateEnd();};}_t.prototype={inflateInit:function(t){const e=this;return e.istate=new lt,t||(t=15),e.istate.inflateInit(e,t)},inflate:function(t){const e=this;return e.istate?e.istate.inflate(e,t):-2},inflateEnd:function(){const t=this;if(!t.istate)return -2;const e=t.istate.inflateEnd(t);return t.istate=null,e},inflateSync:function(){const t=this;return t.istate?t.istate.inflateSync(t):-2},inflateSetDictionary:function(t,e){const n=this;return n.istate?n.istate.inflateSetDictionary(n,t,e):-2},read_byte:function(t){return this.next_in[t]},read_buf:function(t,e){return this.next_in.subarray(t,t+e)}},self.initCodec=()=>{self.Deflate=Q,self.Inflate=dt;};}).toString(),n=URL.createObjectURL(new Blob(["("+e+")()"],{type:"text/javascript"}));configure({workerScripts:{inflate:[n],deflate:[n]}});}}; + + /* + Copyright (c) 2021 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 getMimeType() { + return "application/octet-stream"; + } + + var streamCodecShim = (library, options = {}, registerDataHandler) => { + return { + Deflate: createCodecClass(library.Deflate, options.deflate, registerDataHandler), + Inflate: createCodecClass(library.Inflate, options.inflate, registerDataHandler) + }; + }; + + function createCodecClass(constructor, constructorOptions, registerDataHandler) { + return class { + + constructor(options) { + const codecAdapter = this; + const onData = data => { + if (codecAdapter.pendingData) { + const pendingData = codecAdapter.pendingData; + codecAdapter.pendingData = new Uint8Array(pendingData.length + data.length); + codecAdapter.pendingData.set(pendingData, 0); + codecAdapter.pendingData.set(data, pendingData.length); + } else { + codecAdapter.pendingData = new Uint8Array(data); + } + }; + codecAdapter.codec = new constructor(Object.assign({}, constructorOptions, options)); + registerDataHandler(codecAdapter.codec, onData); + } + async append(data) { + this.codec.push(data); + return getResponse(this); + } + async flush() { + this.codec.push(new Uint8Array(0), true); + return getResponse(this); + } + }; + + function getResponse(codec) { + if (codec.pendingData) { + const output = codec.pendingData; + codec.pendingData = null; + return output; + } else { + return new Uint8Array(0); + } + } + } + + /* + Copyright (c) 2021 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. + */ + + const ERR_HTTP_STATUS = "HTTP error "; + const ERR_HTTP_RANGE = "HTTP Range not supported"; + + const CONTENT_TYPE_TEXT_PLAIN = "text/plain"; + const HTTP_HEADER_CONTENT_LENGTH = "Content-Length"; + const HTTP_HEADER_ACCEPT_RANGES = "Accept-Ranges"; + const HTTP_HEADER_RANGE = "Range"; + const HTTP_METHOD_HEAD = "HEAD"; + const HTTP_METHOD_GET = "GET"; + const HTTP_RANGE_UNIT = "bytes"; + + class Stream { + + constructor() { + this.size = 0; + } + + init() { + this.initialized = true; + } + } + + class Reader extends Stream { + } + + class Writer extends Stream { + + writeUint8Array(array) { + this.size += array.length; + } + } + + class TextReader extends Reader { + + constructor(text) { + super(); + this.blobReader = new BlobReader(new Blob([text], { type: CONTENT_TYPE_TEXT_PLAIN })); + } + + async init() { + super.init(); + this.blobReader.init(); + this.size = this.blobReader.size; + } + + async readUint8Array(offset, length) { + return this.blobReader.readUint8Array(offset, length); + } + } + + class TextWriter extends Writer { + + constructor(encoding) { + super(); + this.encoding = encoding; + this.blob = new Blob([], { type: CONTENT_TYPE_TEXT_PLAIN }); + } + + async writeUint8Array(array) { + super.writeUint8Array(array); + this.blob = new Blob([this.blob, array.buffer], { type: CONTENT_TYPE_TEXT_PLAIN }); + } + + getData() { + const reader = new FileReader(); + return new Promise((resolve, reject) => { + reader.onload = event => resolve(event.target.result); + reader.onerror = reject; + reader.readAsText(this.blob, this.encoding); + }); + } + } + + class Data64URIReader extends Reader { + + constructor(dataURI) { + super(); + this.dataURI = dataURI; + let dataEnd = dataURI.length; + while (dataURI.charAt(dataEnd - 1) == "=") { + dataEnd--; + } + this.dataStart = dataURI.indexOf(",") + 1; + this.size = Math.floor((dataEnd - this.dataStart) * 0.75); + } + + async readUint8Array(offset, length) { + const dataArray = new Uint8Array(length); + const start = Math.floor(offset / 3) * 4; + const bytes = atob(this.dataURI.substring(start + this.dataStart, Math.ceil((offset + length) / 3) * 4 + this.dataStart)); + const delta = offset - Math.floor(start / 4) * 3; + for (let indexByte = delta; indexByte < delta + length; indexByte++) { + dataArray[indexByte - delta] = bytes.charCodeAt(indexByte); + } + return dataArray; + } + } + + class Data64URIWriter extends Writer { + + constructor(contentType) { + super(); + this.data = "data:" + (contentType || "") + ";base64,"; + this.pending = []; + } + + async writeUint8Array(array) { + super.writeUint8Array(array); + let indexArray = 0; + let dataString = this.pending; + const delta = this.pending.length; + this.pending = ""; + for (indexArray = 0; indexArray < (Math.floor((delta + array.length) / 3) * 3) - delta; indexArray++) { + dataString += String.fromCharCode(array[indexArray]); + } + for (; indexArray < array.length; indexArray++) { + this.pending += String.fromCharCode(array[indexArray]); + } + if (dataString.length > 2) { + this.data += btoa(dataString); + } else { + this.pending = dataString; + } + } + + getData() { + return this.data + btoa(this.pending); + } + } + + class BlobReader extends Reader { + + constructor(blob) { + super(); + this.blob = blob; + this.size = blob.size; + } + + async readUint8Array(offset, length) { + const reader = new FileReader(); + return new Promise((resolve, reject) => { + reader.onload = event => resolve(new Uint8Array(event.target.result)); + reader.onerror = reject; + reader.readAsArrayBuffer(this.blob.slice(offset, offset + length)); + }); + } + } + + class BlobWriter extends Writer { + + constructor(contentType) { + super(); + this.offset = 0; + this.contentType = contentType; + this.blob = new Blob([], { type: contentType }); + } + + async writeUint8Array(array) { + super.writeUint8Array(array); + this.blob = new Blob([this.blob, array.buffer], { type: this.contentType }); + this.offset = this.blob.size; + } + + getData() { + return this.blob; + } + } + + class FetchReader extends Reader { + + constructor(url, options) { + super(); + this.url = url; + this.preventHeadRequest = options.preventHeadRequest; + this.useRangeHeader = options.useRangeHeader; + this.forceRangeRequests = options.forceRangeRequests; + this.options = Object.assign({}, options); + delete this.options.preventHeadRequest; + delete this.options.useRangeHeader; + delete this.options.forceRangeRequests; + delete this.options.useXHR; + } + + async init() { + super.init(); + if (isHttpFamily(this.url) && !this.preventHeadRequest) { + const response = await sendFetchRequest(HTTP_METHOD_HEAD, this.url, this.options); + this.size = Number(response.headers.get(HTTP_HEADER_CONTENT_LENGTH)); + if (!this.forceRangeRequests && this.useRangeHeader && response.headers.get(HTTP_HEADER_ACCEPT_RANGES) != HTTP_RANGE_UNIT) { + throw new Error(ERR_HTTP_RANGE); + } else if (this.size === undefined) { + await getFetchData(this, this.options); + } + } else { + await getFetchData(this, this.options); + } + } + + async readUint8Array(index, length) { + if (this.useRangeHeader) { + const response = await sendFetchRequest(HTTP_METHOD_GET, this.url, this.options, Object.assign({}, this.options.headers, + { HEADER_RANGE: HTTP_RANGE_UNIT + "=" + index + "-" + (index + length - 1) })); + if (response.status != 206) { + throw new Error(ERR_HTTP_RANGE); + } + return new Uint8Array(await response.arrayBuffer()); + } else { + if (!this.data) { + await getFetchData(this, this.options); + } + return new Uint8Array(this.data.subarray(index, index + length)); + } + } + } + + async function getFetchData(httpReader, options) { + const response = await sendFetchRequest(HTTP_METHOD_GET, httpReader.url, options); + httpReader.data = new Uint8Array(await response.arrayBuffer()); + if (!httpReader.size) { + httpReader.size = httpReader.data.length; + } + } + + async function sendFetchRequest(method, url, options, headers) { + headers = Object.assign({}, options.headers, headers); + const response = await fetch(url, Object.assign({}, options, { method, headers })); + if (response.status < 400) { + return response; + } else { + throw new Error(ERR_HTTP_STATUS + (response.statusText || response.status)); + } + } + + class XHRReader extends Reader { + + constructor(url, options) { + super(); + this.url = url; + this.preventHeadRequest = options.preventHeadRequest; + this.useRangeHeader = options.useRangeHeader; + this.forceRangeRequests = options.forceRangeRequests; + } + + async init() { + super.init(); + if (isHttpFamily(this.url) && !this.preventHeadRequest) { + return new Promise((resolve, reject) => sendXHR(HTTP_METHOD_HEAD, this.url, request => { + this.size = Number(request.getResponseHeader(HTTP_HEADER_CONTENT_LENGTH)); + if (this.useRangeHeader) { + if (this.forceRangeRequests || request.getResponseHeader(HTTP_HEADER_ACCEPT_RANGES) == HTTP_RANGE_UNIT) { + resolve(); + } else { + reject(new Error(ERR_HTTP_RANGE)); + } + } else if (this.size === undefined) { + getXHRData(this, this.url).then(() => resolve()).catch(reject); + } else { + resolve(); + } + }, reject)); + } else { + await getXHRData(this, this.url); + } + } + + async readUint8Array(index, length) { + if (this.useRangeHeader) { + const request = await new Promise((resolve, reject) => sendXHR(HTTP_METHOD_GET, this.url, request => resolve(new Uint8Array(request.response)), reject, + [[HTTP_HEADER_RANGE, HTTP_RANGE_UNIT + "=" + index + "-" + (index + length - 1)]])); + if (request.status != 206) { + throw new Error(ERR_HTTP_RANGE); + } + } else { + if (!this.data) { + await getXHRData(this, this.url); + } + return new Uint8Array(this.data.subarray(index, index + length)); + } + } + } + + function getXHRData(httpReader, url) { + return new Promise((resolve, reject) => sendXHR(HTTP_METHOD_GET, url, request => { + httpReader.data = new Uint8Array(request.response); + if (!httpReader.size) { + httpReader.size = httpReader.data.length; + } + resolve(); + }, reject)); + } + + function sendXHR(method, url, onload, onerror, headers = []) { + const request = new XMLHttpRequest(); + request.addEventListener("load", () => { + if (request.status < 400) { + onload(request); + } else { + onerror(ERR_HTTP_STATUS + (request.statusText || request.status)); + } + }, false); + request.addEventListener("error", onerror, false); + request.open(method, url); + headers.forEach(header => request.setRequestHeader(header[0], header[1])); + request.responseType = "arraybuffer"; + request.send(); + return request; + } + + class HttpReader extends Reader { + + constructor(url, options = {}) { + super(); + this.url = url; + if (options.useXHR) { + this.reader = new XHRReader(url, options); + } else { + this.reader = new FetchReader(url, options); + } + } + + set size(value) { + // ignored + } + + get size() { + return this.reader.size; + } + + async init() { + super.init(); + await this.reader.init(); + } + + async readUint8Array(index, length) { + return this.reader.readUint8Array(index, length); + } + } + + class HttpRangeReader extends HttpReader { + + constructor(url, options = {}) { + options.useRangeHeader = true; + super(url, options); + } + } + + + class Uint8ArrayReader extends Reader { + + constructor(array) { + super(); + this.array = array; + this.size = array.length; + } + + async readUint8Array(index, length) { + return this.array.slice(index, index + length); + } + } + + class Uint8ArrayWriter extends Writer { + + constructor() { + super(); + this.array = new Uint8Array(0); + } + + async writeUint8Array(array) { + super.writeUint8Array(array); + const previousArray = this.array; + this.array = new Uint8Array(previousArray.length + array.length); + this.array.set(previousArray); + this.array.set(array, previousArray.length); + } + + getData() { + return this.array; + } + } + + function isHttpFamily(url) { + if (typeof document != "undefined") { + const anchor = document.createElement("a"); + anchor.href = url; + return anchor.protocol == "http:" || anchor.protocol == "https:"; + } else { + return /^https?:\/\//i.test(url); + } + } + + /* + Copyright (c) 2021 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. + */ + + const MAX_32_BITS = 0xffffffff; + const MAX_16_BITS = 0xffff; + const COMPRESSION_METHOD_DEFLATE = 0x08; + const COMPRESSION_METHOD_STORE = 0x00; + const COMPRESSION_METHOD_AES = 0x63; + + const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50; + const DATA_DESCRIPTOR_RECORD_SIGNATURE = 0x08074b50; + const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50; + const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50; + const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50; + const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE = 0x07064b50; + const END_OF_CENTRAL_DIR_LENGTH = 22; + const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH = 20; + const ZIP64_END_OF_CENTRAL_DIR_LENGTH = 56; + const ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH = END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LENGTH; + + const ZIP64_TOTAL_NUMBER_OF_DISKS = 1; + + const EXTRAFIELD_TYPE_ZIP64 = 0x0001; + const EXTRAFIELD_TYPE_AES = 0x9901; + const EXTRAFIELD_TYPE_UNICODE_PATH = 0x7075; + const EXTRAFIELD_TYPE_UNICODE_COMMENT = 0x6375; + + const BITFLAG_ENCRYPTED = 0x01; + const BITFLAG_LEVEL = 0x06; + const BITFLAG_DATA_DESCRIPTOR = 0x0008; + const BITFLAG_LANG_ENCODING_FLAG = 0x0800; + const FILE_ATTR_MSDOS_DIR_MASK = 0x10; + + const VERSION_DEFLATE = 0x14; + const VERSION_ZIP64 = 0x2D; + const VERSION_AES = 0x33; + + const DIRECTORY_SIGNATURE = "/"; + + const MAX_DATE = new Date(2107, 11, 31); + const MIN_DATE = new Date(1980, 0, 1); + + /* + Copyright (c) 2021 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. + */ + + const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split(""); + + var decodeCP437 = stringValue => { + let result = ""; + for (let indexCharacter = 0; indexCharacter < stringValue.length; indexCharacter++) { + result += CP437[stringValue[indexCharacter]]; + } + return result; + }; + + /* + Copyright (c) 2021 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. + */ + + const table = []; + for (let i = 0; i < 256; i++) { + let t = i; + for (let j = 0; j < 8; j++) { + if (t & 1) { + t = (t >>> 1) ^ 0xEDB88320; + } else { + t = t >>> 1; + } + } + table[i] = t; + } + + class Crc32 { + + constructor(crc) { + this.crc = crc || -1; + } + + append(data) { + let crc = this.crc | 0; + for (let offset = 0, length = data.length | 0; offset < length; offset++) { + crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF]; + } + this.crc = crc; + } + + get() { + return ~this.crc; + } + } + + // Derived from https://github.com/xqdoo00o/jszip/blob/master/lib/sjcl.js + /*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */ + + /** @fileOverview Arrays of bits, encoded as arrays of Numbers. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + /** + * Arrays of bits, encoded as arrays of Numbers. + * @namespace + * @description + * + * These objects are the currency accepted by SJCL's crypto functions. + *
+ * + *+ * Most of our crypto primitives operate on arrays of 4-byte words internally, + * but many of them can take arguments that are not a multiple of 4 bytes. + * This library encodes arrays of bits (whose size need not be a multiple of 8 + * bits) as arrays of 32-bit words. The bits are packed, big-endian, into an + * array of words, 32 bits at a time. Since the words are double-precision + * floating point numbers, they fit some extra data. We use this (in a private, + * possibly-changing manner) to encode the number of bits actually present + * in the last word of the array. + *
+ * + *+ * Because bitwise ops clear this out-of-band data, these arrays can be passed + * to ciphers like AES which want arrays of words. + *
+ */ + const bitArray = { + /** + * Concatenate two bit arrays. + * @param {bitArray} a1 The first array. + * @param {bitArray} a2 The second array. + * @return {bitArray} The concatenation of a1 and a2. + */ + concat(a1, a2) { + if (a1.length === 0 || a2.length === 0) { + return a1.concat(a2); + } + + const last = a1[a1.length - 1], shift = bitArray.getPartial(last); + if (shift === 32) { + return a1.concat(a2); + } else { + return bitArray._shiftRight(a2, shift, last | 0, a1.slice(0, a1.length - 1)); + } + }, + + /** + * Find the length of an array of bits. + * @param {bitArray} a The array. + * @return {Number} The length of a, in bits. + */ + bitLength(a) { + const l = a.length; + if (l === 0) { + return 0; + } + const x = a[l - 1]; + return (l - 1) * 32 + bitArray.getPartial(x); + }, + + /** + * Truncate an array. + * @param {bitArray} a The array. + * @param {Number} len The length to truncate to, in bits. + * @return {bitArray} A new array, truncated to len bits. + */ + clamp(a, len) { + if (a.length * 32 < len) { + return a; + } + a = a.slice(0, Math.ceil(len / 32)); + const l = a.length; + len = len & 31; + if (l > 0 && len) { + a[l - 1] = bitArray.partial(len, a[l - 1] & 0x80000000 >> (len - 1), 1); + } + return a; + }, + + /** + * Make a partial word for a bit array. + * @param {Number} len The number of bits in the word. + * @param {Number} x The bits. + * @param {Number} [_end=0] Pass 1 if x has already been shifted to the high side. + * @return {Number} The partial word. + */ + partial(len, x, _end) { + if (len === 32) { + return x; + } + return (_end ? x | 0 : x << (32 - len)) + len * 0x10000000000; + }, + + /** + * Get the number of bits used by a partial word. + * @param {Number} x The partial word. + * @return {Number} The number of bits used by the partial word. + */ + getPartial(x) { + return Math.round(x / 0x10000000000) || 32; + }, + + /** Shift an array right. + * @param {bitArray} a The array to shift. + * @param {Number} shift The number of bits to shift. + * @param {Number} [carry=0] A byte to carry in + * @param {bitArray} [out=[]] An array to prepend to the output. + * @private + */ + _shiftRight(a, shift, carry, out) { + if (out === undefined) { + out = []; + } + + for (; shift >= 32; shift -= 32) { + out.push(carry); + carry = 0; + } + if (shift === 0) { + return out.concat(a); + } + + for (let i = 0; i < a.length; i++) { + out.push(carry | a[i] >>> shift); + carry = a[i] << (32 - shift); + } + const last2 = a.length ? a[a.length - 1] : 0; + const shift2 = bitArray.getPartial(last2); + out.push(bitArray.partial(shift + shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(), 1)); + return out; + } + }; + + /** @fileOverview Bit array codec implementations. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + /** + * Arrays of bytes + * @namespace + */ + const codec = { + bytes: { + /** Convert from a bitArray to an array of bytes. */ + fromBits(arr) { + const bl = bitArray.bitLength(arr); + const byteLength = bl / 8; + const out = new Uint8Array(byteLength); + let tmp; + for (let i = 0; i < byteLength; i++) { + if ((i & 3) === 0) { + tmp = arr[i / 4]; + } + out[i] = tmp >>> 24; + tmp <<= 8; + } + return out; + }, + /** Convert from an array of bytes to a bitArray. */ + toBits(bytes) { + const out = []; + let i; + let tmp = 0; + for (i = 0; i < bytes.length; i++) { + tmp = tmp << 8 | bytes[i]; + if ((i & 3) === 3) { + out.push(tmp); + tmp = 0; + } + } + if (i & 3) { + out.push(bitArray.partial(8 * (i & 3), tmp)); + } + return out; + } + } + }; + + const hash = {}; + + /** + * Context for a SHA-1 operation in progress. + * @constructor + */ + hash.sha1 = function (hash) { + if (hash) { + this._h = hash._h.slice(0); + this._buffer = hash._buffer.slice(0); + this._length = hash._length; + } else { + this.reset(); + } + }; + + hash.sha1.prototype = { + /** + * The hash's block size, in bits. + * @constant + */ + blockSize: 512, + + /** + * Reset the hash state. + * @return this + */ + reset: function () { + const sha1 = this; + sha1._h = this._init.slice(0); + sha1._buffer = []; + sha1._length = 0; + return sha1; + }, + + /** + * Input several words to the hash. + * @param {bitArray|String} data the data to hash. + * @return this + */ + update: function (data) { + const sha1 = this; + if (typeof data === "string") { + data = codec.utf8String.toBits(data); + } + const b = sha1._buffer = bitArray.concat(sha1._buffer, data); + const ol = sha1._length; + const nl = sha1._length = ol + bitArray.bitLength(data); + if (nl > 9007199254740991) { + throw new Error("Cannot hash more than 2^53 - 1 bits"); + } + const c = new Uint32Array(b); + let j = 0; + for (let i = sha1.blockSize + ol - ((sha1.blockSize + ol) & (sha1.blockSize - 1)); i <= nl; + i += sha1.blockSize) { + sha1._block(c.subarray(16 * j, 16 * (j + 1))); + j += 1; + } + b.splice(0, 16 * j); + return sha1; + }, + + /** + * Complete hashing and output the hash value. + * @return {bitArray} The hash value, an array of 5 big-endian words. TODO + */ + finalize: function () { + const sha1 = this; + let b = sha1._buffer; + const h = sha1._h; + + // Round out and push the buffer + b = bitArray.concat(b, [bitArray.partial(1, 1)]); + // Round out the buffer to a multiple of 16 words, less the 2 length words. + for (let i = b.length + 2; i & 15; i++) { + b.push(0); + } + + // append the length + b.push(Math.floor(sha1._length / 0x100000000)); + b.push(sha1._length | 0); + + while (b.length) { + sha1._block(b.splice(0, 16)); + } + + sha1.reset(); + return h; + }, + + /** + * The SHA-1 initialization vector. + * @private + */ + _init: [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0], + + /** + * The SHA-1 hash key. + * @private + */ + _key: [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6], + + /** + * The SHA-1 logical functions f(0), f(1), ..., f(79). + * @private + */ + _f: function (t, b, c, d) { + if (t <= 19) { + return (b & c) | (~b & d); + } else if (t <= 39) { + return b ^ c ^ d; + } else if (t <= 59) { + return (b & c) | (b & d) | (c & d); + } else if (t <= 79) { + return b ^ c ^ d; + } + }, + + /** + * Circular left-shift operator. + * @private + */ + _S: function (n, x) { + return (x << n) | (x >>> 32 - n); + }, + + /** + * Perform one cycle of SHA-1. + * @param {Uint32Array|bitArray} words one block of words. + * @private + */ + _block: function (words) { + const sha1 = this; + const h = sha1._h; + // When words is passed to _block, it has 16 elements. SHA1 _block + // function extends words with new elements (at the end there are 80 elements). + // The problem is that if we use Uint32Array instead of Array, + // the length of Uint32Array cannot be changed. Thus, we replace words with a + // normal Array here. + const w = Array(80); // do not use Uint32Array here as the instantiation is slower + for (let j = 0; j < 16; j++) { + w[j] = words[j]; + } + + let a = h[0]; + let b = h[1]; + let c = h[2]; + let d = h[3]; + let e = h[4]; + + for (let t = 0; t <= 79; t++) { + if (t >= 16) { + w[t] = sha1._S(1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]); + } + const tmp = (sha1._S(5, a) + sha1._f(t, b, c, d) + e + w[t] + + sha1._key[Math.floor(t / 20)]) | 0; + e = d; + d = c; + c = sha1._S(30, b); + b = a; + a = tmp; + } + + h[0] = (h[0] + a) | 0; + h[1] = (h[1] + b) | 0; + h[2] = (h[2] + c) | 0; + h[3] = (h[3] + d) | 0; + h[4] = (h[4] + e) | 0; + } + }; + + /** @fileOverview Low-level AES implementation. + * + * This file contains a low-level implementation of AES, optimized for + * size and for efficiency on several browsers. It is based on + * OpenSSL's aes_core.c, a public-domain implementation by Vincent + * Rijmen, Antoon Bosselaers and Paulo Barreto. + * + * An older version of this implementation is available in the public + * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh, + * Stanford University 2008-2010 and BSD-licensed for liability + * reasons. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + const cipher = {}; + + /** + * Schedule out an AES key for both encryption and decryption. This + * is a low-level class. Use a cipher mode to do bulk encryption. + * + * @constructor + * @param {Array} key The key as an array of 4, 6 or 8 words. + */ + cipher.aes = class { + constructor(key) { + /** + * The expanded S-box and inverse S-box tables. These will be computed + * on the client so that we don't have to send them down the wire. + * + * There are two tables, _tables[0] is for encryption and + * _tables[1] is for decryption. + * + * The first 4 sub-tables are the expanded S-box with MixColumns. The + * last (_tables[01][4]) is the S-box itself. + * + * @private + */ + const aes = this; + aes._tables = [[[], [], [], [], []], [[], [], [], [], []]]; + + if (!aes._tables[0][0][0]) { + aes._precompute(); + } + + const sbox = aes._tables[0][4]; + const decTable = aes._tables[1]; + const keyLen = key.length; + + let i, encKey, decKey, rcon = 1; + + if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) { + throw new Error("invalid aes key size"); + } + + aes._key = [encKey = key.slice(0), decKey = []]; + + // schedule encryption keys + for (i = keyLen; i < 4 * keyLen + 28; i++) { + let tmp = encKey[i - 1]; + + // apply sbox + if (i % keyLen === 0 || (keyLen === 8 && i % keyLen === 4)) { + tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255]; + + // shift rows and add rcon + if (i % keyLen === 0) { + tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24; + rcon = rcon << 1 ^ (rcon >> 7) * 283; + } + } + + encKey[i] = encKey[i - keyLen] ^ tmp; + } + + // schedule decryption keys + for (let j = 0; i; j++, i--) { + const tmp = encKey[j & 3 ? i : i - 4]; + if (i <= 4 || j < 4) { + decKey[j] = tmp; + } else { + decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ + decTable[1][sbox[tmp >> 16 & 255]] ^ + decTable[2][sbox[tmp >> 8 & 255]] ^ + decTable[3][sbox[tmp & 255]]; + } + } + } + // public + /* Something like this might appear here eventually + name: "AES", + blockSize: 4, + keySizes: [4,6,8], + */ + + /** + * Encrypt an array of 4 big-endian words. + * @param {Array} data The plaintext. + * @return {Array} The ciphertext. + */ + encrypt(data) { + return this._crypt(data, 0); + } + + /** + * Decrypt an array of 4 big-endian words. + * @param {Array} data The ciphertext. + * @return {Array} The plaintext. + */ + decrypt(data) { + return this._crypt(data, 1); + } + + /** + * Expand the S-box tables. + * + * @private + */ + _precompute() { + const encTable = this._tables[0]; + const decTable = this._tables[1]; + const sbox = encTable[4]; + const sboxInv = decTable[4]; + const d = []; + const th = []; + let xInv, x2, x4, x8; + + // Compute double and third tables + for (let i = 0; i < 256; i++) { + th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i; + } + + for (let x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) { + // Compute sbox + let s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4; + s = s >> 8 ^ s & 255 ^ 99; + sbox[x] = s; + sboxInv[s] = x; + + // Compute MixColumns + x8 = d[x4 = d[x2 = d[x]]]; + let tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100; + let tEnc = d[s] * 0x101 ^ s * 0x1010100; + + for (let i = 0; i < 4; i++) { + encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8; + decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8; + } + } + + // Compactify. Considerable speedup on Firefox. + for (let i = 0; i < 5; i++) { + encTable[i] = encTable[i].slice(0); + decTable[i] = decTable[i].slice(0); + } + } + + /** + * Encryption and decryption core. + * @param {Array} input Four words to be encrypted or decrypted. + * @param dir The direction, 0 for encrypt and 1 for decrypt. + * @return {Array} The four encrypted or decrypted words. + * @private + */ + _crypt(input, dir) { + if (input.length !== 4) { + throw new Error("invalid aes block size"); + } + + const key = this._key[dir]; + + const nInnerRounds = key.length / 4 - 2; + const out = [0, 0, 0, 0]; + const table = this._tables[dir]; + + // load up the tables + const t0 = table[0]; + const t1 = table[1]; + const t2 = table[2]; + const t3 = table[3]; + const sbox = table[4]; + + // state variables a,b,c,d are loaded with pre-whitened data + let a = input[0] ^ key[0]; + let b = input[dir ? 3 : 1] ^ key[1]; + let c = input[2] ^ key[2]; + let d = input[dir ? 1 : 3] ^ key[3]; + let kIndex = 4; + let a2, b2, c2; + + // Inner rounds. Cribbed from OpenSSL. + for (let i = 0; i < nInnerRounds; i++) { + a2 = t0[a >>> 24] ^ t1[b >> 16 & 255] ^ t2[c >> 8 & 255] ^ t3[d & 255] ^ key[kIndex]; + b2 = t0[b >>> 24] ^ t1[c >> 16 & 255] ^ t2[d >> 8 & 255] ^ t3[a & 255] ^ key[kIndex + 1]; + c2 = t0[c >>> 24] ^ t1[d >> 16 & 255] ^ t2[a >> 8 & 255] ^ t3[b & 255] ^ key[kIndex + 2]; + d = t0[d >>> 24] ^ t1[a >> 16 & 255] ^ t2[b >> 8 & 255] ^ t3[c & 255] ^ key[kIndex + 3]; + kIndex += 4; + a = a2; b = b2; c = c2; + } + + // Last round. + for (let i = 0; i < 4; i++) { + out[dir ? 3 & -i : i] = + sbox[a >>> 24] << 24 ^ + sbox[b >> 16 & 255] << 16 ^ + sbox[c >> 8 & 255] << 8 ^ + sbox[d & 255] ^ + key[kIndex++]; + a2 = a; a = b; b = c; c = d; d = a2; + } + + return out; + } + }; + + /** @fileOverview CTR mode implementation. + * + * Special thanks to Roy Nicholson for pointing out a bug in our + * implementation. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + /** Brian Gladman's CTR Mode. + * @constructor + * @param {Object} _prf The aes instance to generate key. + * @param {bitArray} _iv The iv for ctr mode, it must be 128 bits. + */ + + const mode = {}; + + /** + * Brian Gladman's CTR Mode. + * @namespace + */ + mode.ctrGladman = class { + constructor(prf, iv) { + this._prf = prf; + this._initIv = iv; + this._iv = iv; + } + + reset() { + this._iv = this._initIv; + } + + /** Input some data to calculate. + * @param {bitArray} data the data to process, it must be intergral multiple of 128 bits unless it's the last. + */ + update(data) { + return this.calculate(this._prf, data, this._iv); + } + + incWord(word) { + if (((word >> 24) & 0xff) === 0xff) { //overflow + let b1 = (word >> 16) & 0xff; + let b2 = (word >> 8) & 0xff; + let b3 = word & 0xff; + + if (b1 === 0xff) { // overflow b1 + b1 = 0; + if (b2 === 0xff) { + b2 = 0; + if (b3 === 0xff) { + b3 = 0; + } else { + ++b3; + } + } else { + ++b2; + } + } else { + ++b1; + } + + word = 0; + word += (b1 << 16); + word += (b2 << 8); + word += b3; + } else { + word += (0x01 << 24); + } + return word; + } + + incCounter(counter) { + if ((counter[0] = this.incWord(counter[0])) === 0) { + // encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8 + counter[1] = this.incWord(counter[1]); + } + } + + calculate(prf, data, iv) { + let l; + if (!(l = data.length)) { + return []; + } + const bl = bitArray.bitLength(data); + for (let i = 0; i < l; i += 4) { + this.incCounter(iv); + const e = prf.encrypt(iv); + data[i] ^= e[0]; + data[i + 1] ^= e[1]; + data[i + 2] ^= e[2]; + data[i + 3] ^= e[3]; + } + return bitArray.clamp(data, bl); + } + }; + + + const misc = {}; + + /** @fileOverview HMAC implementation. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + /** HMAC with the specified hash function. + * @constructor + * @param {bitArray} key the key for HMAC. + * @param {Object} [Hash=hash.sha1] The hash function to use. + */ + misc.hmacSha1 = class { + + constructor(key) { + const hmac = this; + const Hash = hmac._hash = hash.sha1; + const exKey = [[], []]; + const bs = Hash.prototype.blockSize / 32; + hmac._baseHash = [new Hash(), new Hash()]; + + if (key.length > bs) { + key = Hash.hash(key); + } + + for (let i = 0; i < bs; i++) { + exKey[0][i] = key[i] ^ 0x36363636; + exKey[1][i] = key[i] ^ 0x5C5C5C5C; + } + + hmac._baseHash[0].update(exKey[0]); + hmac._baseHash[1].update(exKey[1]); + hmac._resultHash = new Hash(hmac._baseHash[0]); + } + reset() { + const hmac = this; + hmac._resultHash = new hmac._hash(hmac._baseHash[0]); + hmac._updated = false; + } + + update(data) { + const hmac = this; + hmac._updated = true; + hmac._resultHash.update(data); + } + + digest() { + const hmac = this; + const w = hmac._resultHash.finalize(); + const result = new (hmac._hash)(hmac._baseHash[1]).update(w).finalize(); + + hmac.reset(); + + return result; + } + }; + + /* + Copyright (c) 2021 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. + */ + + const ERR_INVALID_PASSWORD = "Invalid pasword"; + const BLOCK_LENGTH = 16; + const RAW_FORMAT = "raw"; + const PBKDF2_ALGORITHM = { name: "PBKDF2" }; + const HASH_ALGORITHM = { name: "HMAC" }; + const HASH_FUNCTION = "SHA-1"; + const BASE_KEY_ALGORITHM = Object.assign({ hash: HASH_ALGORITHM }, PBKDF2_ALGORITHM); + const DERIVED_BITS_ALGORITHM = Object.assign({ iterations: 1000, hash: { name: HASH_FUNCTION } }, PBKDF2_ALGORITHM); + const DERIVED_BITS_USAGE = ["deriveBits"]; + const SALT_LENGTH = [8, 12, 16]; + const KEY_LENGTH = [16, 24, 32]; + const SIGNATURE_LENGTH = 10; + const COUNTER_DEFAULT_VALUE = [0, 0, 0, 0]; + const subtle = crypto.subtle; + const codecBytes = codec.bytes; + const Aes = cipher.aes; + const CtrGladman = mode.ctrGladman; + const HmacSha1 = misc.hmacSha1; + class AESDecrypt { + + constructor(password, signed, strength) { + Object.assign(this, { + password, + signed, + strength: strength - 1, + pendingInput: new Uint8Array(0) + }); + } + + async append(input) { + const aesCrypto = this; + if (aesCrypto.password) { + const preamble = subarray(input, 0, SALT_LENGTH[aesCrypto.strength] + 2); + await createDecryptionKeys(aesCrypto, preamble, aesCrypto.password); + aesCrypto.password = null; + aesCrypto.aesCtrGladman = new CtrGladman(new Aes(aesCrypto.keys.key), Array.from(COUNTER_DEFAULT_VALUE)); + aesCrypto.hmac = new HmacSha1(aesCrypto.keys.authentication); + input = subarray(input, SALT_LENGTH[aesCrypto.strength] + 2); + } + const output = new Uint8Array(input.length - SIGNATURE_LENGTH - ((input.length - SIGNATURE_LENGTH) % BLOCK_LENGTH)); + return append(aesCrypto, input, output, 0, SIGNATURE_LENGTH, true); + } + + async flush() { + const aesCrypto = this; + const pendingInput = aesCrypto.pendingInput; + const chunkToDecrypt = subarray(pendingInput, 0, pendingInput.length - SIGNATURE_LENGTH); + const originalSignature = subarray(pendingInput, pendingInput.length - SIGNATURE_LENGTH); + let decryptedChunkArray = new Uint8Array(0); + if (chunkToDecrypt.length) { + const encryptedChunk = codecBytes.toBits(chunkToDecrypt); + aesCrypto.hmac.update(encryptedChunk); + const decryptedChunk = aesCrypto.aesCtrGladman.update(encryptedChunk); + decryptedChunkArray = codecBytes.fromBits(decryptedChunk); + } + let valid = true; + if (aesCrypto.signed) { + const signature = subarray(codecBytes.fromBits(aesCrypto.hmac.digest()), 0, SIGNATURE_LENGTH); + for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) { + if (signature[indexSignature] != originalSignature[indexSignature]) { + valid = false; + } + } + } + return { + valid, + data: decryptedChunkArray + }; + } + } + + class AESEncrypt { + + constructor(password, strength) { + Object.assign(this, { + password, + strength: strength - 1, + pendingInput: new Uint8Array(0) + }); + } + + async append(input) { + const aesCrypto = this; + let preamble = new Uint8Array(0); + if (aesCrypto.password) { + preamble = await createEncryptionKeys(aesCrypto, aesCrypto.password); + aesCrypto.password = null; + aesCrypto.aesCtrGladman = new CtrGladman(new Aes(aesCrypto.keys.key), Array.from(COUNTER_DEFAULT_VALUE)); + aesCrypto.hmac = new HmacSha1(aesCrypto.keys.authentication); + } + const output = new Uint8Array(preamble.length + input.length - (input.length % BLOCK_LENGTH)); + output.set(preamble, 0); + return append(aesCrypto, input, output, preamble.length, 0); + } + + async flush() { + const aesCrypto = this; + let encryptedChunkArray = new Uint8Array(0); + if (aesCrypto.pendingInput.length) { + const encryptedChunk = aesCrypto.aesCtrGladman.update(codecBytes.toBits(aesCrypto.pendingInput)); + aesCrypto.hmac.update(encryptedChunk); + encryptedChunkArray = codecBytes.fromBits(encryptedChunk); + } + const signature = subarray(codecBytes.fromBits(aesCrypto.hmac.digest()), 0, SIGNATURE_LENGTH); + return { + data: concat(encryptedChunkArray, signature), + signature + }; + } + } + + function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignature) { + const inputLength = input.length - paddingEnd; + if (aesCrypto.pendingInput.length) { + input = concat(aesCrypto.pendingInput, input); + output = expand(output, inputLength - (inputLength % BLOCK_LENGTH)); + } + let offset; + for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) { + const inputChunk = codecBytes.toBits(subarray(input, offset, offset + BLOCK_LENGTH)); + if (verifySignature) { + aesCrypto.hmac.update(inputChunk); + } + const outputChunk = aesCrypto.aesCtrGladman.update(inputChunk); + if (!verifySignature) { + aesCrypto.hmac.update(outputChunk); + } + output.set(codecBytes.fromBits(outputChunk), offset + paddingStart); + } + aesCrypto.pendingInput = subarray(input, offset); + return output; + } + + async function createDecryptionKeys(decrypt, preambleArray, password) { + await createKeys$1(decrypt, password, subarray(preambleArray, 0, SALT_LENGTH[decrypt.strength])); + const passwordVerification = subarray(preambleArray, SALT_LENGTH[decrypt.strength]); + const passwordVerificationKey = decrypt.keys.passwordVerification; + if (passwordVerificationKey[0] != passwordVerification[0] || passwordVerificationKey[1] != passwordVerification[1]) { + throw new Error(ERR_INVALID_PASSWORD); + } + } + + async function createEncryptionKeys(encrypt, password) { + const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH[encrypt.strength])); + await createKeys$1(encrypt, password, salt); + return concat(salt, encrypt.keys.passwordVerification); + } + + async function createKeys$1(target, password, salt) { + const encodedPassword = (new TextEncoder()).encode(password); + const basekey = await subtle.importKey(RAW_FORMAT, encodedPassword, BASE_KEY_ALGORITHM, false, DERIVED_BITS_USAGE); + const derivedBits = await subtle.deriveBits(Object.assign({ salt }, DERIVED_BITS_ALGORITHM), basekey, 8 * ((KEY_LENGTH[target.strength] * 2) + 2)); + const compositeKey = new Uint8Array(derivedBits); + target.keys = { + key: codecBytes.toBits(subarray(compositeKey, 0, KEY_LENGTH[target.strength])), + authentication: codecBytes.toBits(subarray(compositeKey, KEY_LENGTH[target.strength], KEY_LENGTH[target.strength] * 2)), + passwordVerification: subarray(compositeKey, KEY_LENGTH[target.strength] * 2) + }; + } + + function concat(leftArray, rightArray) { + let array = leftArray; + if (leftArray.length + rightArray.length) { + array = new Uint8Array(leftArray.length + rightArray.length); + array.set(leftArray, 0); + array.set(rightArray, leftArray.length); + } + return array; + } + + function expand(inputArray, length) { + if (length && length > inputArray.length) { + const array = inputArray; + inputArray = new Uint8Array(length); + inputArray.set(array, 0); + } + return inputArray; + } + + function subarray(array, begin, end) { + return array.subarray(begin, end); + } + + /* + Copyright (c) 2021 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. + */ + + const HEADER_LENGTH = 12; + + class ZipCryptoDecrypt { + + constructor(password, passwordVerification) { + const zipCrypto = this; + Object.assign(zipCrypto, { + password, + passwordVerification + }); + createKeys(zipCrypto, password); + } + + async append(input) { + const zipCrypto = this; + if (zipCrypto.password) { + const decryptedHeader = decrypt(zipCrypto, input.subarray(0, HEADER_LENGTH)); + zipCrypto.password = null; + if (decryptedHeader[HEADER_LENGTH - 1] != zipCrypto.passwordVerification) { + throw new Error(ERR_INVALID_PASSWORD); + } + input = input.subarray(HEADER_LENGTH); + } + return decrypt(zipCrypto, input); + } + + async flush() { + return { + valid: true, + data: new Uint8Array(0) + }; + } + } + + class ZipCryptoEncrypt { + + constructor(password, passwordVerification) { + const zipCrypto = this; + Object.assign(zipCrypto, { + password, + passwordVerification + }); + createKeys(zipCrypto, password); + } + + async append(input) { + const zipCrypto = this; + let output; + let offset; + if (zipCrypto.password) { + zipCrypto.password = null; + const header = crypto.getRandomValues(new Uint8Array(HEADER_LENGTH)); + header[HEADER_LENGTH - 1] = zipCrypto.passwordVerification; + output = new Uint8Array(input.length + header.length); + output.set(encrypt(zipCrypto, header), 0); + offset = HEADER_LENGTH; + } else { + output = new Uint8Array(input.length); + offset = 0; + } + output.set(encrypt(zipCrypto, input), offset); + return output; + } + + async flush() { + return { + data: new Uint8Array(0) + }; + } + } + + function decrypt(target, input) { + const output = new Uint8Array(input.length); + for (let index = 0; index < input.length; index++) { + output[index] = getByte(target) ^ input[index]; + updateKeys(target, output[index]); + } + return output; + } + + function encrypt(target, input) { + const output = new Uint8Array(input.length); + for (let index = 0; index < input.length; index++) { + output[index] = getByte(target) ^ input[index]; + updateKeys(target, input[index]); + } + return output; + } + + function createKeys(target, password) { + target.keys = [0x12345678, 0x23456789, 0x34567890]; + target.crcKey0 = new Crc32(target.keys[0]); + target.crcKey2 = new Crc32(target.keys[2]); + for (let index = 0; index < password.length; index++) { + updateKeys(target, password.charCodeAt(index)); + } + } + + function updateKeys(target, byte) { + target.crcKey0.append([byte]); + target.keys[0] = ~target.crcKey0.get(); + target.keys[1] = getInt32(target.keys[1] + getInt8(target.keys[0])); + target.keys[1] = getInt32(Math.imul(target.keys[1], 134775813) + 1); + target.crcKey2.append([target.keys[1] >>> 24]); + target.keys[2] = ~target.crcKey2.get(); + } + + function getByte(target) { + const temp = target.keys[2] | 2; + return getInt8(Math.imul(temp, (temp ^ 1)) >>> 8); + } + + function getInt8(number) { + return number & 0xFF; + } + + function getInt32(number) { + return number & 0xFFFFFFFF; + } + + /* + Copyright (c) 2021 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. + */ + + const CODEC_DEFLATE = "deflate"; + const CODEC_INFLATE = "inflate"; + const ERR_INVALID_SIGNATURE = "Invalid signature"; + + class Inflate { + + constructor(codecConstructor, { + signature, + password, + signed, + compressed, + zipCrypto, + passwordVerification, + encryptionStrength + }, { chunkSize }) { + const encrypted = Boolean(password); + Object.assign(this, { + signature, + encrypted, + signed, + compressed, + inflate: compressed && new codecConstructor({ chunkSize }), + crc32: signed && new Crc32(), + zipCrypto, + decrypt: encrypted && zipCrypto ? + new ZipCryptoDecrypt(password, passwordVerification) : + new AESDecrypt(password, signed, encryptionStrength) + }); + } + + async append(data) { + const codec = this; + if (codec.encrypted && data.length) { + data = await codec.decrypt.append(data); + } + if (codec.compressed && data.length) { + data = await codec.inflate.append(data); + } + if ((!codec.encrypted || codec.zipCrypto) && codec.signed && data.length) { + codec.crc32.append(data); + } + return data; + } + + async flush() { + const codec = this; + let signature; + let data = new Uint8Array(0); + if (codec.encrypted) { + const result = await codec.decrypt.flush(); + if (!result.valid) { + throw new Error(ERR_INVALID_SIGNATURE); + } + data = result.data; + } + if ((!codec.encrypted || codec.zipCrypto) && codec.signed) { + const dataViewSignature = new DataView(new Uint8Array(4).buffer); + signature = codec.crc32.get(); + dataViewSignature.setUint32(0, signature); + if (codec.cipher != dataViewSignature.getUint32(0, false)) { + throw new Error(ERR_INVALID_SIGNATURE); + } + } + if (codec.compressed) { + data = (await codec.inflate.append(data)) || new Uint8Array(0); + await codec.inflate.flush(); + } + return { data, signature }; + } + } + + class Deflate { + + constructor(codecConstructor, { + encrypted, + signed, + compressed, + level, + zipCrypto, + password, + passwordVerification, + encryptionStrength + }, { chunkSize }) { + Object.assign(this, { + encrypted, + signed, + compressed, + deflate: compressed && new codecConstructor({ level: level || 5, chunkSize }), + crc32: signed && new Crc32(), + zipCrypto, + encrypt: encrypted && zipCrypto ? + new ZipCryptoEncrypt(password, passwordVerification) : + new AESEncrypt(password, encryptionStrength) + }); + } + + async append(inputData) { + const codec = this; + let data = inputData; + if (codec.compressed && inputData.length) { + data = await codec.deflate.append(inputData); + } + if (codec.encrypted && data.length) { + data = await codec.encrypt.append(data); + } + if ((!codec.encrypted || codec.zipCrypto) && codec.signed && inputData.length) { + codec.crc32.append(inputData); + } + return data; + } + + async flush() { + const codec = this; + let signature; + let data = new Uint8Array(0); + if (codec.compressed) { + data = (await codec.deflate.flush()) || new Uint8Array(0); + } + if (codec.encrypted) { + data = await codec.encrypt.append(data); + const result = await codec.encrypt.flush(); + signature = result.signature; + const newData = new Uint8Array(data.length + result.data.length); + newData.set(data, 0); + newData.set(result.data, data.length); + data = newData; + } + if ((!codec.encrypted || codec.zipCrypto) && codec.signed) { + signature = codec.crc32.get(); + } + return { data, signature }; + } + } + + function createCodec$1(codecConstructor, options, config) { + if (options.codecType.startsWith(CODEC_DEFLATE)) { + return new Deflate(codecConstructor, options, config); + } else if (options.codecType.startsWith(CODEC_INFLATE)) { + return new Inflate(codecConstructor, options, config); + } + } + + /* + Copyright (c) 2021 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. + */ + + const MESSAGE_INIT = "init"; + const MESSAGE_APPEND = "append"; + const MESSAGE_FLUSH = "flush"; + const MESSAGE_EVENT_TYPE = "message"; + + var getWorker = (workerData, codecConstructor, options, config, onTaskFinished, webWorker, scripts) => { + Object.assign(workerData, { + busy: true, + codecConstructor, + options: Object.assign({}, options), + scripts, + webWorker, + onTaskFinished() { + workerData.busy = false; + const terminateWorker = onTaskFinished(workerData); + if (terminateWorker && workerData.worker) { + workerData.worker.terminate(); + } + } + }); + return webWorker ? createWebWorkerInterface(workerData, config) : createWorkerInterface(workerData, config); + }; + + function createWorkerInterface(workerData, config) { + const interfaceCodec = createCodec$1(workerData.codecConstructor, workerData.options, config); + return { + async append(data) { + try { + return await interfaceCodec.append(data); + } catch (error) { + workerData.onTaskFinished(); + throw error; + } + }, + async flush() { + try { + return await interfaceCodec.flush(); + } finally { + workerData.onTaskFinished(); + } + } + }; + } + + function createWebWorkerInterface(workerData, config) { + let messageTask; + if (!workerData.interface) { + workerData.worker = new Worker(new URL(workerData.scripts[0], (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('zip-fs.js', document.baseURI).href)))); + workerData.worker.addEventListener(MESSAGE_EVENT_TYPE, onMessage, false); + workerData.interface = { + append(data) { + return initAndSendMessage({ type: MESSAGE_APPEND, data }); + }, + flush() { + return initAndSendMessage({ type: MESSAGE_FLUSH }); + } + }; + } + return workerData.interface; + + async function initAndSendMessage(message) { + if (!messageTask) { + const options = workerData.options; + const scripts = workerData.scripts.slice(1); + await sendMessage({ scripts, type: MESSAGE_INIT, options, config: { chunkSize: config.chunkSize } }); + } + return sendMessage(message); + } + + function sendMessage(message) { + const worker = workerData.worker; + const result = new Promise((resolve, reject) => messageTask = { resolve, reject }); + try { + if (message.data) { + try { + message.data = message.data.buffer; + worker.postMessage(message, [message.data]); + } catch (error) { + worker.postMessage(message); + } + } else { + worker.postMessage(message); + } + } catch (error) { + messageTask.reject(error); + messageTask = null; + workerData.onTaskFinished(); + } + return result; + } + + function onMessage(event) { + const message = event.data; + if (messageTask) { + const reponseError = message.error; + const type = message.type; + if (reponseError) { + const error = new Error(reponseError.message); + error.stack = reponseError.stack; + messageTask.reject(error); + messageTask = null; + workerData.onTaskFinished(); + } else if (type == MESSAGE_INIT || type == MESSAGE_FLUSH || type == MESSAGE_APPEND) { + const data = message.data; + if (type == MESSAGE_FLUSH) { + messageTask.resolve({ data: new Uint8Array(data), signature: message.signature }); + messageTask = null; + workerData.onTaskFinished(); + } else { + messageTask.resolve(data && new Uint8Array(data)); + } + } + } + } + } + + /* + Copyright (c) 2021 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. + */ + + let pool = []; + let pendingRequests = []; + + function createCodec(codecConstructor, options, config) { + const streamCopy = !options.compressed && !options.signed && !options.encrypted; + const webWorker = !streamCopy && (options.useWebWorkers || (options.useWebWorkers === undefined && config.useWebWorkers)); + const scripts = webWorker && config.workerScripts ? config.workerScripts[options.codecType] : []; + if (pool.length < config.maxWorkers) { + const workerData = {}; + pool.push(workerData); + return getWorker(workerData, codecConstructor, options, config, onTaskFinished, webWorker, scripts); + } else { + const workerData = pool.find(workerData => !workerData.busy); + if (workerData) { + return getWorker(workerData, codecConstructor, options, config, onTaskFinished, webWorker, scripts); + } else { + return new Promise(resolve => pendingRequests.push({ resolve, codecConstructor, options, webWorker, scripts })); + } + } + + function onTaskFinished(workerData) { + const finished = !pendingRequests.length; + if (finished) { + pool = pool.filter(data => data != workerData); + } else { + const [{ resolve, codecConstructor, options, webWorker, scripts }] = pendingRequests.splice(0, 1); + resolve(getWorker(workerData, codecConstructor, options, config, onTaskFinished, webWorker, scripts)); + } + return finished; + } + } + + /* + Copyright (c) 2021 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. + */ + + const MINIMUM_CHUNK_SIZE = 64; + const ERR_ABORT = "Abort error"; + + async function processData(codec, reader, writer, offset, inputLength, config, options) { + const chunkSize = Math.max(config.chunkSize, MINIMUM_CHUNK_SIZE); + return processChunk(); + + async function processChunk(chunkOffset = 0, outputLength = 0) { + const signal = options.signal; + if (chunkOffset < inputLength) { + testAborted(signal); + const inputData = await reader.readUint8Array(chunkOffset + offset, Math.min(chunkSize, inputLength - chunkOffset)); + const chunkLength = inputData.length; + testAborted(signal); + const data = await codec.append(inputData); + testAborted(signal); + outputLength += await writeData(writer, data); + if (options.onprogress) { + try { + options.onprogress(chunkOffset + chunkLength, inputLength); + } catch (error) { + // ignored + } + } + return processChunk(chunkOffset + chunkSize, outputLength); + } else { + const result = await codec.flush(); + outputLength += await writeData(writer, result.data); + return { signature: result.signature, length: outputLength }; + } + } + } + + function testAborted(signal) { + if (signal && signal.aborted) { + throw new Error(ERR_ABORT); + } + } + + async function writeData(writer, data) { + if (data.length) { + await writer.writeUint8Array(data); + } + return data.length; + } + + /* + Copyright (c) 2021 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. + */ + + const PROPERTY_NAMES = [ + "filename", "rawFilename", "directory", "encrypted", "compressedSize", "uncompressedSize", + "lastModDate", "rawLastModDate", "comment", "rawComment", "signature", "extraField", + "rawExtraField", "bitFlag", "extraFieldZip64", "extraFieldUnicodePath", "extraFieldUnicodeComment", + "extraFieldAES", "filenameUTF8", "commentUTF8", "offset", "zip64"]; + + class Entry { + + constructor(data) { + PROPERTY_NAMES.forEach(name => this[name] = data[name]); + } + + } + + /* + Copyright (c) 2021 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. + */ + + const ERR_BAD_FORMAT = "File format is not recognized"; + const ERR_EOCDR_NOT_FOUND = "End of central directory not found"; + const ERR_EOCDR_ZIP64_NOT_FOUND = "End of Zip64 central directory not found"; + const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found"; + const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found"; + const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found"; + const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found"; + const ERR_ENCRYPTED = "File contains encrypted entry"; + const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported"; + const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported"; + const CHARSET_UTF8 = "utf-8"; + const ZIP64_PROPERTIES = ["uncompressedSize", "compressedSize", "offset"]; + + class ZipReader { + + constructor(reader, options = {}) { + Object.assign(this, { + reader, + options, + config: getConfiguration() + }); + } + + async getEntries(options = {}) { + const zipReader = this; + const reader = zipReader.reader; + if (!reader.initialized) { + await reader.init(); + } + if (reader.size < END_OF_CENTRAL_DIR_LENGTH) { + throw new Error(ERR_BAD_FORMAT); + } + const endOfDirectoryInfo = await seekSignature(reader, END_OF_CENTRAL_DIR_SIGNATURE, reader.size, END_OF_CENTRAL_DIR_LENGTH, MAX_16_BITS * 16); + if (!endOfDirectoryInfo) { + throw new Error(ERR_EOCDR_NOT_FOUND); + } + const endOfDirectoryView = getDataView$1(endOfDirectoryInfo); + let directoryDataLength = getUint32(endOfDirectoryView, 12); + let directoryDataOffset = getUint32(endOfDirectoryView, 16); + let filesLength = getUint16(endOfDirectoryView, 8); + let prependedDataLength = 0; + if (directoryDataOffset == MAX_32_BITS || filesLength == MAX_16_BITS) { + const endOfDirectoryLocatorArray = await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH); + const endOfDirectoryLocatorView = getDataView$1(endOfDirectoryLocatorArray); + if (getUint32(endOfDirectoryLocatorView, 0) != ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) { + throw new Error(ERR_EOCDR_ZIP64_NOT_FOUND); + } + directoryDataOffset = getBigUint64(endOfDirectoryLocatorView, 8); + let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH); + let endOfDirectoryView = getDataView$1(endOfDirectoryArray); + const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH; + if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) { + const originalDirectoryDataOffset = directoryDataOffset; + directoryDataOffset = expectedDirectoryDataOffset; + prependedDataLength = directoryDataOffset - originalDirectoryDataOffset; + endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH); + endOfDirectoryView = getDataView$1(endOfDirectoryArray); + } + if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) { + throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND); + } + filesLength = getBigUint64(endOfDirectoryView, 24); + directoryDataLength = getUint32(endOfDirectoryLocatorView, 4); + directoryDataOffset -= getBigUint64(endOfDirectoryView, 40); + } + if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) { + throw new Error(ERR_BAD_FORMAT); + } + let offset = 0; + let directoryArray = await readUint8Array(reader, directoryDataOffset, reader.size - directoryDataOffset); + let directoryView = getDataView$1(directoryArray); + const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - directoryDataLength; + if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) { + const originalDirectoryDataOffset = directoryDataOffset; + directoryDataOffset = expectedDirectoryDataOffset; + prependedDataLength = directoryDataOffset - originalDirectoryDataOffset; + directoryArray = await readUint8Array(reader, directoryDataOffset, reader.size - directoryDataOffset); + directoryView = getDataView$1(directoryArray); + } + if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) { + throw new Error(ERR_BAD_FORMAT); + } + const entries = []; + for (let indexFile = 0; indexFile < filesLength; indexFile++) { + const fileEntry = new ZipEntry$1(reader, zipReader.config, zipReader.options); + if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) { + throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND); + } + readCommonHeader(fileEntry, directoryView, offset + 6); + const languageEncodingFlag = Boolean(fileEntry.bitFlag.languageEncodingFlag); + const filenameOffset = offset + 46; + const extraFieldOffset = filenameOffset + fileEntry.filenameLength; + const commentOffset = extraFieldOffset + fileEntry.extraFieldLength; + Object.assign(fileEntry, { + compressedSize: 0, + uncompressedSize: 0, + commentLength: getUint16(directoryView, offset + 32), + directory: (getUint8(directoryView, offset + 38) & FILE_ATTR_MSDOS_DIR_MASK) == FILE_ATTR_MSDOS_DIR_MASK, + offset: getUint32(directoryView, offset + 42) + prependedDataLength, + rawFilename: directoryArray.subarray(filenameOffset, extraFieldOffset), + filenameUTF8: languageEncodingFlag, + commentUTF8: languageEncodingFlag, + rawExtraField: directoryArray.subarray(extraFieldOffset, commentOffset) + }); + const endOffset = commentOffset + fileEntry.commentLength; + fileEntry.rawComment = directoryArray.subarray(commentOffset, endOffset); + fileEntry.filename = decodeString(fileEntry.rawFilename, fileEntry.filenameUTF8 ? CHARSET_UTF8 : getOptionValue$1(zipReader, options, "filenameEncoding")); + fileEntry.comment = decodeString(fileEntry.rawComment, fileEntry.commentUTF8 ? CHARSET_UTF8 : getOptionValue$1(zipReader, options, "commentEncoding")); + if (!fileEntry.directory && fileEntry.filename.endsWith(DIRECTORY_SIGNATURE)) { + fileEntry.directory = true; + } + readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6); + const entry = new Entry(fileEntry); + entry.getData = (writer, options) => fileEntry.getData(writer, options); + entries.push(entry); + offset = endOffset; + } + return entries; + } + + async close() { + } + } + + class ZipEntry$1 { + + constructor(reader, config, options) { + Object.assign(this, { + reader, + config, + options + }); + } + + async getData(writer, options = {}) { + const zipEntry = this; + const { + reader, + offset, + extraFieldAES, + compressionMethod, + config, + bitFlag, + signature, + rawLastModDate, + compressedSize + } = zipEntry; + const localDirectory = zipEntry.localDirectory = {}; + if (!reader.initialized) { + await reader.init(); + } + const dataArray = await readUint8Array(reader, offset, 30); + const dataView = getDataView$1(dataArray); + let password = getOptionValue$1(zipEntry, options, "password"); + password = password && password.length && password; + if (extraFieldAES) { + if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) { + throw new Error(ERR_UNSUPPORTED_COMPRESSION); + } + } + if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE) { + throw new Error(ERR_UNSUPPORTED_COMPRESSION); + } + if (getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) { + throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND); + } + readCommonHeader(localDirectory, dataView, 4); + const extraFieldOffset = offset + 30 + localDirectory.filenameLength; + const dataOffset = extraFieldOffset + localDirectory.extraFieldLength; + localDirectory.rawExtraField = dataArray.subarray(extraFieldOffset, dataOffset); + readCommonFooter(zipEntry, localDirectory, dataView, 4); + const encrypted = zipEntry.encrypted && localDirectory.encrypted; + const zipCrypto = encrypted && !extraFieldAES; + if (encrypted) { + if (!zipCrypto && extraFieldAES.strength === undefined) { + throw new Error(ERR_UNSUPPORTED_ENCRYPTION); + } else if (!password) { + throw new Error(ERR_ENCRYPTED); + } + } + const codec = await createCodec(config.Inflate, { + codecType: CODEC_INFLATE, + password, + zipCrypto, + encryptionStrength: extraFieldAES && extraFieldAES.strength, + signed: getOptionValue$1(zipEntry, options, "checkSignature"), + passwordVerification: zipCrypto && (bitFlag.dataDescriptor ? ((rawLastModDate >>> 8) & 0xFF) : ((signature >>> 24) & 0xFF)), + signature, + compressed: compressionMethod != 0, + encrypted, + useWebWorkers: getOptionValue$1(zipEntry, options, "useWebWorkers") + }, config); + if (!writer.initialized) { + await writer.init(); + } + const signal = getOptionValue$1(zipEntry, options, "signal"); + await processData(codec, reader, writer, dataOffset, compressedSize, config, { onprogress: options.onprogress, signal }); + return writer.getData(); + } + } + + function readCommonHeader(directory, dataView, offset) { + const rawBitFlag = directory.rawBitFlag = getUint16(dataView, offset + 2); + const encrypted = (rawBitFlag & BITFLAG_ENCRYPTED) == BITFLAG_ENCRYPTED; + Object.assign(directory, { + encrypted, + version: getUint16(dataView, offset), + bitFlag: { + level: (rawBitFlag & BITFLAG_LEVEL) >> 1, + dataDescriptor: (rawBitFlag & BITFLAG_DATA_DESCRIPTOR) == BITFLAG_DATA_DESCRIPTOR, + languageEncodingFlag: (rawBitFlag & BITFLAG_LANG_ENCODING_FLAG) == BITFLAG_LANG_ENCODING_FLAG + }, + rawLastModDate: getUint32(dataView, offset + 6), + lastModDate: getDate(directory.rawLastModDate), + filenameLength: getUint16(dataView, offset + 22), + extraFieldLength: getUint16(dataView, offset + 24) + }); + } + + function readCommonFooter(fileEntry, directory, dataView, offset) { + const rawExtraField = directory.rawExtraField; + const extraField = directory.extraField = new Map(); + const rawExtraFieldView = getDataView$1(new Uint8Array(rawExtraField)); + let offsetExtraField = 0; + try { + while (offsetExtraField < rawExtraField.length) { + const type = getUint16(rawExtraFieldView, offsetExtraField); + const size = getUint16(rawExtraFieldView, offsetExtraField + 2); + extraField.set(type, { + type, + data: rawExtraField.slice(offsetExtraField + 4, offsetExtraField + 4 + size) + }); + offsetExtraField += 4 + size; + } + } catch (error) { + // ignored + } + const compressionMethod = getUint16(dataView, offset + 4); + directory.signature = getUint32(dataView, offset + 10); + directory.uncompressedSize = getUint32(dataView, offset + 18); + directory.compressedSize = getUint32(dataView, offset + 14); + const extraFieldZip64 = directory.extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64); + if (extraFieldZip64) { + readExtraFieldZip64(extraFieldZip64, directory); + } + const extraFieldUnicodePath = directory.extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH); + if (extraFieldUnicodePath) { + readExtraFieldUnicode(extraFieldUnicodePath, "filename", "rawFilename", directory, fileEntry); + } + const extraFieldUnicodeComment = directory.extraFieldUnicodeComment = extraField.get(EXTRAFIELD_TYPE_UNICODE_COMMENT); + if (extraFieldUnicodeComment) { + readExtraFieldUnicode(extraFieldUnicodeComment, "comment", "rawComment", directory, fileEntry); + } + const extraFieldAES = directory.extraFieldAES = extraField.get(EXTRAFIELD_TYPE_AES); + if (extraFieldAES) { + readExtraFieldAES(extraFieldAES, directory, compressionMethod); + } else { + directory.compressionMethod = compressionMethod; + } + } + + function readExtraFieldZip64(extraFieldZip64, directory) { + directory.zip64 = true; + const extraFieldView = getDataView$1(extraFieldZip64.data); + extraFieldZip64.values = []; + for (let indexValue = 0; indexValue < Math.floor(extraFieldZip64.data.length / 8); indexValue++) { + extraFieldZip64.values.push(getBigUint64(extraFieldView, 0 + indexValue * 8)); + } + const missingProperties = ZIP64_PROPERTIES.filter(propertyName => directory[propertyName] == MAX_32_BITS); + for (let indexMissingProperty = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) { + extraFieldZip64[missingProperties[indexMissingProperty]] = extraFieldZip64.values[indexMissingProperty]; + } + ZIP64_PROPERTIES.forEach(propertyName => { + if (directory[propertyName] == MAX_32_BITS) { + if (extraFieldZip64 && extraFieldZip64[propertyName] !== undefined) { + directory[propertyName] = extraFieldZip64[propertyName]; + } else { + throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND); + } + } + }); + } + + function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName, directory, fileEntry) { + const extraFieldView = getDataView$1(extraFieldUnicode.data); + extraFieldUnicode.version = getUint8(extraFieldView, 0); + extraFieldUnicode.signature = getUint32(extraFieldView, 1); + const crc32 = new Crc32(); + crc32.append(fileEntry[rawPropertyName]); + const dataViewSignature = getDataView$1(new Uint8Array(4)); + dataViewSignature.setUint32(0, crc32.get(), true); + extraFieldUnicode[propertyName] = (new TextDecoder()).decode(extraFieldUnicode.data.subarray(5)); + extraFieldUnicode.valid = !fileEntry.bitFlag.languageEncodingFlag && extraFieldUnicode.signature == getUint32(dataViewSignature, 0); + if (extraFieldUnicode.valid) { + directory[propertyName] = extraFieldUnicode[propertyName]; + directory[propertyName + "UTF8"] = true; + } + } + + function readExtraFieldAES(extraFieldAES, directory, compressionMethod) { + if (extraFieldAES) { + const extraFieldView = getDataView$1(extraFieldAES.data); + extraFieldAES.vendorVersion = getUint8(extraFieldView, 0); + extraFieldAES.vendorId = getUint8(extraFieldView, 2); + const strength = getUint8(extraFieldView, 4); + extraFieldAES.strength = strength; + extraFieldAES.originalCompressionMethod = compressionMethod; + directory.compressionMethod = extraFieldAES.compressionMethod = getUint16(extraFieldView, 5); + } else { + directory.compressionMethod = compressionMethod; + } + } + + async function seekSignature(reader, signature, startOffset, minimumBytes, maximumLength) { + const signatureArray = new Uint8Array(4); + const signatureView = getDataView$1(signatureArray); + setUint32$1(signatureView, 0, signature); + const maximumBytes = minimumBytes + maximumLength; + return (await seek(minimumBytes)) || await seek(Math.min(maximumBytes, startOffset)); + + async function seek(length) { + const offset = startOffset - length; + const bytes = await readUint8Array(reader, offset, length); + for (let indexByte = bytes.length - minimumBytes; indexByte >= 0; indexByte--) { + if (bytes[indexByte] == signatureArray[0] && bytes[indexByte + 1] == signatureArray[1] && + bytes[indexByte + 2] == signatureArray[2] && bytes[indexByte + 3] == signatureArray[3]) { + return { + offset: offset + indexByte, + buffer: bytes.slice(indexByte, indexByte + minimumBytes).buffer + }; + } + } + } + } + + function getOptionValue$1(zipReader, options, name) { + return options[name] === undefined ? zipReader.options[name] : options[name]; + } + + function decodeString(value, encoding) { + if (!encoding || encoding.trim().toLowerCase() == "cp437") { + return decodeCP437(value); + } else { + return (new TextDecoder(encoding)).decode(value); + } + } + + function getDate(timeRaw) { + const 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 (error) { + // ignored + } + } + + function getUint8(view, offset) { + return view.getUint8(offset); + } + + function getUint16(view, offset) { + return view.getUint16(offset, true); + } + + function getUint32(view, offset) { + return view.getUint32(offset, true); + } + + function getBigUint64(view, offset) { + return Number(view.getBigUint64(offset, true)); + } + + function setUint32$1(view, offset, value) { + view.setUint32(offset, value, true); + } + + function getDataView$1(array) { + return new DataView(array.buffer); + } + + function readUint8Array(reader, offset, size) { + return reader.readUint8Array(offset, size); + } + + /* + Copyright (c) 2021 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. + */ + + const ERR_DUPLICATED_NAME = "File already exists"; + const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB"; + const ERR_INVALID_ENTRY_COMMENT = "File entry comment exceeds 64KB"; + const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB"; + const ERR_INVALID_VERSION = "Version exceeds 65535"; + const ERR_INVALID_DATE = "The modification date must be between 1/1/1980 and 12/31/2107"; + const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3"; + const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535"; + const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB"; + + const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]); + const EXTRAFIELD_LENGTH_ZIP64 = 24; + + class ZipWriter { + + constructor(writer, options = {}) { + Object.assign(this, { + writer, + options, + config: getConfiguration(), + files: new Map(), + offset: writer.size, + pendingOutputSize: 0 + }); + } + + async add(name = "", reader, options = {}) { + const zipWriter = this; + name = name.trim(); + if (options.directory && (!name.endsWith(DIRECTORY_SIGNATURE))) { + name += DIRECTORY_SIGNATURE; + } else { + options.directory = name.endsWith(DIRECTORY_SIGNATURE); + } + if (zipWriter.files.has(name)) { + throw new Error(ERR_DUPLICATED_NAME); + } + const rawFilename = (new TextEncoder()).encode(name); + if (rawFilename.length > MAX_16_BITS) { + throw new Error(ERR_INVALID_ENTRY_NAME); + } + const comment = options.comment || ""; + const rawComment = (new TextEncoder()).encode(comment); + if (rawComment.length > MAX_16_BITS) { + throw new Error(ERR_INVALID_ENTRY_COMMENT); + } + const version = zipWriter.options.version || options.version || 0; + if (version > MAX_16_BITS) { + throw new Error(ERR_INVALID_VERSION); + } + const lastModDate = options.lastModDate || new Date(); + if (lastModDate < MIN_DATE || lastModDate > MAX_DATE) { + throw new Error(ERR_INVALID_DATE); + } + const password = getOptionValue(zipWriter, options, "password"); + const encryptionStrength = getOptionValue(zipWriter, options, "encryptionStrength") || 3; + const zipCrypto = getOptionValue(zipWriter, options, "zipCrypto"); + if (password !== undefined && encryptionStrength !== undefined && (encryptionStrength < 1 || encryptionStrength > 3)) { + throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH); + } + let rawExtraField = new Uint8Array(0); + const extraField = options.extraField; + if (extraField) { + let extraFieldSize = 0; + let offset = 0; + extraField.forEach(data => extraFieldSize += 4 + data.length); + rawExtraField = new Uint8Array(extraFieldSize); + extraField.forEach((data, type) => { + if (type > MAX_16_BITS) { + throw new Error(ERR_INVALID_EXTRAFIELD_TYPE); + } + if (data.length > MAX_16_BITS) { + throw new Error(ERR_INVALID_EXTRAFIELD_DATA); + } + arraySet(rawExtraField, new Uint16Array([type]), offset); + arraySet(rawExtraField, new Uint16Array([data.length]), offset + 2); + arraySet(rawExtraField, data, offset + 4); + offset += 4 + data.length; + }); + } + let zip64 = false; + let outputSize = 0; + const zip64Enabled = reader && options.zip64 !== false && zipWriter.options.zip64 !== false; + if (zip64Enabled) { + zip64 = options.zip64 || zipWriter.options.zip64; + if (!zip64) { + if (!reader.initialized) { + await reader.init(); + } + outputSize = Math.floor(reader.size * 1.05); + zipWriter.pendingOutputSize += outputSize; + zip64 = zipWriter.offset >= MAX_32_BITS || outputSize >= MAX_32_BITS || zipWriter.offset + zipWriter.pendingOutputSize >= MAX_32_BITS; + await Promise.resolve(); + } + } + const level = getOptionValue(zipWriter, options, "level"); + const useWebWorkers = getOptionValue(zipWriter, options, "useWebWorkers"); + const bufferedWrite = getOptionValue(zipWriter, options, "bufferedWrite"); + let keepOrder = getOptionValue(zipWriter, options, "keepOrder"); + let dataDescriptor = getOptionValue(zipWriter, options, "dataDescriptor"); + const signal = getOptionValue(zipWriter, options, "signal"); + if (dataDescriptor === undefined) { + dataDescriptor = true; + } + if (keepOrder === undefined) { + keepOrder = true; + } + const fileEntry = await addFile(zipWriter, name, reader, Object.assign({}, options, { + rawFilename, + rawComment, + version, + lastModDate, + rawExtraField, + zip64, + password, + level, + useWebWorkers, + encryptionStrength, + zipCrypto, + bufferedWrite, + keepOrder, + dataDescriptor, + signal + })); + if (zip64Enabled) { + zipWriter.pendingOutputSize -= outputSize; + } + Object.assign(fileEntry, { name, comment, extraField }); + return new Entry(fileEntry); + } + + async close(comment = new Uint8Array(0)) { + const zipWriter = this; + const writer = zipWriter.writer; + const files = zipWriter.files; + let offset = 0; + let directoryDataLength = 0; + let directoryOffset = zipWriter.offset; + let filesLength = files.size; + for (const [, fileEntry] of files) { + directoryDataLength += 46 + + fileEntry.rawFilename.length + + fileEntry.rawComment.length + + fileEntry.rawExtraFieldZip64.length + + fileEntry.rawExtraFieldAES.length + + fileEntry.rawExtraField.length; + } + const zip64 = zipWriter.options.zip64 || directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || filesLength >= MAX_16_BITS; + const directoryArray = new Uint8Array(directoryDataLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH)); + const directoryView = getDataView(directoryArray); + if (comment.length) { + if (comment.length <= MAX_16_BITS) { + setUint16(directoryView, offset + 20, comment.length); + } else { + throw new Error(ERR_INVALID_COMMENT); + } + } + for (const [, fileEntry] of files) { + const { + rawFilename, + rawExtraFieldZip64, + rawExtraFieldAES, + rawExtraField, + rawComment, + version, + headerArray, + directory, + zip64 + } = fileEntry; + const extraFieldLength = rawExtraFieldZip64.length + rawExtraFieldAES.length + rawExtraField.length; + setUint32(directoryView, offset, CENTRAL_FILE_HEADER_SIGNATURE); + setUint16(directoryView, offset + 4, version); + arraySet(directoryArray, headerArray, offset + 6); + setUint16(directoryView, offset + 30, extraFieldLength); + setUint16(directoryView, offset + 32, rawComment.length); + if (directory) { + setUint8(directoryView, offset + 38, FILE_ATTR_MSDOS_DIR_MASK); + } + if (zip64) { + setUint32(directoryView, offset + 42, MAX_32_BITS); + } else { + setUint32(directoryView, offset + 42, fileEntry.offset); + } + arraySet(directoryArray, rawFilename, offset + 46); + arraySet(directoryArray, rawExtraFieldZip64, offset + 46 + rawFilename.length); + arraySet(directoryArray, rawExtraFieldAES, offset + 46 + rawFilename.length + rawExtraFieldZip64.length); + arraySet(directoryArray, rawExtraField, 46 + rawFilename.length + rawExtraFieldZip64.length + rawExtraFieldAES.length); + arraySet(directoryArray, rawComment, offset + 46 + rawFilename.length + extraFieldLength); + offset += 46 + rawFilename.length + extraFieldLength + rawComment.length; + } + if (zip64) { + setUint32(directoryView, offset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE); + setBigUint64(directoryView, offset + 4, BigInt(44)); + setUint16(directoryView, offset + 12, 45); + setUint16(directoryView, offset + 14, 45); + setBigUint64(directoryView, offset + 24, BigInt(filesLength)); + setBigUint64(directoryView, offset + 32, BigInt(filesLength)); + setBigUint64(directoryView, offset + 40, BigInt(directoryDataLength)); + setBigUint64(directoryView, offset + 48, BigInt(directoryOffset)); + setUint32(directoryView, offset + 56, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE); + setBigUint64(directoryView, offset + 64, BigInt(directoryOffset) + BigInt(directoryDataLength)); + setUint32(directoryView, offset + 72, ZIP64_TOTAL_NUMBER_OF_DISKS); + filesLength = MAX_16_BITS; + directoryOffset = MAX_32_BITS; + directoryDataLength = MAX_32_BITS; + offset += 76; + } + setUint32(directoryView, offset, END_OF_CENTRAL_DIR_SIGNATURE); + setUint16(directoryView, offset + 8, filesLength); + setUint16(directoryView, offset + 10, filesLength); + setUint32(directoryView, offset + 12, directoryDataLength); + setUint32(directoryView, offset + 16, directoryOffset); + await writer.writeUint8Array(directoryArray); + if (comment.length) { + await writer.writeUint8Array(comment); + } + return writer.getData(); + } + } + + async function addFile(zipWriter, name, reader, options) { + const files = zipWriter.files; + const writer = zipWriter.writer; + files.set(name, null); + let resolveLockWrite; + let resolveLockPreviousFile; + try { + let lockPreviousFile; + let fileWriter; + let fileEntry; + try { + if (options.keepOrder) { + lockPreviousFile = zipWriter.lockPreviousFile; + zipWriter.lockPreviousFile = new Promise(resolve => resolveLockPreviousFile = resolve); + } + if (options.bufferedWrite || zipWriter.lockWrite || !options.dataDescriptor) { + fileWriter = new BlobWriter(); + fileWriter.init(); + } else { + zipWriter.lockWrite = new Promise(resolve => resolveLockWrite = resolve); + if (!writer.initialized) { + await writer.init(); + } + fileWriter = writer; + } + fileEntry = await createFileEntry(reader, fileWriter, zipWriter.config, options); + } catch (error) { + files.delete(name); + throw error; + } + files.set(name, fileEntry); + if (fileWriter != writer) { + const blob = fileWriter.getData(); + const fileReader = new FileReader(); + const arrayBufferPromise = new Promise((resolve, reject) => { + fileReader.onload = event => resolve(event.target.result); + fileReader.onerror = reject; + fileReader.readAsArrayBuffer(blob); + }); + const [arrayBuffer] = await Promise.all([arrayBufferPromise, zipWriter.lockWrite, lockPreviousFile]); + if (!options.dataDescriptor) { + const arrayBufferView = new DataView(arrayBuffer); + if (!fileEntry.encrypted || options.zipCrypto) { + setUint32(arrayBufferView, 14, fileEntry.signature); + } + if (fileEntry.zip64) { + setUint32(arrayBufferView, 18, MAX_32_BITS); + setUint32(arrayBufferView, 22, MAX_32_BITS); + } else { + setUint32(arrayBufferView, 18, fileEntry.compressedSize); + setUint32(arrayBufferView, 22, fileEntry.uncompressedSize); + } + } + await writer.writeUint8Array(new Uint8Array(arrayBuffer)); + } + fileEntry.offset = zipWriter.offset; + if (fileEntry.zip64) { + const rawExtraFieldZip64View = getDataView(fileEntry.rawExtraFieldZip64); + setBigUint64(rawExtraFieldZip64View, 20, BigInt(fileEntry.offset)); + } + zipWriter.offset += fileEntry.length; + return fileEntry; + } finally { + if (resolveLockPreviousFile) { + resolveLockPreviousFile(); + } + if (resolveLockWrite) { + resolveLockWrite(); + } + } + } + + async function createFileEntry(reader, writer, config, options) { + const { + rawFilename, + lastModDate, + password, + level, + zip64, + zipCrypto, + dataDescriptor, + directory, + version, + rawComment, + rawExtraField, + useWebWorkers, + onprogress, + signal, + encryptionStrength + } = options; + const encrypted = Boolean(password && password.length); + const compressed = level !== 0 && !directory; + let rawExtraFieldAES; + if (encrypted && !zipCrypto) { + rawExtraFieldAES = new Uint8Array(EXTRAFIELD_DATA_AES.length + 2); + const extraFieldAESView = getDataView(rawExtraFieldAES); + setUint16(extraFieldAESView, 0, EXTRAFIELD_TYPE_AES); + arraySet(rawExtraFieldAES, EXTRAFIELD_DATA_AES, 2); + setUint8(extraFieldAESView, 8, encryptionStrength); + } else { + rawExtraFieldAES = new Uint8Array(0); + } + const fileEntry = { + version: version || VERSION_DEFLATE, + zip64, + directory: Boolean(directory), + filenameUTF8: true, + rawFilename, + commentUTF8: true, + rawComment, + rawExtraFieldZip64: zip64 ? new Uint8Array(EXTRAFIELD_LENGTH_ZIP64 + 4) : new Uint8Array(0), + rawExtraFieldAES, + rawExtraField + }; + let bitFlag = BITFLAG_LANG_ENCODING_FLAG; + if (dataDescriptor) { + bitFlag = bitFlag | BITFLAG_DATA_DESCRIPTOR; + } + let compressionMethod = COMPRESSION_METHOD_STORE; + if (compressed) { + compressionMethod = COMPRESSION_METHOD_DEFLATE; + } + if (zip64) { + fileEntry.version = fileEntry.version > VERSION_ZIP64 ? fileEntry.version : VERSION_ZIP64; + } + if (encrypted) { + bitFlag = bitFlag | BITFLAG_ENCRYPTED; + if (!zipCrypto) { + fileEntry.version = fileEntry.version > VERSION_AES ? fileEntry.version : VERSION_AES; + compressionMethod = COMPRESSION_METHOD_AES; + if (compressed) { + fileEntry.rawExtraFieldAES[9] = COMPRESSION_METHOD_DEFLATE; + } + } + } + const headerArray = fileEntry.headerArray = new Uint8Array(26); + const headerView = getDataView(headerArray); + setUint16(headerView, 0, fileEntry.version); + setUint16(headerView, 2, bitFlag); + setUint16(headerView, 4, compressionMethod); + const dateArray = new Uint32Array(1); + const dateView = getDataView(dateArray); + setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2); + setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate()); + const rawLastModDate = dateArray[0]; + setUint32(headerView, 6, rawLastModDate); + setUint16(headerView, 22, rawFilename.length); + setUint16(headerView, 24, 0); + setUint16(headerView, 24, rawExtraFieldAES.length + fileEntry.rawExtraField.length); + const localHeaderArray = new Uint8Array(30 + rawFilename.length + rawExtraFieldAES.length + fileEntry.rawExtraField.length); + const localHeaderView = getDataView(localHeaderArray); + setUint32(localHeaderView, 0, LOCAL_FILE_HEADER_SIGNATURE); + arraySet(localHeaderArray, headerArray, 4); + arraySet(localHeaderArray, rawFilename, 30); + arraySet(localHeaderArray, rawExtraFieldAES, 30 + rawFilename.length); + arraySet(localHeaderArray, fileEntry.rawExtraField, 30 + rawFilename.length + rawExtraFieldAES.length); + let result; + let uncompressedSize = 0; + let compressedSize = 0; + if (reader) { + uncompressedSize = reader.size; + const codec = await createCodec(config.Deflate, { + codecType: CODEC_DEFLATE, + level, + password, + encryptionStrength, + zipCrypto: encrypted && zipCrypto, + passwordVerification: encrypted && zipCrypto && (rawLastModDate >> 8) & 0xFF, + signed: true, + compressed, + encrypted, + useWebWorkers + }, config); + await writer.writeUint8Array(localHeaderArray); + if (!reader.initialized) { + await reader.init(); + } + result = await processData(codec, reader, writer, 0, uncompressedSize, config, { onprogress, signal }); + compressedSize = result.length; + } else { + await writer.writeUint8Array(localHeaderArray); + } + let dataDescriptorArray = new Uint8Array(0); + let dataDescriptorView; + if (dataDescriptor) { + dataDescriptorArray = new Uint8Array(zip64 ? 24 : 16); + dataDescriptorView = getDataView(dataDescriptorArray); + setUint32(dataDescriptorView, 0, DATA_DESCRIPTOR_RECORD_SIGNATURE); + } + if (reader) { + const signature = result.signature; + if ((!encrypted || zipCrypto) && signature !== undefined) { + setUint32(headerView, 10, signature); + fileEntry.signature = signature; + if (dataDescriptor) { + setUint32(dataDescriptorView, 4, signature); + } + } + if (zip64) { + const rawExtraFieldZip64View = getDataView(fileEntry.rawExtraFieldZip64); + setUint16(rawExtraFieldZip64View, 0, EXTRAFIELD_TYPE_ZIP64); + setUint16(rawExtraFieldZip64View, 2, EXTRAFIELD_LENGTH_ZIP64); + setUint32(headerView, 14, MAX_32_BITS); + setBigUint64(rawExtraFieldZip64View, 12, BigInt(compressedSize)); + setUint32(headerView, 18, MAX_32_BITS); + setBigUint64(rawExtraFieldZip64View, 4, BigInt(uncompressedSize)); + if (dataDescriptor) { + setBigUint64(dataDescriptorView, 8, BigInt(compressedSize)); + setBigUint64(dataDescriptorView, 16, BigInt(uncompressedSize)); + } + } else { + setUint32(headerView, 14, compressedSize); + setUint32(headerView, 18, uncompressedSize); + if (dataDescriptor) { + setUint32(dataDescriptorView, 8, compressedSize); + setUint32(dataDescriptorView, 12, uncompressedSize); + } + } + } + if (dataDescriptor) { + await writer.writeUint8Array(dataDescriptorArray); + } + const length = localHeaderArray.length + compressedSize + dataDescriptorArray.length; + Object.assign(fileEntry, { compressedSize, uncompressedSize, lastModDate, rawLastModDate, encrypted, length }); + return fileEntry; + } + + function getOptionValue(zipWriter, options, name) { + return options[name] === undefined ? zipWriter.options[name] : options[name]; + } + + function setUint8(view, offset, value) { + view.setUint8(offset, value); + } + + function setUint16(view, offset, value) { + view.setUint16(offset, value, true); + } + + function setUint32(view, offset, value) { + view.setUint32(offset, value, true); + } + + function setBigUint64(view, offset, value) { + view.setBigUint64(offset, value, true); + } + + function arraySet(array, typedArray, offset) { + array.set(typedArray, offset); + } + + function getDataView(array) { + return new DataView(array.buffer); + } + + /* + Copyright (c) 2021 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. + */ + + const CHUNK_SIZE = 512 * 1024; + + class ZipEntry { + + constructor(fs, name, params, parent) { + const zipEntry = this; + if (fs.root && parent && parent.getChildByName(name)) { + throw new Error("Entry filename already exists"); + } + if (!params) { + params = {}; + } + Object.assign(zipEntry, { + fs, + name, + data: params.data, + id: fs.entries.length, + parent, + children: [], + uncompressedSize: 0 + }); + fs.entries.push(zipEntry); + if (parent) { + zipEntry.parent.children.push(zipEntry); + } + } + + moveTo(target) { + // deprecated + const zipEntry = this; + zipEntry.fs.move(zipEntry, target); + } + + getFullname() { + return this.getRelativeName(); + } + + getRelativeName(ancestor = this.fs.root) { + const zipEntry = this; + let relativeName = zipEntry.name; + let entry = zipEntry.parent; + while (entry && entry != ancestor) { + relativeName = (entry.name ? entry.name + "/" : "") + relativeName; + entry = entry.parent; + } + return relativeName; + } + + isDescendantOf(ancestor) { + let entry = this.parent; + while (entry && entry.id != ancestor.id) { + entry = entry.parent; + } + return Boolean(entry); + } + } + + class ZipFileEntry extends ZipEntry { + + constructor(fs, name, params, parent) { + super(fs, name, params, parent); + const zipEntry = this; + zipEntry.Reader = params.Reader; + zipEntry.Writer = params.Writer; + if (params.getData) { + zipEntry.getData = params.getData; + } + } + + async getData(writer, options = {}) { + const zipEntry = this; + if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) { + return zipEntry.data; + } else { + zipEntry.reader = new zipEntry.Reader(zipEntry.data, options); + await zipEntry.reader.init(); + if (!writer.initialized) { + await writer.init(); + } + zipEntry.uncompressedSize = zipEntry.reader.size; + return pipe(zipEntry.reader, writer); + } + } + + getText(encoding, options) { + return this.getData(new TextWriter(encoding), options); + } + + getBlob(mimeType, options) { + return this.getData(new BlobWriter(mimeType), options); + } + + getData64URI(mimeType, options) { + return this.getData(new Data64URIWriter(mimeType), options); + } + + getUint8Array(options) { + return this.getData(new Uint8ArrayWriter(), options); + } + + replaceBlob(blob) { + Object.assign(this, { + data: blob, + Reader: BlobReader, + Writer: BlobWriter, + reader: null + }); + } + + replaceText(text) { + Object.assign(this, { + data: text, + Reader: TextReader, + Writer: TextWriter, + reader: null + }); + } + + replaceData64URI(dataURI) { + Object.assign(this, { + data: dataURI, + Reader: Data64URIReader, + Writer: Data64URIWriter, + reader: null + }); + } + + replaceUint8Array(array) { + Object.assign(this, { + data: array, + Reader: Uint8ArrayReader, + Writer: Uint8ArrayWriter, + reader: null + }); + } + } + + class ZipDirectoryEntry extends ZipEntry { + + constructor(fs, name, params, parent) { + super(fs, name, params, parent); + this.directory = true; + } + + addDirectory(name) { + return addChild(this, name, null, true); + } + + addText(name, text) { + return addChild(this, name, { + data: text, + Reader: TextReader, + Writer: TextWriter + }); + } + + addBlob(name, blob) { + return addChild(this, name, { + data: blob, + Reader: BlobReader, + Writer: BlobWriter + }); + } + + addData64URI(name, dataURI) { + return addChild(this, name, { + data: dataURI, + Reader: Data64URIReader, + Writer: Data64URIWriter + }); + } + + addUint8Array(name, array) { + return addChild(this, name, { + data: array, + Reader: Uint8ArrayReader, + Writer: Uint8ArrayWriter + }); + } + + addHttpContent(name, url, options = {}) { + return addChild(this, name, { + data: url, + Reader: class extends HttpReader { + constructor(url) { + super(url, options); + } + } + }); + } + + async addFileSystemEntry(fileSystemEntry) { + return addFileSystemEntry(this, fileSystemEntry); + } + + async addData(name, params) { + return addChild(this, name, params); + } + + async importBlob(blob, options = {}) { + await this.importZip(new BlobReader(blob), options); + } + + async importData64URI(dataURI, options = {}) { + await this.importZip(new Data64URIReader(dataURI), options); + } + + async importUint8Array(array, options = {}) { + await this.importZip(new Uint8ArrayReader(array), options); + } + + async importHttpContent(url, options = {}) { + await this.importZip(new HttpReader(url, options), options); + } + + async exportBlob(options = {}) { + return this.exportZip(new BlobWriter("application/zip"), options); + } + + async exportData64URI(options = {}) { + return this.exportZip(new Data64URIWriter("application/zip"), options); + } + + async exportUint8Array(options = {}) { + return this.exportZip(new Uint8ArrayWriter(), options); + } + + async importZip(reader, options) { + if (!reader.initialized) { + await reader.init(); + } + const zipReader = new ZipReader(reader, options); + const entries = await zipReader.getEntries(); + entries.forEach((entry) => { + let parent = this; + const path = entry.filename.split("/"); + const name = path.pop(); + path.forEach(pathPart => parent = parent.getChildByName(pathPart) || new ZipDirectoryEntry(this.fs, pathPart, null, parent)); + if (!entry.directory) { + addChild(parent, name, { + data: entry, + Reader: getZipBlobReader(Object.assign({}, options)) + }); + } + }); + } + + async exportZip(writer, options) { + const zipEntry = this; + await initReaders(zipEntry); + await writer.init(); + const zipWriter = new ZipWriter(writer, options); + await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options); + await zipWriter.close(); + return writer.getData(); + } + + getChildByName(name) { + const children = this.children; + for (let childIndex = 0; childIndex < children.length; childIndex++) { + const child = children[childIndex]; + if (child.name == name) { + return child; + } + } + } + } + + + class FS { + + constructor() { + resetFS(this); + } + + get children() { + return this.root.children; + } + + remove(entry) { + detach(entry); + this.entries[entry.id] = null; + } + + move(entry, destination) { + if (entry == this.root) { + throw new Error("Root directory cannot be moved"); + } else { + if (destination.directory) { + if (!destination.isDescendantOf(entry)) { + if (entry != destination) { + if (destination.getChildByName(entry.name)) { + throw new Error("Entry filename already exists"); + } + detach(entry); + entry.parent = destination; + destination.children.push(entry); + } + } else { + throw new Error("Entry is a ancestor of target entry"); + } + } else { + throw new Error("Target entry is not a directory"); + } + } + } + + find(fullname) { + const path = fullname.split("/"); + let node = this.root; + for (let index = 0; node && index < path.length; index++) { + node = node.getChildByName(path[index]); + } + return node; + } + + getById(id) { + return this.entries[id]; + } + + getChildByName(name) { + return this.root.getChildByName(name); + } + + addDirectory(name) { + return this.root.addDirectory(name); + } + + addText(name, text) { + return this.root.addText(name, text); + } + + addBlob(name, blob) { + return this.root.addBlob(name, blob); + } + + addData64URI(name, dataURI) { + return this.root.addData64URI(name, dataURI); + } + + addHttpContent(name, url, options) { + return this.root.addHttpContent(name, url, options); + } + + async addFileSystemEntry(fileSystemEntry) { + return this.root.addFileSystemEntry(fileSystemEntry); + } + + async addData(name, params) { + return this.root.addData(name, params); + } + + async importBlob(blob, options) { + resetFS(this); + await this.root.importBlob(blob, options); + } + + async importData64URI(dataURI, options) { + resetFS(this); + await this.root.importData64URI(dataURI, options); + } + + async importHttpContent(url, options) { + resetFS(this); + await this.root.importHttpContent(url, options); + } + + async exportBlob(options) { + return this.root.exportBlob(options); + } + + async exportData64URI(options) { + return this.root.exportData64URI(options); + } + } + + const fs = { FS, ZipDirectoryEntry, ZipFileEntry }; + + function getTotalSize(entries, propertyName) { + let size = 0; + entries.forEach(process); + return size; + + function process(entry) { + size += entry[propertyName]; + if (entry.children) { + entry.children.forEach(process); + } + } + } + + function getZipBlobReader(options) { + return class extends Reader { + + constructor(entry, options = {}) { + super(); + this.entry = entry; + this.options = options; + } + + async init() { + const zipBlobReader = this; + zipBlobReader.size = zipBlobReader.entry.uncompressedSize; + const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, zipBlobReader.options, options)); + zipBlobReader.data = data; + zipBlobReader.blobReader = new BlobReader(data); + } + + async readUint8Array(index, length) { + return this.blobReader.readUint8Array(index, length); + } + }; + } + + async function initReaders(entry) { + if (entry.children.length) { + for (const child of entry.children) { + if (child.directory) { + await initReaders(child); + } else { + child.reader = new child.Reader(child.data); + await child.reader.init(); + child.uncompressedSize = child.reader.size; + } + } + } + } + + function detach(entry) { + const children = entry.parent.children; + children.forEach((child, index) => { + if (child.id == entry.id) { + children.splice(index, 1); + } + }); + } + + async function exportZip(zipWriter, entry, totalSize, options) { + const selectedEntry = entry; + const entryOffsets = new Map(); + await process(zipWriter, entry); + + async function process(zipWriter, entry) { + await exportChild(); + + async function exportChild() { + if (options.bufferedWrite) { + await Promise.all(entry.children.map(processChild)); + } else { + for (const child of entry.children) { + await processChild(child); + } + } + } + + async function processChild(child) { + const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname(); + await zipWriter.add(name, child.reader, Object.assign({ + directory: child.directory + }, Object.assign({}, options, { + onprogress: indexProgress => { + if (options.onprogress) { + entryOffsets.set(name, indexProgress); + try { + options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize); + } catch (error) { + // ignored + } + } + } + }))); + await process(zipWriter, child); + } + } + } + + async function addFileSystemEntry(zipEntry, fileSystemEntry) { + if (fileSystemEntry.isDirectory) { + const entry = zipEntry.addDirectory(fileSystemEntry.name); + await addDirectory(entry, fileSystemEntry); + return entry; + } else { + return new Promise((resolve, reject) => fileSystemEntry.file(file => resolve(zipEntry.addBlob(fileSystemEntry.name, file)), reject)); + } + + async function addDirectory(zipEntry, fileEntry) { + const children = await getChildren(fileEntry); + for (const child of children) { + if (child.isDirectory) { + await addDirectory(zipEntry.addDirectory(child.name), child); + } else { + await new Promise((resolve, reject) => { + child.file(file => { + const childZipEntry = zipEntry.addBlob(child.name, file); + childZipEntry.uncompressedSize = file.size; + resolve(childZipEntry); + }, reject); + }); + } + } + } + + function getChildren(fileEntry) { + return new Promise((resolve, reject) => { + let entries = []; + if (fileEntry.isDirectory) { + readEntries(fileEntry.createReader()); + } + if (fileEntry.isFile) { + resolve(entries); + } + + function readEntries(directoryReader) { + directoryReader.readEntries(temporaryEntries => { + if (!temporaryEntries.length) { + resolve(entries); + } else { + entries = entries.concat(temporaryEntries); + readEntries(directoryReader); + } + }, reject); + } + }); + } + } + + function resetFS(fs) { + fs.entries = []; + fs.root = new ZipDirectoryEntry(fs); + } + + async function pipe(reader, writer) { + return copyChunk(); + + async function copyChunk(chunkIndex = 0) { + const index = chunkIndex * CHUNK_SIZE; + if (index < reader.size) { + const array = await reader.readUint8Array(index, Math.min(CHUNK_SIZE, reader.size - index)); + await writer.writeUint8Array(array); + return copyChunk(chunkIndex + 1); + } else { + return writer.getData(); + } + } + } + + function addChild(parent, name, params, directory) { + if (parent.directory) { + return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent); + } else { + throw new Error("Parent entry is not a directory"); + } + } + + /* + Copyright (c) 2021 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. + */ + + configureWebWorker(); + + exports.BlobReader = BlobReader; + exports.BlobWriter = BlobWriter; + exports.Data64URIReader = Data64URIReader; + exports.Data64URIWriter = Data64URIWriter; + exports.ERR_ABORT = ERR_ABORT; + exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT; + exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND; + exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME; + exports.ERR_ENCRYPTED = ERR_ENCRYPTED; + exports.ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND; + exports.ERR_EOCDR_NOT_FOUND = ERR_EOCDR_NOT_FOUND; + exports.ERR_EOCDR_ZIP64_NOT_FOUND = ERR_EOCDR_ZIP64_NOT_FOUND; + exports.ERR_EXTRAFIELD_ZIP64_NOT_FOUND = ERR_EXTRAFIELD_ZIP64_NOT_FOUND; + exports.ERR_HTTP_RANGE = ERR_HTTP_RANGE; + exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT; + exports.ERR_INVALID_DATE = ERR_INVALID_DATE; + exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH; + exports.ERR_INVALID_ENTRY_COMMENT = ERR_INVALID_ENTRY_COMMENT; + exports.ERR_INVALID_ENTRY_NAME = ERR_INVALID_ENTRY_NAME; + exports.ERR_INVALID_EXTRAFIELD_DATA = ERR_INVALID_EXTRAFIELD_DATA; + exports.ERR_INVALID_EXTRAFIELD_TYPE = ERR_INVALID_EXTRAFIELD_TYPE; + exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD; + exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE; + exports.ERR_INVALID_VERSION = ERR_INVALID_VERSION; + exports.ERR_LOCAL_FILE_HEADER_NOT_FOUND = ERR_LOCAL_FILE_HEADER_NOT_FOUND; + exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION; + exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION; + exports.HttpRangeReader = HttpRangeReader; + exports.HttpReader = HttpReader; + exports.Reader = Reader; + exports.TextReader = TextReader; + exports.TextWriter = TextWriter; + exports.Uint8ArrayReader = Uint8ArrayReader; + exports.Uint8ArrayWriter = Uint8ArrayWriter; + exports.Writer = Writer; + exports.ZipReader = ZipReader; + exports.ZipWriter = ZipWriter; + exports.configure = configure; + exports.fs = fs; + exports.getMimeType = getMimeType; + exports.initShimAsyncCodec = streamCodecShim; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/o2web/source/x_component_process_FormDesigner/Module/Attachment/attachment.html b/o2web/source/x_component_process_FormDesigner/Module/Attachment/attachment.html index 6ce50adac3e075c58dc2600456583e6455e978c2..385883b0473605a1c7892871717df61cf82b6918 100644 --- a/o2web/source/x_component_process_FormDesigner/Module/Attachment/attachment.html +++ b/o2web/source/x_component_process_FormDesigner/Module/Attachment/attachment.html @@ -147,6 +147,13 @@ 不允许 ++ 允许预览: ++ 允许 + 不允许 +
+允许下载: diff --git a/o2web/source/x_component_process_Xform/Attachment.js b/o2web/source/x_component_process_Xform/Attachment.js index 63f3fe432c10704601cbca2ecc9d9f1877d12693..516fffc6e6237c1a742ae0b8c4558d15f56c803d 100644 --- a/o2web/source/x_component_process_Xform/Attachment.js +++ b/o2web/source/x_component_process_Xform/Attachment.js @@ -4,6 +4,7 @@ MWF.xApplication.process.Xform.AttachmentController = new Class({ Extends: MWF.widget.ATTER, "options": { "officeFiles": ["doc", "docx", "dotx", "dot", "xls", "xlsx", "xlsm", "xlt", "xltx", "pptx", "ppt", "pot", "potx", "potm", "pdf"], + "allowPreviewExtension" : ["zip","pdf", "ofd", "png", "jpg", "bmp", "jpeg", "gif", "js", "css", "java", "json", "xml", "php", "html", "htm", "xhtml", "log", "md", "txt"], "checkTextEnable": true }, checkAttachmentDeleteAction: function () { @@ -139,6 +140,31 @@ MWF.xApplication.process.Xform.AttachmentController = new Class({ // } } }, + checkPreviewAttAction: function () { + if (!this.options.isPreviewAtt){ + this.setActionDisabled(this.previewAttAction); + //this.setActionDisabled(this.min_downloadAction); + }else{ + if (this.selectedAttachments.length){ + var flag = false; + for (var i = 0; i < this.selectedAttachments.length; i++) { + var att = this.selectedAttachments[i]; + if (this.options.allowPreviewExtension.contains(att.data.extension)) { + flag = true; + break; + } + } + if(flag){ + this.setActionEnabled(this.previewAttAction); + //this.setActionEnabled(this.min_downloadAction); + } + + }else{ + this.setActionDisabled(this.previewAttAction); + //this.setActionDisabled(this.min_downloadAction); + } + } + }, isAttDeleteAvailable: function (att) { if (this.options.readonly) return false; if (this.options.toolbarGroupHidden.contains("edit")) return false; @@ -413,6 +439,7 @@ MWF.xApplication.process.Xform.AttachmentController = new Class({ this.checkUploadAction(); this.checkDeleteAction(); this.checkReplaceAction(); + this.checkPreviewAttAction(); //this.checkOfficeAction(); this.checkDownloadAction(); this.checkSizeAction(); @@ -511,7 +538,9 @@ MWF.xApplication.process.Xform.AttachmentController = new Class({ this.deleteAction = this.createAction(this.editActionsGroupNode, "delete", o2.LP.widget["delete"], function (e, node) { this.deleteAttachment(e, node); }.bind(this)); - + this.previewAttAction = this.createAction(this.editActionsGroupNode, "previewAtt", o2.LP.widget["previewAtt"], function (e, node) { + this.previewAttachment(e, node); + }.bind(this)); if (!this.options.isReplaceHidden) { this.replaceAction = this.createAction(this.editActionsGroupNode, "replace", o2.LP.widget.replace, function (e, node) { this.replaceAttachment(e, node); @@ -1147,6 +1176,7 @@ MWF.xApplication.process.Xform.Attachment = MWF.APPAttachment = new Class( "isDelete": (this.json.isDelete === "y" || this.json.isDelete === "true"), "isReplace": (this.json.isReplace === "y" || this.json.isReplace === "true"), "isDownload": (this.json.isDownload === "y" || this.json.isDownload === "true"), + "isPreviewAtt": (this.json.isPreviewAtt === "y" || this.json.isPreviewAtt === "true"), "isSizeChange": (this.json.isSizeChange === "y" || this.json.isSizeChange === "true"), "readonly": (this.json.readonly === "y" || this.json.readonly === "true" || this.json.isReadonly ), "availableListStyles": this.json.availableListStyles ? this.json.availableListStyles : ["list", "seq", "icon", "preview"], @@ -1410,6 +1440,10 @@ MWF.xApplication.process.Xform.Attachment = MWF.APPAttachment = new Class( this.close(); }, null, null, this.form.json.confirmStyle); }, + previewAttachment: function (attachments) { + var att = attachments[0].data; + new MWF.xApplication.process.Xform.AttachmenPreview(att,this); + }, deleteAttachment: function (attachment) { this.fireEvent("delete", [attachment.data]); var id = attachment.data.id; @@ -1896,7 +1930,217 @@ MWF.xApplication.process.Xform.Attachment = MWF.APPAttachment = new Class( } }); +MWF.xApplication.process.Xform.AttachmenPreview = new Class({ + Implements: [Options, Events], + + initialize : function(att,app ){ + this.att = att; + this.app = app; + this.load(); + }, + load:function(){ + + var extension = this.att.extension; + if(extension === "ofd"){ + this.previewOfd(); + } + if(extension === "zip"){ + this.previewZip(); + } + if(extension === "pdf"){ + this.previewPdf(); + } + if(["png","jpg","bmp","jpeg","gif"].contains(extension)){ + this.previewImage(); + } + if(extension === "js"){ + this.previewAce("javascript"); + } + if(extension === "css"){ + this.previewAce("css"); + } + if(extension === "java"){ + this.previewAce("java"); + } + if(extension === "json"){ + this.previewAce("json"); + } + if(extension === "xml"){ + this.previewAce("xml"); + } + if(extension === "php"){ + this.previewAce("php"); + } + if(["html","htm","xhtml"].contains(extension)){ + this.previewAce("html"); + } + if(["log","md","txt"].contains(extension)){ + this.previewAce("text"); + } + }, + previewZip : function (){ + //zip压缩包预览 + var _self = this; + var zipViewNode = new Element("div.ztree").inject(document.body); + o2.load("/o2_lib/zipjs/zip-fs.js",function(){ + + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + var cookie = Cookie.read("x-token"); + url = url + "?x-token=" + cookie; + unzip().catch(error => console.error(error)); + async function unzip() { + zip.configure({ chunkSize: 128 }); + let zipFs = new zip.fs.FS(); + let directory = zipFs.addDirectory("import"); + await directory.importHttpContent(url); + + o2.loadCss("/o2_lib/zTree/zTreeStyle.css",function(){ + o2.load(["/o2_lib/jquery/jquery.min.js","/o2_lib/zTree/jquery.ztree.core.min.js"], {"sequence": true}, function(){ + jQuery = jQuery.noConflict(true); //避免js框架冲突 + var nodes = []; + loadNodes(directory,nodes); + jQuery.fn.zTree.init(jQuery(zipViewNode), {}, nodes); + + var dlg = o2.DL.open({ + "title": _self.att.name, + "width": "660px", + "height": "510px", + "mask": true, + "content": zipViewNode, + "container": null, + "positionNode": document.body, + "onQueryClose": function () { + zipViewNode.destroy(); + }, + "buttonList": [ + { + "text": "关闭", + "action": function () { + dlg.close(); + } + } + ], + "onPostShow": function () { + dlg.reCenter(); + } + }); + + }.bind(this)); + }) + } + + function loadNodes(directory,nodes){ + var folderList = []; + var fileList = []; + directory.children.each(function(file){ + if(file.directory){ + folderList.push(file) + } + }) + directory.children.each(function(file){ + if(!file.directory){ + fileList.push(file) + } + }) + folderList.append(fileList); + folderList.each(function(file){ + var node = { + name : file.name + } + if(nodes.children){ + nodes.children.push(node); + }else{ + nodes.push(node); + } + if(file.directory){ + node.children = []; + loadNodes(file,node); + } + }) + } + }.bind(this)); + }.bind(this)); + }, + previewPdf : function(){ + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + window.open("../o2_lib/pdfjs/web/viewer.html?file=" + url) + }); + }, + previewOfd : function(){ + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + window.open("../o2_lib/ofdjs/index.html?file=" + url) + }); + }, + previewImage : function(){ + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + var imgNode = new Element("img",{"src":url,"alt":this.att.name}).inject(document.body).hide(); + o2.loadCss("../m_app/yunFile/css/viewer.css", document.body,function(){ + o2.load("../m_app/yunFile/js/viewer.js", function(){ + this.viewer = new Viewer(imgNode,{ + navbar : false, + toolbar : false, + hidden : function(){ + imgNode.destroy(); + this.viewer.destroy(); + }.bind(this) + }); + this.viewer.show(); + }.bind(this)); + }.bind(this)); + }.bind(this)); + }, + previewAce:function(type){ + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + o2.require("o2.widget.ace", null, false); + var fileRequest = new Request({ + url: url, + method: 'get', + withCredentials: true, + onSuccess: function(responseText){ + var editorNode = new Element("div",{"style":"padding:10px"}); + editorNode.set("text",responseText); + + o2.widget.ace.load(function(){ + o2.load("../o2_lib/ace/src-min-noconflict/ext-static_highlight.js", function(){ + var highlight = ace.require("ace/ext/static_highlight"); + highlight(editorNode, {mode: "ace/mode/"+ type , theme: "ace/theme/tomorrow", "fontSize": 30,"showLineNumbers":true}); + }.bind(this)); + + }.bind(this)); + var dlg = o2.DL.open({ + "title": this.att.name, + "width": "960px", + "height": "610px", + "mask": true, + "content": editorNode, + "container": null, + "positionNode": document.body, + "onQueryClose": function () { + editorNode.destroy(); + }.bind(this), + "buttonList": [ + { + "text": "关闭", + "action": function () { + dlg.close(); + }.bind(this) + } + ], + "onPostShow": function () { + dlg.reCenter(); + }.bind(this) + }); + }.bind(this), + onFailure: function(){ + console.log('text', 'Sorry, your request failed :('); + } + }); + fileRequest.send(); + }.bind(this)); + + }, +}); MWF.xApplication.process.Xform.AttachmentDg = MWF.APPAttachmentDg = new Class({ Extends: MWF.APPAttachment, loadAttachmentController: function () {