@javascriptcommon/react-native-xz 1.0.0

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Aspect Apps
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # react-native-xz
2
+
3
+ Native XZ/LZMA2 decompression for React Native. Provides fast, efficient decompression of `.xz` files using native libraries on both iOS and Android.
4
+
5
+ ## Features
6
+
7
+ - Native XZ/LZMA2 decompression
8
+ - Decompress files to disk or directly to string
9
+ - iOS: Uses [SWCompression](https://github.com/tsolomko/SWCompression)
10
+ - Android: Uses [XZ for Java](https://tukaani.org/xz/java.html)
11
+ - Supports React Native 0.72+
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @javascriptcommon/react-native-xz
17
+ # or
18
+ yarn add @javascriptcommon/react-native-xz
19
+ ```
20
+
21
+ ### iOS
22
+
23
+ ```bash
24
+ cd ios && pod install
25
+ ```
26
+
27
+ ### Android
28
+
29
+ No additional setup required.
30
+
31
+ ## Usage
32
+
33
+ ```typescript
34
+ import { decompressFile, decompressToString } from '@javascriptcommon/react-native-xz';
35
+
36
+ // Decompress a file to another file
37
+ const outputPath = await decompressFile('/path/to/file.xz', '/path/to/output');
38
+
39
+ // Decompress a file directly to a string
40
+ const content = await decompressToString('/path/to/file.xz');
41
+ ```
42
+
43
+ ## API
44
+
45
+ ### `decompressFile(inputPath: string, outputPath: string): Promise<string>`
46
+
47
+ Decompresses an XZ file to a destination path.
48
+
49
+ - `inputPath`: Path to the `.xz` compressed file
50
+ - `outputPath`: Path where decompressed file will be written
51
+ - Returns: Promise resolving to the output path
52
+
53
+ ### `decompressToString(inputPath: string): Promise<string>`
54
+
55
+ Decompresses an XZ file and returns the contents as a UTF-8 string.
56
+
57
+ - `inputPath`: Path to the `.xz` compressed file
58
+ - Returns: Promise resolving to the decompressed string content
59
+
60
+ ## Requirements
61
+
62
+ - React Native >= 0.72.0
63
+ - iOS >= 13.0
64
+ - Android minSdk >= 21
65
+
66
+ ## License
67
+
68
+ MIT
@@ -0,0 +1,48 @@
1
+ buildscript {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ }
6
+ dependencies {
7
+ classpath "com.android.tools.build:gradle:7.4.2"
8
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10"
9
+ }
10
+ }
11
+
12
+ apply plugin: "com.android.library"
13
+ apply plugin: "kotlin-android"
14
+
15
+ android {
16
+ namespace "com.xz"
17
+ compileSdkVersion 34
18
+
19
+ defaultConfig {
20
+ minSdkVersion 21
21
+ targetSdkVersion 34
22
+ }
23
+
24
+ sourceSets {
25
+ main {
26
+ java.srcDirs = ['src/main/java']
27
+ }
28
+ }
29
+
30
+ compileOptions {
31
+ sourceCompatibility JavaVersion.VERSION_11
32
+ targetCompatibility JavaVersion.VERSION_11
33
+ }
34
+
35
+ kotlinOptions {
36
+ jvmTarget = "11"
37
+ }
38
+ }
39
+
40
+ repositories {
41
+ google()
42
+ mavenCentral()
43
+ }
44
+
45
+ dependencies {
46
+ implementation "com.facebook.react:react-android"
47
+ implementation "org.tukaani:xz:1.9"
48
+ }
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.xz">
3
+ </manifest>
@@ -0,0 +1,89 @@
1
+ package com.xz
2
+
3
+ import android.util.Log
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
6
+ import com.facebook.react.bridge.ReactMethod
7
+ import com.facebook.react.bridge.Promise
8
+ import org.tukaani.xz.XZInputStream
9
+ import java.io.File
10
+ import java.io.FileInputStream
11
+ import java.io.FileOutputStream
12
+ import java.io.ByteArrayOutputStream
13
+ import kotlinx.coroutines.CoroutineScope
14
+ import kotlinx.coroutines.Dispatchers
15
+ import kotlinx.coroutines.launch
16
+
17
+ class XzModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
18
+
19
+ companion object {
20
+ private const val TAG = "XzNative"
21
+ }
22
+
23
+ override fun getName(): String = "Xz"
24
+
25
+ @ReactMethod
26
+ fun decompressFile(inputPath: String, outputPath: String, promise: Promise) {
27
+ Log.d(TAG, "decompressFile called, input: $inputPath, output: $outputPath")
28
+ CoroutineScope(Dispatchers.IO).launch {
29
+ try {
30
+ val inputFile = File(inputPath)
31
+ val outputFile = File(outputPath)
32
+
33
+ Log.d(TAG, "Reading compressed file, size: ${inputFile.length()} bytes")
34
+
35
+ FileInputStream(inputFile).use { fis ->
36
+ XZInputStream(fis).use { xzis ->
37
+ FileOutputStream(outputFile).use { fos ->
38
+ val buffer = ByteArray(8192)
39
+ var bytesRead: Int
40
+ var totalBytes = 0L
41
+ while (xzis.read(buffer).also { bytesRead = it } != -1) {
42
+ fos.write(buffer, 0, bytesRead)
43
+ totalBytes += bytesRead
44
+ }
45
+ Log.d(TAG, "Decompressed size: $totalBytes bytes")
46
+ }
47
+ }
48
+ }
49
+
50
+ Log.d(TAG, "Written to output file")
51
+ promise.resolve(outputPath)
52
+ } catch (e: Exception) {
53
+ Log.e(TAG, "Error: ${e.message}", e)
54
+ promise.reject("XZ_ERROR", "Failed to decompress XZ file: ${e.message}", e)
55
+ }
56
+ }
57
+ }
58
+
59
+ @ReactMethod
60
+ fun decompressToString(inputPath: String, promise: Promise) {
61
+ Log.d(TAG, "decompressToString called, input: $inputPath")
62
+ CoroutineScope(Dispatchers.IO).launch {
63
+ try {
64
+ val inputFile = File(inputPath)
65
+ Log.d(TAG, "Reading compressed file, size: ${inputFile.length()} bytes")
66
+
67
+ val result = FileInputStream(inputFile).use { fis ->
68
+ XZInputStream(fis).use { xzis ->
69
+ ByteArrayOutputStream().use { baos ->
70
+ val buffer = ByteArray(8192)
71
+ var bytesRead: Int
72
+ while (xzis.read(buffer).also { bytesRead = it } != -1) {
73
+ baos.write(buffer, 0, bytesRead)
74
+ }
75
+ Log.d(TAG, "Decompressed size: ${baos.size()} bytes")
76
+ baos.toString("UTF-8")
77
+ }
78
+ }
79
+ }
80
+
81
+ Log.d(TAG, "String length: ${result.length} characters")
82
+ promise.resolve(result)
83
+ } catch (e: Exception) {
84
+ Log.e(TAG, "Error: ${e.message}", e)
85
+ promise.reject("XZ_ERROR", "Failed to decompress XZ file: ${e.message}", e)
86
+ }
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,16 @@
1
+ package com.xz
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ class XzPackage : ReactPackage {
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
+ return listOf(XzModule(reactContext))
11
+ }
12
+
13
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
14
+ return emptyList()
15
+ }
16
+ }
@@ -0,0 +1 @@
1
+ #import <React/RCTBridgeModule.h>
package/ios/Xz.h ADDED
@@ -0,0 +1,11 @@
1
+ #ifdef RCT_NEW_ARCH_ENABLED
2
+ #import "RNXzSpec/RNXzSpec.h"
3
+
4
+ @interface Xz : NSObject <NativeXzSpec>
5
+ #else
6
+ #import <React/RCTBridgeModule.h>
7
+
8
+ @interface Xz : NSObject <RCTBridgeModule>
9
+ #endif
10
+
11
+ @end
package/ios/Xz.mm ADDED
@@ -0,0 +1,14 @@
1
+ #import <React/RCTBridgeModule.h>
2
+
3
+ @interface RCT_EXTERN_MODULE(Xz, NSObject)
4
+
5
+ RCT_EXTERN_METHOD(decompressFile:(NSString *)inputPath
6
+ outputPath:(NSString *)outputPath
7
+ resolve:(RCTPromiseResolveBlock)resolve
8
+ reject:(RCTPromiseRejectBlock)reject)
9
+
10
+ RCT_EXTERN_METHOD(decompressToString:(NSString *)inputPath
11
+ resolve:(RCTPromiseResolveBlock)resolve
12
+ reject:(RCTPromiseRejectBlock)reject)
13
+
14
+ @end
package/ios/Xz.swift ADDED
@@ -0,0 +1,67 @@
1
+ import Foundation
2
+ import SWCompression
3
+
4
+ @objc(Xz)
5
+ class Xz: NSObject {
6
+
7
+ @objc
8
+ static func requiresMainQueueSetup() -> Bool {
9
+ return false
10
+ }
11
+
12
+ @objc
13
+ func decompressFile(_ inputPath: String, outputPath: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
14
+ print("[Xz Native] decompressFile called, input: \(inputPath), output: \(outputPath)")
15
+ DispatchQueue.global(qos: .userInitiated).async {
16
+ do {
17
+ let inputURL = URL(fileURLWithPath: inputPath)
18
+ let outputURL = URL(fileURLWithPath: outputPath)
19
+
20
+ print("[Xz Native] Reading compressed file...")
21
+ let compressedData = try Data(contentsOf: inputURL)
22
+ print("[Xz Native] Compressed size: \(compressedData.count) bytes")
23
+
24
+ print("[Xz Native] Decompressing...")
25
+ let decompressedData = try XZArchive.unarchive(archive: compressedData)
26
+ print("[Xz Native] Decompressed size: \(decompressedData.count) bytes")
27
+
28
+ try decompressedData.write(to: outputURL)
29
+ print("[Xz Native] Written to output file")
30
+ resolve(outputPath)
31
+ } catch {
32
+ print("[Xz Native] Error: \(error.localizedDescription)")
33
+ reject("XZ_ERROR", "Failed to decompress XZ file: \(error.localizedDescription)", error)
34
+ }
35
+ }
36
+ }
37
+
38
+ @objc
39
+ func decompressToString(_ inputPath: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
40
+ print("[Xz Native] decompressToString called, input: \(inputPath)")
41
+ DispatchQueue.global(qos: .userInitiated).async {
42
+ do {
43
+ let inputURL = URL(fileURLWithPath: inputPath)
44
+
45
+ print("[Xz Native] Reading compressed file...")
46
+ let compressedData = try Data(contentsOf: inputURL)
47
+ print("[Xz Native] Compressed size: \(compressedData.count) bytes")
48
+
49
+ print("[Xz Native] Decompressing...")
50
+ let decompressedData = try XZArchive.unarchive(archive: compressedData)
51
+ print("[Xz Native] Decompressed size: \(decompressedData.count) bytes")
52
+
53
+ guard let string = String(data: decompressedData, encoding: .utf8) else {
54
+ print("[Xz Native] Error: Failed to decode as UTF-8")
55
+ reject("XZ_ERROR", "Failed to decode decompressed data as UTF-8 string", nil)
56
+ return
57
+ }
58
+
59
+ print("[Xz Native] String length: \(string.count) characters")
60
+ resolve(string)
61
+ } catch {
62
+ print("[Xz Native] Error: \(error.localizedDescription)")
63
+ reject("XZ_ERROR", "Failed to decompress XZ file: \(error.localizedDescription)", error)
64
+ }
65
+ }
66
+ }
67
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@javascriptcommon/react-native-xz",
3
+ "version": "1.0.0",
4
+ "description": "Native XZ/LZMA2 decompression for React Native",
5
+ "main": "src/index.ts",
6
+ "types": "src/index.ts",
7
+ "source": "src/index.ts",
8
+ "react-native": "src/index.ts",
9
+ "files": [
10
+ "src",
11
+ "ios",
12
+ "android",
13
+ "react-native-xz.podspec",
14
+ "README.md",
15
+ "!**/__tests__"
16
+ ],
17
+ "scripts": {
18
+ "typescript": "tsc --noEmit"
19
+ },
20
+ "keywords": [
21
+ "react-native",
22
+ "xz",
23
+ "lzma",
24
+ "lzma2",
25
+ "compression",
26
+ "decompression"
27
+ ],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/Spicy-Sparks/react-native-xz"
31
+ },
32
+ "author": "Aspect Apps",
33
+ "license": "MIT",
34
+ "peerDependencies": {
35
+ "react": "*",
36
+ "react-native": "*"
37
+ },
38
+ "devDependencies": {
39
+ "@types/react": "^18.0.0",
40
+ "@types/react-native": "^0.72.0",
41
+ "react": "^18.0.0",
42
+ "react-native": "^0.72.0",
43
+ "typescript": "^5.0.0"
44
+ },
45
+ "codegenConfig": {
46
+ "name": "RNXzSpec",
47
+ "type": "modules",
48
+ "jsSrcsDir": "src",
49
+ "android": {
50
+ "javaPackageName": "com.xz"
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,43 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5
+
6
+ Pod::Spec.new do |s|
7
+ s.name = "react-native-xz"
8
+ s.version = package["version"]
9
+ s.summary = package["description"]
10
+ s.homepage = "https://github.com/Spicy-Sparks/react-native-xz"
11
+ s.license = package["license"]
12
+ s.authors = package["author"]
13
+
14
+ s.platforms = { :ios => min_ios_version_supported }
15
+ s.source = { :git => "https://github.com/Spicy-Sparks/react-native-xz.git", :tag => "#{s.version}" }
16
+
17
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
18
+ s.swift_version = "5.0"
19
+
20
+ s.dependency "SWCompression", "~> 4.8"
21
+
22
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
23
+ if respond_to?(:install_modules_dependencies, true)
24
+ install_modules_dependencies(s)
25
+ else
26
+ s.dependency "React-Core"
27
+
28
+ # Don't install the dependencies when we run `pod install` in the old architecture.
29
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
30
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
31
+ s.pod_target_xcconfig = {
32
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
33
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
34
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
35
+ }
36
+ s.dependency "React-Codegen"
37
+ s.dependency "RCT-Folly"
38
+ s.dependency "RCTRequired"
39
+ s.dependency "RCTTypeSafety"
40
+ s.dependency "ReactCommon/turbomodule/core"
41
+ end
42
+ end
43
+ end
package/src/index.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { NativeModules, Platform } from 'react-native'
2
+
3
+ const LINKING_ERROR =
4
+ `The package 'react-native-xz' doesn't seem to be linked. Make sure: \n\n` +
5
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
6
+ '- You rebuilt the app after installing the package\n' +
7
+ '- You are not using Expo Go\n'
8
+
9
+ interface XzModule {
10
+ decompressFile(inputPath: string, outputPath: string): Promise<string>
11
+ decompressToString(inputPath: string): Promise<string>
12
+ }
13
+
14
+ const Xz: XzModule = NativeModules.Xz
15
+ ? NativeModules.Xz
16
+ : new Proxy(
17
+ {},
18
+ {
19
+ get() {
20
+ throw new Error(LINKING_ERROR)
21
+ },
22
+ }
23
+ )
24
+
25
+ /**
26
+ * Decompress an XZ file to a destination path
27
+ * @param inputPath Path to the .xz compressed file
28
+ * @param outputPath Path where decompressed file will be written
29
+ * @returns Promise resolving to the output path
30
+ */
31
+ export function decompressFile(inputPath: string, outputPath: string): Promise<string> {
32
+ return Xz.decompressFile(inputPath, outputPath)
33
+ }
34
+
35
+ /**
36
+ * Decompress an XZ file and return contents as string
37
+ * @param inputPath Path to the .xz compressed file
38
+ * @returns Promise resolving to the decompressed string content
39
+ */
40
+ export function decompressToString(inputPath: string): Promise<string> {
41
+ return Xz.decompressToString(inputPath)
42
+ }
43
+
44
+ export default {
45
+ decompressFile,
46
+ decompressToString,
47
+ }