Skip to content

Commit

Permalink
Merging PR MobileChromeApps#17: Adding support for progress events
Browse files Browse the repository at this point in the history
Rebasing onto changes that Andrew added since the time of the patch.

Conflicts:
	src/android/Zip.java
  • Loading branch information
mmocny committed Mar 31, 2014
2 parents 1510e74 + 1c13601 commit 2034a7b
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 9 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,22 @@ A Cordova plugin to unzip files in Android and iOS.

##Usage

zip.unzip(<source zip>, <destination dir>, <callback>);
zip.unzip(<source zip>, <destination dir>, <callback>, [<progressCallback>]);

Both source and destination arguments can be URLs obtained from the HTML File
interface or absolute paths to files on the device.

The callback argument will be executed when the unzip is complete, or when an
error occurs. It will be called with a single argument, which will be 0 on
success, or -1 on failure.

The progressCallback argument is optional and will be executed whenever a new ZipEntry
has been extracted. E.g.:

var progressCallback = function(progressEvent) {
$( "#progressbar" ).progressbar("value", Math.round((progressEvent.loaded / progressEvent.total) * 100));
};

The values `loaded` and `total` are the number of compressed bytes processed and total. Total is the
file size of the zip file.

49 changes: 48 additions & 1 deletion src/android/Zip.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
import android.net.Uri;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaResourceApi.OpenForReadResult;
import org.apache.cordova.PluginResult;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

Expand Down Expand Up @@ -74,9 +77,14 @@ private void unzipSync(CordovaArgs args, CallbackContext callbackContext) {
throw new FileNotFoundException("File: \"" + outputDirectory + "\" not found");
}

inputStream = new BufferedInputStream(resourceApi.openForRead(zipUri).inputStream);
OpenForReadResult zipFile = resourceApi.openForRead(zipUri);
ProgressEvent progress = new ProgressEvent();
progress.setTotal(zipFile.length);

inputStream = new BufferedInputStream(zipFile.inputStream);
inputStream.mark(10);
int magic = readInt(inputStream);

if (magic != 875721283) { // CRX identifier
inputStream.reset();
} else {
Expand All @@ -93,6 +101,7 @@ private void unzipSync(CordovaArgs args, CallbackContext callbackContext) {
int signatureLength = readInt(inputStream);

inputStream.skip(pubkeyLength + signatureLength);
progress.setLoaded(16 + pubkeyLength + signatureLength);
}

// The inputstream is now pointing at the start of the actual zip file content.
Expand Down Expand Up @@ -126,8 +135,15 @@ private void unzipSync(CordovaArgs args, CallbackContext callbackContext) {
}

}
progress.addLoaded(ze.getCompressedSize());
updateProgress(callbackContext, progress);
zis.closeEntry();
}

// final progress = 100%
progress.setLoaded(progress.getTotal());
updateProgress(callbackContext, progress);

if (anyEntries)
callbackContext.success();
else
Expand All @@ -146,10 +162,41 @@ private void unzipSync(CordovaArgs args, CallbackContext callbackContext) {
}
}

private void updateProgress(CallbackContext callbackContext, ProgressEvent progress) throws JSONException {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
}

private Uri getUriForArg(String arg) {
CordovaResourceApi resourceApi = webView.getResourceApi();
Uri tmpTarget = Uri.parse(arg);
return resourceApi.remapUri(
tmpTarget.getScheme() != null ? tmpTarget : Uri.fromFile(new File(arg)));
}

private static class ProgressEvent {
private long loaded;
private long total;
public long getLoaded() {
return loaded;
}
public void setLoaded(long loaded) {
this.loaded = loaded;
}
public void addLoaded(long add) {
this.loaded += add;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public JSONObject toJSONObject() throws JSONException {
return new JSONObject(
"{loaded:" + loaded +
",total:" + total + "}");
}
}
}
1 change: 1 addition & 0 deletions src/ios/SSZipArchive.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@
- (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;

- (void)zipArchiveProgressEvent:(NSInteger)loaded total:(NSInteger)total;
@end
18 changes: 18 additions & 0 deletions src/ios/SSZipArchive.m
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination o
return NO;
}

NSDictionary * fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
ZPOS64_T fileSize = fileAttributes.fileSize;
ZPOS64_T currentPosition = 0;


