coyotte508 commited on
Commit
b5430db
1 Parent(s): e5bb1dc

✨ Check zip format

Browse files
dduf-content/tokenizer_2/{spiece.model → spiece.gguf} RENAMED
File without changes
file-64.dduf CHANGED
Binary files a/file-64.dduf and b/file-64.dduf differ
 
file.dduf CHANGED
Binary files a/file.dduf and b/file.dduf differ
 
package.json CHANGED
@@ -9,7 +9,8 @@
9
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
10
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
11
  "format": "prettier --write .",
12
- "lint": "prettier --check . && eslint ."
 
13
  },
14
  "devDependencies": {
15
  "@eslint/compat": "^1.2.3",
 
9
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
10
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
11
  "format": "prettier --write .",
12
+ "lint": "prettier --check . && eslint .",
13
+ "gen": "cd dduf-content && zip -r -0 ../file.dduf . && zip -r -0 -fz ../file-64.dduf ."
14
  },
15
  "devDependencies": {
16
  "@eslint/compat": "^1.2.3",
src/lib/check-dduf.ts CHANGED
@@ -1,3 +1,4 @@
 
1
  import { WebBlob } from './WebBlob';
2
 
3
  export async function* checkDduf(url: string): AsyncGenerator<string> {
@@ -7,9 +8,105 @@ export async function* checkDduf(url: string): AsyncGenerator<string> {
7
 
8
  // DDUF is a zip file, uncompressed.
9
 
10
- const last100kb = await blob.slice(blob.size - 100000, blob.size).arrayBuffer();
11
 
12
- const view = new DataView(last100kb);
13
 
14
  let index = view.byteLength - 22;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
 
1
+ import { checkFilename } from './check-filename';
2
  import { WebBlob } from './WebBlob';
3
 
4
  export async function* checkDduf(url: string): AsyncGenerator<string> {
 
8
 
9
  // DDUF is a zip file, uncompressed.
10
 
11
+ const last100kB = await blob.slice(blob.size - 100000, blob.size).arrayBuffer();
12
 
13
+ const view = new DataView(last100kB);
14
 
15
  let index = view.byteLength - 22;
16
+ let found = false;
17
+
18
+ while (index >= 0) {
19
+ if (view.getUint32(index, true) === 0x06054b50) {
20
+ found = true;
21
+ break;
22
+ }
23
+
24
+ index--;
25
+ }
26
+
27
+ if (!found) {
28
+ throw new Error('DDUF footer not found in last 100kB of file');
29
+ }
30
+
31
+ yield 'DDUF footer found at offset ' + (blob.size - last100kB.byteLength + index);
32
+
33
+ const diskNumber = view.getUint16(index + 4, true);
34
+
35
+ if (diskNumber === 0xffff) {
36
+ throw new Error('Spanned archives (ZIP64) not yet supported');
37
+ }
38
+
39
+ if (diskNumber !== 0) {
40
+ throw new Error('Multi-disk archives not supported');
41
+ }
42
+
43
+ const fileCount = view.getUint16(index + 10, true);
44
+ const centralDirSize = view.getUint32(index + 12, true);
45
+ const centralDirOffset = view.getUint32(index + 16, true);
46
+
47
+ yield 'File count: ' + fileCount;
48
+ yield 'Central directory size: ' + centralDirSize;
49
+ yield 'Central directory offset: ' + centralDirOffset;
50
+
51
+ const centralDir =
52
+ centralDirOffset > blob.size - last100kB.byteLength
53
+ ? last100kB.slice(
54
+ centralDirOffset - (blob.size - last100kB.byteLength),
55
+ centralDirOffset - (blob.size - last100kB.byteLength) + centralDirSize
56
+ )
57
+ : await blob.slice(centralDirOffset, centralDirOffset + centralDirSize).arrayBuffer();
58
+
59
+ const centralDirView = new DataView(centralDir);
60
+ let offset = 0;
61
+
62
+ for (let i = 0; i < fileCount; i++) {
63
+ if (centralDirView.getUint32(offset + 0, true) !== 0x02014b50) {
64
+ throw new Error('Invalid central directory file header');
65
+ }
66
+
67
+ if (offset + 46 > centralDir.byteLength) {
68
+ throw new Error('Unexpected end of central directory');
69
+ }
70
+
71
+ const compressionMethod = centralDirView.getUint16(offset + 10, true);
72
+
73
+ if (compressionMethod !== 0) {
74
+ throw new Error('Unsupported compression method: ' + compressionMethod);
75
+ }
76
+
77
+ const size = centralDirView.getUint32(offset + 24, true);
78
+ const compressedSize = centralDirView.getUint32(offset + 20, true);
79
+
80
+ if (size !== compressedSize) {
81
+ throw new Error('Compressed size and size differ');
82
+ }
83
+
84
+ const filenameLength = centralDirView.getUint16(offset + 28, true);
85
+ const fileName = new TextDecoder().decode(
86
+ new Uint8Array(centralDir, offset + 46, filenameLength)
87
+ );
88
+
89
+ yield 'File ' + i;
90
+ yield 'File name: ' + fileName;
91
+ yield 'File size: ' + size;
92
+
93
+ checkFilename(fileName);
94
+
95
+ const fileDiskNumber = centralDirView.getUint16(34, true);
96
+
97
+ if (fileDiskNumber !== 0) {
98
+ throw new Error('Multi-disk archives not supported');
99
+ }
100
+
101
+ const extraFieldLength = centralDirView.getUint16(offset + 30, true);
102
+ const commentLength = centralDirView.getUint16(offset + 32, true);
103
+
104
+ const filePosition = centralDirView.getUint32(offset + 42, true);
105
+
106
+ yield 'File position in archive: ' + filePosition;
107
+
108
+ offset += 46 + filenameLength + extraFieldLength + commentLength;
109
+ }
110
+
111
+ yield 'All files checked';
112
  }
src/lib/check-filename.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function checkFilename(filename: string) {
2
+ if (
3
+ !filename.endsWith('.safetensors') &&
4
+ !filename.endsWith('.json') &&
5
+ !filename.endsWith('.gguf') &&
6
+ !filename.endsWith('/')
7
+ ) {
8
+ throw new Error('Files must have a .safetensors, .gguf or .json extension');
9
+ }
10
+
11
+ const split = filename.split('/');
12
+
13
+ if (split.length > 2) {
14
+ throw new Error('Files must be only one level deep, not more');
15
+ }
16
+ }
src/routes/+page.svelte CHANGED
@@ -1,16 +1,22 @@
1
  <script lang="ts">
2
- import { goto } from '$app/navigation';
3
  import { checkDduf } from '$lib/check-dduf';
4
 
5
  let url = 'https://huggingface.co/spaces/coyotte508/dduf-check/resolve/main/file.dduf';
6
  let output = '';
 
7
 
8
  async function handleSubmit(event: Event) {
9
  event.preventDefault();
10
  output = 'Checking...';
 
11
 
12
- for await (const str of checkDduf(url)) {
13
- output += '\n' + str;
 
 
 
 
 
14
  }
15
  }
16
  </script>
@@ -35,5 +41,9 @@
35
  <textarea class="w-full rounded-md border border-gray-300 p-2" rows="10" readonly
36
  >{output}</textarea
37
  >
 
 
 
 
38
  </form>
39
  </div>
 
1
  <script lang="ts">
 
2
  import { checkDduf } from '$lib/check-dduf';
3
 
4
  let url = 'https://huggingface.co/spaces/coyotte508/dduf-check/resolve/main/file.dduf';
5
  let output = '';
6
+ let error = '';
7
 
8
  async function handleSubmit(event: Event) {
9
  event.preventDefault();
10
  output = 'Checking...';
11
+ error = '';
12
 
13
+ try {
14
+ for await (const str of checkDduf(url)) {
15
+ output += '\n' + str;
16
+ }
17
+ } catch (e) {
18
+ console.error(e);
19
+ error = (e as Error).message;
20
  }
21
  }
22
  </script>
 
41
  <textarea class="w-full rounded-md border border-gray-300 p-2" rows="10" readonly
42
  >{output}</textarea
43
  >
44
+
45
+ {#if error}
46
+ <p class="text-red-500">{error}</p>
47
+ {/if}
48
  </form>
49
  </div>