From c632732dba88f01e382179cef77551b6166b4e65 Mon Sep 17 00:00:00 2001 From: l3utterfly Date: Sat, 16 Nov 2024 17:12:34 +0800 Subject: [PATCH 1/6] handle content uri assets --- .../java/com/rnziparchive/RNZipArchiveModule.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java index 9da38dc..efe2bcb 100644 --- a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java +++ b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java @@ -181,9 +181,18 @@ public void run() { final long size; try { - assetsInputStream = getReactApplicationContext().getAssets().open(assetsPath); - AssetFileDescriptor fileDescriptor = getReactApplicationContext().getAssets().openFd(assetsPath); - size = fileDescriptor.getLength(); + if(assetsPath.startsWith("content://")) { + var assetUri = Uri.parse(assetsPath); + var contentResolver = getReactApplicationContext().getContentResolver(); + + assetsInputStream = contentResolver.openInputStream(assetUri); + var fileDescriptor = contentResolver.openFileDescriptor(assetUri, "r"); + size = fileDescriptor.getStatSize(); + } else { + assetsInputStream = getReactApplicationContext().getAssets().open(assetsPath); + AssetFileDescriptor fileDescriptor = getReactApplicationContext().getAssets().openFd(assetsPath); + size = fileDescriptor.getLength(); + } } catch (IOException e) { promise.reject(null, String.format("Asset file `%s` could not be opened", assetsPath)); return; From 3dfe7f7f85c5574ee76e71574b135fe50a7ceea4 Mon Sep 17 00:00:00 2001 From: l3utterfly Date: Sat, 16 Nov 2024 17:32:08 +0800 Subject: [PATCH 2/6] added progress for extracting zip files --- .../com/rnziparchive/RNZipArchiveModule.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java index efe2bcb..0f028b4 100644 --- a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java +++ b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java @@ -149,11 +149,26 @@ public void run() { zipFile = new net.lingala.zip4j.ZipFile(zipFilePath); } + ProgressMonitor progressMonitor = zipFile.getProgressMonitor(); + + zipFile.setRunInThread(true); zipFile.extractAll(destDirectory); - zipFile.close(); - updateProgress(1, 1, zipFilePath); // force 100% - promise.resolve(destDirectory); + while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) { + updateProgress(progressMonitor.getWorkCompleted(), progressMonitor.getTotalWork(), zipFilePath); + + Thread.sleep(100); + } + + if (progressMonitor.getResult().equals(ProgressMonitor.Result.SUCCESS)) { + zipFile.close(); + updateProgress(1, 1, zipFilePath); // force 100% + promise.resolve(destDirectory); + } else if (progressMonitor.getResult().equals(ProgressMonitor.Result.ERROR)) { + throw new Exception("Error occurred. Error message: " + progressMonitor.getException().getMessage()); + } else if (progressMonitor.getResult().equals(ProgressMonitor.Result.CANCELLED)) { + throw new Exception("Task cancelled"); + } } catch (Exception ex) { updateProgress(0, 1, zipFilePath); // force 0% promise.reject(null, "Failed to extract file " + ex.getLocalizedMessage()); From 66b556dd4a6d28fc1a4368bdf8becfba44c4c0ac Mon Sep 17 00:00:00 2001 From: l3utterfly Date: Thu, 21 Nov 2024 23:20:12 +0900 Subject: [PATCH 3/6] fixed missing import --- .../java/com/rnziparchive/RNZipArchiveModule.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java index 0f028b4..b079b20 100644 --- a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java +++ b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java @@ -36,6 +36,7 @@ import net.lingala.zip4j.model.enums.CompressionLevel; import net.lingala.zip4j.model.enums.EncryptionMethod; import net.lingala.zip4j.model.enums.AesKeyStrength; +import net.lingala.zip4j.progress.ProgressMonitor; import java.nio.charset.Charset; @@ -67,7 +68,7 @@ public void isPasswordProtected(final String zipFilePath, final Promise promise) @ReactMethod public void unzipWithPassword(final String zipFilePath, final String destDirectory, - final String password, final Promise promise) { + final String password, final Promise promise) { new Thread(new Runnable() { @Override public void run() { @@ -92,11 +93,11 @@ public void run() { String destDirCanonicalPath = (new File(destDirectory).getCanonicalPath()) + File.separator; if (!canonicalPath.startsWith(destDirCanonicalPath)) { - throw new SecurityException(String.format("Found Zip Path Traversal Vulnerability with %s", canonicalPath)); + throw new SecurityException(String.format("Found Zip Path Traversal Vulnerability with %s", canonicalPath)); } if (!fileHeader.isDirectory()) { - zipFile.extractFile(fileHeader, destDirectory); + zipFile.extractFile(fileHeader, destDirectory); extractedFileNames.add(fileHeader.getFileName()); } updateProgress(i + 1, totalFiles, zipFilePath); @@ -237,7 +238,7 @@ public void run() { String destDirCanonicalPath = (new File(destDirectory).getCanonicalPath()) + File.separator; if (!canonicalPath.startsWith(destDirCanonicalPath)) { - throw new SecurityException(String.format("Found Zip Path Traversal Vulnerability with %s", canonicalPath)); + throw new SecurityException(String.format("Found Zip Path Traversal Vulnerability with %s", canonicalPath)); } if (!fout.exists()) { @@ -300,21 +301,21 @@ public void zipFolder(final String folder, final String destFile, final Promise @ReactMethod public void zipFilesWithPassword(final ReadableArray files, final String destFile, final String password, - String encryptionMethod, Promise promise) { + String encryptionMethod, Promise promise) { zipWithPassword(files.toArrayList(), destFile, password, encryptionMethod, promise); } @ReactMethod public void zipFolderWithPassword(final String folder, final String destFile, final String password, - String encryptionMethod, Promise promise) { + String encryptionMethod, Promise promise) { ArrayList folderAsArrayList = new ArrayList<>(); folderAsArrayList.add(folder); zipWithPassword(folderAsArrayList, destFile, password, encryptionMethod, promise); } private void zipWithPassword(final ArrayList filesOrDirectory, final String destFile, final String password, - String encryptionMethod, Promise promise) { + String encryptionMethod, Promise promise) { try{ ZipParameters parameters = new ZipParameters(); From f88b870b6a2897245aff6e9e56a2f8b8db156539 Mon Sep 17 00:00:00 2001 From: l3utterfly Date: Thu, 21 Nov 2024 23:20:40 +0900 Subject: [PATCH 4/6] fixed missing imports --- android/src/main/java/com/rnziparchive/RNZipArchiveModule.java | 1 + 1 file changed, 1 insertion(+) diff --git a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java index b079b20..056450e 100644 --- a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java +++ b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java @@ -1,6 +1,7 @@ package com.rnziparchive; import android.content.res.AssetFileDescriptor; +import android.net.Uri; import android.os.Build; import android.util.Log; From 98695af62185c6fecb49dee63000ebcb191e0a61 Mon Sep 17 00:00:00 2001 From: l3utterfly Date: Mon, 2 Dec 2024 20:39:43 +0900 Subject: [PATCH 5/6] fixed progress display --- .../com/rnziparchive/RNZipArchiveModule.java | 41 ++++++++----------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java index 056450e..6c8ea21 100644 --- a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java +++ b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java @@ -24,6 +24,7 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.zip.ZipEntry; @@ -195,7 +196,7 @@ public void unzipAssets(final String assetsPath, final String destDirectory, fin @Override public void run() { InputStream assetsInputStream; - final long size; + final long compressedSize; try { if(assetsPath.startsWith("content://")) { @@ -204,11 +205,11 @@ public void run() { assetsInputStream = contentResolver.openInputStream(assetUri); var fileDescriptor = contentResolver.openFileDescriptor(assetUri, "r"); - size = fileDescriptor.getStatSize(); + compressedSize = fileDescriptor.getStatSize(); } else { assetsInputStream = getReactApplicationContext().getAssets().open(assetsPath); AssetFileDescriptor fileDescriptor = getReactApplicationContext().getAssets().openFd(assetsPath); - size = fileDescriptor.getLength(); + compressedSize = fileDescriptor.getLength(); } } catch (IOException e) { promise.reject(null, String.format("Asset file `%s` could not be opened", assetsPath)); @@ -227,13 +228,15 @@ public void run() { ZipEntry entry; - final long[] extractedBytes = {0}; - final int[] lastPercentage = {0}; + long extractedBytes = 0; + updateProgress(extractedBytes, compressedSize, assetsPath); // force 0% - updateProgress(0, 1, assetsPath); // force 0% File fout; while ((entry = zipIn.getNextEntry()) != null) { if (entry.isDirectory()) continue; + + Log.i("rnziparchive", "Extracting: " + entry.getName()); + fout = new File(destDirectory, entry.getName()); String canonicalPath = fout.getCanonicalPath(); String destDirCanonicalPath = (new File(destDirectory).getCanonicalPath()) + File.separator; @@ -247,31 +250,19 @@ public void run() { (new File(fout.getParent())).mkdirs(); } - final ZipEntry finalEntry = entry; - StreamUtil.ProgressCallback cb = new StreamUtil.ProgressCallback() { - @Override - public void onCopyProgress(long bytesRead) { - extractedBytes[0] += bytesRead; - - int lastTime = lastPercentage[0]; - int percentDone = (int) ((double) extractedBytes[0] * 100 / (double) size); - - // update at most once per percent. - if (percentDone > lastTime) { - lastPercentage[0] = percentDone; - updateProgress(extractedBytes[0], size, finalEntry.getName()); - } - } - }; - FileOutputStream out = new FileOutputStream(fout); BufferedOutputStream Bout = new BufferedOutputStream(out); - StreamUtil.copy(bin, Bout, cb); + StreamUtil.copy(bin, Bout, null); Bout.close(); out.close(); + + extractedBytes += entry.getCompressedSize(); + + updateProgress(extractedBytes, compressedSize, entry.getName()); } - updateProgress(1, 1, assetsPath); // force 100% + updateProgress(compressedSize, compressedSize, assetsPath); // force 100% + bin.close(); zipIn.close(); } catch (Exception ex) { From f749ca6fd9222a0742b6abea3dda2e5331e8887c Mon Sep 17 00:00:00 2001 From: l3utterfly Date: Mon, 9 Dec 2024 00:39:49 +0900 Subject: [PATCH 6/6] updated logic to handle extraction progress --- android/src/main/java/com/rnziparchive/RNZipArchiveModule.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java index 6c8ea21..54f1955 100644 --- a/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java +++ b/android/src/main/java/com/rnziparchive/RNZipArchiveModule.java @@ -258,6 +258,9 @@ public void run() { extractedBytes += entry.getCompressedSize(); + // do not let the percentage go over 99% because we want it to hit 100% only when we are sure it's finished + if(extractedBytes > compressedSize*0.99) extractedBytes = (long) (compressedSize*0.99); + updateProgress(extractedBytes, compressedSize, entry.getName()); }