diff --git a/README.md b/README.md index 737f3fd..988d148 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,31 @@ To extract an archive: var result = Ti.Compression.unzip(Ti.Filesystem.applicationDataDirectory + 'data', 'test.zip', true); ``` + See example for more details. +## zip Parameter + +Android: +* filename:String, files:Array, options: Object [compression: Compression.BEST_SPEED| Compression.DEFAULT_COMPRESSION | Compression.NO_COMPRESSION] + +iOS: +* filename:String, files:Array + +## Create demo files + +Create demo files + +good compression (no content) +```bash +truncate -s 5M file1.dat +``` + +Bad compression (random content) +```bash +dd if=/dev/urandom of=file1 bs=5M count=1 +``` + ## Author Clint Tredway diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..f79dfc4 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,5 @@ + +dependencies { + // Add the module's library dependencies here. + // See: https://developer.android.com/studio/build/dependencies +} diff --git a/android/manifest b/android/manifest index f1de2fd..7bfbee5 100644 --- a/android/manifest +++ b/android/manifest @@ -2,7 +2,7 @@ # this is your module manifest and used by Titanium # during compilation, packaging, distribution, etc. # -version: 5.0.0 +version: 6.0.0 apiversion: 4 architectures: arm64-v8a armeabi-v7a x86 x86_64 description: Lets you zip and unzip files. diff --git a/android/src/ti/compression/CompressionModule.java b/android/src/ti/compression/CompressionModule.java index ece7439..68b6eca 100644 --- a/android/src/ti/compression/CompressionModule.java +++ b/android/src/ti/compression/CompressionModule.java @@ -6,6 +6,14 @@ package ti.compression; +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollModule; +import org.appcelerator.kroll.annotations.Kroll; +import org.appcelerator.kroll.common.Log; +import org.appcelerator.titanium.io.TiBaseFile; +import org.appcelerator.titanium.io.TiFileFactory; +import org.appcelerator.titanium.util.TiConvert; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -13,161 +21,172 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.HashMap; import java.util.LinkedList; +import java.util.zip.CRC32; +import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -import org.appcelerator.kroll.KrollModule; -import org.appcelerator.kroll.annotations.Kroll; -import org.appcelerator.titanium.io.TiBaseFile; -import org.appcelerator.titanium.io.TiFileFactory; @Kroll.module(name = "Compression", id = "ti.compression") -public class CompressionModule extends KrollModule -{ - - public CompressionModule() - { - super(); - } - - @Kroll.method - public String zip(Object[] args) - { - // Check that our arguments are valid. - if (args.length != 2) { - return "Invalid number of arguments provided!"; - } - - String rawZip = (String) args[0]; - if (rawZip == null || rawZip.length() == 0) { - return "archiveFile was not specified or was empty!"; - } - TiBaseFile zip = TiFileFactory.createTitaniumFile(rawZip, false); - - Object[] rawFiles = (Object[]) args[1]; - if (rawFiles == null || rawFiles.length == 0) { - return "fileArray was not specified or was empty!"; - } - LinkedList files = new LinkedList(); - for (Object rawFile : rawFiles) { - files.add(TiFileFactory.createTitaniumFile(rawFile.toString(), false)); - } - - // And then zip the files in to the archive. - try { - OutputStream fout = zip.getOutputStream(); - ZipOutputStream zout = new ZipOutputStream(new BufferedOutputStream(fout)); - - while (!files.isEmpty()) { - TiBaseFile file = files.remove(); - if (!file.exists()) { - Util.e("Skipping over file, because it does not exist: " + file.nativePath()); - } else { - ZipEntry ze = new ZipEntry(file.name()); - zout.putNextEntry(ze); - writeInFile(file, zout); - zout.closeEntry(); - } - } - zout.close(); - return "success"; - } catch (Exception e) { - Util.e("Hit exception while unzipping the archive!", e); - return e.toString(); - } - } - - @Kroll.method - public String unzip(Object[] args) - { - // Check that our arguments are valid. - if (args.length != 3) { - return "Invalid number of arguments provided!"; - } - - String rawDest = (String) args[0]; - if (rawDest == null || rawDest.length() == 0) { - return "destinationFolder was not specified or was empty!"; - } - String destPath = TiFileFactory.createTitaniumFile(rawDest, false).getNativeFile().getAbsolutePath(); - - String rawZip = (String) args[1]; - if (rawZip == null || rawZip.length() == 0) { - return "archiveFile was not specified or was empty!"; - } - TiBaseFile zip = TiFileFactory.createTitaniumFile(rawZip, false); - if (!zip.exists()) - return "archiveFile was not found at " + rawZip + "!"; - - Boolean overwrite = (Boolean) args[2]; - if (overwrite == null) { - return "overwrite was not specified!"; - } - - // And then unzip the archive. - try { - InputStream fin = zip.getInputStream(); - ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fin)); - ZipEntry ze = null; - while ((ze = zin.getNextEntry()) != null) { - String target = destPath + "/" + ze.getName(); - if (ze.isDirectory()) { - ensureDirectoryExists(target); - } else { - File file = new File(target); - if (overwrite || !file.exists()) { - writeOutFile(file, target, zin); - } - } - } - zin.close(); - fin.close(); - return "success"; - } catch (Exception e) { - Util.e("Hit exception while unzipping the archive!", e); - return e.toString(); - } - } - - public void ensureDirectoryExists(String target) - { - File f = new File(target); - if (!f.isDirectory()) { - f.mkdirs(); - } - } - - private void writeInFile(TiBaseFile tifile, ZipOutputStream zout) throws IOException - { - int size; - byte[] buffer = new byte[2048]; - InputStream fos = tifile.getInputStream(); - BufferedInputStream bos = new BufferedInputStream(fos, buffer.length); - while ((size = bos.read(buffer, 0, buffer.length)) != -1) { - zout.write(buffer, 0, size); - } - } - - private void writeOutFile(File file, String target, ZipInputStream zin) throws IOException - { - // Make sure the parent directory exists. - file.getParentFile().mkdirs(); - // Write out the file. - int size; - byte[] buffer = new byte[2048]; - FileOutputStream fos = new FileOutputStream(target); - BufferedOutputStream bos = new BufferedOutputStream(fos, buffer.length); - while ((size = zin.read(buffer, 0, buffer.length)) != -1) { - bos.write(buffer, 0, size); - } - bos.flush(); - bos.close(); - } - - @Override - public String getApiName() - { - return "Ti.Compression"; - } +public class CompressionModule extends KrollModule { + + + @Kroll.constant + static final int BEST_SPEED = Deflater.BEST_SPEED; + @Kroll.constant + static final int NO_COMPRESSION = Deflater.NO_COMPRESSION; + @Kroll.constant + static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION; + + int level = -1; + + public CompressionModule() { + super(); + } + + @Kroll.method + public String zip(Object[] args) { + level = -1; + // Check that our arguments are valid. + if (args.length == 3) { + HashMap options = (HashMap) args[2]; + if (options.get("compression") != null) { + level = (int) options.get("compression"); + } + } else if (args.length != 2) { + return "Invalid number of arguments provided!"; + } + + + + String rawZip = (String) args[0]; + if (rawZip == null || rawZip.length() == 0) { + return "archiveFile was not specified or was empty!"; + } + TiBaseFile zip = TiFileFactory.createTitaniumFile(rawZip, false); + + Object[] rawFiles = (Object[]) args[1]; + if (rawFiles == null || rawFiles.length == 0) { + return "fileArray was not specified or was empty!"; + } + LinkedList files = new LinkedList(); + for (Object rawFile : rawFiles) { + files.add(TiFileFactory.createTitaniumFile(rawFile.toString(), false)); + } + + // And then zip the files in to the archive. + try { + OutputStream fout = zip.getOutputStream(); + ZipOutputStream zout = new ZipOutputStream(new BufferedOutputStream(fout)); + + zout.setLevel(level); + + while (!files.isEmpty()) { + TiBaseFile file = files.remove(); + if (!file.exists()) { + Util.e("Skipping over file, because it does not exist: " + file.nativePath()); + } else { + ZipEntry ze = new ZipEntry(file.name()); + zout.putNextEntry(ze); + writeInFile(file, zout); + zout.closeEntry(); + } + } + zout.close(); + return "success"; + } catch (Exception e) { + Util.e("Hit exception while unzipping the archive!", e); + return e.toString(); + } + } + + @Kroll.method + public String unzip(Object[] args) { + // Check that our arguments are valid. + if (args.length != 3) { + return "Invalid number of arguments provided!"; + } + + String rawDest = (String) args[0]; + if (rawDest == null || rawDest.length() == 0) { + return "destinationFolder was not specified or was empty!"; + } + String destPath = TiFileFactory.createTitaniumFile(rawDest, false).getNativeFile().getAbsolutePath(); + + String rawZip = (String) args[1]; + if (rawZip == null || rawZip.length() == 0) { + return "archiveFile was not specified or was empty!"; + } + TiBaseFile zip = TiFileFactory.createTitaniumFile(rawZip, false); + if (!zip.exists()) + return "archiveFile was not found at " + rawZip + "!"; + + Boolean overwrite = (Boolean) args[2]; + if (overwrite == null) { + return "overwrite was not specified!"; + } + + // And then unzip the archive. + try { + InputStream fin = zip.getInputStream(); + ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fin)); + ZipEntry ze = null; + while ((ze = zin.getNextEntry()) != null) { + String target = destPath + "/" + ze.getName(); + if (ze.isDirectory()) { + ensureDirectoryExists(target); + } else { + File file = new File(target); + if (overwrite || !file.exists()) { + writeOutFile(file, target, zin); + } + } + } + zin.close(); + fin.close(); + return "success"; + } catch (Exception e) { + Util.e("Hit exception while unzipping the archive!", e); + return e.toString(); + } + } + + public void ensureDirectoryExists(String target) { + File f = new File(target); + if (!f.isDirectory()) { + f.mkdirs(); + } + } + + private void writeInFile(TiBaseFile tifile, ZipOutputStream zout) throws IOException { + int size; + byte[] buffer = new byte[2048]; + InputStream fos = tifile.getInputStream(); + BufferedInputStream bos = new BufferedInputStream(fos, buffer.length); + while ((size = bos.read(buffer, 0, buffer.length)) != -1) { + zout.write(buffer, 0, size); + } + } + + private void writeOutFile(File file, String target, ZipInputStream zin) throws IOException { + // Make sure the parent directory exists. + file.getParentFile().mkdirs(); + // Write out the file. + int size; + byte[] buffer = new byte[2048]; + FileOutputStream fos = new FileOutputStream(target); + BufferedOutputStream bos = new BufferedOutputStream(fos, buffer.length); + while ((size = zin.read(buffer, 0, buffer.length)) != -1) { + bos.write(buffer, 0, size); + } + bos.flush(); + bos.close(); + } + + @Override + public String getApiName() { + return "Ti.Compression"; + } } diff --git a/example/app.js b/example/app.js index 2825abd..1c8fa13 100644 --- a/example/app.js +++ b/example/app.js @@ -7,7 +7,7 @@ * - Unzipping an archive. */ var win = Ti.UI.createWindow({ - backgroundColor: 'white' + layout: "vertical" }); win.open(); @@ -21,27 +21,88 @@ var inputDirectory = Ti.Filesystem.resourcesDirectory + 'data/'; */ var zipFiles = Ti.UI.createButton({ title: 'Zip a.txt and b.txt', - top: 20, left: 20, right: 20, + top: 10, + left: 20, + right: 20, height: 40 }); -zipFiles.addEventListener('click', function () { +var zipFiles2 = Ti.UI.createButton({ + title: 'Zip a.txt and b.txt (fast)', + top: 10, + left: 20, + right: 20, + height: 40 +}); +zipFiles.addEventListener('click', function() { + var startTime = new Date(); var writeToZip = outputDirectory + '/zipFiles.zip'; + var file = Ti.Filesystem.getFile(writeToZip); + if (file.exists()) { + file.deleteFile(); + } var result = Compression.zip(writeToZip, [ inputDirectory + 'a.txt', - inputDirectory + 'b.txt' + inputDirectory + 'b.txt', + inputDirectory + 'file1.dat', + inputDirectory + 'file2.dat', + inputDirectory + 'file3.dat', + inputDirectory + 'file4.dat', + inputDirectory + 'file5.dat', + inputDirectory + 'file6.dat', + inputDirectory + 'file7.dat', + inputDirectory + 'icon1.png', + inputDirectory + 'icon2.png', + inputDirectory + 'icon3.png' ]); Ti.API.info(status.text = 'Zip Files: ' + result + ', to: ' + writeToZip); // eslint-disable-next-line eqeqeq if (result == 'success') { - if (!Ti.Filesystem.getFile(writeToZip).exists()) { + var file = Ti.Filesystem.getFile(writeToZip); + if (!file.exists()) { alert('FAIL: The target zip does not exist!'); } else { - alert('PASS: The target zip exists!'); + alert('PASS: The target zip exists!\nFile size: ' + file.size + "\nTime: " + (new Date() - startTime)); } } }); -win.add(zipFiles); +zipFiles2.addEventListener('click', function() { + var writeToZip = outputDirectory + '/zipFiles.zip'; + + var file = Ti.Filesystem.getFile(writeToZip); + if (file.exists()) { + file.deleteFile(); + } + var startTime = new Date(); + var result = Compression.zip(writeToZip, [ + inputDirectory + 'a.txt', + inputDirectory + 'b.txt', + inputDirectory + 'file1.dat', + inputDirectory + 'file2.dat', + inputDirectory + 'file3.dat', + inputDirectory + 'file4.dat', + inputDirectory + 'file5.dat', + inputDirectory + 'file6.dat', + inputDirectory + 'file7.dat', + inputDirectory + 'icon1.png', + inputDirectory + 'icon2.png', + inputDirectory + 'icon3.png' + ], { + compression: Compression.BEST_SPEED, + optimizeStorage: true + }); + Ti.API.info(status.text = 'Zip Files: ' + result + ', to: ' + writeToZip); + + if (result == 'success') { + var file = Ti.Filesystem.getFile(writeToZip); + if (!file.exists()) { + alert('FAIL: The target zip does not exist!'); + } else { + alert('PASS: The target zip exists!\nFile size: ' + file.size + "\nTime: " + (new Date() - startTime)); + } + } +}); +win.add([zipFiles, zipFiles2]); /** * The following lines extract the contents of the "a+b.zip" file @@ -50,15 +111,16 @@ win.add(zipFiles); */ var unzipArchive = Ti.UI.createButton({ title: 'Unzip ab.zip', - top: 80, left: 20, right: 20, + top: 10, + left: 20, + right: 20, height: 40 }); -unzipArchive.addEventListener('click', function () { +unzipArchive.addEventListener('click', function() { var zipFileName = inputDirectory + 'ab.zip'; var result = Compression.unzip(outputDirectory, zipFileName, true); Ti.API.info(status.text = 'Unzip: ' + result + ', to: ' + outputDirectory); - // eslint-disable-next-line eqeqeq if (result == 'success') { if (!Ti.Filesystem.getFile(outputDirectory, 'a.txt').exists()) { alert('FAIL: The unzipped a.txt does not exist!'); @@ -71,7 +133,8 @@ win.add(unzipArchive); var status = Ti.UI.createLabel({ text: 'Hit one of the buttons above, and the result will display here.', - color: '#333', - top: 140, left: 20, right: 20, bottom: 20 + top: 10, + left: 20, + right: 20 }); win.add(status); diff --git a/example/data/Archiv.zip b/example/data/Archiv.zip new file mode 100644 index 0000000..432e502 Binary files /dev/null and b/example/data/Archiv.zip differ diff --git a/example/data/file1.dat b/example/data/file1.dat new file mode 100644 index 0000000..3995316 Binary files /dev/null and b/example/data/file1.dat differ diff --git a/example/data/file2.dat b/example/data/file2.dat new file mode 100644 index 0000000..3995316 Binary files /dev/null and b/example/data/file2.dat differ diff --git a/example/data/file3.dat b/example/data/file3.dat new file mode 100644 index 0000000..3995316 Binary files /dev/null and b/example/data/file3.dat differ diff --git a/example/data/file4.dat b/example/data/file4.dat new file mode 100644 index 0000000..24fdbfe Binary files /dev/null and b/example/data/file4.dat differ diff --git a/example/data/file6.dat b/example/data/file6.dat new file mode 100644 index 0000000..3995316 Binary files /dev/null and b/example/data/file6.dat differ diff --git a/example/data/icon1.png b/example/data/icon1.png new file mode 100644 index 0000000..3000bd7 Binary files /dev/null and b/example/data/icon1.png differ diff --git a/example/data/icon2.png b/example/data/icon2.png new file mode 100644 index 0000000..a98a73a Binary files /dev/null and b/example/data/icon2.png differ diff --git a/example/data/icon3.png b/example/data/icon3.png new file mode 100644 index 0000000..a98a73a Binary files /dev/null and b/example/data/icon3.png differ