@hot-updater/bsdiff 0.30.12 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +95 -9
- package/NOTICE.md +52 -0
- package/assets/hdiff.wasm +0 -0
- package/dist/internal/bsdiff.js +2 -2
- package/dist/internal/bsdiff.js.map +1 -1
- package/package.json +3 -1
- package/rust/hdiff-wasm/src/lib.rs +21 -134
package/LICENSE
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
Hot Updater bsdiff package
|
|
2
|
+
|
|
3
|
+
This package is distributed under the MIT license for Hot Updater package code
|
|
4
|
+
and includes BSD-2-Clause licensed bsdiff functionality plus bzip2-licensed
|
|
5
|
+
compression functionality in its compiled WASM artifact. See NOTICE.md for
|
|
6
|
+
source URLs and dependency attribution.
|
|
7
|
+
|
|
1
8
|
MIT License
|
|
2
9
|
|
|
3
|
-
Copyright (c)
|
|
10
|
+
Copyright (c) 2025-present Hot Updater contributors
|
|
4
11
|
|
|
5
12
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
13
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -20,14 +27,93 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
20
27
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
28
|
SOFTWARE.
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
BSD 2-Clause License
|
|
31
|
+
|
|
32
|
+
Copyright 2003-2005 Colin Percival
|
|
33
|
+
Copyright 2012 Matthew Endsley
|
|
34
|
+
Modified 2017 Pieter-Jan Briers
|
|
35
|
+
Modified 2021 Kornel Lesinski
|
|
36
|
+
All rights reserved
|
|
37
|
+
|
|
38
|
+
Redistribution and use in source and binary forms, with or without
|
|
39
|
+
modification, are permitted providing that the following conditions are met:
|
|
40
|
+
|
|
41
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
42
|
+
list of conditions and the following disclaimer.
|
|
43
|
+
|
|
44
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
45
|
+
this list of conditions and the following disclaimer in the documentation
|
|
46
|
+
and/or other materials provided with the distribution.
|
|
47
|
+
|
|
48
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
49
|
+
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
50
|
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
51
|
+
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
52
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
53
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
54
|
+
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
55
|
+
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
56
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
57
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
58
|
+
|
|
59
|
+
MIT License for bzip2 crate
|
|
60
|
+
|
|
61
|
+
Copyright (c) 2014-2025 Alex Crichton and Contributors
|
|
62
|
+
|
|
63
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
64
|
+
this software and associated documentation files (the "Software"), to deal in the
|
|
65
|
+
Software without restriction, including without limitation the rights to use,
|
|
66
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
|
67
|
+
Software, and to permit persons to whom the Software is furnished to do so,
|
|
68
|
+
subject to the following conditions:
|
|
69
|
+
|
|
70
|
+
The above copyright notice and this permission notice shall be included in all
|
|
71
|
+
copies or substantial portions of the Software.
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
75
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
76
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
77
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
78
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
79
|
+
|
|
80
|
+
bzip2-1.0.6 License for libbzip2-rs
|
|
81
|
+
|
|
82
|
+
The original program, "bzip2", the associated library "libbzip2", and all
|
|
83
|
+
documentation, are
|
|
84
|
+
|
|
85
|
+
Copyright (C) 1996-2021 Julian R Seward.
|
|
86
|
+
Copyright (C) 2019-2020 Federico Mena Quintero
|
|
87
|
+
Copyright (C) 2021 Micah Snyder
|
|
88
|
+
|
|
89
|
+
This Rust translation, "libbzip2-rs" is a derived work based on "bzip2" and
|
|
90
|
+
"libbzip2", and is Copyright (C) 2024-2025 Trifecta Tech Foundation and
|
|
91
|
+
contributors
|
|
92
|
+
|
|
93
|
+
Redistribution and use in source and binary forms, with or without
|
|
94
|
+
modification, are permitted provided that the following conditions are met:
|
|
95
|
+
|
|
96
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
97
|
+
list of conditions and the following disclaimer.
|
|
98
|
+
|
|
99
|
+
2. The origin of this software must not be misrepresented; you must not claim
|
|
100
|
+
that you wrote the original software. If you use this software in a product,
|
|
101
|
+
an acknowledgment in the product documentation would be appreciated but is
|
|
102
|
+
not required.
|
|
24
103
|
|
|
25
|
-
|
|
104
|
+
3. Altered source versions must be plainly marked as such, and must not be
|
|
105
|
+
misrepresented as being the original software.
|
|
26
106
|
|
|
27
|
-
The
|
|
28
|
-
|
|
29
|
-
distribution, or integration of this software.
|
|
107
|
+
4. The name of the author may not be used to endorse or promote products
|
|
108
|
+
derived from this software without specific prior written permission.
|
|
30
109
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
110
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
111
|
+
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
112
|
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
113
|
+
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
114
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
115
|
+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
116
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
117
|
+
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
118
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
119
|
+
DAMAGE.
|
package/NOTICE.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Notices for @hot-updater/bsdiff
|
|
2
|
+
|
|
3
|
+
This package contains Hot Updater code plus a precompiled WebAssembly artifact
|
|
4
|
+
that incorporates third-party bsdiff and bzip2 implementations.
|
|
5
|
+
|
|
6
|
+
## Hot Updater package code
|
|
7
|
+
|
|
8
|
+
- Source: https://github.com/gronxb/hot-updater
|
|
9
|
+
- License: MIT
|
|
10
|
+
- Copyright: 2025-present Hot Updater contributors
|
|
11
|
+
|
|
12
|
+
## bsdiff
|
|
13
|
+
|
|
14
|
+
- Crate: `bsdiff` 0.2.1
|
|
15
|
+
- Source: https://github.com/space-wizards/bsdiff-rs
|
|
16
|
+
- Crates.io: https://crates.io/crates/bsdiff
|
|
17
|
+
- License: BSD-2-Clause
|
|
18
|
+
|
|
19
|
+
The Rust crate is a port of Matthew Endsley's bsdiff library:
|
|
20
|
+
|
|
21
|
+
- Source: https://github.com/mendsley/bsdiff
|
|
22
|
+
- Copyright: 2003-2005 Colin Percival
|
|
23
|
+
- Copyright: 2012 Matthew Endsley
|
|
24
|
+
- Modified: 2017 Pieter-Jan Briers
|
|
25
|
+
- Modified: 2021 Kornel Lesinski
|
|
26
|
+
|
|
27
|
+
Hot Updater uses this implementation to produce and apply the control/diff/extra
|
|
28
|
+
stream that is wrapped as an `ENDSLEY/BSDIFF43` patch.
|
|
29
|
+
|
|
30
|
+
## bzip2-rs
|
|
31
|
+
|
|
32
|
+
- Crate: `bzip2` 0.6.1
|
|
33
|
+
- Source: https://github.com/trifectatechfoundation/bzip2-rs
|
|
34
|
+
- Crates.io: https://crates.io/crates/bzip2
|
|
35
|
+
- License: MIT OR Apache-2.0
|
|
36
|
+
- Copyright: 2014-2025 Alex Crichton and Contributors
|
|
37
|
+
|
|
38
|
+
This distribution satisfies the `bzip2` crate's dual license under the MIT
|
|
39
|
+
license option.
|
|
40
|
+
|
|
41
|
+
## libbzip2-rs
|
|
42
|
+
|
|
43
|
+
- Crate: `libbz2-rs-sys` 0.2.2
|
|
44
|
+
- Source: https://github.com/trifectatechfoundation/libbzip2-rs
|
|
45
|
+
- Crates.io: https://crates.io/crates/libbz2-rs-sys
|
|
46
|
+
- License: bzip2-1.0.6
|
|
47
|
+
- Copyright: 1996-2021 Julian R Seward
|
|
48
|
+
- Copyright: 2019-2020 Federico Mena Quintero
|
|
49
|
+
- Copyright: 2021 Micah Snyder
|
|
50
|
+
- Copyright: 2024-2025 Trifecta Tech Foundation and contributors
|
|
51
|
+
|
|
52
|
+
`libbzip2-rs` is a Rust translation and derived work based on bzip2/libbzip2.
|
package/assets/hdiff.wasm
CHANGED
|
Binary file
|
package/dist/internal/bsdiff.js
CHANGED
|
@@ -50,13 +50,13 @@ function readAndFreeOutput(wasm) {
|
|
|
50
50
|
}
|
|
51
51
|
function mapPatchError(status) {
|
|
52
52
|
if (status === BsdiffStatus.INVALID_INPUT) return new HdiffError("PATCH_FAILED", "Invalid input bytes provided to bsdiff wasm");
|
|
53
|
-
if (status === BsdiffStatus.PATCH_FAILED) return new HdiffError("PATCH_FAILED", "Failed to generate
|
|
53
|
+
if (status === BsdiffStatus.PATCH_FAILED) return new HdiffError("PATCH_FAILED", "Failed to generate ENDSLEY/BSDIFF43 patch");
|
|
54
54
|
if (status === BsdiffStatus.INVALID_PATCH) return new HdiffError("PATCH_FAILED", "Unexpected patch-validation status while creating patch");
|
|
55
55
|
return new HdiffError("PATCH_FAILED", `Unknown bsdiff wasm status: ${status}`);
|
|
56
56
|
}
|
|
57
57
|
function mapApplyError(status) {
|
|
58
58
|
if (status === BsdiffStatus.INVALID_INPUT) return new HdiffError("PATCH_FAILED", "Invalid input bytes provided to bspatch wasm");
|
|
59
|
-
if (status === BsdiffStatus.INVALID_PATCH) return new HdiffError("PATCH_FAILED", "Invalid
|
|
59
|
+
if (status === BsdiffStatus.INVALID_PATCH) return new HdiffError("PATCH_FAILED", "Invalid ENDSLEY/BSDIFF43 patch bytes");
|
|
60
60
|
if (status === BsdiffStatus.PATCH_FAILED) return new HdiffError("PATCH_FAILED", "Unexpected patch-generation status while applying patch");
|
|
61
61
|
return new HdiffError("PATCH_FAILED", `Unknown bspatch wasm status: ${status}`);
|
|
62
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bsdiff.js","names":[],"sources":["../../src/internal/bsdiff.ts"],"sourcesContent":["import { HdiffError } from \"../errors.js\";\nimport type { Bytes } from \"./bytes.js\";\n\ntype BsdiffExports = {\n memory: WebAssembly.Memory;\n alloc: (len: number) => number;\n dealloc: (ptr: number, len: number) => void;\n create_patch: (\n basePtr: number,\n baseLen: number,\n nextPtr: number,\n nextLen: number,\n ) => number;\n apply_patch: (\n basePtr: number,\n baseLen: number,\n patchPtr: number,\n patchLen: number,\n ) => number;\n output_ptr: () => number;\n output_len: () => number;\n free_output: () => void;\n};\n\nenum BsdiffStatus {\n OK = 0,\n INVALID_INPUT = 1,\n PATCH_FAILED = 2,\n INVALID_PATCH = 3,\n}\n\nlet wasmPromise: Promise<BsdiffExports> | undefined;\n\nexport async function createBsdiffPatch(\n base: Bytes,\n next: Bytes,\n): Promise<Bytes> {\n const wasm = await getBsdiffWasm();\n\n const status = runBinaryOperation(\n wasm,\n base,\n next,\n (basePtr, baseLen, nextPtr, nextLen) =>\n wasm.create_patch(basePtr, baseLen, nextPtr, nextLen),\n );\n\n if (status !== BsdiffStatus.OK) {\n throw mapPatchError(status);\n }\n\n return readAndFreeOutput(wasm);\n}\n\nexport async function applyBsdiffPatch(\n base: Bytes,\n patch: Bytes,\n): Promise<Bytes> {\n const wasm = await getBsdiffWasm();\n\n const status = runBinaryOperation(\n wasm,\n base,\n patch,\n (basePtr, baseLen, patchPtr, patchLen) =>\n wasm.apply_patch(basePtr, baseLen, patchPtr, patchLen),\n );\n\n if (status !== BsdiffStatus.OK) {\n throw mapApplyError(status);\n }\n\n return readAndFreeOutput(wasm);\n}\n\nfunction runBinaryOperation(\n wasm: BsdiffExports,\n left: Bytes,\n right: Bytes,\n run: (\n leftPtr: number,\n leftLen: number,\n rightPtr: number,\n rightLen: number,\n ) => number,\n): number {\n const leftPtr = wasm.alloc(left.byteLength);\n const rightPtr = wasm.alloc(right.byteLength);\n\n try {\n writeBytesToMemory(wasm.memory, leftPtr, left);\n writeBytesToMemory(wasm.memory, rightPtr, right);\n return run(leftPtr, left.byteLength, rightPtr, right.byteLength);\n } finally {\n if (left.byteLength > 0) {\n wasm.dealloc(leftPtr, left.byteLength);\n }\n if (right.byteLength > 0) {\n wasm.dealloc(rightPtr, right.byteLength);\n }\n }\n}\n\nfunction writeBytesToMemory(\n memory: WebAssembly.Memory,\n ptr: number,\n bytes: Bytes,\n): void {\n if (bytes.byteLength === 0) {\n return;\n }\n new Uint8Array(memory.buffer, ptr, bytes.byteLength).set(bytes);\n}\n\nfunction readAndFreeOutput(wasm: BsdiffExports): Bytes {\n const outPtr = wasm.output_ptr();\n const outLen = wasm.output_len();\n\n if (outLen === 0) {\n wasm.free_output();\n return new Uint8Array();\n }\n\n const output = new Uint8Array(wasm.memory.buffer, outPtr, outLen);\n const copied = new Uint8Array(output);\n wasm.free_output();\n return copied;\n}\n\nfunction mapPatchError(status: number): HdiffError {\n if (status === BsdiffStatus.INVALID_INPUT) {\n return new HdiffError(\n \"PATCH_FAILED\",\n \"Invalid input bytes provided to bsdiff wasm\",\n );\n }\n if (status === BsdiffStatus.PATCH_FAILED) {\n return new HdiffError(\"PATCH_FAILED\"
|
|
1
|
+
{"version":3,"file":"bsdiff.js","names":[],"sources":["../../src/internal/bsdiff.ts"],"sourcesContent":["import { HdiffError } from \"../errors.js\";\nimport type { Bytes } from \"./bytes.js\";\n\ntype BsdiffExports = {\n memory: WebAssembly.Memory;\n alloc: (len: number) => number;\n dealloc: (ptr: number, len: number) => void;\n create_patch: (\n basePtr: number,\n baseLen: number,\n nextPtr: number,\n nextLen: number,\n ) => number;\n apply_patch: (\n basePtr: number,\n baseLen: number,\n patchPtr: number,\n patchLen: number,\n ) => number;\n output_ptr: () => number;\n output_len: () => number;\n free_output: () => void;\n};\n\nenum BsdiffStatus {\n OK = 0,\n INVALID_INPUT = 1,\n PATCH_FAILED = 2,\n INVALID_PATCH = 3,\n}\n\nlet wasmPromise: Promise<BsdiffExports> | undefined;\n\nexport async function createBsdiffPatch(\n base: Bytes,\n next: Bytes,\n): Promise<Bytes> {\n const wasm = await getBsdiffWasm();\n\n const status = runBinaryOperation(\n wasm,\n base,\n next,\n (basePtr, baseLen, nextPtr, nextLen) =>\n wasm.create_patch(basePtr, baseLen, nextPtr, nextLen),\n );\n\n if (status !== BsdiffStatus.OK) {\n throw mapPatchError(status);\n }\n\n return readAndFreeOutput(wasm);\n}\n\nexport async function applyBsdiffPatch(\n base: Bytes,\n patch: Bytes,\n): Promise<Bytes> {\n const wasm = await getBsdiffWasm();\n\n const status = runBinaryOperation(\n wasm,\n base,\n patch,\n (basePtr, baseLen, patchPtr, patchLen) =>\n wasm.apply_patch(basePtr, baseLen, patchPtr, patchLen),\n );\n\n if (status !== BsdiffStatus.OK) {\n throw mapApplyError(status);\n }\n\n return readAndFreeOutput(wasm);\n}\n\nfunction runBinaryOperation(\n wasm: BsdiffExports,\n left: Bytes,\n right: Bytes,\n run: (\n leftPtr: number,\n leftLen: number,\n rightPtr: number,\n rightLen: number,\n ) => number,\n): number {\n const leftPtr = wasm.alloc(left.byteLength);\n const rightPtr = wasm.alloc(right.byteLength);\n\n try {\n writeBytesToMemory(wasm.memory, leftPtr, left);\n writeBytesToMemory(wasm.memory, rightPtr, right);\n return run(leftPtr, left.byteLength, rightPtr, right.byteLength);\n } finally {\n if (left.byteLength > 0) {\n wasm.dealloc(leftPtr, left.byteLength);\n }\n if (right.byteLength > 0) {\n wasm.dealloc(rightPtr, right.byteLength);\n }\n }\n}\n\nfunction writeBytesToMemory(\n memory: WebAssembly.Memory,\n ptr: number,\n bytes: Bytes,\n): void {\n if (bytes.byteLength === 0) {\n return;\n }\n new Uint8Array(memory.buffer, ptr, bytes.byteLength).set(bytes);\n}\n\nfunction readAndFreeOutput(wasm: BsdiffExports): Bytes {\n const outPtr = wasm.output_ptr();\n const outLen = wasm.output_len();\n\n if (outLen === 0) {\n wasm.free_output();\n return new Uint8Array();\n }\n\n const output = new Uint8Array(wasm.memory.buffer, outPtr, outLen);\n const copied = new Uint8Array(output);\n wasm.free_output();\n return copied;\n}\n\nfunction mapPatchError(status: number): HdiffError {\n if (status === BsdiffStatus.INVALID_INPUT) {\n return new HdiffError(\n \"PATCH_FAILED\",\n \"Invalid input bytes provided to bsdiff wasm\",\n );\n }\n if (status === BsdiffStatus.PATCH_FAILED) {\n return new HdiffError(\n \"PATCH_FAILED\",\n \"Failed to generate ENDSLEY/BSDIFF43 patch\",\n );\n }\n if (status === BsdiffStatus.INVALID_PATCH) {\n return new HdiffError(\n \"PATCH_FAILED\",\n \"Unexpected patch-validation status while creating patch\",\n );\n }\n return new HdiffError(\n \"PATCH_FAILED\",\n `Unknown bsdiff wasm status: ${status}`,\n );\n}\n\nfunction mapApplyError(status: number): HdiffError {\n if (status === BsdiffStatus.INVALID_INPUT) {\n return new HdiffError(\n \"PATCH_FAILED\",\n \"Invalid input bytes provided to bspatch wasm\",\n );\n }\n if (status === BsdiffStatus.INVALID_PATCH) {\n return new HdiffError(\n \"PATCH_FAILED\",\n \"Invalid ENDSLEY/BSDIFF43 patch bytes\",\n );\n }\n if (status === BsdiffStatus.PATCH_FAILED) {\n return new HdiffError(\n \"PATCH_FAILED\",\n \"Unexpected patch-generation status while applying patch\",\n );\n }\n return new HdiffError(\n \"PATCH_FAILED\",\n `Unknown bspatch wasm status: ${status}`,\n );\n}\n\nasync function getBsdiffWasm(): Promise<BsdiffExports> {\n wasmPromise ??= loadBsdiffWasm();\n return wasmPromise;\n}\n\nasync function loadBsdiffWasm(): Promise<BsdiffExports> {\n const precompiled = getPrecompiledBsdiffModule();\n const directExports = asBsdiffExports(precompiled);\n if (directExports) {\n return directExports;\n }\n\n if (isWasmModuleLike(precompiled)) {\n const instance = await WebAssembly.instantiate(precompiled);\n return toBsdiffExports(instance.exports);\n }\n\n throw new HdiffError(\n \"PATCH_FAILED\",\n \"No precompiled bsdiff WASM configured. Import a runtime entry such as @hot-updater/bsdiff/node, /bun, /deno, or /worker.\",\n );\n}\n\nfunction getPrecompiledBsdiffModule(): unknown {\n const hdiffGlobal = globalThis as {\n __HDIFF_PRECOMPILED_WASM__?: unknown;\n __HDIFF_PRECOMPILED_BSDIFF_WASM__?: unknown;\n };\n\n const mod =\n hdiffGlobal.__HDIFF_PRECOMPILED_BSDIFF_WASM__ ??\n hdiffGlobal.__HDIFF_PRECOMPILED_WASM__;\n if (mod && typeof mod === \"object\" && \"default\" in mod) {\n return (mod as { default?: unknown }).default;\n }\n return mod;\n}\n\nfunction isWasmModuleLike(mod: unknown): mod is WebAssembly.Module {\n if (mod instanceof WebAssembly.Module) {\n return true;\n }\n return Object.prototype.toString.call(mod) === \"[object WebAssembly.Module]\";\n}\n\nfunction isWasmMemoryLike(memory: unknown): memory is WebAssembly.Memory {\n if (memory instanceof WebAssembly.Memory) {\n return true;\n }\n return (\n Object.prototype.toString.call(memory) === \"[object WebAssembly.Memory]\"\n );\n}\n\nfunction toBsdiffExports(source: unknown): BsdiffExports {\n const direct = asBsdiffExports(source);\n if (direct) {\n return direct;\n }\n\n throw new HdiffError(\"PATCH_FAILED\", \"bsdiff wasm exports are incomplete\");\n}\n\nfunction asBsdiffExports(source: unknown): BsdiffExports | undefined {\n if (source && typeof source === \"object\") {\n const maybe = source as Partial<BsdiffExports>;\n if (\n isWasmMemoryLike(maybe.memory) &&\n typeof maybe.alloc === \"function\" &&\n typeof maybe.dealloc === \"function\" &&\n typeof maybe.create_patch === \"function\" &&\n typeof maybe.apply_patch === \"function\" &&\n typeof maybe.output_ptr === \"function\" &&\n typeof maybe.output_len === \"function\" &&\n typeof maybe.free_output === \"function\"\n ) {\n return maybe as BsdiffExports;\n }\n }\n return undefined;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/bsdiff",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.1",
|
|
4
4
|
"description": "Hot Updater BSdiff library that produces BSDIFF40 patches for RN bspatch flows",
|
|
5
|
+
"license": "MIT AND BSD-2-Clause AND bzip2-1.0.6",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "./dist/node.js",
|
|
7
8
|
"types": "./dist/index.d.ts",
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
}
|
|
39
40
|
},
|
|
40
41
|
"files": [
|
|
42
|
+
"NOTICE.md",
|
|
41
43
|
"dist",
|
|
42
44
|
"assets",
|
|
43
45
|
"scripts/wasm-build",
|
|
@@ -2,7 +2,6 @@ use bzip2::read::BzDecoder;
|
|
|
2
2
|
use bzip2::write::BzEncoder;
|
|
3
3
|
use bzip2::Compression;
|
|
4
4
|
use std::io::Cursor;
|
|
5
|
-
use std::io::Read;
|
|
6
5
|
use std::io::Write;
|
|
7
6
|
|
|
8
7
|
const MIN_HEADER_LEN: u32 = 128;
|
|
@@ -100,7 +99,7 @@ pub unsafe extern "C" fn create_patch(
|
|
|
100
99
|
Err(_) => return STATUS_INVALID_INPUT,
|
|
101
100
|
};
|
|
102
101
|
|
|
103
|
-
match
|
|
102
|
+
match generate_endsley_bsdiff43_patch(&base, &next) {
|
|
104
103
|
Ok(patch) => {
|
|
105
104
|
store_output(patch);
|
|
106
105
|
STATUS_OK
|
|
@@ -125,7 +124,7 @@ pub unsafe extern "C" fn apply_patch(
|
|
|
125
124
|
Err(_) => return STATUS_INVALID_INPUT,
|
|
126
125
|
};
|
|
127
126
|
|
|
128
|
-
match
|
|
127
|
+
match apply_endsley_bsdiff43_patch(&base, &patch) {
|
|
129
128
|
Ok(next) => {
|
|
130
129
|
store_output(next);
|
|
131
130
|
STATUS_OK
|
|
@@ -197,160 +196,48 @@ unsafe fn free_output_buffer() {
|
|
|
197
196
|
LAST_OUTPUT_CAP = 0;
|
|
198
197
|
}
|
|
199
198
|
|
|
200
|
-
fn
|
|
199
|
+
fn generate_endsley_bsdiff43_patch(old: &[u8], new: &[u8]) -> Result<Vec<u8>, String> {
|
|
201
200
|
let mut legacy_patch = Vec::new();
|
|
202
201
|
bsdiff::diff(old, new, &mut legacy_patch).map_err(|error| format!("{error}"))?;
|
|
203
202
|
|
|
204
|
-
let
|
|
203
|
+
let compressed_patch = bzip2_compress(&legacy_patch)?;
|
|
205
204
|
|
|
206
|
-
let
|
|
207
|
-
|
|
208
|
-
let extra_bz = bzip2_compress(&extra_block)?;
|
|
209
|
-
|
|
210
|
-
let mut patch = Vec::with_capacity(32 + ctrl_bz.len() + diff_bz.len() + extra_bz.len());
|
|
211
|
-
patch.extend_from_slice(b"BSDIFF40");
|
|
212
|
-
write_offt(ctrl_bz.len() as i64, &mut patch)?;
|
|
213
|
-
write_offt(diff_bz.len() as i64, &mut patch)?;
|
|
205
|
+
let mut patch = Vec::with_capacity(24 + compressed_patch.len());
|
|
206
|
+
patch.extend_from_slice(b"ENDSLEY/BSDIFF43");
|
|
214
207
|
write_offt(new.len() as i64, &mut patch)?;
|
|
215
|
-
patch.extend_from_slice(&
|
|
216
|
-
patch.extend_from_slice(&diff_bz);
|
|
217
|
-
patch.extend_from_slice(&extra_bz);
|
|
208
|
+
patch.extend_from_slice(&compressed_patch);
|
|
218
209
|
|
|
219
210
|
Ok(patch)
|
|
220
211
|
}
|
|
221
212
|
|
|
222
|
-
fn
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
let mut extra_data = Vec::new();
|
|
226
|
-
|
|
227
|
-
let mut cursor = 0usize;
|
|
228
|
-
while cursor < legacy_patch.len() {
|
|
229
|
-
if legacy_patch.len() - cursor < 24 {
|
|
230
|
-
return Err("invalid legacy patch control length".to_string());
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
let ctrl_bytes = &legacy_patch[cursor..cursor + 24];
|
|
234
|
-
let add_len = read_offt(&ctrl_bytes[0..8])?;
|
|
235
|
-
let copy_len = read_offt(&ctrl_bytes[8..16])?;
|
|
236
|
-
let _seek = read_offt(&ctrl_bytes[16..24])?;
|
|
237
|
-
|
|
238
|
-
if add_len < 0 || copy_len < 0 {
|
|
239
|
-
return Err("invalid legacy patch control values".to_string());
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
let add_len = usize::try_from(add_len).map_err(|_| "add length overflow".to_string())?;
|
|
243
|
-
let copy_len =
|
|
244
|
-
usize::try_from(copy_len).map_err(|_| "copy length overflow".to_string())?;
|
|
245
|
-
cursor += 24;
|
|
246
|
-
|
|
247
|
-
if legacy_patch.len() - cursor < add_len {
|
|
248
|
-
return Err("legacy patch truncated in diff section".to_string());
|
|
249
|
-
}
|
|
250
|
-
diff_data.extend_from_slice(&legacy_patch[cursor..cursor + add_len]);
|
|
251
|
-
cursor += add_len;
|
|
252
|
-
|
|
253
|
-
if legacy_patch.len() - cursor < copy_len {
|
|
254
|
-
return Err("legacy patch truncated in extra section".to_string());
|
|
255
|
-
}
|
|
256
|
-
extra_data.extend_from_slice(&legacy_patch[cursor..cursor + copy_len]);
|
|
257
|
-
cursor += copy_len;
|
|
258
|
-
|
|
259
|
-
controls.extend_from_slice(ctrl_bytes);
|
|
213
|
+
fn apply_endsley_bsdiff43_patch(old: &[u8], patch: &[u8]) -> Result<Vec<u8>, String> {
|
|
214
|
+
if patch.len() < 24 || &patch[0..16] != b"ENDSLEY/BSDIFF43" {
|
|
215
|
+
return Err("invalid ENDSLEY/BSDIFF43 header".to_string());
|
|
260
216
|
}
|
|
261
217
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
fn apply_bsdiff40_patch(old: &[u8], patch: &[u8]) -> Result<Vec<u8>, String> {
|
|
266
|
-
if patch.len() < 32 || &patch[0..8] != b"BSDIFF40" {
|
|
267
|
-
return Err("invalid BSDIFF40 header".to_string());
|
|
218
|
+
let new_size = read_offt(&patch[16..24])?;
|
|
219
|
+
if new_size < 0 {
|
|
220
|
+
return Err("negative ENDSLEY/BSDIFF43 target size".to_string());
|
|
268
221
|
}
|
|
269
222
|
|
|
270
|
-
let ctrl_len = read_offt(&patch[8..16])?;
|
|
271
|
-
let diff_len = read_offt(&patch[16..24])?;
|
|
272
|
-
let new_size = read_offt(&patch[24..32])?;
|
|
273
|
-
if ctrl_len < 0 || diff_len < 0 || new_size < 0 {
|
|
274
|
-
return Err("negative BSDIFF40 header values".to_string());
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
let ctrl_len = usize::try_from(ctrl_len).map_err(|_| "control length overflow".to_string())?;
|
|
278
|
-
let diff_len = usize::try_from(diff_len).map_err(|_| "diff length overflow".to_string())?;
|
|
279
223
|
let new_size = usize::try_from(new_size).map_err(|_| "new size overflow".to_string())?;
|
|
224
|
+
let mut patch_reader = BzDecoder::new(Cursor::new(&patch[24..]));
|
|
225
|
+
let mut output = Vec::with_capacity(new_size);
|
|
280
226
|
|
|
281
|
-
|
|
282
|
-
let ctrl_end = ctrl_start
|
|
283
|
-
.checked_add(ctrl_len)
|
|
284
|
-
.ok_or_else(|| "control block overflow".to_string())?;
|
|
285
|
-
let diff_end = ctrl_end
|
|
286
|
-
.checked_add(diff_len)
|
|
287
|
-
.ok_or_else(|| "diff block overflow".to_string())?;
|
|
288
|
-
if diff_end > patch.len() {
|
|
289
|
-
return Err("BSDIFF40 block bounds are invalid".to_string());
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
let mut ctrl_reader = BzDecoder::new(Cursor::new(&patch[ctrl_start..ctrl_end]));
|
|
293
|
-
let mut diff_reader = BzDecoder::new(Cursor::new(&patch[ctrl_end..diff_end]));
|
|
294
|
-
let mut extra_reader = BzDecoder::new(Cursor::new(&patch[diff_end..]));
|
|
295
|
-
|
|
296
|
-
let mut out = Vec::with_capacity(new_size);
|
|
297
|
-
let mut old_pos: i64 = 0;
|
|
298
|
-
|
|
299
|
-
while out.len() < new_size {
|
|
300
|
-
let mut ctrl_buf = [0u8; 24];
|
|
301
|
-
ctrl_reader
|
|
302
|
-
.read_exact(&mut ctrl_buf)
|
|
303
|
-
.map_err(|error| format!("failed to read control block: {error}"))?;
|
|
304
|
-
|
|
305
|
-
let add_len = read_offt(&ctrl_buf[0..8])?;
|
|
306
|
-
let copy_len = read_offt(&ctrl_buf[8..16])?;
|
|
307
|
-
let seek_len = read_offt(&ctrl_buf[16..24])?;
|
|
308
|
-
if add_len < 0 || copy_len < 0 {
|
|
309
|
-
return Err("negative add/copy length in control block".to_string());
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
let add_len = usize::try_from(add_len).map_err(|_| "add length overflow".to_string())?;
|
|
313
|
-
let copy_len =
|
|
314
|
-
usize::try_from(copy_len).map_err(|_| "copy length overflow".to_string())?;
|
|
315
|
-
|
|
316
|
-
let mut diff_bytes = vec![0u8; add_len];
|
|
317
|
-
diff_reader
|
|
318
|
-
.read_exact(&mut diff_bytes)
|
|
319
|
-
.map_err(|error| format!("failed to read diff block: {error}"))?;
|
|
320
|
-
for delta_byte in diff_bytes {
|
|
321
|
-
if old_pos < 0 || old_pos as usize >= old.len() {
|
|
322
|
-
return Err("old file offset out of bounds".to_string());
|
|
323
|
-
}
|
|
324
|
-
let old_byte = old[old_pos as usize];
|
|
325
|
-
out.push(delta_byte.wrapping_add(old_byte));
|
|
326
|
-
old_pos += 1;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
let mut extra_bytes = vec![0u8; copy_len];
|
|
330
|
-
extra_reader
|
|
331
|
-
.read_exact(&mut extra_bytes)
|
|
332
|
-
.map_err(|error| format!("failed to read extra block: {error}"))?;
|
|
333
|
-
out.extend_from_slice(&extra_bytes);
|
|
334
|
-
|
|
335
|
-
old_pos = old_pos
|
|
336
|
-
.checked_add(seek_len)
|
|
337
|
-
.ok_or_else(|| "old file seek overflow".to_string())?;
|
|
338
|
-
|
|
339
|
-
if out.len() > new_size {
|
|
340
|
-
return Err("patch output exceeds target size".to_string());
|
|
341
|
-
}
|
|
342
|
-
}
|
|
227
|
+
bsdiff::patch(old, &mut patch_reader, &mut output).map_err(|error| format!("{error}"))?;
|
|
343
228
|
|
|
344
|
-
if
|
|
229
|
+
if output.len() != new_size {
|
|
345
230
|
return Err("patch output length mismatch".to_string());
|
|
346
231
|
}
|
|
347
232
|
|
|
348
|
-
Ok(
|
|
233
|
+
Ok(output)
|
|
349
234
|
}
|
|
350
235
|
|
|
351
236
|
fn bzip2_compress(input: &[u8]) -> Result<Vec<u8>, String> {
|
|
352
237
|
let mut encoder = BzEncoder::new(Vec::new(), Compression::new(6));
|
|
353
|
-
encoder
|
|
238
|
+
encoder
|
|
239
|
+
.write_all(input)
|
|
240
|
+
.map_err(|error| format!("{error}"))?;
|
|
354
241
|
encoder.finish().map_err(|error| format!("{error}"))
|
|
355
242
|
}
|
|
356
243
|
|