unz_global_info globalInfo = {0ul, 0ul};
unzGetGlobalInfo(zip, &globalInfo);

Expand All @@ -77,6 +82,9 @@ + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination o
if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipArchiveAtPath:zipInfo:)]) {
[delegate zipArchiveWillUnzipArchiveAtPath:path zipInfo:globalInfo];
}
if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {
[delegate zipArchiveProgressEvent:currentPosition total:fileSize];
}

NSInteger currentFileNumber = 0;
do {
Expand All @@ -102,11 +110,16 @@ + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination o
break;
}

currentPosition += fileInfo.compressed_size;

// Message delegate
if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {
[delegate zipArchiveWillUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry
archivePath:path fileInfo:fileInfo];
}
if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {
[delegate zipArchiveProgressEvent:currentPosition total:fileSize];
}

char *filename = (char *)malloc(fileInfo.size_filename + 1);
unzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
Expand Down Expand Up @@ -268,6 +281,11 @@ + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination o
if (success && [delegate respondsToSelector:@selector(zipArchiveDidUnzipArchiveAtPath:zipInfo:unzippedPath:)]) {
[delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination];
}
// final progress event = 100%
if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {
[delegate zipArchiveProgressEvent:fileSize total:fileSize];
}


return success;
}
Expand Down
7 changes: 6 additions & 1 deletion src/ios/Zip.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
#import <Cordova/CDVPlugin.h>
#import "SSZipArchive.h"

@interface Zip : CDVPlugin
@interface Zip : CDVPlugin <SSZipArchiveDelegate> {
@private
CDVInvokedUrlCommand* _command;
}


- (void)unzip:(CDVInvokedUrlCommand*)command;
- (void)zipArchiveProgressEvent:(NSInteger)loaded total:(NSInteger)total;

@end
13 changes: 12 additions & 1 deletion src/ios/Zip.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ - (NSString *)pathForURL:(NSString *)urlString

- (void)unzip:(CDVInvokedUrlCommand*)command
{
self->_command = command;
[self.commandDelegate runInBackground:^{
CDVPluginResult* pluginResult = nil;

Expand All @@ -33,7 +34,7 @@ - (void)unzip:(CDVInvokedUrlCommand*)command
NSString *zipPath = [self pathForURL:zipURL];
NSString *destinationPath = [self pathForURL:destinationURL];

if([SSZipArchive unzipFileAtPath:zipPath toDestination:destinationPath overwrite:YES password:nil error:&error]) {
if([SSZipArchive unzipFileAtPath:zipPath toDestination:destinationPath overwrite:YES password:nil error:&error delegate:self]) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
} else {
NSLog(@"%@ - %@", @"Error occurred during unzipping", [error localizedDescription]);
Expand All @@ -48,4 +49,14 @@ - (void)unzip:(CDVInvokedUrlCommand*)command
}];
}

- (void)zipArchiveProgressEvent:(NSInteger)loaded total:(NSInteger)total
{
NSMutableDictionary* message = [NSMutableDictionary dictionaryWithCapacity:2];
[message setObject:[NSNumber numberWithLongLong:loaded] forKey:@"loaded"];
[message setObject:[NSNumber numberWithLongLong:total] forKey:@"total"];

CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:message];
[pluginResult setKeepCallbackAsBool:YES];
[self.commandDelegate sendPluginResult:pluginResult callbackId:self->_command.callbackId];
}
@end
26 changes: 21 additions & 5 deletions zip.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
var exec = cordova.require('cordova/exec');

exports.unzip = function(fileName, outputDirectory, callback) {
var win = callback && function() {
callback(0);
function newProgressEvent(result) {
var event = {
loaded: result.loaded,
total: result.total
};
var fail = callback && function() {
callback(-1);
return event;
}

exports.unzip = function(fileName, outputDirectory, callback, progressCallback) {
var win = function(result) {
if (result && typeof result.loaded != "undefined") {
if (progressCallback) {
return progressCallback(newProgressEvent(result));
}
} else if (callback) {
callback(0);
}
};
var fail = function(result) {
if (callback) {
callback(-1);
}
};
exec(win, fail, 'Zip', 'unzip', [fileName, outputDirectory]);
};

0 comments on commit 2034a7b

Please sign in to comment.