Zip extraction support.
This commit is contained in:
@@ -32,5 +32,5 @@
|
||||
- (id)initWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)game;
|
||||
- (BOOL)start;
|
||||
- (BOOL)cancel;
|
||||
|
||||
- (BOOL)extractToPath:(NSString *)aPath;
|
||||
@end
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
|
||||
{
|
||||
status = @"COMPLETE";
|
||||
status = @"DOWNLOADED";
|
||||
bytesCompleted = bytesTotal = [[[NSFileManager defaultManager] attributesOfItemAtPath:filename error:NULL] fileSize];
|
||||
}
|
||||
else
|
||||
@@ -49,7 +49,35 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)utilityResponded:(NSNotification *)n
|
||||
|
||||
- (BOOL)start
|
||||
{
|
||||
status = @"DOWNLOADING";
|
||||
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename]
|
||||
delegate:self
|
||||
responseSelector:@selector(downloadResponded:)
|
||||
terminatedSelector:@selector(utilityTerminated:)];
|
||||
[task retain];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)cancel
|
||||
{
|
||||
status = @"ERROR";
|
||||
error = @"Download Cancelled";
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:filename error:NULL];
|
||||
bytesCompleted = bytesTotal = -1;
|
||||
|
||||
[[JSBridge sharedInstance] notifyDownloadProgress:self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSFileHandleReadCompletionNotification
|
||||
object:[[task standardOutput] fileHandleForReading]];
|
||||
[task terminate];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)downloadResponded:(NSNotification *)n
|
||||
{
|
||||
NSData *data = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
||||
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
||||
@@ -80,7 +108,7 @@
|
||||
{
|
||||
if ([message isEqualToString:@"Completed"])
|
||||
{
|
||||
status = @"COMPLETE";
|
||||
status = @"DOWNLOADED";
|
||||
}
|
||||
|
||||
// Parse download status info
|
||||
@@ -99,36 +127,60 @@
|
||||
[[n object] readInBackgroundAndNotify];
|
||||
}
|
||||
|
||||
- (BOOL)start
|
||||
- (BOOL)extractToPath:(NSString *)aPath
|
||||
{
|
||||
status = @"DOWNLOADING";
|
||||
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename]
|
||||
status = @"EXTRACTING";
|
||||
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--extract-zip=%@,%@",filename,aPath]
|
||||
delegate:self
|
||||
responseSelector:@selector(utilityResponded:)
|
||||
responseSelector:@selector(extractResponded:)
|
||||
terminatedSelector:@selector(utilityTerminated:)];
|
||||
[task retain];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)cancel
|
||||
- (void)extractResponded:(NSNotification *)n
|
||||
{
|
||||
NSData *data = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
||||
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
||||
|
||||
// Response can contain multiple lines, or no lines. Split into lines, and parse each in turn
|
||||
NSArray *lines = [response componentsSeparatedByString:@"\n"];
|
||||
for (NSString *line in lines)
|
||||
{
|
||||
NSLog(@"%@",line);
|
||||
NSRange separator = [line rangeOfString:@":"];
|
||||
if (separator.location == NSNotFound)
|
||||
continue; // We only care about messages of the form key: value
|
||||
|
||||
NSString *type = [line substringToIndex:separator.location];
|
||||
NSString *message = [[line substringFromIndex:separator.location+1]
|
||||
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
if ([type isEqualToString:@"Error"])
|
||||
{
|
||||
status = @"ERROR";
|
||||
error = @"Download Cancelled";
|
||||
[error autorelease];
|
||||
error = [message retain];
|
||||
}
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:filename error:NULL];
|
||||
bytesCompleted = bytesTotal = -1;
|
||||
else if ([type isEqualToString:@"Status"])
|
||||
{
|
||||
if ([message isEqualToString:@"Completed"])
|
||||
{
|
||||
status = @"EXTRACTED";
|
||||
}
|
||||
}
|
||||
}
|
||||
[[JSBridge sharedInstance] notifyExtractProgress:self];
|
||||
|
||||
[[JSBridge sharedInstance] notifyDownloadProgress:self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSFileHandleReadCompletionNotification
|
||||
object:[[task standardOutput] fileHandleForReading]];
|
||||
[task terminate];
|
||||
return YES;
|
||||
// Keep reading
|
||||
if ([n object] != nil)
|
||||
[[n object] readInBackgroundAndNotify];
|
||||
}
|
||||
|
||||
- (void)utilityTerminated:(NSNotification *)n
|
||||
{
|
||||
NSLog(@"utility terminated");
|
||||
NSLog(@"download terminated");
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc removeObserver:self name:NSFileHandleReadCompletionNotification object:[[task standardOutput] fileHandleForReading]];
|
||||
[nc removeObserver:self name:NSTaskDidTerminateNotification object:task];
|
||||
|
||||
@@ -52,6 +52,7 @@ static JSBridge *SharedInstance;
|
||||
@"downloadError", NSStringFromSelector(@selector(downloadError:)),
|
||||
@"bytesCompleted", NSStringFromSelector(@selector(bytesCompleted:)),
|
||||
@"bytesTotal", NSStringFromSelector(@selector(bytesTotal:)),
|
||||
@"extractDownload", NSStringFromSelector(@selector(extractDownload:toPath:inMod:)),
|
||||
nil] retain];
|
||||
}
|
||||
return self;
|
||||
@@ -153,6 +154,40 @@ static JSBridge *SharedInstance;
|
||||
[NSString stringWithFormat:@"downloadProgressed('%@')",[download key]]];
|
||||
}
|
||||
|
||||
- (void)notifyExtractProgress:(Download *)download
|
||||
{
|
||||
[[[controller webView] windowScriptObject] evaluateWebScript:
|
||||
[NSString stringWithFormat:@"extractProgressed('%@')",[download key]]];
|
||||
}
|
||||
|
||||
- (BOOL)extractDownload:(NSString *)key toPath:(NSString *)aFile inMod:(NSString *)aMod
|
||||
{
|
||||
Download *d = [controller downloadWithKey:key];
|
||||
if (d == nil)
|
||||
{
|
||||
NSLog(@"Unknown download");
|
||||
return NO;
|
||||
}
|
||||
if (![[d status] isEqualToString:@"DOWNLOADED"])
|
||||
{
|
||||
NSLog(@"Invalid download status");
|
||||
return NO;
|
||||
}
|
||||
|
||||
id mod = [[controller allMods] objectForKey:aMod];
|
||||
if (mod == nil)
|
||||
{
|
||||
NSLog(@"Invalid or unknown mod: %@", aMod);
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Disallow traversing up the directory tree
|
||||
id path = [aMod stringByAppendingPathComponent:[aFile stringByReplacingOccurrencesOfString:@"../"
|
||||
withString:@""]];
|
||||
|
||||
[d extractToPath:path];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)log:(NSString *)message
|
||||
{
|
||||
|
||||
@@ -58,6 +58,11 @@
|
||||
font-size:0.75em;
|
||||
}
|
||||
|
||||
.status
|
||||
{
|
||||
font-size:0.8em;
|
||||
}
|
||||
|
||||
.button
|
||||
{
|
||||
border: solid 3px #650b03;
|
||||
@@ -113,7 +118,7 @@
|
||||
|
||||
function extract()
|
||||
{
|
||||
window.external.log("Todo: Extract package");
|
||||
window.external.extractDownload("cnc-packages","packages","cnc");
|
||||
}
|
||||
|
||||
function onLoad()
|
||||
@@ -140,24 +145,31 @@
|
||||
document.getElementById("download-available").style.display = "none";
|
||||
document.getElementById("download-downloading").style.display = "none";
|
||||
document.getElementById("download-extract").style.display = "none";
|
||||
document.getElementById("download-extracting").style.display = "none";
|
||||
document.getElementById("download-error").style.display = "none";
|
||||
// status can be NOT_REGISTERED, AVAILABLE, DOWNLOADING, COMPLETE, ERROR
|
||||
|
||||
// status can be NOT_REGISTERED, AVAILABLE, DOWNLOADING, DOWNLOADED, EXTRACTING, EXTRACTED, ERROR
|
||||
var status = window.external.downloadStatus("cnc-packages");
|
||||
|
||||
// Download complete, offer button to extract it
|
||||
if (status == "COMPLETE")
|
||||
if (status == "AVAILABLE")
|
||||
{
|
||||
document.getElementById("download-extract").style.display = "";
|
||||
document.getElementById("download-available").style.display = "";
|
||||
}
|
||||
// Show the download progress
|
||||
else if (status == "DOWNLOADING")
|
||||
{
|
||||
document.getElementById("download-downloading").style.display = "";
|
||||
}
|
||||
// Show the download button
|
||||
else if (status == "AVAILABLE")
|
||||
if (status == "DOWNLOADED")
|
||||
{
|
||||
document.getElementById("download-available").style.display = "";
|
||||
document.getElementById("download-extract").style.display = "";
|
||||
}
|
||||
else if (status == "EXTRACTING")
|
||||
{
|
||||
document.getElementById("download-extracting").style.display = "";
|
||||
}
|
||||
else if (status == "EXTRACTED")
|
||||
{
|
||||
refreshSections();
|
||||
}
|
||||
else if (status == "ERROR")
|
||||
{
|
||||
@@ -183,6 +195,16 @@
|
||||
}
|
||||
refreshDownloadButtons();
|
||||
}
|
||||
|
||||
function extractProgressed(file)
|
||||
{
|
||||
if (file != "cnc-packages")
|
||||
return;
|
||||
|
||||
// Todo: show an extraction ticker?
|
||||
|
||||
refreshDownloadButtons();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="onLoad();">
|
||||
@@ -213,12 +235,15 @@
|
||||
<input type="button" class="button" id="download-status" value="Initializing..." />
|
||||
<input type="button" class="button" onclick="cancel();" value="Cancel" />
|
||||
</div>
|
||||
<div id="download-error" style="display:none">
|
||||
<input type="button" class="button" onclick="download();" value="Retry" />
|
||||
<span class="status" id="error-message"></span>
|
||||
</div>
|
||||
<div id="download-extract" style="display:none">
|
||||
<input type="button" class="button" onclick="extract();" value="Install" />
|
||||
</div>
|
||||
<div id="download-error" style="display:none">
|
||||
<input type="button" class="button" onclick="download();" value="Retry" />
|
||||
<span class="desc" id="error-message"></span>
|
||||
<div id="download-extracting" style="display:none">
|
||||
<input type="button" class="button" value="Installing..." />
|
||||
</div>
|
||||
</div>
|
||||
<div id="buttons-upgrade" class="buttons" style="display:none">
|
||||
|
||||
Reference in New Issue
Block a user