過去の記事では一括圧縮方式の書庫の作り方を解説しました。今回は分割方式の書庫を作り方を解説。
手口
まずfile名だけを圧縮します。いわゆるheaderという部分です。続けてfile内容圧縮して、file名順に格納していきます。これだけではfileを個別に展開できないので、file内容の直前に圧縮後の大きさも付け加えます。
書庫生成program(1)
html,body,form{font-size:100%;padding:0;margin:0}
html,body{overflow:hidden;height:100%}
body,input,select{color:snow;font-family:"MS Gothic",monospace}
input,select,label[id]{background:#848;border:1px solid #c6c;border-radius:4px;font-size:1em}
a{color:#99f;text-decoration:none}
a:hover,label:hover{color:#9ff}
input,label,select{cursor:pointer;text-shadow:1px 1px #000}
input[type=file]{display:none}
#info{position:absolute;bottom:0;cursor:help;height:1.25em;text-align:left;width:100%;z-index:999}
#uform{width:100%;height:100%;background:#212;background:radial-gradient(circle at center center,#848,#212)}
/* drop area */
ul{border:2px dashed #caf;overflow:auto;background:rgba(48,32,48,.75);margin:0;position:absolute;top:1.4em;bottom:1.25em;left:0;right:0}
ul:empty:before{content:"Drop files here";display:block;text-align:center;position:relative;top:45%}
ol li{border:0 dashed #a5a;border-width:0 0 1px;margin-bottom:3px}
li input{border:0;position:absolute;right:0}
.dover{background:#424}
.dpass{background:rgba(48,32,48,.75)}
書庫はfetch
関数で自身再召喚後に展開する高速復号回路搭載(local環境で動作しないbrowser有り)
const H=[[//html(decoders for solid)
'<script>fetch``.then(a=>a.arrayBuffer().then(a=>new Response(new Blob([a.slice(554)]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).arrayBuffer().then(a=>{for(a=new Uint8Array(a),b=0;a[b]+1;l.innerHTML+=`<li><a download="${f}"href=${URL.createObjectURL(new Blob([a.subarray(b,b+=d)]))}>${f}</a> ${d}`){var b,c=32,d=a[b++],f=d>>5;for(d&=31;f--;c*=256)d+=c*a[b++];for(f=b;a[b++];);f=new TextDecoder().decode(new Uint8Array(a.subarray(f,b-1)))}})))<\/script><button onclick="for(let a of links)a.click()">save</button><ol id=l></ol><noscript>',
atob`PHNjcmlwdD5mb3IoZT0nZj0RcmUQJHtmfQ8pKSkOZWNvZGUMcnJheQt1YmELKAl0EGFtKAhmb3IoB2FbYisrXQZuZXcgBSgFQmxvYihbYS5zBGBgLnRoZW4oYT0+AwVVaW50OEELKGECLmELQnVmZmVyAwFmZXRjaANhAQVSZXNwb25zZQRsaWNlKDUyOCldKS5zCCkucGlwZVRocm91Z2goBURlY29tcBBzc2lvblMIImRlZmxhdGUtcmF3Ig4BewdhPQIpLGI9MDthW2JdKzE7bC5pbm5lckhUTUwrPWA8bGk+PGEgZG93bmxvYWQ9Ig8iaBARJHtVUkwuYxBhdGVPYmplY3RVUkwECWIsYis9ZCldKSl9Pg88L2E+ICR7ZH1gKXt2YXIgYixjPTMyLGQ9BiwRZD4+NTsHZCY9MzE7Zi0tO2MqPTI1NilkKz1jKgY7BxFiOwY7KTsRBVRleHREDHIoKS5kDCgCLnMJZixiLTEOfX0OJzthPS9bAS0RXS8uZXhlYyhlKTspd2l0aChlLnNwbGl0KGEpKWU9am9pbihzaGlmdCgpKTtldmFsKGUpPC9zY3JpcHQ+PGJ1dHRvbiBvbmNsaWNrPSJmb3IobGV0IGEgb2YgbGlua3MpYS5jbGljaygpIj5zYXZlPC9idXR0b24+PG9sIGlkPWw+PC9vbD48bm9zY3JpcHQ+`,
atob`PHN2ZyBvbmxvYWQ9J2ZvcihlPSYjMzlmPRVyZRRsaRNvbhIke2Z9ESkpKRBlY29kZQ9ycmF5DnViYQ4oDGMTY2sLdBRhbSgJYnV0dBIIZm9yKAdhW2IrK10GbmV3IAUoBUJsb2IoW2EucwRgYC50aGVuKGE9PgMFVWludDhBDihhAi5hDkJ1ZmZlcgMBd3JpdGVgPAggEgs9IgdsZXQgYSBvZiATbmtzKWEuCygpIj5zYXZlPC8IPjxvbCBpZD1sPmA7ZmV0Y2gDYQEFUmVzcBJzZQQTY2UoNTM3KV0pLnMJKS5waXBlVGhyb3VnaCgFRGVjb21wFHNzaRJTCSJkZWZsYXRlLXJhdyIQAXsHYT0CKSxiPTA7YVtiXSsxO2wuaW5uZXJIVE1MKz1gPBM+PGEgZG93bmxvYWQ9IhEiaBQVJHtzZWxmLlVSTC5jFGF0ZU9iamVjdFVSTAQMYixiKz1kKV0pKX0+ETwvYT4gJHtkfWApe3ZhciBiLGM9MzIsZD0GLBVkPj41OwdkJj0zMTtmLS07Yyo9MjU2KWQrPWMqBjsHFWI7BjspOxUFVGV4dEQPcigpLmQPKAIucwxmLGItMRB9fRAmIzM5IDthPS9bAS0VXS8uZXhlYyhlKTspd2l0aChlLnNwbGl0KGEpKWU9am9pbihzaGlmdCgpKTtldmFsKGUpJz48L3N2Zz48bm9zY3JpcHQ+`
],[//html(decoders for split)
'<script>fetch``.then(a=>a.arrayBuffer().then(async a=>{a=new Uint8Array(a.slice(790));var f,h=[],i=0,b=0,c=32,d=a[b++],e=d>>5;for(d&=31;e--;c*=256)d+=c*a[b++];f=new Uint8Array(await new Response(new Blob([a.subarray(b,b+=d)]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).arrayBuffer());for(d=0;f[c=d];h[i++]=new TextDecoder().decode(f.subarray(c,d-1)))for(;f[d++];);for(i of h){c=32,d=a[b++],e=d>>5;for(d&=31;e--;c*=256)d+=c*a[b++];f=new Uint8Array(await new Response(new Blob([a.subarray(b,b+=d)]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).arrayBuffer());l.innerHTML+=`<li><a download="${i}"href=${URL.createObjectURL(new Blob([f]))}>${i}</a> ${f.length}`}}))<\/script><button onclick="for(let a of links)a.click()">save</button><ol id=l></ol><noscript>',
atob`PHNjcmlwdD5mb3IoZT0nKytdE2FbYhMSZXIoKREkexByZQ9lY28OdA9hbSgMcnJheQsuc3ViYQsoCS50aGVuKGEIKSkHbmV3IAYoBkJsb2IoWwVmb3IoBD0GVWludDhBCyhhAy5hC0J1ZmYRAmM9MzIsZD0SLGU9ZD4+NTsEZCY9MzE7ZS0tO2MqPTI1NilkKz1jKhI7ZgN3YWl0IAZSZXNwb25zZQVhCWIsYis9ZCldKS5zDCkucGlwZVRocm91Z2goBkQObXAPc3Npb25TDCJkZWZsYXRlLXJhdyIHKQIpOwFmZXRjaCgiIikIPT5hAghzeW5jIGE9PnthAy5zbGljZSg1ODQHO3ZhciBmLGg9W10saT0wLGI9MCwBBGQ9MDtmW2M9ZF07aFtpEz0GVGV4dEQOZBEuZA5kZShmCWMsZC0xBykEO2ZbZBM7KTsEaSBvZiBoKXsBbC5pbm5lckhUTUwrPWA8bGk+PGEgZG93bmxvYWQ9IhBpfSJoD2Y9EFVSTC5jD2F0ZU9iamVjdFVSTAVmXQd9PhBpfTwvYT4gEGYubGVuZ3RofWB9fQcnO2E9L1sBLRNdLy5leGVjKGUpOyl3aXRoKGUuc3BsaXQoYSkpZT1qb2luKHNoaWZ0KCkpO2V2YWwoZSk8L3NjcmlwdD48YnV0dG9uIG9uY2xpY2s9ImZvcihsZXQgYSBvZiBsaW5rcylhLmNsaWNrKCkiPnNhdmU8L2J1dHRvbj48b2wgaWQ9bD48L29sPjxub3NjcmlwdD4`,
atob`PHN2ZyBvbmxvYWQ9J2ZvcihlPSYjMzlyZRk7ZhhkPRdsaRZvbhUke2l9FCsrXRNhW2ITEiBvZiARZWNvZGUQYxZjaw90GWFtKA5idXR0FQxycmF5Cy5zdWJhCygJKSkIbmV3IAcoB0Jsb2IoWwYuYQtCdWZmZXIFYGAudGhlbihhBD0HVWludDhBCyhhA2ZvcigCYz0zMiwXEixlPWQ+PjU7AmQmPTMxO2UtLTtjKj0yNTYpZCs9YyoSGAN3YWl0IAdSZXNwFXNlBmEJYixiKz1kKV0pLnMOKS5waXBlVGhyb3VnaCgHRGVjb21wGXNzaRVTDiJkZWZsYXRlLXJhdyIIKQUoCDsBd3JpdGVgPAwgFQ89IgJsZXQgYREWbmtzKWEuDygpIj5zYXZlPC8MPjxvbCBpF2w+PC9vbD5gGGV0Y2gEPT5hBQRzeW5jIGE9PnthAy5zFmNlKDU5Mwg7dmFyIGYsaD1bXSxpPTAsYj0wLAECFzAYW2M9ZF07aFtpEz0HVGV4dEQQcigpLmQQKGYJYyxkLTEIKQIYW2QTOyk7AmkRaCl7AWwuaW5uZXJIVE1MKz1gPBY+PGEgZG93bmxvYRciFCJoGWY9JHtzZWxmLlVSTC5jGWF0ZU9iamVjdFVSTAZmXQh9PhQ8L2E+ICR7Zi5sZW5ndGh9YH19CCYjMzkgO2E9L1sBLRldLy5leGVjKGUpOyl3aXRoKGUuc3BsaXQoYSkpZT1qb2luKHNoaWZ0KCkpO2V2YWwoZSknPjwvc3ZnPjxub3NjcmlwdD4`
],[//html(decoders for split2)
'<script>fetch``.then(a=>a.arrayBuffer().then(a=>{a=new Uint8Array(a.slice(935));g=i=>{var[b,d]=h[i];new Response(new Blob([a.subarray(b,b+=d)]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).arrayBuffer().then(a=>{URL.revokeObjectURL(A.href=URL.createObjectURL(new Blob([a])),A.click(A.download=document.links[i].innerHTML));document.anchors[i].innerHTML=a.byteLength})};var h=[],s,n=0,i=0,b=0,c=32,d=a[b++],e=d>>5;for(d&=31;e--;c*=256)d+=c*a[b++];new Response(new Blob([a.subarray(b,b+=d)]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).arrayBuffer().then(f=>{for(f=new Uint8Array(f);f[s=n];l.innerHTML+=`<li><a href=javascript:g(${i++})>${new TextDecoder().decode(f.subarray(s,n-1))}</a> ${d} <a name></a>`){for(;f[n++];);c=32,d=a[b++],e=d>>5;for(d&=31;e--;c*=256)d+=c*a[b++];h[i]=[b,d],b+=d}})}))<\/script><button onclick="for(let a of links)a.click()">save</button><ol id=l></ol><a id=A></a><noscript>',
atob`PHNjcmlwdD5mb3IoZT0nPC9hPh9yZR5oHmY9HWVyKCkcXTsbbGkaYVtiKysZdB5hbSgYLGIrPWQXW2IsZF0WPTAsFVVSTBRlY28TW2ldEi50aGVuKBFycmF5EC5zdWJhECgPZm9yKA49PnsMKSkLbmV3IAkJQmxvYihbYQhkb2N1bWVudC4HZU9iamVjdBQoBi5pbm5lckhUTUwFLmEQQnVmZhwRBD0JVWludDhBECgDYz0zMixkPRldLGU9ZD4+NTsOZCY9MzE7ZS0tO2MqPTI1NilkKz1jKhkCGwlSZXNwb25zZSgID2IXKV0pLnMYKS5waXBlVGhyb3VnaCgJRBNtcB5zc2lvblMYImRlZmxhdGUtcmF3IgspBAFmZXRjaGBgEWE9PmEEYQxhA2EucxpjZSg3MDALO2c9aQx2YXIWPWhbaQFhDBQuHnZvawZBLh0ULmMeYXQGCANhKV0LLEEuYxpjayhBLmRvd25sb2FkPQcabmtzEgULOwdhbmNob3JzEgU9YS5sZW5ndGh9KX07dmFyIGg9W10scyxuFWkVYhUCAWYMDmYDZik7ZltzPW4bbAUrPWA8Gj48YSAdamF2YXNjcmlwdDpnKCR7aSsrfSk+JHsJVGV4dEQTZBwuZBNkZShmD3Msbi0xC30fICR7ZH0gPGEgbmFtZT4fYCl7DjtmW24rKxspOwIbaBI9Fhd9fSl9Cyc7YT0vWwEtH10vLmV4ZWMoZSk7KXdpdGgoZS5zcGxpdChhKSllPWpvaW4oc2hpZnQoKSk7ZXZhbChlKTwvc2NyaXB0PjxidXR0b24gb25jbGljaz0iZm9yKGxldCBhIG9mIGxpbmtzKWEuY2xpY2soKSI+c2F2ZTwvYnV0dG9uPjxvbCBpZD1sPjwvb2w+PGEgaWQ9QT48L2E+PG5vc2NyaXB0Pg`,
atob`PHN2ZyBvbmxvYWQ9J2ZvcihlPSYjMzlyZX5ofmY9WmVyKClZbGlYWG5rc1ddO1ZkPR9vbh5hW2IrKx10fmFtKBwsYis9ZBtbYixkXRo9MCwZZWNvGFtpXRc8YSAWLnRoZW4oFWJ1dHQeFHJyYXkTLnN1YmETKBI8L2E+ET0+exApKQ9uZXcgDg5CbG9iKFthDGRvY3VtZW50LgtzZWxmLlVSTC4JY1hjawhmb3IoB2VPYmplY3RVUkwoBi5pbm5lckhUTUwFLmETQnVmZlkVBD0OVWludDhBEygDYz0zMiwfHV0sZT1kPj41OwdkJj0zMTtlLS07Yyo9MjU2KWQrPWMqHQJWDlJlc3Aec2UoDBJiGyldKS5zHCkucGlwZVRocm91Z2goDkQYbXB+c3NpHlMcImRlZmxhdGUtcmF3Ig8pBAF3cml0ZWA8FCAeCD0iB2xldCBhIG9mIFcpYS4IKCkiPnNhdmU8LxQ+PG9sIGkfbD48L29sPhZpH0E+EWA7ZmV0Y2hgYBVhPT5hBGEQYQNhLnNYY2UoNzA4DztnPWkQdmFyGj1oW2kBYRAJfnZvawZBLloJY35hdAYMA2EpXQ8sQS4IKEEuZG93bmxvYR8LVxcFDzsLYW5jaG9ycxcFPWEubGVuZ3RofSl9O3ZhciBoPVtdLHMsbhlpGWIZAgFmEAdmA2YpO2Zbcz1uVmwFKz1gPFg+FlpqYXZhc2NyaXB0OmcoJHtpKyt9KT4kew5UZXh0RBhkWS5kGGRlKGYScyxuLTEPfREgJHtkfSAWbmFtZT4RYCl7BztmW24rK1YpOwJWaBc9Ght9fSl9DyYjMzkgO2E9L1teIC1VWy19XS8uZXhlYyhlKTspd2l0aChlLnNwbGl0KGEpKWU9am9pbihzaGlmdCgpKTtldmFsKGUpJz48L3N2Zz48bm9zY3JpcHQ+`
]],
g=a=>document.getElementById(a), info=g("info"), ul=g("flist"), lf=g("load");
let id=0;
ul.ondragover=function(e){
this.className="dover";e.preventDefault();
e.dataTransfer.dropEffect='copy'
};
ul.ondragleave=function(){this.className="dpass"};
ul.ondrop=lf.oninput=async function(e){
e.preventDefault(e.stopPropagation());
ul.className="dpass";
var a=0,b,c,d,Files=(e.dataTransfer||this).files,r,sum=0,total=0,P=[],p=0,
li=document.createElement("li"),ol=document.createElement("ol"),grow=g("list").checked,mode=g("mode").selectedIndex,O=mode?"\0":"",start=new Date;
ul.appendChild(li);
li.innerHTML="<a download='arc"+id+".htm'>arc"+id+++".htm</a>";
li.appendChild(ol);
for(e of Files)P[p++]=b=new TextEncoder().encode(c=e.name+O),
total+=r=e.size,a+=b.length,
grow&&(ol.appendChild(d=document.createElement("li")),d.innerHTML=c+" <input type=button value="+r+">");
if(mode){
//add packed names
P=[,,await new Response(new Blob(P).stream().pipeThrough(new CompressionStream("deflate-raw"))).arrayBuffer()];
//add above size
O=new Uint8Array(6);b=d=P[p=2].byteLength;
console.log("names",a,"->",b);
for(a=0,c=32;d-=O[a++]=d&c-1;c=256)d/=c,O[0]+=32;
P[p-1]=O.subarray(0,a);b+=a;
grow&&(ol=ol.getElementsByTagName("input"));
for(e of Files){
//add packed file
P[p+=2]=await new Response(new Blob([e=await e.arrayBuffer()]).stream().pipeThrough(new CompressionStream("deflate-raw"))).arrayBuffer();
b+=d=P[p].byteLength;
grow&&(ol[p-3>>1].value+=" -> "+d);
//add packed size
O=new Uint8Array(6);
for(a=0,c=32;d-=O[a++]=d&c-1;c=256)d/=c,O[0]+=32;
P[p-1]=O.subarray(0,a);
b+=a;sum+=e.byteLength;
info.value=info.style.width=(sum/total*1e4|0)/100+"%"
}
}else{//solid
O=new Uint8Array(a+total+p*6);a=p=0;
for(e of Files){
e=new Uint8Array(await e.arrayBuffer(b=a));
sum+=d=r=e.length;
info.value=info.style.width=(sum/total*1e4|0)/100+"%";
//add size
for(c=32;d-=O[a++]=d&c-1;c=256)d/=c,O[b]+=32;
//add name
O.set(c=P[p++],a,a-=~c.length);
//add data
O.set(e,a,a+=r)
}
info.value="compressing...";
O=await new Response(new Blob([O.subarray(0,a)]).stream().pipeThrough(new CompressionStream("deflate-raw"))).arrayBuffer();
b=O.byteLength
}
//result
d=H[mode][type.selectedIndex];b+=d.length;
mode&&(P[0]=d);c=total+" \u2192 "+b;
a=li.firstChild;a.innerHTML+=" <u>"+c+"</u>";
a.href=URL.createObjectURL(new Blob(mode?P:[d,O]));
info.value=c+"("+(b/total*1e4|0)/100+"%)"+", "+(new Date-start)+"ms"
};
// remove files
g("kill").onclick=function(){
for(var e=ul.getElementsByTagName("a"),b=id=0,c;c=e[b++];)c.download&&URL.revokeObjectURL(c.href);
if(b>1)g("info").value="removed all files",ul.innerHTML=""
};
// save files
g("save").onclick=function(){
for(var b=ul.getElementsByTagName("a"),c=0,d;d=b[c++];)d.click();
if(c<2)b=this,b.innerText="miss",setTimeout(function(){b.innerText="Save"},500)
}
操作部を構成するhtml
<!doctype html><html><head>
<meta name=viewport content="width=device-width,initial-scale=1">
<title>arc2html</title>
<link rel=stylesheet href=arc.css></head><body>
<form id=uform><div style="text-align:center">
html<select id=type><option>raw<option>shrink<option>svg</select>
mode<select id=mode><option>solid<option>split<option>split2</select>
<label id><input type=file multiple id=load>LOAD</label>
<label id=save>Save</label>
<label id=kill>kill</label>
<label><input type=checkbox id=list>listing</label>
</div>
<ul id=flist></ul>
</form>
<input type=button value="sfx archive creater" id=info>
<script src=arc-fetch.js></script>
説明的解説
- html
- raw
復号噐原型
- tiny
復号器圧縮
- clear
復号器圧縮。script要素排除。svgのonload属性で処理
- raw
- mode
- solid
file一括圧縮
- split
file単位で圧縮。展開処理は一括
- split2
file単位で圧縮。展開処理はfile単位
- solid
- listing
圧縮時にfile名を羅列する
- LOAD
fileを読み込む。複数選択可
- Save
書庫を一括download
- kill
書庫を一括削除
動作模様
See the Pen sfx arcive creater3 by xezz (@xezz) on CodePen.
書庫生成program(2)
こちらはlocal環境でも書庫展開できるbrowserが多い。ただし圧縮率も速度も落ちます。
何をやらかしているかというと、noscript要素のinnerText
を読み取ってUint8Array
に変換しているのです。Unicode番号13の文字をescapeする必要があるので性能劣化します。ついでに展開処理も複雑化
const M="<meta charset=l1><body onload='",
L1=atob`LChjLGkpPT4oaT1jLmNoYXJDb2RlQXQoKSU2NTUzMyk+Pjg/MTI5KyIggoOEhYaHiImKi4wgjiAgkZKTlJWWl5iZmpucIJ6fIi5pbmRleE9mKGMpOmkp`,
L2=atob`IoCBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6fIg`,
H=[//html
//tiny,slow
[//solid
M+"new Response(new Blob([Uint8Array.from(s.innerText",
L1+']).stream().pipeThrough(new DecompressionStream("deflate-raw"))).arrayBuffer().then((A,a=0)=>{for(A=new Uint8Array(A);A[a]+1;l.innerHTML+=`<li><a download="${f}"href=${URL.createObjectURL(new Blob([A.subarray(a,a+=d)]))}>${f}</a> ${d}`){var c=32,d=A[a++],f=d>>5;for(d&=31;f--;c*=256)d+=c*A[a++];for(f=a;A[a++];);f=new TextDecoder().decode(A.subarray(f,a-1))}})\'><button onclick="for(let a of links)a.click()">save</button><ol id=l></ol><noscript id=s>'
],[//split
M+"let a=Uint8Array.from(g.innerText",
L1+atob`LGg9W10scyxuPTAsaT0wLGI9MCxjLGQ9JiMzOXJlfmh+Zj0fKS4eZXIoHh1vbhxkPRtsaW5rcxp0fmFtKBksYis9ZBhbYixkXRc8YSAWVVJMFWVjbxQ9PnsTKSkSYnV0dBwRYVtiKytdEHJyYXkPLnN1YmEPKA48L2E+DFtpXQtuZXcgCQlCbG9iKFthCGNsaWNrB2ZvcigGZU9iamVjdBUoBWRvY3VtZW50LgQuaW5uZXJIVE1MA2M9MzIsGxAsZT1kPj41OwZkJj0zMTtlLS07Yyo9MjU2KWQrPWMqEDsCOwlSZXNwHHNlKAgOYhgpXR5zGR5waXBlVGhyb3VnaCgJRBRtcH5zc2kcUxkiZGVmbGF0ZS1yYXciEh5hD0J1ZmYddGhlbigBAmc9aRN2YXIXPWgLAWETFS5+dm9rBUEuHxUuY35hdAUIXRIsQS4HKEEuZG93bmxvYRsEGgsDEjsEYW5jaG9ycwsDPWEuYnl0ZUxlbmd0aH0pfQFmEwZmPQlVaW50OEEPKGYpO2Zbcz1uXTtsAys9YDxsaT4WH2phdmFzY3JpcHQ6Zygke2krK30pPiR7CVRleHREFGQdZBRkZShmDnMsbi0xEn0MICR7ZH0gFm5hbWU+DGApewY7ZltuKytdOyk7AmgLPRcYfX0pOwR3cml0ZWA8ESAcBz0iBmxldCBhIG9mIBopYS4HKCkiPnNhdmU8LxE+PG9sIGkbbD48L29sPhZpG0E+DGAmIzM5LGU7Zm9yKDtjPS9bXiAtfV0vLmV4ZWMoZCk7KXdpdGgoZC5zcGxpdChjKSlkPWpvaW4oc2hpZnQoKSk7ZXZhbChkKSc+PG5vc2NyaXB0IGlkPWc+`
],
//big,fast
[//solid
M+"let s=g.innerText",
atob`LEEsZj0mIzM5cmUaKS4ZZm9yKBg7GBdmPRZvbhUke2Z9FHJyYXkTZWNvEmVyKBkRbmV3IBA9EFVpbnQPEygOQQ84QQ4McyBvZiALY2xpY2sJLnN1YmEOCHQaYW0oB2J1dHQVBmRvd25sb2FkBSgQQmxvYihbQQQuaW5uZXJIVE1MAy5jaGFyQ29kZUF0KAJBW2ErK10BYgM9YDwGIBUJPSIYbGV0IAtsaW5rcylzLgkoKSI+BTwvBj48b2wgaWQ9bD48L29sPmA7DHMubGVuZ3RoKSxmDzE2QQ42NTUzNCkXO2E7KWZb`+L2+
atob`AmZbLS1hXT1hKV09YSsxMjgXC3MpAT1mW3MCKV07EFJlc3AVc2UEXRlzBxlwaXBlVGhyb3VnaCgQRBJtcBpzc2kVUwciZGVmbGF0ZS1yYXciKSkZYRNCdWZmEXRoZW4oKEEsYT0wKT0+exgMQSk7QVthXSsxO2wDKz1gPGxpPjxhIAU9IhQiaBoWJHtVUkwuYxphdGVPYmplY3RVUkwECGEsYSs9ZCldKSl9PhQ8L2E+ICR7ZH1gKXt2YXIgYz0zMixkPQEsFmQ+PjUXZCY9MzE7Zi0tO2MqPTI1NilkKz1jKgEXFmE7ATspOxYQVGV4dEQSZBFkEmRlKEEIZixhLTEpKX19KSYjMzksYT0yNTY7Zm9yKDtBPS9bAS0aXS8uZXhlYyhmKTspd2l0aChmLnNwbGl0KEEpKWY9am9pbihzaGlmdCgpKTtldmFsKGYpJ2lkPWI+PG5vc2NyaXB0IGlkPWc+`
],[//split
M+"let s=g.innerText",
atob`LGg9W10sbj0wLGk9MCxhLGI9MjU2LGMsZD0mIzM5cmVKaEpmPUlEZWNvWnJyYXlZbmV3IFg9WFVpbnRXWShWVzhBVh9vbh5kPR1saW5rcxx0SmFtKBssYis9ZBpbYixkXRlzIG9mIBhlbmd0aBc8YSAWVVJMFT0+exQpLhNkZRIpOxFidXR0HhAuc3ViYVYPPC9hPg5baV0MWEJsb2IoW2ELY2xpY2sJZU9iamVjdBUoCGFbYisrXQcuY2hhckNvEkF0KAZmb3IoBWRvY3VtZW50LgQuaW5uZXJIVE1MAztjPTMyLB0HLGU9ZD4+NTsFZCY9MzE7ZS0tO2MqPTI1NilkKz1jKgc7AjtYUmVzcB5zZSgLD2IaKV0TcxsTcGlwZVRocm91Z2goWFptcEpzc2keUxsiEmZsYXRlLXJhdyIpKRNhWUJ1ZmZlcigTdGhlbigBYR9zLmwXEQVjVzE2QVY2NTUzNBFiOyljWw`+L2+
atob`BmNbLS1iXT1iKV09YisxMjg7BRhzKQc9Y1tzBildO2I9MAJnPWkUdmFyGT1oDAFhFBUuSnZvawhBLkkVLmNKYXQIC10pKSxBLgkoQS5kb3dubG9hHQQcDAMpEQRhbmNob3JzDAM9YS5ieXRlTBd9KX0BZhQFZh9mEWZbcz1uXTtsAys9YDxsaT4WSWphdmFzY3JpcHQ6Zygke2krK30pPiR7WFRleHRaEnIoExJjbxIoZg9zLG4tMSkpfQ4gJHtkfSAWbmFtZT4OYCl7BTtmW24rK107KQJoDD0ZGn19EQR3cml0ZWA8ECAeCT0iBWxldCAYHClzLgkoKSI+c2F2ZTwvED48b2wgaR1sPjwvb2w+FmkdQT4OYCYjMzksZTtmb3IoO2M9L1sBLR9WLVpJSl0vLmV4ZWMoZCk7KXdpdGgoZC5zcGxpdChjKSlkPWpvaW4oc2hpZnQoKSk7ZXZhbChkKSc+PG5vc2NyaXB0IGlkPWc+`
]
],
g=a=>document.getElementById(a), info=g("info"), ul=g("flist"), lf=g("load");
let id=0;
ul.ondragover=function(e){
this.className="dover";e.preventDefault();
e.dataTransfer.dropEffect='copy'
};
ul.ondragleave=function(){this.className="dpass"};
ul.ondrop=lf.oninput=async function(e){
e.preventDefault(e.stopPropagation());
ul.className="dpass";
var a=0,b,c,d,F=(e.dataTransfer||this).files,r,sum=0,total=0,P=[],p=0,
li=document.createElement("li"),ol=document.createElement("ol"),fl=g("list").checked,mode=g("mode").selectedIndex,O=mode&1?"\0":"",start=new Date;
ul.appendChild(li);
li.innerHTML="<a download='arc"+id+".htm'>arc"+id+++".htm</a>";
li.appendChild(ol);
//get names, build list
for(e of F)P[p++]=b=new TextEncoder().encode(c=e.name+O),
total+=r=e.size,a+=b.length,
fl&&(ol.appendChild(d=document.createElement("li")),d.innerHTML=c+" <input type=button value="+r+">");
if(mode&1){//split
//add packed names
P=[,await new Response(new Blob(P).stream().pipeThrough(new CompressionStream("deflate-raw"))).arrayBuffer()];
//add above size
O=new Uint8Array(6);b=d=P[p=1].byteLength;
console.log("names",a,"->",b);
for(a=0,c=32;d-=O[a++]=d&c-1;c=256)d/=c,O[0]+=32;
P[p-1]=O.subarray(0,a);b+=a;
fl&&(ol=ol.getElementsByTagName("input"));
for(e of F){
//add packed data
P[p+=2]=await new Response(new Blob([e=new Uint8Array(await e.arrayBuffer())]).stream().pipeThrough(new CompressionStream("deflate-raw"))).arrayBuffer();
//add packed size
O=new Uint8Array(6);
b+=d=P[p].byteLength;
fl&&(ol[p-3>>1].value+=" -> "+d);
for(a=0,c=32;d-=O[a++]=d&c-1;c=256)d/=c,O[0]+=32;
P[p-1]=O.subarray(0,a);
b+=a;sum+=e.length;
info.value=info.style.width=(sum/total*1e4|0)/100+"%"
}
O=new Uint8Array(await new Blob(P).arrayBuffer(a=b))
}else{//solid
O=new Uint8Array(a+total+p*6);a=p=0;
for(e of F){
e=new Uint8Array(await e.arrayBuffer(b=a));
sum+=d=r=e.length;
info.value=info.style.width=(sum/total*1e4|0)/100+"%";
//add size
for(c=32;d-=O[a++]=d&c-1;c=256)d/=c,O[b]+=32;
//add name
O.set(c=P[p++],a,a-=~c.length);
//add data
O.set(e,a,a+=r)
}
info.value="compressing...";
O=new Uint8Array(await new Response(new Blob([O.subarray(0,a)]).stream().pipeThrough(new CompressionStream("deflate-raw"))).arrayBuffer())
}
F=new Uint32Array(256);
for(e of O)F[e]++;r=H[mode][0];
//select escape code for \r
for(e=256;e;a>c&&e^39&&e^13&&(a=c,d=e))c=F[--e];
e=String.fromCharCode(d);
c=F[13];P=+!d;F=d^96?"`":'"';
//\n()*+?[\\ must be escaped in regexp
p=~"()*+?[\\".indexOf(e)?"\\"+e:d^10?e:"\\n";
if(c)r+=`.replace(/${p+p}|${p+String.fromCharCode(P)}/g,a=>a[0]!=a[1]?\`\\r\`:${F+(d^92?e:p)+F})`;
F=new Uint8Array(a+c+O.length+(r+=H[mode][1]).length);a=0;
//add decoder+html
for(e of r)F[a++]=e.charCodeAt();
//add archive data
if(c)for(e of O)e==13?(F[a++]=d,e=P):e==d&&(F[a++]=e=d),F[a++]=e;
else F.set(O,a,a+=O.length);
//reslut
e=li.firstChild;c=total+" \u2192 "+a;
e.innerHTML+=" <u>"+c+"</u>";
e.href=URL.createObjectURL(new Blob([F]));
info.value=c+"("+(a/total*1e4|0)/100+"%)"+", "+(new Date-start)+"ms"
};
//remove files
g("kill").onclick=function(){
for(var e=ul.getElementsByTagName("a"),b=id=0,c;c=e[b++];)c.download&&URL.revokeObjectURL(c.href);
if(b>1)g("info").value="removed all files",ul.innerHTML=""
};
//save files
g("save").onclick=function(){
for(var b=ul.getElementsByTagName("a"),c=0,d;d=b[c++];)d.click();
if(c<2)b=this,b.innerText="miss",setTimeout(function(){b.innerText="Save"},500)
}
操作部のhtml。cssはprogram(1)から流用
<!doctype html><html><head>
<meta charset=sjis><meta name=viewport content="width=device-width,initial-scale=1">
<title>arc2html</title>
<link rel=stylesheet href="arc.css"></head><body>
<form id=uform><div style="text-align:center">
mode<select id=mode><option>solid tiny<option>split tiny<option>solid fast<option>split fast</select>
<label id><input type=file multiple id=load>LOAD</label>
<label id=save>Save</label>
<label id=kill>kill</label>
<label><input type=checkbox id=list>listing</label>
</div>
<ul id=flist></ul>
</form>
<input type=button value="sfx archive creater" id=info>
<script src=arc-latin1.js></script>
説明的解説
program(1)との違いだけ網羅
- mode
- solid tiny
一括圧縮、小型回路、低速展開
- split tiny
分割圧縮、小型回路、低速展開
- solid fast
一括圧縮、大型回路、高速展開
- split fast
分割圧縮、大型回路、高速展開
- solid tiny
動作実験
See the Pen sfx archive creater4 by xezz (@xezz) on CodePen.
書庫的説明
書庫の圧縮には大きく分けて一括圧縮と分割圧縮があります。
一括圧縮
別名solid圧縮。全てのfileを一塊として扱って圧縮。実装は簡単です。
長所
類似性のあるfileが密集していると高い圧縮率になりやすい。
短所
fileを個別に展開できない(書庫内の途中にあるfileまで全て展開する必要がある)。そのため低速で空間消費も大。
分割圧縮
ある単位に分けて圧縮します。実装は複雑になります。
長所
無駄な領域展開が少ない。
短所
小さいfileが多いと圧縮効率が悪い。
分割法
- file単位で分割
- file複数単位で分割
- 固定幅で分割
- 可変幅で分割
最後に…
このprogramの使用によってたっぷり損害を受けたとしても、その責任は全てあなたのものです(^o^)。遠慮なく享受して下さい!