Skip to content

Commit 246360b

Browse files
committed
fix: base64 encoding hash mismatch and corruption issue
Signed-off-by: Neko Ayaka <[email protected]>
1 parent af9decf commit 246360b

File tree

7 files changed

+56
-35
lines changed

7 files changed

+56
-35
lines changed

app/components/InputSlide.vue

+1-13
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ watch(max, (val) => {
9292
</div>
9393
</template>
9494

95-
<style less>
95+
<style scoped less>
9696
.qrs-slider {
9797
--qrs-slider-height: 24px;
9898
--qrs-slider-shadow-color: #aeaeaecd;
@@ -264,15 +264,3 @@ watch(max, (val) => {
264264
cursor: col-resize;
265265
}
266266
</style>
267-
268-
<style scoped>
269-
.fade-enter-active,
270-
.fade-leave-active {
271-
transition: opacity 0.2s ease-in-out;
272-
}
273-
274-
.fade-enter-from,
275-
.fade-leave-to {
276-
opacity: 0;
277-
}
278-
</style>

app/pages/index.vue

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts" setup>
2-
import { slice } from '~~/utils/slicing'
2+
import { merge, slice } from '~~/utils/slicing'
33
44
const count = ref(10)
55
@@ -20,6 +20,7 @@ async function onFileChange(e: Event) {
2020
const file = target.files?.[0]
2121
if (!file)
2222
return
23+
2324
const content = await file.arrayBuffer()
2425
const chunks = await slice(content)
2526
data.value = chunks.map(i => JSON.stringify(i))

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"test": "vitest"
1616
},
1717
"dependencies": {
18+
"js-base64": "^3.7.7",
1819
"qr-scanner-wechat": "^0.1.3",
1920
"uqr": "^0.1.2"
2021
},

pnpm-lock.yaml

+21-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/SampleJPGImage_100kbmb.jpg

100 KB
Loading

test/slicing.test.ts

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,44 @@
11
import fs from 'node:fs/promises'
2+
import { join } from 'node:path'
3+
24
import { expect, it } from 'vitest'
35
import { merge, slice } from '../utils/slicing'
46

57
it('slice string', async () => {
68
const input = await fs.readFile('package.json', 'utf-8')
9+
710
const chunks = await slice(input, 64)
811
expect(chunks.length)
912
.toMatchInlineSnapshot(`15`)
13+
1014
const recovered = await merge(chunks)
1115
expect(input).toBe(recovered)
1216
})
1317

1418
it('slice binary', async () => {
1519
const input = (await fs.readFile('package.json', null)).buffer
20+
const inputBytes = new Uint8Array(input).length
21+
1622
const chunks = await slice(input, 64)
1723
expect(chunks.length)
18-
.toMatchInlineSnapshot(`15`)
24+
.toMatchInlineSnapshot(`23`)
25+
26+
const recovered = await merge(chunks)
27+
expect(new Uint8Array(recovered as any).length).toBe(inputBytes)
28+
expect(String(input)).toBe(String(recovered))
29+
})
30+
31+
it('slice image binary', async () => {
32+
// Sample file from Download Sample JPG Image for Demo Use
33+
// https:// sample-videos.com/download-sample-jpg-image.php
34+
const input = (await fs.readFile(join('test', 'SampleJPGImage_100kbmb.jpg'), null)).buffer
35+
const inputBytes = new Uint8Array(input).length
36+
37+
const chunks = await slice(input, 64)
38+
expect(chunks.length)
39+
.toMatchInlineSnapshot(`2554`)
40+
1941
const recovered = await merge(chunks)
42+
expect(new Uint8Array(recovered as any).length).toBe(inputBytes)
2043
expect(String(input)).toBe(String(recovered))
2144
})

utils/slicing.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { compress, compressToBase64, decompress, decompressFromBase64 } from 'lz-string'
1+
import { fromUint8Array, toUint8Array } from 'js-base64'
2+
import { compressToBase64, decompressFromBase64 } from 'lz-string'
23
import { hash as getHash } from 'ohash'
34

45
export type SliceData = [
@@ -9,14 +10,12 @@ export type SliceData = [
910
chunk: string,
1011
]
1112

12-
function arrayBufferToBase64(buffer: ArrayBuffer): Promise<string> {
13-
const blob = new Blob([buffer], { type: 'text/plain; charset=utf-8' })
14-
return blob.text()
13+
async function arrayBufferToBase64(buffer: ArrayBuffer): Promise<string> {
14+
return fromUint8Array(new Uint8Array(buffer))
1515
}
1616

17-
function base64ToArrayBuffer(str: string): Promise<ArrayBuffer> {
18-
const blob = new Blob([str], { type: 'text/plain; charset=utf-8' })
19-
return blob.arrayBuffer()
17+
async function base64ToArrayBuffer(str: string): Promise<ArrayBuffer> {
18+
return toUint8Array(str).buffer
2019
}
2120

2221
export async function slice(input: string | ArrayBuffer, chunkSize = 256): Promise<SliceData[]> {
@@ -54,5 +53,6 @@ export async function merge(slices: SliceData[]): Promise<string | ArrayBuffer>
5453
if (hash !== targetHash) {
5554
throw new Error('Hash mismatch')
5655
}
56+
5757
return data
5858
}

0 commit comments

Comments
 (0)