@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.
Files changed (113) hide show
  1. package/ReactNativeRangeDownloader.podspec +8 -0
  2. package/android/build.gradle +1 -0
  3. package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveRules.kt +284 -0
  4. package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactStore.kt +842 -0
  5. package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/ReactNativeRangeDownloader.kt +148 -0
  6. package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveRulesTest.kt +75 -0
  7. package/ios/FirmwareArchiveMinizipBridge.h +33 -0
  8. package/ios/FirmwareArchiveMinizipBridge.mm +213 -0
  9. package/ios/FirmwareArtifactStore.swift +1276 -0
  10. package/ios/FirmwareBackgroundSessionEventRouter.swift +17 -0
  11. package/ios/ReactNativeRangeDownloader.swift +638 -6
  12. package/lib/module/index.js +2 -1
  13. package/lib/module/index.js.map +1 -1
  14. package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts +95 -1
  15. package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts.map +1 -1
  16. package/lib/typescript/src/index.d.ts +1 -0
  17. package/lib/typescript/src/index.d.ts.map +1 -1
  18. package/nitrogen/generated/android/c++/JDownloadChannel.hpp +3 -0
  19. package/nitrogen/generated/android/c++/JFirmwareArchiveExpectedEntry.hpp +69 -0
  20. package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializeParams.hpp +86 -0
  21. package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializeResult.hpp +80 -0
  22. package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializedArtifact.hpp +63 -0
  23. package/nitrogen/generated/android/c++/JFirmwareArtifactCancelParams.hpp +57 -0
  24. package/nitrogen/generated/android/c++/JFirmwareArtifactCapabilities.hpp +88 -0
  25. package/nitrogen/generated/android/c++/JFirmwareArtifactDownloadParams.hpp +98 -0
  26. package/nitrogen/generated/android/c++/JFirmwareArtifactLease.hpp +57 -0
  27. package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseCreateParams.hpp +57 -0
  28. package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseReconcileParams.hpp +76 -0
  29. package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseReleaseParams.hpp +61 -0
  30. package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseRetainParams.hpp +61 -0
  31. package/nitrogen/generated/android/c++/JFirmwareArtifactReaderCloseParams.hpp +57 -0
  32. package/nitrogen/generated/android/c++/JFirmwareArtifactReaderInfo.hpp +61 -0
  33. package/nitrogen/generated/android/c++/JFirmwareArtifactReaderReadParams.hpp +65 -0
  34. package/nitrogen/generated/android/c++/JFirmwareArtifactReceipt.hpp +65 -0
  35. package/nitrogen/generated/android/c++/JFirmwareArtifactRefParams.hpp +57 -0
  36. package/nitrogen/generated/android/c++/JFirmwareArtifactSweepResult.hpp +61 -0
  37. package/nitrogen/generated/android/c++/JHybridReactNativeRangeDownloaderSpec.cpp +267 -0
  38. package/nitrogen/generated/android/c++/JHybridReactNativeRangeDownloaderSpec.hpp +13 -0
  39. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/DownloadChannel.kt +2 -1
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveExpectedEntry.kt +47 -0
  41. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializeParams.kt +44 -0
  42. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializeResult.kt +38 -0
  43. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializedArtifact.kt +41 -0
  44. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactCancelParams.kt +38 -0
  45. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactCapabilities.kt +47 -0
  46. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactDownloadParams.kt +68 -0
  47. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLease.kt +38 -0
  48. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseCreateParams.kt +38 -0
  49. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseReconcileParams.kt +38 -0
  50. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseReleaseParams.kt +41 -0
  51. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseRetainParams.kt +41 -0
  52. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReaderCloseParams.kt +38 -0
  53. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReaderInfo.kt +41 -0
  54. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReaderReadParams.kt +44 -0
  55. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReceipt.kt +44 -0
  56. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactRefParams.kt +38 -0
  57. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactSweepResult.kt +41 -0
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/HybridReactNativeRangeDownloaderSpec.kt +53 -0
  59. package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Bridge.cpp +48 -0
  60. package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Bridge.hpp +329 -0
  61. package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Umbrella.hpp +56 -0
  62. package/nitrogen/generated/ios/c++/HybridReactNativeRangeDownloaderSpecSwift.hpp +163 -0
  63. package/nitrogen/generated/ios/swift/DownloadChannel.swift +4 -0
  64. package/nitrogen/generated/ios/swift/FirmwareArchiveExpectedEntry.swift +69 -0
  65. package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializeParams.swift +70 -0
  66. package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializeResult.swift +48 -0
  67. package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializedArtifact.swift +47 -0
  68. package/nitrogen/generated/ios/swift/FirmwareArtifactCancelParams.swift +36 -0
  69. package/nitrogen/generated/ios/swift/FirmwareArtifactCapabilities.swift +81 -0
  70. package/nitrogen/generated/ios/swift/FirmwareArtifactDownloadParams.swift +177 -0
  71. package/nitrogen/generated/ios/swift/FirmwareArtifactLease.swift +36 -0
  72. package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseCreateParams.swift +36 -0
  73. package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseReconcileParams.swift +48 -0
  74. package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseReleaseParams.swift +47 -0
  75. package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseRetainParams.swift +47 -0
  76. package/nitrogen/generated/ios/swift/FirmwareArtifactReaderCloseParams.swift +36 -0
  77. package/nitrogen/generated/ios/swift/FirmwareArtifactReaderInfo.swift +47 -0
  78. package/nitrogen/generated/ios/swift/FirmwareArtifactReaderReadParams.swift +58 -0
  79. package/nitrogen/generated/ios/swift/FirmwareArtifactReceipt.swift +58 -0
  80. package/nitrogen/generated/ios/swift/FirmwareArtifactRefParams.swift +36 -0
  81. package/nitrogen/generated/ios/swift/FirmwareArtifactSweepResult.swift +47 -0
  82. package/nitrogen/generated/ios/swift/Func_void_FirmwareArchiveMaterializeResult.swift +47 -0
  83. package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactLease.swift +47 -0
  84. package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactReaderInfo.swift +47 -0
  85. package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactReceipt.swift +47 -0
  86. package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactSweepResult.swift +47 -0
  87. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_ArrayBuffer_.swift +47 -0
  88. package/nitrogen/generated/ios/swift/HybridReactNativeRangeDownloaderSpec.swift +13 -0
  89. package/nitrogen/generated/ios/swift/HybridReactNativeRangeDownloaderSpec_cxx.swift +240 -0
  90. package/nitrogen/generated/shared/c++/DownloadChannel.hpp +4 -0
  91. package/nitrogen/generated/shared/c++/FirmwareArchiveExpectedEntry.hpp +87 -0
  92. package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializeParams.hpp +86 -0
  93. package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializeResult.hpp +77 -0
  94. package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializedArtifact.hpp +81 -0
  95. package/nitrogen/generated/shared/c++/FirmwareArtifactCancelParams.hpp +75 -0
  96. package/nitrogen/generated/shared/c++/FirmwareArtifactCapabilities.hpp +88 -0
  97. package/nitrogen/generated/shared/c++/FirmwareArtifactDownloadParams.hpp +116 -0
  98. package/nitrogen/generated/shared/c++/FirmwareArtifactLease.hpp +75 -0
  99. package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseCreateParams.hpp +75 -0
  100. package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseReconcileParams.hpp +76 -0
  101. package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseReleaseParams.hpp +79 -0
  102. package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseRetainParams.hpp +79 -0
  103. package/nitrogen/generated/shared/c++/FirmwareArtifactReaderCloseParams.hpp +75 -0
  104. package/nitrogen/generated/shared/c++/FirmwareArtifactReaderInfo.hpp +79 -0
  105. package/nitrogen/generated/shared/c++/FirmwareArtifactReaderReadParams.hpp +83 -0
  106. package/nitrogen/generated/shared/c++/FirmwareArtifactReceipt.hpp +83 -0
  107. package/nitrogen/generated/shared/c++/FirmwareArtifactRefParams.hpp +75 -0
  108. package/nitrogen/generated/shared/c++/FirmwareArtifactSweepResult.hpp +79 -0
  109. package/nitrogen/generated/shared/c++/HybridReactNativeRangeDownloaderSpec.cpp +13 -0
  110. package/nitrogen/generated/shared/c++/HybridReactNativeRangeDownloaderSpec.hpp +62 -0
  111. package/package.json +4 -2
  112. package/src/ReactNativeRangeDownloader.nitro.ts +134 -1
  113. 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