HTMLの自己展開書庫2

[過去の記事](https://qiita.com/mashuel/items/6e4ad7153dc7430be74a)では一括圧縮方式の書庫の作り方を解説しました。今回は分割方式の書庫を作り方を解説。
## 手口
まずfile名だけを圧縮します。いわゆるheaderという部分です。続けてfile内容圧縮して、file名順に格納していきます。これだけではfileを個別に展開できないので、file内容の直前に圧縮後の大きさも付け加えます。
## 書庫生成program(1)
```css:arc.css
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有り)
```js:arc-fetch.js
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
```html:arc.htm
<!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<p>復号噐原型
	* tiny<p>復号器圧縮
	* clear<p>復号器圧縮。script要素排除。svgのonload属性で処理
* mode
	* solid<p>file一括圧縮
	* split<p>file単位で圧縮。展開処理は一括
	* split2<p>file単位で圧縮。展開処理はfile単位
* listing<p>圧縮時にfile名を羅列する
* LOAD<p>fileを読み込む。複数選択可
* Save<p>書庫を一括download
* kill<p>書庫を一括削除

動作模様
<p class=codepen data-height="300" data-default-tab="result" data-slug-hash="emOmKpz" data-pen-title="sfx arcive creater3" data-user="xezz" style="height:300px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;border:2px solid;margin:1em 0;padding:1em"><span>See the Pen <a href="https://codepen.io/xezz/pen/emOmKpz">sfx arcive creater3</a> by xezz (<a href="https://codepen.io/xezz">@xezz</a>) on <a href="https://codepen.io">CodePen</a>.</span></p><script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 書庫生成program(2)
こちらはlocal環境でも書庫展開できるbrowserが多い。ただし圧縮率も速度も落ちます。
何をやらかしているかというと、noscript要素の`innerText`を読み取って`Uint8Array`に変換しているのです。Unicode番号13の文字をescapeする必要があるので性能劣化します。ついでに展開処理も複雑化
```js:arc-latin1.js
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)から流用
```html:arc2.htm
<!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<p>一括圧縮、小型回路、低速展開
	* split tiny<p>分割圧縮、小型回路、低速展開
	* solid fast<p>一括圧縮、大型回路、高速展開
	* split fast<p>分割圧縮、大型回路、高速展開

動作実験
<p class=codepen data-height="300" data-default-tab="result" data-slug-hash="yyBNVKJ" data-pen-title="sfx archive creater4" data-user="xezz" style="height:300px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;border:2px solid;margin:1em 0;padding:1em"><span>See the Pen <a href="https://codepen.io/xezz/pen/yyBNVKJ">sfx archive creater4</a> by xezz (<a href="https://codepen.io/xezz">@xezz</a>) on <a href="https://codepen.io">CodePen</a>.</span></p><script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 書庫的説明
書庫の圧縮には大きく分けて一括圧縮と分割圧縮があります。
## 一括圧縮
別名solid圧縮。全てのfileを一塊として扱って圧縮。実装は簡単です。
### 長所
類似性のあるfileが密集していると高い圧縮率になりやすい。
### 短所
fileを個別に展開できない(書庫内の途中にあるfileまで全て展開する必要がある)。そのため低速で空間消費も大。
## 分割圧縮
ある単位に分けて圧縮します。実装は複雑になります。
### 長所
無駄な領域展開が少ない。
### 短所
小さいfileが多いと圧縮効率が悪い。
### 分割法
* file単位で分割
* file複数単位で分割
* 固定幅で分割
* 可変幅で分割

## 最後に…
このprogramの使用によってたっぷり損害を受けたとしても、その責任は全てあなたのものです(^o^)。遠慮なく享受して下さい!