JavaScriptで独自の書庫を作る

独自形式の書庫を作り出す超簡単お気軽お手軽足軽尻軽programを紹介します。今やJavaScriptでも容易に実装できる時代となりました。外部jsにも頼る必要はありません。
## 仕様
- 書庫には1個のfileにつきfile尺、file名、file中身、という順番に配置
- file名はUTF8形式で書き込む。終端に0を書き込む
- file尺の書き込み量は可変長。file尺をLとすると...
  - 0 byte目<p>上位3bitsにbyte数、下位5bitsにLの下位5bits
  - 1 byte目<p>`L>>5&255`
  - 2 byte目以降<p>`L>>5+8*n&255`
  >という具合なので書き込み量は、Lが31以下なら1 byte、Lが8191以下なら2 bytes、2097151以下なら3 bytes、53687091以下なら4 bytes... などという内容に違いない。ちなみに64 bits浮動小数点数で計算している都合上、Lは53 bitsまでしか正確に書き込めません
## 書庫構築program
html+jsで以下のようになります。
```html
<input multiple type=file id=i><script>
i.onchange=async function(e,n=[]){
	for(e of this.files){
		let a=0,b=new Uint8Array(await e.arrayBuffer()),o=new Uint8Array(7),c=32,d=b.length;
		for(;d-=o[a++]=d&c-1;c=256)d/=c,o[0]+=32;
		n.push(o.subarray(0,a),e.name+"\0",b)
	}l.innerText=l.href=URL.createObjectURL(new Blob(n))
}
</script><a id=l download>
```
- input要素にmultiple属性を付ける事で複数File選択可能に
- file尺(`b.length`)とfile名(`e.name`)とfile本体(`e.arrayBuffer()`)を出力配列にぶち込む
- 出力配列からURLに変換してlink生成

最低限にも程があります…
### 使い方
- File buttonを押下してFile選択窓が現れたら、Fileを範囲選択して開いて下さい。もしくは複数FileをFile buttonに直接Drag & Dropして下さい
- 処理が完了するとそれらをまとめたFile(書庫)のlinkが生成されます。clickすればdownload可能

## 書庫展開program
```html
<input type=file id=i>
<input type=button value=save onclick="for(let a of links)a.click()">
<input type=button value=kill onclick="for(let a of links)self.URL.revokeObjectURL(a.href);l.textContent=i.value=''">
<script>
i.onchange=async function(){
	for(var A=new Uint8Array(await this.files[0].arrayBuffer()),a=0,z=A.length;a<z;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++]; //read size
		for(f=a;A[a++];);
		f=new TextDecoder().decode(new Uint8Array(A.subarray(f,a-1)))
	}
}
</script><ol id=l>
```
- fileを読み込みUint8Arrayに変換
- file尺を解読
- file名の終端まで読み飛ばしてその範囲を確定
- 配列からURLに変換してlink生成

### 使い方
- File buttonを押下してFileを1個開いて下さい。もしくはFileを直接Drag & Dropして下さい
- 処理が完了すると書庫に含まれているFileとその尺が列挙されます。そのlinkをclickすればFileをdownload可能
- killを押下するとFileへのlinkを全て削除
- saveをclickすると成果物を全てdownload可能

## 圧縮書庫構築program
手始めに書庫に必要な領域を計算。無圧縮版とは異なりfile尺、file名、file中身の3点をUint8Arrayに詰め込んでいきます。そしてCompressionStream様にそれを圧縮してもらいます。**完全に`tar.gz`の劣化書庫**ですね
```html
<input multiple type=file id=i><script>
i.onchange=async function(e){
	var a=0,c,d,f=this.files,i,r,n=[],o;
	for(e of f)n.push(r=new TextEncoder().encode(e.name)),a+=r.length+e.size+6;
	o=new Uint8Array(a);a=0;
	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)
	}
	l.href=URL.createObjectURL(new Blob([f=await new Response(new Blob([o.subarray(0,a)]).stream().pipeThrough(new CompressionStream("deflate-raw"))).arrayBuffer()]))
	l.innerText=f.byteLength
}
</script><a id=l download>
```
## 圧縮書庫展開program
DecompressionStream様が暗躍している以外は無圧縮版とほぼ同じ
```html
<input type=file id=i>
<input type=button value=save onclick="for(let a of links)a.click()">
<input type=button value=kill onclick="for(let a of links)self.URL.revokeObjectURL(a.href);l.textContent=i.value=''">
<script>
i.onchange=async function(){
	for(var A=new Uint8Array(await new Response(new Blob([await this.files[0].arrayBuffer()]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).arrayBuffer()),a=0,z=A.length;a<z;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++]; //read size
		for(f=a;A[a++];);
		f=new TextDecoder().decode(new Uint8Array(A.subarray(f,a-1)))
	}
}
</script><ol id=l>
```
## まとめて実演
<p class=codepen data-height="300" data-default-tab="result" data-slug-hash="jOJgEqK" 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/jOJgEqK">create original archive</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>

## 備考
何気に`</a>`、`</ol>`等の閉じtagを省略していますが、html最後の要素という事で動作上は無問題。むしろcode golferとしての常識的な作法です。非常識な方は決して真似しないように(^-^;)