@hot-updater/react-native 1.0.0-rc.1 → 1.0.0-rc.15
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/android/proguard-rules.pro +17 -2
- package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
- package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +651 -637
- package/android/src/main/java/com/hotupdater/BundleMetadata.kt +10 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +0 -13
- package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +10 -14
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +37 -54
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +64 -0
- package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +19 -0
- package/android/src/main/java/com/hotupdater/TarArchiveInputStream.kt +214 -375
- package/android/src/main/java/com/hotupdater/TarBrArchiveExtractor.kt +119 -0
- package/android/src/newarch/HotUpdater.kt +7 -9
- package/android/src/newarch/HotUpdaterModule.kt +40 -20
- package/android/src/oldarch/HotUpdater.kt +7 -9
- package/android/src/oldarch/HotUpdaterModule.kt +40 -20
- package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +1126 -74
- package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +4 -5
- package/android/src/test/java/com/hotupdater/HotUpdaterRecoveryStateTest.kt +97 -0
- package/android/src/test/java/com/hotupdater/PendingCrashRecoveryTest.kt +44 -0
- package/android/src/test/java/com/hotupdater/TarBrArchiveExtractorTest.kt +206 -0
- package/ios/HotUpdater/Internal/BrotliFileDecompressor.swift +167 -0
- package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +196 -0
- package/ios/HotUpdater/Internal/BundleFileStorageService.swift +773 -1016
- package/ios/HotUpdater/Internal/BundleMetadata.swift +5 -0
- package/ios/HotUpdater/Internal/FileUtilities.swift +64 -0
- package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +0 -1
- package/ios/HotUpdater/Internal/HotUpdater.mm +5 -27
- package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +149 -51
- package/ios/HotUpdater/Internal/NotificationExtension.swift +0 -2
- package/ios/HotUpdater/Internal/TarArchiveExtractor.swift +182 -311
- package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +13 -72
- package/ios/HotUpdater/Recovery/HotUpdaterRecovery.h +16 -0
- package/ios/HotUpdater/Recovery/HotUpdaterRecovery.mm +83 -0
- package/ios/HotUpdater/Recovery/HotUpdaterRecoveryHooks.mm +49 -0
- package/lib/commonjs/checkForUpdate.js +32 -23
- package/lib/commonjs/checkForUpdate.js.map +1 -1
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +97 -28
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +1 -1
- package/lib/commonjs/error.js +4 -13
- package/lib/commonjs/error.js.map +1 -1
- package/lib/commonjs/fetchJSON.js +9 -2
- package/lib/commonjs/fetchJSON.js.map +1 -1
- package/lib/commonjs/httpClient.js +46 -29
- package/lib/commonjs/httpClient.js.map +1 -1
- package/lib/commonjs/httpClient.spec.js +57 -5
- package/lib/commonjs/httpClient.spec.js.map +1 -1
- package/lib/commonjs/index.js +31 -14
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.spec.js +56 -11
- package/lib/commonjs/index.spec.js.map +1 -1
- package/lib/commonjs/native.js +15 -14
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/native.spec.js +128 -22
- package/lib/commonjs/native.spec.js.map +1 -1
- package/lib/commonjs/{notifyAppReadyAnalytics.boundary.spec.js → notifyAppReadyInsights.boundary.spec.js} +28 -21
- package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +1 -0
- package/lib/commonjs/notifyAppReadyInsights.js +188 -0
- package/lib/commonjs/notifyAppReadyInsights.js.map +1 -0
- package/lib/commonjs/{notifyAppReadyAnalytics.spec.js → notifyAppReadyInsights.spec.js} +161 -29
- package/lib/commonjs/notifyAppReadyInsights.spec.js.map +1 -0
- package/lib/commonjs/{notifyAppReadyAnalytics.test-utils.js → notifyAppReadyInsights.test-utils.js} +3 -3
- package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +1 -0
- package/lib/commonjs/{notifyAppReadyAnalytics.transport.spec.js → notifyAppReadyInsights.transport.spec.js} +14 -7
- package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +1 -0
- package/lib/commonjs/sdkVersion.js +1 -1
- package/lib/commonjs/sdkVersion.js.map +1 -1
- package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
- package/lib/commonjs/store.js +3 -10
- package/lib/commonjs/store.js.map +1 -1
- package/lib/commonjs/store.notification.spec.js +12 -4
- package/lib/commonjs/store.notification.spec.js.map +1 -1
- package/lib/commonjs/store.spec.js +2 -136
- package/lib/commonjs/store.spec.js.map +1 -1
- package/lib/commonjs/wrap.js +11 -12
- package/lib/commonjs/wrap.js.map +1 -1
- package/lib/commonjs/wrap.spec.js +97 -25
- package/lib/commonjs/wrap.spec.js.map +1 -1
- package/lib/module/checkForUpdate.js +32 -23
- package/lib/module/checkForUpdate.js.map +1 -1
- package/lib/module/checkForUpdate.releaseCatalog.spec.js +97 -28
- package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +1 -1
- package/lib/module/error.js +4 -13
- package/lib/module/error.js.map +1 -1
- package/lib/module/fetchJSON.js +7 -1
- package/lib/module/fetchJSON.js.map +1 -1
- package/lib/module/httpClient.js +48 -31
- package/lib/module/httpClient.js.map +1 -1
- package/lib/module/httpClient.spec.js +57 -5
- package/lib/module/httpClient.spec.js.map +1 -1
- package/lib/module/index.js +32 -15
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.spec.js +56 -11
- package/lib/module/index.spec.js.map +1 -1
- package/lib/module/native.js +13 -12
- package/lib/module/native.js.map +1 -1
- package/lib/module/native.spec.js +128 -22
- package/lib/module/native.spec.js.map +1 -1
- package/lib/module/{notifyAppReadyAnalytics.boundary.spec.js → notifyAppReadyInsights.boundary.spec.js} +23 -16
- package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +1 -0
- package/lib/module/notifyAppReadyInsights.js +181 -0
- package/lib/module/notifyAppReadyInsights.js.map +1 -0
- package/lib/module/{notifyAppReadyAnalytics.spec.js → notifyAppReadyInsights.spec.js} +153 -21
- package/lib/module/notifyAppReadyInsights.spec.js.map +1 -0
- package/lib/module/{notifyAppReadyAnalytics.test-utils.js → notifyAppReadyInsights.test-utils.js} +3 -3
- package/lib/module/notifyAppReadyInsights.test-utils.js.map +1 -0
- package/lib/module/{notifyAppReadyAnalytics.transport.spec.js → notifyAppReadyInsights.transport.spec.js} +11 -4
- package/lib/module/notifyAppReadyInsights.transport.spec.js.map +1 -0
- package/lib/module/sdkVersion.js +1 -1
- package/lib/module/sdkVersion.js.map +1 -1
- package/lib/module/specs/NativeHotUpdater.js.map +1 -1
- package/lib/module/store.js +3 -10
- package/lib/module/store.js.map +1 -1
- package/lib/module/store.notification.spec.js +12 -4
- package/lib/module/store.notification.spec.js.map +1 -1
- package/lib/module/store.spec.js +2 -136
- package/lib/module/store.spec.js.map +1 -1
- package/lib/module/wrap.js +11 -12
- package/lib/module/wrap.js.map +1 -1
- package/lib/module/wrap.spec.js +99 -25
- package/lib/module/wrap.spec.js.map +1 -1
- package/lib/typescript/commonjs/checkForUpdate.d.ts +2 -3
- package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/commonjs/error.d.ts +4 -13
- package/lib/typescript/commonjs/error.d.ts.map +1 -1
- package/lib/typescript/commonjs/fetchJSON.d.ts +4 -0
- package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
- package/lib/typescript/commonjs/httpClient.d.ts +6 -6
- package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -7
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/native.d.ts +5 -9
- package/lib/typescript/commonjs/native.d.ts.map +1 -1
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +25 -0
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +1 -0
- package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +8 -0
- package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
- package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +8 -35
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/commonjs/store.d.ts +1 -3
- package/lib/typescript/commonjs/store.d.ts.map +1 -1
- package/lib/typescript/commonjs/wrap.types.d.ts +5 -8
- package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
- package/lib/typescript/module/checkForUpdate.d.ts +2 -3
- package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/module/error.d.ts +4 -13
- package/lib/typescript/module/error.d.ts.map +1 -1
- package/lib/typescript/module/fetchJSON.d.ts +4 -0
- package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
- package/lib/typescript/module/httpClient.d.ts +6 -6
- package/lib/typescript/module/httpClient.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +4 -7
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/native.d.ts +5 -9
- package/lib/typescript/module/native.d.ts.map +1 -1
- package/lib/typescript/module/notifyAppReadyInsights.d.ts +25 -0
- package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +1 -0
- package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +8 -0
- package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +1 -0
- package/lib/typescript/module/sdkVersion.d.ts +1 -1
- package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts +8 -35
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/module/store.d.ts +1 -3
- package/lib/typescript/module/store.d.ts.map +1 -1
- package/lib/typescript/module/wrap.types.d.ts +5 -8
- package/lib/typescript/module/wrap.types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/checkForUpdate.releaseCatalog.spec.ts +137 -61
- package/src/checkForUpdate.ts +35 -29
- package/src/error.ts +4 -14
- package/src/fetchJSON.ts +12 -1
- package/src/httpClient.spec.ts +70 -5
- package/src/httpClient.ts +78 -64
- package/src/index.spec.ts +59 -11
- package/src/index.ts +41 -17
- package/src/native.spec.ts +133 -22
- package/src/native.ts +21 -32
- package/src/{notifyAppReadyAnalytics.boundary.spec.ts → notifyAppReadyInsights.boundary.spec.ts} +25 -17
- package/src/{notifyAppReadyAnalytics.spec.ts → notifyAppReadyInsights.spec.ts} +141 -22
- package/src/{notifyAppReadyAnalytics.test-utils.ts → notifyAppReadyInsights.test-utils.ts} +4 -4
- package/src/{notifyAppReadyAnalytics.transport.spec.ts → notifyAppReadyInsights.transport.spec.ts} +13 -5
- package/src/notifyAppReadyInsights.ts +293 -0
- package/src/sdkVersion.ts +1 -1
- package/src/specs/NativeHotUpdater.ts +8 -36
- package/src/store.notification.spec.ts +13 -3
- package/src/store.spec.ts +0 -157
- package/src/store.ts +2 -23
- package/src/wrap.spec.ts +109 -31
- package/src/wrap.tsx +11 -11
- package/src/wrap.types.ts +5 -8
- package/android/src/main/java/com/hotupdater/DecompressService.kt +0 -89
- package/android/src/main/java/com/hotupdater/DecompressionStrategy.kt +0 -26
- package/android/src/main/java/com/hotupdater/TarBrDecompressionStrategy.kt +0 -117
- package/android/src/main/java/com/hotupdater/TarGzDecompressionStrategy.kt +0 -117
- package/android/src/main/java/com/hotupdater/ZipDecompressionStrategy.kt +0 -192
- package/android/src/test/java/com/hotupdater/TarArchiveInputStreamTest.kt +0 -68
- package/ios/HotUpdater/Internal/ArchiveExtractionUtilities.swift +0 -178
- package/ios/HotUpdater/Internal/DecompressService.swift +0 -112
- package/ios/HotUpdater/Internal/DecompressionStrategy.swift +0 -22
- package/ios/HotUpdater/Internal/StreamingTarArchiveExtractor.swift +0 -370
- package/ios/HotUpdater/Internal/TarBrDecompressionStrategy.swift +0 -39
- package/ios/HotUpdater/Internal/TarGzDecompressionStrategy.swift +0 -59
- package/ios/HotUpdater/Internal/ZipArchiveExtractor.swift +0 -482
- package/ios/HotUpdater/Internal/ZipDecompressionStrategy.swift +0 -56
- package/lib/commonjs/notifyAppReadyAnalytics.boundary.spec.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.js +0 -133
- package/lib/commonjs/notifyAppReadyAnalytics.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.spec.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.test-utils.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.transport.spec.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.boundary.spec.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.js +0 -128
- package/lib/module/notifyAppReadyAnalytics.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.spec.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.test-utils.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.transport.spec.js.map +0 -1
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts +0 -13
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts.map +0 -1
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts +0 -8
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts.map +0 -1
- package/lib/typescript/module/notifyAppReadyAnalytics.d.ts +0 -13
- package/lib/typescript/module/notifyAppReadyAnalytics.d.ts.map +0 -1
- package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts +0 -8
- package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts.map +0 -1
- package/src/notifyAppReadyAnalytics.ts +0 -194
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
import Compression
|
|
2
|
-
import Foundation
|
|
3
|
-
import zlib
|
|
4
|
-
|
|
5
|
-
enum CompressedTarAlgorithm {
|
|
6
|
-
case gzip
|
|
7
|
-
case brotli
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
enum StreamingTarArchiveExtractor {
|
|
11
|
-
private static let bufferSize = 64 * 1024
|
|
12
|
-
private static let decompressionProgressWeight = 0.45
|
|
13
|
-
|
|
14
|
-
static func extractCompressedTar(
|
|
15
|
-
file: String,
|
|
16
|
-
to destination: String,
|
|
17
|
-
algorithm: CompressedTarAlgorithm,
|
|
18
|
-
progressHandler: @escaping (Double) -> Void
|
|
19
|
-
) throws {
|
|
20
|
-
try withTemporaryTarFile { temporaryTarURL in
|
|
21
|
-
switch algorithm {
|
|
22
|
-
case .gzip:
|
|
23
|
-
try decompressGzipArchive(
|
|
24
|
-
from: file,
|
|
25
|
-
to: temporaryTarURL.path,
|
|
26
|
-
progressHandler: { progress in
|
|
27
|
-
progressHandler(progress * decompressionProgressWeight)
|
|
28
|
-
}
|
|
29
|
-
)
|
|
30
|
-
case .brotli:
|
|
31
|
-
try decompressBrotliArchive(
|
|
32
|
-
from: file,
|
|
33
|
-
to: temporaryTarURL.path,
|
|
34
|
-
progressHandler: { progress in
|
|
35
|
-
progressHandler(progress * decompressionProgressWeight)
|
|
36
|
-
}
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
try extractTarArchive(
|
|
41
|
-
from: temporaryTarURL.path,
|
|
42
|
-
to: destination,
|
|
43
|
-
progressHandler: { progress in
|
|
44
|
-
let extractionStart = decompressionProgressWeight
|
|
45
|
-
let extractionWeight = 1.0 - decompressionProgressWeight
|
|
46
|
-
progressHandler(extractionStart + (progress * extractionWeight))
|
|
47
|
-
}
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
static func decompressBrotliFile(
|
|
53
|
-
from sourcePath: String,
|
|
54
|
-
to outputPath: String
|
|
55
|
-
) throws {
|
|
56
|
-
try decompressBrotliArchive(
|
|
57
|
-
from: sourcePath,
|
|
58
|
-
to: outputPath,
|
|
59
|
-
progressHandler: { _ in }
|
|
60
|
-
)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static func containsTarEntries(file: String, algorithm: CompressedTarAlgorithm) -> Bool {
|
|
64
|
-
do {
|
|
65
|
-
return try withTemporaryTarFile { temporaryTarURL in
|
|
66
|
-
switch algorithm {
|
|
67
|
-
case .gzip:
|
|
68
|
-
try decompressGzipArchive(
|
|
69
|
-
from: file,
|
|
70
|
-
to: temporaryTarURL.path,
|
|
71
|
-
progressHandler: { _ in }
|
|
72
|
-
)
|
|
73
|
-
case .brotli:
|
|
74
|
-
try decompressBrotliArchive(
|
|
75
|
-
from: file,
|
|
76
|
-
to: temporaryTarURL.path,
|
|
77
|
-
progressHandler: { _ in }
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return try tarArchiveHasEntries(at: temporaryTarURL.path)
|
|
82
|
-
}
|
|
83
|
-
} catch {
|
|
84
|
-
NSLog("[TarStreamExtractor] Validation failed: \(error.localizedDescription)")
|
|
85
|
-
return false
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private static func withTemporaryTarFile<T>(
|
|
90
|
-
perform: (URL) throws -> T
|
|
91
|
-
) throws -> T {
|
|
92
|
-
let temporaryTarURL = FileManager.default.temporaryDirectory
|
|
93
|
-
.appendingPathComponent("hot-updater-\(UUID().uuidString)")
|
|
94
|
-
.appendingPathExtension("tar")
|
|
95
|
-
|
|
96
|
-
defer {
|
|
97
|
-
try? FileManager.default.removeItem(at: temporaryTarURL)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return try perform(temporaryTarURL)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private static func tarArchiveHasEntries(at tarPath: String) throws -> Bool {
|
|
104
|
-
try TarArchiveExtractor.containsEntries(at: tarPath)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private static func extractTarArchive(
|
|
108
|
-
from tarPath: String,
|
|
109
|
-
to destination: String,
|
|
110
|
-
progressHandler: @escaping (Double) -> Void
|
|
111
|
-
) throws {
|
|
112
|
-
try TarArchiveExtractor.extract(
|
|
113
|
-
from: tarPath,
|
|
114
|
-
to: destination,
|
|
115
|
-
progressHandler: progressHandler
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
private static func decompressGzipArchive(
|
|
120
|
-
from sourcePath: String,
|
|
121
|
-
to outputPath: String,
|
|
122
|
-
progressHandler: @escaping (Double) -> Void
|
|
123
|
-
) throws {
|
|
124
|
-
let totalSourceSize = try fileSize(atPath: sourcePath)
|
|
125
|
-
try prepareEmptyFile(at: outputPath)
|
|
126
|
-
|
|
127
|
-
let outputHandle = try FileHandle(forWritingTo: URL(fileURLWithPath: outputPath))
|
|
128
|
-
|
|
129
|
-
defer {
|
|
130
|
-
try? outputHandle.close()
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
guard let gzipFile = sourcePath.withCString({ pathPointer in
|
|
134
|
-
"rb".withCString { modePointer in
|
|
135
|
-
gzopen(pathPointer, modePointer)
|
|
136
|
-
}
|
|
137
|
-
}) else {
|
|
138
|
-
throw NSError(
|
|
139
|
-
domain: "StreamingTarArchiveExtractor",
|
|
140
|
-
code: 5,
|
|
141
|
-
userInfo: [NSLocalizedDescriptionKey: "Failed to open gzip archive"]
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
defer {
|
|
146
|
-
gzclose(gzipFile)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
var buffer = [UInt8](repeating: 0, count: bufferSize)
|
|
150
|
-
|
|
151
|
-
while true {
|
|
152
|
-
let bytesRead = gzread(gzipFile, &buffer, UInt32(buffer.count))
|
|
153
|
-
|
|
154
|
-
if bytesRead > 0 {
|
|
155
|
-
outputHandle.write(Data(buffer[0..<Int(bytesRead)]))
|
|
156
|
-
|
|
157
|
-
if totalSourceSize > 0 {
|
|
158
|
-
let compressedOffset = max(Int64(gzoffset(gzipFile)), 0)
|
|
159
|
-
let progress = min(Double(compressedOffset) / Double(totalSourceSize), 1.0)
|
|
160
|
-
progressHandler(progress)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
continue
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if bytesRead == 0 {
|
|
167
|
-
progressHandler(1.0)
|
|
168
|
-
return
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
var errorCode: Int32 = 0
|
|
172
|
-
let messagePointer = gzerror(gzipFile, &errorCode)
|
|
173
|
-
let message = messagePointer.map { String(cString: $0) } ?? "Unknown gzip error"
|
|
174
|
-
|
|
175
|
-
throw NSError(
|
|
176
|
-
domain: "StreamingTarArchiveExtractor",
|
|
177
|
-
code: Int(errorCode),
|
|
178
|
-
userInfo: [NSLocalizedDescriptionKey: "GZIP decompression failed: \(message)"]
|
|
179
|
-
)
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
private static func decompressBrotliArchive(
|
|
184
|
-
from sourcePath: String,
|
|
185
|
-
to outputPath: String,
|
|
186
|
-
progressHandler: @escaping (Double) -> Void
|
|
187
|
-
) throws {
|
|
188
|
-
let totalSourceSize = try fileSize(atPath: sourcePath)
|
|
189
|
-
try prepareEmptyFile(at: outputPath)
|
|
190
|
-
|
|
191
|
-
let inputHandle = try FileHandle(forReadingFrom: URL(fileURLWithPath: sourcePath))
|
|
192
|
-
let outputHandle = try FileHandle(forWritingTo: URL(fileURLWithPath: outputPath))
|
|
193
|
-
|
|
194
|
-
defer {
|
|
195
|
-
try? inputHandle.close()
|
|
196
|
-
try? outputHandle.close()
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
var stream = compression_stream(
|
|
200
|
-
dst_ptr: UnsafeMutablePointer<UInt8>(bitPattern: 1)!,
|
|
201
|
-
dst_size: 0,
|
|
202
|
-
src_ptr: UnsafePointer<UInt8>(bitPattern: 1)!,
|
|
203
|
-
src_size: 0,
|
|
204
|
-
state: nil
|
|
205
|
-
)
|
|
206
|
-
let status = compression_stream_init(&stream, COMPRESSION_STREAM_DECODE, COMPRESSION_BROTLI)
|
|
207
|
-
|
|
208
|
-
guard status == COMPRESSION_STATUS_OK else {
|
|
209
|
-
throw NSError(
|
|
210
|
-
domain: "StreamingTarArchiveExtractor",
|
|
211
|
-
code: 6,
|
|
212
|
-
userInfo: [NSLocalizedDescriptionKey: "Failed to initialize Brotli decompression stream"]
|
|
213
|
-
)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
defer {
|
|
217
|
-
compression_stream_destroy(&stream)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
let outputBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
|
|
221
|
-
|
|
222
|
-
defer {
|
|
223
|
-
outputBuffer.deallocate()
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
var processedSourceBytes: UInt64 = 0
|
|
227
|
-
var reachedStreamEnd = false
|
|
228
|
-
|
|
229
|
-
while !reachedStreamEnd {
|
|
230
|
-
let chunk = try ArchiveExtractionUtilities.readUpToCount(
|
|
231
|
-
from: inputHandle,
|
|
232
|
-
count: bufferSize
|
|
233
|
-
) ?? Data()
|
|
234
|
-
processedSourceBytes += UInt64(chunk.count)
|
|
235
|
-
|
|
236
|
-
let streamStatus: compression_status
|
|
237
|
-
if chunk.isEmpty {
|
|
238
|
-
stream.src_ptr = UnsafePointer<UInt8>(bitPattern: 1)!
|
|
239
|
-
stream.src_size = 0
|
|
240
|
-
streamStatus = try flushCompressionStream(
|
|
241
|
-
&stream,
|
|
242
|
-
into: outputHandle,
|
|
243
|
-
outputBuffer: outputBuffer,
|
|
244
|
-
finalize: true
|
|
245
|
-
)
|
|
246
|
-
} else {
|
|
247
|
-
streamStatus = try chunk.withUnsafeBytes { rawBuffer in
|
|
248
|
-
guard let baseAddress = rawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
|
249
|
-
return COMPRESSION_STATUS_OK
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
stream.src_ptr = baseAddress
|
|
253
|
-
stream.src_size = chunk.count
|
|
254
|
-
|
|
255
|
-
return try flushCompressionStream(
|
|
256
|
-
&stream,
|
|
257
|
-
into: outputHandle,
|
|
258
|
-
outputBuffer: outputBuffer,
|
|
259
|
-
finalize: false
|
|
260
|
-
)
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if totalSourceSize > 0 {
|
|
265
|
-
let progress = min(Double(processedSourceBytes) / Double(totalSourceSize), 1.0)
|
|
266
|
-
progressHandler(progress)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if streamStatus == COMPRESSION_STATUS_END {
|
|
270
|
-
reachedStreamEnd = true
|
|
271
|
-
} else if chunk.isEmpty {
|
|
272
|
-
throw NSError(
|
|
273
|
-
domain: "StreamingTarArchiveExtractor",
|
|
274
|
-
code: 7,
|
|
275
|
-
userInfo: [NSLocalizedDescriptionKey: "Brotli decompression ended before reaching the end of stream"]
|
|
276
|
-
)
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
progressHandler(1.0)
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
private static func flushCompressionStream(
|
|
284
|
-
_ stream: inout compression_stream,
|
|
285
|
-
into outputHandle: FileHandle,
|
|
286
|
-
outputBuffer: UnsafeMutablePointer<UInt8>,
|
|
287
|
-
finalize: Bool
|
|
288
|
-
) throws -> compression_status {
|
|
289
|
-
let flags = finalize ? Int32(COMPRESSION_STREAM_FINALIZE.rawValue) : 0
|
|
290
|
-
var lastStatus = COMPRESSION_STATUS_OK
|
|
291
|
-
|
|
292
|
-
repeat {
|
|
293
|
-
let previousSourceSize = stream.src_size
|
|
294
|
-
|
|
295
|
-
stream.dst_ptr = outputBuffer
|
|
296
|
-
stream.dst_size = bufferSize
|
|
297
|
-
|
|
298
|
-
lastStatus = compression_stream_process(&stream, flags)
|
|
299
|
-
|
|
300
|
-
switch lastStatus {
|
|
301
|
-
case COMPRESSION_STATUS_OK, COMPRESSION_STATUS_END:
|
|
302
|
-
let producedBytes = bufferSize - stream.dst_size
|
|
303
|
-
if producedBytes > 0 {
|
|
304
|
-
outputHandle.write(
|
|
305
|
-
Data(bytes: outputBuffer, count: producedBytes)
|
|
306
|
-
)
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if finalize,
|
|
310
|
-
lastStatus == COMPRESSION_STATUS_OK,
|
|
311
|
-
producedBytes == 0,
|
|
312
|
-
previousSourceSize == stream.src_size {
|
|
313
|
-
throw NSError(
|
|
314
|
-
domain: "StreamingTarArchiveExtractor",
|
|
315
|
-
code: 8,
|
|
316
|
-
userInfo: [NSLocalizedDescriptionKey: "Brotli decompression stalled before reaching the end of stream"]
|
|
317
|
-
)
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
default:
|
|
321
|
-
throw NSError(
|
|
322
|
-
domain: "StreamingTarArchiveExtractor",
|
|
323
|
-
code: 9,
|
|
324
|
-
userInfo: [NSLocalizedDescriptionKey: "Brotli decompression failed"]
|
|
325
|
-
)
|
|
326
|
-
}
|
|
327
|
-
} while stream.src_size > 0 || stream.dst_size == 0 || (finalize && lastStatus == COMPRESSION_STATUS_OK)
|
|
328
|
-
|
|
329
|
-
return lastStatus
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
private static func prepareEmptyFile(at path: String) throws {
|
|
333
|
-
let fileManager = FileManager.default
|
|
334
|
-
let parentDirectory = (path as NSString).deletingLastPathComponent
|
|
335
|
-
|
|
336
|
-
if !fileManager.fileExists(atPath: parentDirectory) {
|
|
337
|
-
try fileManager.createDirectory(
|
|
338
|
-
atPath: parentDirectory,
|
|
339
|
-
withIntermediateDirectories: true,
|
|
340
|
-
attributes: nil
|
|
341
|
-
)
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if fileManager.fileExists(atPath: path) {
|
|
345
|
-
try fileManager.removeItem(atPath: path)
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
guard fileManager.createFile(atPath: path, contents: nil) else {
|
|
349
|
-
throw NSError(
|
|
350
|
-
domain: "StreamingTarArchiveExtractor",
|
|
351
|
-
code: 10,
|
|
352
|
-
userInfo: [NSLocalizedDescriptionKey: "Failed to create temporary archive file"]
|
|
353
|
-
)
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
private static func fileSize(atPath path: String) throws -> UInt64 {
|
|
358
|
-
let attributes = try FileManager.default.attributesOfItem(atPath: path)
|
|
359
|
-
if let value = attributes[.size] as? NSNumber {
|
|
360
|
-
return value.uint64Value
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if let value = attributes[.size] as? UInt64 {
|
|
364
|
-
return value
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return 0
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Strategy for handling TAR+Brotli compressed files
|
|
5
|
-
*/
|
|
6
|
-
class TarBrDecompressionStrategy: DecompressionStrategy {
|
|
7
|
-
private static let MIN_FILE_SIZE: UInt64 = 10
|
|
8
|
-
|
|
9
|
-
func isValid(file: String) -> Bool {
|
|
10
|
-
guard FileManager.default.fileExists(atPath: file) else {
|
|
11
|
-
NSLog("[TarBrStrategy] Invalid file: doesn't exist")
|
|
12
|
-
return false
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
do {
|
|
16
|
-
let attributes = try FileManager.default.attributesOfItem(atPath: file)
|
|
17
|
-
guard let fileSize = attributes[.size] as? UInt64, fileSize >= Self.MIN_FILE_SIZE else {
|
|
18
|
-
NSLog("[TarBrStrategy] Invalid file: too small")
|
|
19
|
-
return false
|
|
20
|
-
}
|
|
21
|
-
} catch {
|
|
22
|
-
NSLog("[TarBrStrategy] Invalid file: cannot read attributes - \(error.localizedDescription)")
|
|
23
|
-
return false
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return StreamingTarArchiveExtractor.containsTarEntries(file: file, algorithm: .brotli)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
func decompress(file: String, to destination: String, progressHandler: @escaping (Double) -> Void) throws {
|
|
30
|
-
NSLog("[TarBrStrategy] Starting extraction of \(file) to \(destination)")
|
|
31
|
-
try StreamingTarArchiveExtractor.extractCompressedTar(
|
|
32
|
-
file: file,
|
|
33
|
-
to: destination,
|
|
34
|
-
algorithm: .brotli,
|
|
35
|
-
progressHandler: progressHandler
|
|
36
|
-
)
|
|
37
|
-
NSLog("[TarBrStrategy] Successfully extracted all entries")
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Strategy for handling TAR+GZIP compressed files
|
|
5
|
-
*/
|
|
6
|
-
class TarGzDecompressionStrategy: DecompressionStrategy {
|
|
7
|
-
private static let MIN_FILE_SIZE: UInt64 = 10
|
|
8
|
-
|
|
9
|
-
func isValid(file: String) -> Bool {
|
|
10
|
-
guard FileManager.default.fileExists(atPath: file) else {
|
|
11
|
-
NSLog("[TarGzStrategy] Invalid file: doesn't exist")
|
|
12
|
-
return false
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
do {
|
|
16
|
-
let attributes = try FileManager.default.attributesOfItem(atPath: file)
|
|
17
|
-
guard let fileSize = attributes[.size] as? UInt64, fileSize >= Self.MIN_FILE_SIZE else {
|
|
18
|
-
NSLog("[TarGzStrategy] Invalid file: too small")
|
|
19
|
-
return false
|
|
20
|
-
}
|
|
21
|
-
} catch {
|
|
22
|
-
NSLog("[TarGzStrategy] Invalid file: cannot read attributes - \(error.localizedDescription)")
|
|
23
|
-
return false
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Check GZIP magic bytes (0x1F 0x8B)
|
|
27
|
-
guard let fileHandle = FileHandle(forReadingAtPath: file) else {
|
|
28
|
-
NSLog("[TarGzStrategy] Invalid file: cannot open file")
|
|
29
|
-
return false
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
defer {
|
|
33
|
-
fileHandle.closeFile()
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
guard let header = try? ArchiveExtractionUtilities.readUpToCount(from: fileHandle, count: 2),
|
|
37
|
-
header.count == 2 else {
|
|
38
|
-
NSLog("[TarGzStrategy] Invalid file: cannot read header")
|
|
39
|
-
return false
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
let isGzip = header[0] == 0x1F && header[1] == 0x8B
|
|
43
|
-
if !isGzip {
|
|
44
|
-
NSLog("[TarGzStrategy] Invalid file: wrong magic bytes (expected 0x1F 0x8B, got 0x\(String(format: "%02X", header[0])) 0x\(String(format: "%02X", header[1])))")
|
|
45
|
-
}
|
|
46
|
-
return isGzip
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
func decompress(file: String, to destination: String, progressHandler: @escaping (Double) -> Void) throws {
|
|
50
|
-
NSLog("[TarGzStrategy] Starting extraction of \(file) to \(destination)")
|
|
51
|
-
try StreamingTarArchiveExtractor.extractCompressedTar(
|
|
52
|
-
file: file,
|
|
53
|
-
to: destination,
|
|
54
|
-
algorithm: .gzip,
|
|
55
|
-
progressHandler: progressHandler
|
|
56
|
-
)
|
|
57
|
-
NSLog("[TarGzStrategy] Successfully extracted all entries")
|
|
58
|
-
}
|
|
59
|
-
}
|