0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HTMLの自己展開書庫2

Last updated at Posted at 2024-11-29

過去の記事では一括圧縮方式の書庫の作り方を解説しました。今回は分割方式の書庫を作り方を解説。

手口

まずfile名だけを圧縮します。いわゆるheaderという部分です。続けてfile内容圧縮して、file名順に格納していきます。これだけではfileを個別に展開できないので、file内容の直前に圧縮後の大きさも付け加えます。

書庫生成program(1)

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有り)

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

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

      復号噐原型

    • tiny

      復号器圧縮

    • clear

      復号器圧縮。script要素排除。svgのonload属性で処理

  • mode
    • solid

      file一括圧縮

    • split

      file単位で圧縮。展開処理は一括

    • split2

      file単位で圧縮。展開処理はfile単位

  • 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する必要があるので性能劣化します。ついでに展開処理も複雑化

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)から流用

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

      一括圧縮、小型回路、低速展開

    • split tiny

      分割圧縮、小型回路、低速展開

    • solid fast

      一括圧縮、大型回路、高速展開

    • split fast

      分割圧縮、大型回路、高速展開

動作実験

See the Pen sfx archive creater4 by xezz (@xezz) on CodePen.

書庫的説明

書庫の圧縮には大きく分けて一括圧縮と分割圧縮があります。

一括圧縮

別名solid圧縮。全てのfileを一塊として扱って圧縮。実装は簡単です。

長所

類似性のあるfileが密集していると高い圧縮率になりやすい。

短所

fileを個別に展開できない(書庫内の途中にあるfileまで全て展開する必要がある)。そのため低速で空間消費も大。

分割圧縮

ある単位に分けて圧縮します。実装は複雑になります。

長所

無駄な領域展開が少ない。

短所

小さいfileが多いと圧縮効率が悪い。

分割法

  • file単位で分割
  • file複数単位で分割
  • 固定幅で分割
  • 可変幅で分割

最後に…

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

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?