2
0

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形式の自己展開書庫

Last updated at Posted at 2024-03-14

厳密に言う自己展開圧縮書庫。htmlなのでbrowserで書庫の中身を取り出す事が可能です。自己展開という事で外部js不要。programを以下に示す。御覧の通りhtml+JavaScriptなのでbrowserで動作させます(CompressionStreamを実装しているbrowser専用)。

arc.htm
<input multiple type=file id=i><script>
//書庫のhtml部品群
const D0=`<meta charset=l1><noscript id=s>`,
D1='</noscript><script>new Response(new Blob([Uint8Array.from(s.innerText',
D2=',(c,i)=>(i=c.charCodeAt()%65533)>>8?129+" \x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C \x8E  \x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C \x9E\x9F".indexOf(c):i)]).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(new Uint8Array(A.subarray(f,a-1)))}})<\/script><input type=button value=save onclick="for(let a of links)a.click()"><ol id=l>';

i.onchange=async function(e){
	var a=0,c,d,f=this.files,i,r,n=[],o;
	//file名かき集める
	for(e of f)n.push(r=new TextEncoder().encode(e.name)),a+=r.length+e.size+6;
	o=new Uint8Array(a);a=0;
	//file尺とfile中身かき集める
	for(e of f){
		e=new Uint8Array(await e.arrayBuffer(i=a));
		for(c=32,d=r=e.length;d-=o[a++]=d&c-1;c=256)d/=c,o[i]+=32;
		o.set(c=n.shift(),a,a-=~c.length);
		o.set(e,a,a+=r)
	}
	//それら全て圧縮
	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=D1;

	//escape文字の候補選出
	for(e=256;e;a>c&&e^13&&(a=c,d=e))c=f[--e];
	c=f[13];e=String.fromCharCode(d);n=+!d;
	if(c)r+=`.replace(/${e+e}|${e+String.fromCharCode(n)}/g,a=>a[0]!=a[1]?\`\\r\`:\`${e}\`)`;
	r+=D2;
	f=new Uint8Array(a+c+o.length+D0.length+r.length);
	//meta + noscript
	a=0;for(e of D0)f[a++]=e.charCodeAt();
	//write archive data
	if(c)for(e of o)e==13?(f[a++]=d,e=n):e==d&&(f[a++]=d,e=d),f[a++]=e;
	else f.set(o,a,a+=o.length);
	//write decoder + html
	for(e of r)f[a++]=e.charCodeAt();
	l.innerText=a;l.href=URL.createObjectURL(new Blob([f]))
}
</script><a id=l download=a.htm>

2024.11.22更新版
書庫のnoscript要素をhtmlの末端に追いやり、安全性を高め、script要素を排除してbody要素のonload属性に展開処理を全て詰め込み、記述量を削減

arc.htm
<input multiple type=file id=i><script>
//書庫のhtml部品群
const D1="<meta charset=l1><body onload='new Response(new Blob([Uint8Array.from(s.innerText",
D2=',(c,i)=>(i=c.charCodeAt()%65533)>>8?129+" \x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C \x8E  \x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C \x9E\x9F".indexOf(c):i)]).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(new Uint8Array(A.subarray(f,a-1)))}})\'><button onclick="for(let a of links)a.click()">save</button><ol id=l></ol><noscript id=s>';

i.oninput=async function(e){
	var a=0,c,d,f=this.files,i,r,n=[],o;
	//file名かき集める
	for(e of f)n.push(r=new TextEncoder().encode(e.name)),a+=r.length+e.size+6;
	o=new Uint8Array(a);a=0;
	//file尺とfile中身かき集める
	for(e of f){
		e=new Uint8Array(await e.arrayBuffer(i=a));
		for(c=32,d=r=e.length;d-=o[a++]=d&c-1;c=256)d/=c,o[i]+=32;
		o.set(c=n.shift(),a,a-=~c.length);
		o.set(e,a,a+=r)
	}
	//それら全て圧縮
	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=D1;

	//escape文字の候補選出
	for(e=256;e;a>c&&e^39&&e^13&&(a=c,d=e))c=f[--e];
	c=f[13];e=String.fromCharCode(d);n=+!d;
	if(c)r+=`.replace(/${e+e}|${e+String.fromCharCode(n)}/g,a=>a[0]!=a[1]?\`\\r\`:\`${e}\`)`;

	f=new Uint8Array(a+c+o.length+(r+=D2).length);a=0;
	//wirte decoder+html
	for(e of r)f[a++]=e.charCodeAt();
	//write archive data
	if(c)for(e of o)e==13?(f[a++]=d,e=n):e==d&&(f[a++]=d,e=d),f[a++]=e;
	else f.set(o,a,a+=o.length);
	l.innerText=a;l.href=URL.createObjectURL(new Blob([f]));this.value=""
}
</script><a id=l download=a.htm>

file選択buttonを押下して複数fileを選択、または複数fileをbuttonにDrag & Dropすると書庫を作り始めやがります。無事に書庫が完成したらdownload linkが生成されやがるので、どうしても書庫が欲しければclickでもして下さいな。
標準でa.htmという名前の書庫を落とせるはずなので、保存したらbrowserで開いてみて下さい。先程選び抜いたfileどもの一覧が表示されるはずです。file名の横の数字はfileの大きさを表しています。
saveを押下すると全file連続download可能。file名をclickすると個別downloadとなります。

実演

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


過去に投稿した JavaScriptで独自の書庫を作る とかいう記事では自己展開しない書庫の作り方を網羅しています。本記事のprogramの参考になるので、解説が気になる人は読んでみて下さい。
それからbinary dataをhtmlに埋め込む方法はこの記事で解説

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?