@onekeyfe/react-native-range-downloader 3.0.80 → 3.0.81-alpha.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/ReactNativeRangeDownloader.podspec +8 -0
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveRules.kt +284 -0
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactStore.kt +842 -0
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/ReactNativeRangeDownloader.kt +148 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveRulesTest.kt +75 -0
- package/ios/FirmwareArchiveMinizipBridge.h +33 -0
- package/ios/FirmwareArchiveMinizipBridge.mm +213 -0
- package/ios/FirmwareArtifactStore.swift +1276 -0
- package/ios/FirmwareBackgroundSessionEventRouter.swift +17 -0
- package/ios/ReactNativeRangeDownloader.swift +638 -6
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts +95 -1
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JDownloadChannel.hpp +3 -0
- package/nitrogen/generated/android/c++/JFirmwareArchiveExpectedEntry.hpp +69 -0
- package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializeParams.hpp +86 -0
- package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializeResult.hpp +80 -0
- package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializedArtifact.hpp +63 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactCancelParams.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactCapabilities.hpp +88 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactDownloadParams.hpp +98 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLease.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseCreateParams.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseReconcileParams.hpp +76 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseReleaseParams.hpp +61 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseRetainParams.hpp +61 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactReaderCloseParams.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactReaderInfo.hpp +61 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactReaderReadParams.hpp +65 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactReceipt.hpp +65 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactRefParams.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactSweepResult.hpp +61 -0
- package/nitrogen/generated/android/c++/JHybridReactNativeRangeDownloaderSpec.cpp +267 -0
- package/nitrogen/generated/android/c++/JHybridReactNativeRangeDownloaderSpec.hpp +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/DownloadChannel.kt +2 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveExpectedEntry.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializeParams.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializeResult.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializedArtifact.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactCancelParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactCapabilities.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactDownloadParams.kt +68 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLease.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseCreateParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseReconcileParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseReleaseParams.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseRetainParams.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReaderCloseParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReaderInfo.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReaderReadParams.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReceipt.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactRefParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactSweepResult.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/HybridReactNativeRangeDownloaderSpec.kt +53 -0
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Bridge.cpp +48 -0
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Bridge.hpp +329 -0
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Umbrella.hpp +56 -0
- package/nitrogen/generated/ios/c++/HybridReactNativeRangeDownloaderSpecSwift.hpp +163 -0
- package/nitrogen/generated/ios/swift/DownloadChannel.swift +4 -0
- package/nitrogen/generated/ios/swift/FirmwareArchiveExpectedEntry.swift +69 -0
- package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializeParams.swift +70 -0
- package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializeResult.swift +48 -0
- package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializedArtifact.swift +47 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactCancelParams.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactCapabilities.swift +81 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactDownloadParams.swift +177 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLease.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseCreateParams.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseReconcileParams.swift +48 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseReleaseParams.swift +47 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseRetainParams.swift +47 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactReaderCloseParams.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactReaderInfo.swift +47 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactReaderReadParams.swift +58 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactReceipt.swift +58 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactRefParams.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactSweepResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArchiveMaterializeResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactLease.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactReaderInfo.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactReceipt.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactSweepResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_ArrayBuffer_.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridReactNativeRangeDownloaderSpec.swift +13 -0
- package/nitrogen/generated/ios/swift/HybridReactNativeRangeDownloaderSpec_cxx.swift +240 -0
- package/nitrogen/generated/shared/c++/DownloadChannel.hpp +4 -0
- package/nitrogen/generated/shared/c++/FirmwareArchiveExpectedEntry.hpp +87 -0
- package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializeParams.hpp +86 -0
- package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializeResult.hpp +77 -0
- package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializedArtifact.hpp +81 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactCancelParams.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactCapabilities.hpp +88 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactDownloadParams.hpp +116 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLease.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseCreateParams.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseReconcileParams.hpp +76 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseReleaseParams.hpp +79 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseRetainParams.hpp +79 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactReaderCloseParams.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactReaderInfo.hpp +79 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactReaderReadParams.hpp +83 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactReceipt.hpp +83 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactRefParams.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactSweepResult.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridReactNativeRangeDownloaderSpec.cpp +13 -0
- package/nitrogen/generated/shared/c++/HybridReactNativeRangeDownloaderSpec.hpp +62 -0
- package/package.json +4 -2
- package/src/ReactNativeRangeDownloader.nitro.ts +134 -1
- package/src/index.tsx +3 -1
|
@@ -2,6 +2,7 @@ package com.margelo.nitro.reactnativerangedownloader
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.proguard.annotations.DoNotStrip
|
|
4
4
|
import com.margelo.nitro.NitroModules
|
|
5
|
+
import com.margelo.nitro.core.ArrayBuffer
|
|
5
6
|
import com.margelo.nitro.core.Promise
|
|
6
7
|
import com.margelo.nitro.nativelogger.OneKeyLog
|
|
7
8
|
import java.io.File
|
|
@@ -265,6 +266,153 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
265
266
|
return ctx.cacheDir.absolutePath
|
|
266
267
|
}
|
|
267
268
|
|
|
269
|
+
override fun getFirmwareArtifactCapabilities(): FirmwareArtifactCapabilities {
|
|
270
|
+
return FirmwareArtifactCapabilities(
|
|
271
|
+
firmwareArtifactProtocolVersion = 1.0,
|
|
272
|
+
supportedRouteTypes = arrayOf("domain", "pinnedIp"),
|
|
273
|
+
supportsArchiveMaterialization = true,
|
|
274
|
+
maxReadBytes = FirmwareArtifactStore.MAX_READ_BYTES.toDouble(),
|
|
275
|
+
)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
override fun downloadFirmwareArtifact(
|
|
279
|
+
params: FirmwareArtifactDownloadParams,
|
|
280
|
+
): Promise<FirmwareArtifactReceipt> {
|
|
281
|
+
return Promise.async {
|
|
282
|
+
val artifact = FirmwareArtifactStore.download(params)
|
|
283
|
+
FirmwareArtifactReceipt(
|
|
284
|
+
artifactRef = artifact.artifactRef,
|
|
285
|
+
size = artifact.size.toDouble(),
|
|
286
|
+
sha256 = artifact.sha256,
|
|
287
|
+
)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
override fun cancelFirmwareArtifactDownloads(
|
|
292
|
+
params: FirmwareArtifactCancelParams,
|
|
293
|
+
): Promise<Unit> {
|
|
294
|
+
return Promise.async {
|
|
295
|
+
FirmwareArtifactStore.cancelDownloads(params.transactionId)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
override fun discardFirmwareArtifact(
|
|
300
|
+
params: FirmwareArtifactRefParams,
|
|
301
|
+
): Promise<Unit> {
|
|
302
|
+
return Promise.async {
|
|
303
|
+
FirmwareArtifactStore.discard(params.artifactRef)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
override fun openFirmwareArtifact(
|
|
308
|
+
params: FirmwareArtifactRefParams,
|
|
309
|
+
): Promise<FirmwareArtifactReaderInfo> {
|
|
310
|
+
return Promise.async {
|
|
311
|
+
val (readerId, size) = FirmwareArtifactStore.open(params.artifactRef)
|
|
312
|
+
FirmwareArtifactReaderInfo(readerId = readerId, size = size.toDouble())
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
override fun readFirmwareArtifact(
|
|
317
|
+
params: FirmwareArtifactReaderReadParams,
|
|
318
|
+
): Promise<ArrayBuffer> {
|
|
319
|
+
return Promise.async {
|
|
320
|
+
require(
|
|
321
|
+
params.offset.isFinite() &&
|
|
322
|
+
params.offset >= 0 &&
|
|
323
|
+
params.offset.toLong().toDouble() == params.offset &&
|
|
324
|
+
params.length.isFinite() &&
|
|
325
|
+
params.length > 0 &&
|
|
326
|
+
params.length.toInt().toDouble() == params.length
|
|
327
|
+
) {
|
|
328
|
+
"Invalid firmware artifact read"
|
|
329
|
+
}
|
|
330
|
+
ArrayBuffer.copy(
|
|
331
|
+
FirmwareArtifactStore.read(
|
|
332
|
+
readerId = params.readerId,
|
|
333
|
+
offset = params.offset.toLong(),
|
|
334
|
+
length = params.length.toInt(),
|
|
335
|
+
),
|
|
336
|
+
)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
override fun closeFirmwareArtifact(
|
|
341
|
+
params: FirmwareArtifactReaderCloseParams,
|
|
342
|
+
): Promise<Unit> {
|
|
343
|
+
return Promise.async {
|
|
344
|
+
FirmwareArtifactStore.close(params.readerId)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
override fun materializeFirmwareArchive(
|
|
349
|
+
params: FirmwareArchiveMaterializeParams,
|
|
350
|
+
): Promise<FirmwareArchiveMaterializeResult> {
|
|
351
|
+
return Promise.async {
|
|
352
|
+
val artifacts = FirmwareArtifactStore.materializeArchive(
|
|
353
|
+
params.leaseRef,
|
|
354
|
+
params.archiveArtifactRef,
|
|
355
|
+
params.expectedEntries,
|
|
356
|
+
)
|
|
357
|
+
FirmwareArchiveMaterializeResult(
|
|
358
|
+
artifacts = artifacts.map { entry ->
|
|
359
|
+
FirmwareArchiveMaterializedArtifact(
|
|
360
|
+
entryName = entry.entryName,
|
|
361
|
+
receipt = FirmwareArtifactReceipt(
|
|
362
|
+
artifactRef = entry.artifact.artifactRef,
|
|
363
|
+
size = entry.artifact.size.toDouble(),
|
|
364
|
+
sha256 = entry.artifact.sha256,
|
|
365
|
+
),
|
|
366
|
+
)
|
|
367
|
+
}.toTypedArray(),
|
|
368
|
+
)
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
override fun createFirmwareArtifactLease(
|
|
373
|
+
params: FirmwareArtifactLeaseCreateParams,
|
|
374
|
+
): Promise<FirmwareArtifactLease> {
|
|
375
|
+
return Promise.async {
|
|
376
|
+
FirmwareArtifactLease(
|
|
377
|
+
leaseRef = FirmwareArtifactStore.createLease(params.transactionId),
|
|
378
|
+
)
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
override fun retainFirmwareArtifact(
|
|
383
|
+
params: FirmwareArtifactLeaseRetainParams,
|
|
384
|
+
): Promise<Unit> {
|
|
385
|
+
return Promise.async {
|
|
386
|
+
FirmwareArtifactStore.retain(params.leaseRef, params.artifactRef)
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
override fun releaseFirmwareArtifactLease(
|
|
391
|
+
params: FirmwareArtifactLeaseReleaseParams,
|
|
392
|
+
): Promise<Unit> {
|
|
393
|
+
return Promise.async {
|
|
394
|
+
FirmwareArtifactStore.releaseLease(params.leaseRef, params.disposition)
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
override fun reconcileFirmwareArtifactLeases(
|
|
399
|
+
params: FirmwareArtifactLeaseReconcileParams,
|
|
400
|
+
): Promise<Unit> {
|
|
401
|
+
return Promise.async {
|
|
402
|
+
FirmwareArtifactStore.reconcileLeases(params.activeLeaseRefs)
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
override fun sweepFirmwareArtifactOrphans(): Promise<FirmwareArtifactSweepResult> {
|
|
407
|
+
return Promise.async {
|
|
408
|
+
val (deletedFiles, deletedBytes) = FirmwareArtifactStore.sweepOrphans()
|
|
409
|
+
FirmwareArtifactSweepResult(
|
|
410
|
+
deletedFiles = deletedFiles.toDouble(),
|
|
411
|
+
deletedBytes = deletedBytes.toDouble(),
|
|
412
|
+
)
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
268
416
|
// Broadcast one event to every registered listener. Listeners filter by
|
|
269
417
|
// channel/taskId on their side (shared registry, per the design).
|
|
270
418
|
private fun sendEvent(
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
package com.margelo.nitro.reactnativerangedownloader
|
|
2
|
+
|
|
3
|
+
import org.junit.Assert.assertEquals
|
|
4
|
+
import org.junit.Assert.assertThrows
|
|
5
|
+
import org.junit.Test
|
|
6
|
+
|
|
7
|
+
class FirmwareArchiveRulesTest {
|
|
8
|
+
private fun entry(
|
|
9
|
+
artifactId: String = "resource-entry",
|
|
10
|
+
entryName: String = "assets/icon.png",
|
|
11
|
+
expectedSize: Double = 128.0,
|
|
12
|
+
expectedSha256: String = "a".repeat(64),
|
|
13
|
+
) = FirmwareArchiveExpectedEntry(
|
|
14
|
+
artifactId = artifactId,
|
|
15
|
+
entryName = entryName,
|
|
16
|
+
expectedSize = expectedSize,
|
|
17
|
+
expectedSha256 = expectedSha256,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
@Test
|
|
21
|
+
fun acceptsAnExactPortableAllowlist() {
|
|
22
|
+
val requirements = FirmwareArchiveRules.validateRequirements(
|
|
23
|
+
arrayOf(
|
|
24
|
+
entry(),
|
|
25
|
+
entry(
|
|
26
|
+
artifactId = "resource-entry-2",
|
|
27
|
+
entryName = "assets/sub/icon-2.png",
|
|
28
|
+
expectedSha256 = "b".repeat(64),
|
|
29
|
+
),
|
|
30
|
+
),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
assertEquals(2, requirements.size)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Test
|
|
37
|
+
fun rejectsTraversalAndNestedArchives() {
|
|
38
|
+
for (entryName in listOf("../icon.png", "assets/../icon.png", "assets.zip")) {
|
|
39
|
+
assertThrows(IllegalArgumentException::class.java) {
|
|
40
|
+
FirmwareArchiveRules.validateRequirements(
|
|
41
|
+
arrayOf(entry(entryName = entryName)),
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@Test
|
|
48
|
+
fun rejectsCaseFoldedDuplicateNames() {
|
|
49
|
+
assertThrows(IllegalArgumentException::class.java) {
|
|
50
|
+
FirmwareArchiveRules.validateRequirements(
|
|
51
|
+
arrayOf(
|
|
52
|
+
entry(entryName = "assets/Icon.png"),
|
|
53
|
+
entry(
|
|
54
|
+
artifactId = "resource-entry-2",
|
|
55
|
+
entryName = "assets/icon.png",
|
|
56
|
+
),
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Test
|
|
63
|
+
fun rejectsNonIntegralSizesAndInvalidDigests() {
|
|
64
|
+
assertThrows(IllegalArgumentException::class.java) {
|
|
65
|
+
FirmwareArchiveRules.validateRequirements(
|
|
66
|
+
arrayOf(entry(expectedSize = 1.5)),
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
assertThrows(IllegalArgumentException::class.java) {
|
|
70
|
+
FirmwareArchiveRules.validateRequirements(
|
|
71
|
+
arrayOf(entry(expectedSha256 = "not-a-digest")),
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
4
|
+
|
|
5
|
+
@interface FirmwareArchiveEntryInfo : NSObject
|
|
6
|
+
|
|
7
|
+
@property(nonatomic, readonly) NSString *name;
|
|
8
|
+
@property(nonatomic, readonly) int64_t compressedSize;
|
|
9
|
+
@property(nonatomic, readonly) int64_t uncompressedSize;
|
|
10
|
+
@property(nonatomic, readonly) uint32_t crc32;
|
|
11
|
+
@property(nonatomic, readonly) uint16_t flags;
|
|
12
|
+
@property(nonatomic, readonly) uint16_t compressionMethod;
|
|
13
|
+
@property(nonatomic, readonly) uint16_t versionMadeBy;
|
|
14
|
+
@property(nonatomic, readonly) uint32_t externalAttributes;
|
|
15
|
+
@property(nonatomic, readonly) uint32_t diskNumber;
|
|
16
|
+
@property(nonatomic, readonly, nullable) NSString *linkName;
|
|
17
|
+
|
|
18
|
+
@end
|
|
19
|
+
|
|
20
|
+
@interface FirmwareArchiveMinizipBridge : NSObject
|
|
21
|
+
|
|
22
|
+
+ (nullable NSArray<FirmwareArchiveEntryInfo *> *)scanArchiveAtPath:
|
|
23
|
+
(NSString *)path
|
|
24
|
+
error:(NSError * _Nullable * _Nullable)error;
|
|
25
|
+
|
|
26
|
+
+ (BOOL)extractEntryNamed:(NSString *)entryName
|
|
27
|
+
archivePath:(NSString *)archivePath
|
|
28
|
+
consumer:(BOOL (^)(NSData *chunk))consumer
|
|
29
|
+
error:(NSError * _Nullable * _Nullable)error;
|
|
30
|
+
|
|
31
|
+
@end
|
|
32
|
+
|
|
33
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#import "FirmwareArchiveMinizipBridge.h"
|
|
2
|
+
|
|
3
|
+
#import "mz.h"
|
|
4
|
+
#import "mz_strm.h"
|
|
5
|
+
#import "mz_zip.h"
|
|
6
|
+
#import "mz_zip_rw.h"
|
|
7
|
+
|
|
8
|
+
#include <cstring>
|
|
9
|
+
|
|
10
|
+
static NSString *const FirmwareArchiveBridgeErrorDomain =
|
|
11
|
+
@"so.onekey.firmware.archive.minizip";
|
|
12
|
+
|
|
13
|
+
static NSError *FirmwareArchiveBridgeError(NSString *message, int32_t code) {
|
|
14
|
+
return [NSError errorWithDomain:FirmwareArchiveBridgeErrorDomain
|
|
15
|
+
code:code
|
|
16
|
+
userInfo:@{NSLocalizedDescriptionKey : message}];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@interface FirmwareArchiveEntryInfo ()
|
|
20
|
+
|
|
21
|
+
@property(nonatomic, readwrite) NSString *name;
|
|
22
|
+
@property(nonatomic, readwrite) int64_t compressedSize;
|
|
23
|
+
@property(nonatomic, readwrite) int64_t uncompressedSize;
|
|
24
|
+
@property(nonatomic, readwrite) uint32_t crc32;
|
|
25
|
+
@property(nonatomic, readwrite) uint16_t flags;
|
|
26
|
+
@property(nonatomic, readwrite) uint16_t compressionMethod;
|
|
27
|
+
@property(nonatomic, readwrite) uint16_t versionMadeBy;
|
|
28
|
+
@property(nonatomic, readwrite) uint32_t externalAttributes;
|
|
29
|
+
@property(nonatomic, readwrite) uint32_t diskNumber;
|
|
30
|
+
@property(nonatomic, readwrite, nullable) NSString *linkName;
|
|
31
|
+
|
|
32
|
+
@end
|
|
33
|
+
|
|
34
|
+
@implementation FirmwareArchiveEntryInfo
|
|
35
|
+
@end
|
|
36
|
+
|
|
37
|
+
@implementation FirmwareArchiveMinizipBridge
|
|
38
|
+
|
|
39
|
+
+ (nullable NSArray<FirmwareArchiveEntryInfo *> *)scanArchiveAtPath:
|
|
40
|
+
(NSString *)path
|
|
41
|
+
error:(NSError * _Nullable * _Nullable)error {
|
|
42
|
+
void *reader = nullptr;
|
|
43
|
+
mz_zip_reader_create(&reader);
|
|
44
|
+
if (reader == nullptr) {
|
|
45
|
+
if (error != nullptr) {
|
|
46
|
+
*error = FirmwareArchiveBridgeError(@"Archive reader allocation failed",
|
|
47
|
+
MZ_MEM_ERROR);
|
|
48
|
+
}
|
|
49
|
+
return nil;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
int32_t result = mz_zip_reader_open_file(reader, path.fileSystemRepresentation);
|
|
53
|
+
if (result != MZ_OK) {
|
|
54
|
+
mz_zip_reader_delete(&reader);
|
|
55
|
+
if (error != nullptr) {
|
|
56
|
+
*error = FirmwareArchiveBridgeError(@"Archive open failed", result);
|
|
57
|
+
}
|
|
58
|
+
return nil;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
NSMutableArray<FirmwareArchiveEntryInfo *> *entries =
|
|
62
|
+
[NSMutableArray array];
|
|
63
|
+
result = mz_zip_reader_goto_first_entry(reader);
|
|
64
|
+
while (result == MZ_OK) {
|
|
65
|
+
mz_zip_file *fileInfo = nullptr;
|
|
66
|
+
result = mz_zip_reader_entry_get_info(reader, &fileInfo);
|
|
67
|
+
if (result != MZ_OK || fileInfo == nullptr ||
|
|
68
|
+
fileInfo->filename == nullptr) {
|
|
69
|
+
result = result == MZ_OK ? MZ_FORMAT_ERROR : result;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
const size_t filenameLength = std::strlen(fileInfo->filename);
|
|
73
|
+
if (filenameLength == 0 || filenameLength > 4096) {
|
|
74
|
+
result = MZ_FORMAT_ERROR;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
if ((fileInfo->flag & (1 << 11)) == 0) {
|
|
78
|
+
const unsigned char *filenameBytes =
|
|
79
|
+
reinterpret_cast<const unsigned char *>(fileInfo->filename);
|
|
80
|
+
bool isAscii = true;
|
|
81
|
+
for (size_t index = 0; index < filenameLength; index += 1) {
|
|
82
|
+
if (filenameBytes[index] >= 0x80) {
|
|
83
|
+
isAscii = false;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (!isAscii) {
|
|
88
|
+
result = MZ_FORMAT_ERROR;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
NSString *name = [NSString stringWithUTF8String:fileInfo->filename];
|
|
93
|
+
if (name == nil) {
|
|
94
|
+
result = MZ_FORMAT_ERROR;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
NSString *linkName = nil;
|
|
98
|
+
if (fileInfo->linkname != nullptr) {
|
|
99
|
+
linkName = [NSString stringWithUTF8String:fileInfo->linkname];
|
|
100
|
+
if (linkName == nil) {
|
|
101
|
+
result = MZ_FORMAT_ERROR;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
FirmwareArchiveEntryInfo *entry =
|
|
107
|
+
[[FirmwareArchiveEntryInfo alloc] init];
|
|
108
|
+
entry.name = name;
|
|
109
|
+
entry.compressedSize = fileInfo->compressed_size;
|
|
110
|
+
entry.uncompressedSize = fileInfo->uncompressed_size;
|
|
111
|
+
entry.crc32 = fileInfo->crc;
|
|
112
|
+
entry.flags = fileInfo->flag;
|
|
113
|
+
entry.compressionMethod = fileInfo->compression_method;
|
|
114
|
+
entry.versionMadeBy = fileInfo->version_madeby;
|
|
115
|
+
entry.externalAttributes = fileInfo->external_fa;
|
|
116
|
+
entry.diskNumber = fileInfo->disk_number;
|
|
117
|
+
entry.linkName = linkName;
|
|
118
|
+
[entries addObject:entry];
|
|
119
|
+
if (entries.count > 4096) {
|
|
120
|
+
result = MZ_FORMAT_ERROR;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
result = mz_zip_reader_goto_next_entry(reader);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (result == MZ_END_OF_LIST) {
|
|
127
|
+
result = MZ_OK;
|
|
128
|
+
}
|
|
129
|
+
int32_t closeResult = mz_zip_reader_close(reader);
|
|
130
|
+
mz_zip_reader_delete(&reader);
|
|
131
|
+
if (result != MZ_OK || closeResult != MZ_OK) {
|
|
132
|
+
if (error != nullptr) {
|
|
133
|
+
*error = FirmwareArchiveBridgeError(@"Archive scan failed",
|
|
134
|
+
result != MZ_OK ? result
|
|
135
|
+
: closeResult);
|
|
136
|
+
}
|
|
137
|
+
return nil;
|
|
138
|
+
}
|
|
139
|
+
return entries;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
+ (BOOL)extractEntryNamed:(NSString *)entryName
|
|
143
|
+
archivePath:(NSString *)archivePath
|
|
144
|
+
consumer:(BOOL (^)(NSData *chunk))consumer
|
|
145
|
+
error:(NSError * _Nullable * _Nullable)error {
|
|
146
|
+
void *reader = nullptr;
|
|
147
|
+
bool archiveOpened = false;
|
|
148
|
+
bool entryOpened = false;
|
|
149
|
+
mz_zip_reader_create(&reader);
|
|
150
|
+
if (reader == nullptr) {
|
|
151
|
+
if (error != nullptr) {
|
|
152
|
+
*error = FirmwareArchiveBridgeError(@"Archive reader allocation failed",
|
|
153
|
+
MZ_MEM_ERROR);
|
|
154
|
+
}
|
|
155
|
+
return NO;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
int32_t result =
|
|
159
|
+
mz_zip_reader_open_file(reader, archivePath.fileSystemRepresentation);
|
|
160
|
+
if (result == MZ_OK) {
|
|
161
|
+
archiveOpened = true;
|
|
162
|
+
}
|
|
163
|
+
if (result == MZ_OK) {
|
|
164
|
+
result = mz_zip_reader_locate_entry(
|
|
165
|
+
reader, entryName.UTF8String, 0);
|
|
166
|
+
}
|
|
167
|
+
if (result == MZ_OK) {
|
|
168
|
+
result = mz_zip_reader_entry_open(reader);
|
|
169
|
+
if (result == MZ_OK) {
|
|
170
|
+
entryOpened = true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
uint8_t buffer[64 * 1024];
|
|
175
|
+
while (result == MZ_OK) {
|
|
176
|
+
int32_t count =
|
|
177
|
+
mz_zip_reader_entry_read(reader, buffer, (int32_t)sizeof(buffer));
|
|
178
|
+
if (count < 0) {
|
|
179
|
+
result = count;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
if (count == 0) {
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
NSData *chunk = [NSData dataWithBytes:buffer length:(NSUInteger)count];
|
|
186
|
+
if (!consumer(chunk)) {
|
|
187
|
+
result = MZ_WRITE_ERROR;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
int32_t entryCloseResult =
|
|
193
|
+
entryOpened ? mz_zip_reader_entry_close(reader) : MZ_OK;
|
|
194
|
+
int32_t archiveCloseResult =
|
|
195
|
+
archiveOpened ? mz_zip_reader_close(reader) : MZ_OK;
|
|
196
|
+
mz_zip_reader_delete(&reader);
|
|
197
|
+
if (result != MZ_OK || entryCloseResult != MZ_OK ||
|
|
198
|
+
archiveCloseResult != MZ_OK) {
|
|
199
|
+
if (error != nullptr) {
|
|
200
|
+
int32_t failure = result != MZ_OK
|
|
201
|
+
? result
|
|
202
|
+
: (entryCloseResult != MZ_OK
|
|
203
|
+
? entryCloseResult
|
|
204
|
+
: archiveCloseResult);
|
|
205
|
+
*error = FirmwareArchiveBridgeError(
|
|
206
|
+
@"Archive entry extraction or CRC validation failed", failure);
|
|
207
|
+
}
|
|
208
|
+
return NO;
|
|
209
|
+
}
|
|
210
|
+
return YES;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@end
|