Permalink
Browse files

Merge commit 'bdash/delta-updates'

This is a big one, guys. Haven't tested the new features in the merged branch yet.
  • Loading branch information...
2 parents 2e3ed79 + ab23fed commit 9bc63ccf7e5f73cadbd72b4e836578841c6f0e1d @andymatuschak andymatuschak committed Jan 11, 2010
@@ -0,0 +1,9 @@
+// BinaryDelta tool only
+
+PRODUCT_NAME = BinaryDelta
+GCC_PREFIX_HEADER =
+SDKROOT = macosx10.5
+MACOSX_DEPLOYMENT_TARGET[arch=i386] = 10.5
+MACOSX_DEPLOYMENT_TARGET[arch=ppc64] = 10.5
+MACOSX_DEPLOYMENT_TARGET[arch=ppc] = 10.5
+MACOSX_DEPLOYMENT_TARGET[arch=x86_64] = 10.5
@@ -0,0 +1,5 @@
+#include "ConfigCommon.xcconfig"
+#include "ConfigCommonDebug.xcconfig"
+#include "ConfigBinaryDelta.xcconfig"
+
+OTHER_CFLAGS = -fsingle-precision-constant -DDEBUG
@@ -0,0 +1,3 @@
+#include "ConfigCommon.xcconfig"
+#include "ConfigCommonRelease.xcconfig"
+#include "ConfigBinaryDelta.xcconfig"
@@ -47,3 +47,4 @@ GCC_WARN_UNUSED_PARAMETER = YES
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
GCC_WARN_UNDECLARED_SELECTOR = YES
WARNING_CFLAGS = -Wall -Wundef -Wendif-labels -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-noreturn -Wmissing-format-attribute -Wpacked -Wredundant-decls -Winline -Wdisabled-optimization -Wformat=2 -Wlarger-than-32768 -Winvalid-pch
+LIBRARY_SEARCH_PATHS = $(inherited) $(SRCROOT)
View
@@ -123,4 +123,31 @@ Original SSLeay License
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
-*/
+*/
+
+License for bspatch.c and bsdiff.c, from bsdiff 4.3 (<http://www.daemonology.net/bsdiff/>:
+/*-
+ * Copyright 2003-2005 Colin Percival
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
View
@@ -9,6 +9,23 @@
#import "Sparkle.h"
#import "SUAppcast.h"
+@interface NSXMLElement (SUAppcastExtensions)
+- (NSDictionary *)attributesAsDictionary;
+@end
+
+@implementation NSXMLElement (SUAppcastExtensions)
+- (NSDictionary *)attributesAsDictionary
+{
+ NSEnumerator *attributeEnum = [[self attributes] objectEnumerator];
+ NSXMLNode *attribute;
+ NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
+
+ while ((attribute = [attributeEnum nextObject]))
+ [dictionary setObject:[attribute stringValue] forKey:[attribute name]];
+ return dictionary;
+}
+@end
+
@interface SUAppcast (Private)
- (void)reportError:(NSError *)error;
- (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes;
@@ -121,12 +138,7 @@ - (void)downloadDidFinish:(NSURLDownload *)aDownload
if ([name isEqualToString:@"enclosure"])
{
// enclosure is flattened as a separate dictionary for some reason
- NSEnumerator *attributeEnum = [[(NSXMLElement *)node attributes] objectEnumerator];
- NSXMLNode *attribute;
- NSMutableDictionary *encDict = [NSMutableDictionary dictionary];
-
- while ((attribute = [attributeEnum nextObject]))
- [encDict setObject:[attribute stringValue] forKey:[attribute name]];
+ NSDictionary *encDict = [(NSXMLElement *)node attributesAsDictionary];
[dict setObject:encDict forKey:@"enclosure"];
}
@@ -137,8 +149,19 @@ - (void)downloadDidFinish:(NSURLDownload *)aDownload
if (date)
[dict setObject:date forKey:name];
}
- else if (name != nil)
- {
+ else if ([name isEqualToString:@"sparkle:deltas"])
+ {
+ NSMutableArray *deltas = [NSMutableArray array];
+ NSEnumerator *childEnum = [[node children] objectEnumerator];
+ NSXMLNode *child;
+ while ((child = [childEnum nextObject])) {
+ if ([[child name] isEqualToString:@"enclosure"])
+ [deltas addObject:[(NSXMLElement *)child attributesAsDictionary]];
+ }
+ [dict setObject:deltas forKey:@"deltas"];
+ }
+ else if (name != nil)
+ {
// add all other values as strings
[dict setObject:[[node stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:name];
}
View
@@ -24,7 +24,9 @@
NSURL *fileURL;
NSString *versionString;
NSString *displayVersionString;
-
+
+ NSDictionary *deltaUpdates;
+
NSDictionary *propertiesDictionary;
}
@@ -41,6 +43,8 @@
- (NSURL *)fileURL;
- (NSString *)DSASignature;
- (NSString *)minimumSystemVersion;
+- (NSDictionary *)deltaUpdates;
+- (BOOL)isDeltaUpdate;
// Returns the dictionary provided in initWithDictionary; this might be useful later for extensions.
- (NSDictionary *)propertiesDictionary;
View
@@ -101,6 +101,19 @@ - (void)setMinimumSystemVersion:(NSString *)systemVersionString
minimumSystemVersion = [systemVersionString copy];
}
+- (NSDictionary *)deltaUpdates { return [[deltaUpdates retain] autorelease]; }
+- (void)setDeltaUpdates:(NSDictionary *)updates
+{
+ if (deltaUpdates == updates) return;
+ [deltaUpdates release];
+ deltaUpdates = [updates copy];
+}
+
+- (BOOL)isDeltaUpdate
+{
+ return [[propertiesDictionary objectForKey:@"enclosure"] objectForKey:@"sparkle:deltaFrom"] != nil;
+}
+
- initWithDictionary:(NSDictionary *)dict
{
return [self initWithDictionary:dict failureReason:nil];
@@ -155,30 +168,58 @@ - (void)setMinimumSystemVersion:(NSString *)systemVersionString
return nil;
}
- propertiesDictionary = [[NSMutableDictionary alloc] initWithDictionary:dict];
- [self setTitle:[dict objectForKey:@"title"]];
- [self setDate:[dict objectForKey:@"pubDate"]];
- [self setItemDescription:[dict objectForKey:@"description"]];
-
- [self setFileURL:[NSURL URLWithString:[[enclosure objectForKey:@"url"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
- [self setDSASignature:[enclosure objectForKey:@"sparkle:dsaSignature"]];
-
- [self setVersionString:newVersion];
- [self setMinimumSystemVersion:[dict objectForKey:@"sparkle:minimumSystemVersion"]];
-
- NSString *shortVersionString = [enclosure objectForKey:@"sparkle:shortVersionString"];
- if (shortVersionString)
- [self setDisplayVersionString:shortVersionString];
- else
- [self setDisplayVersionString:[self versionString]];
-
- // Find the appropriate release notes URL.
- if ([dict objectForKey:@"sparkle:releaseNotesLink"])
- [self setReleaseNotesURL:[NSURL URLWithString:[dict objectForKey:@"sparkle:releaseNotesLink"]]];
- else if ([[self itemDescription] hasPrefix:@"http://"]) // if the description starts with http://, use that.
- [self setReleaseNotesURL:[NSURL URLWithString:[self itemDescription]]];
- else
- [self setReleaseNotesURL:nil];
+ if (enclosure == nil || [enclosure objectForKey:@"url"] == nil || newVersion == nil)
+ {
+ [self release];
+ self = nil;
+ }
+ else
+ {
+ propertiesDictionary = [[NSMutableDictionary alloc] initWithDictionary:dict];
+ [self setTitle:[dict objectForKey:@"title"]];
+ [self setDate:[dict objectForKey:@"pubDate"]];
+ [self setItemDescription:[dict objectForKey:@"description"]];
+
+ [self setFileURL:[NSURL URLWithString:[[enclosure objectForKey:@"url"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
+ [self setDSASignature:[enclosure objectForKey:@"sparkle:dsaSignature"]];
+
+ [self setVersionString:newVersion];
+ [self setMinimumSystemVersion:[dict objectForKey:@"sparkle:minimumSystemVersion"]];
+
+ NSString *shortVersionString = [enclosure objectForKey:@"sparkle:shortVersionString"];
+ if (shortVersionString)
+ [self setDisplayVersionString:shortVersionString];
+ else
+ [self setDisplayVersionString:[self versionString]];
+
+ // Find the appropriate release notes URL.
+ if ([dict objectForKey:@"sparkle:releaseNotesLink"])
+ [self setReleaseNotesURL:[NSURL URLWithString:[dict objectForKey:@"sparkle:releaseNotesLink"]]];
+ else if ([[self itemDescription] hasPrefix:@"http://"]) // if the description starts with http://, use that.
+ [self setReleaseNotesURL:[NSURL URLWithString:[self itemDescription]]];
+ else
+ [self setReleaseNotesURL:nil];
+
+ if ([dict objectForKey:@"deltas"])
+ {
+ NSMutableDictionary *deltas = [NSMutableDictionary dictionary];
+ NSArray *deltaDictionaries = [dict objectForKey:@"deltas"];
+ NSEnumerator *deltaDictionariesEnum = [deltaDictionaries objectEnumerator];
+ NSDictionary *deltaDictionary;
+ while ((deltaDictionary = [deltaDictionariesEnum nextObject]))
+ {
+ NSMutableDictionary *fakeAppCastDict = [dict mutableCopy];
+ [fakeAppCastDict removeObjectForKey:@"deltas"];
+ [fakeAppCastDict setObject:deltaDictionary forKey:@"enclosure"];
+ SUAppcastItem *deltaItem = [[[self class] alloc] initWithDictionary:fakeAppCastDict];
+ [fakeAppCastDict release];
+
+ [deltas setObject:deltaItem forKey:[deltaDictionary objectForKey:@"sparkle:deltaFrom"]];
+ [deltaItem release];
+ }
+ [self setDeltaUpdates:deltas];
+ }
+ }
}
return self;
}
View
@@ -15,6 +15,7 @@
@class SUAppcastItem, SUUnarchiver, SUAppcast, SUUnarchiver, SUHost;
@interface SUBasicUpdateDriver : SUUpdateDriver {
SUAppcastItem *updateItem;
+ SUAppcastItem *nonDeltaUpdateItem;
NSURLDownload *download;
NSString *downloadPath;
@@ -42,6 +43,7 @@
- (void)extractUpdate;
- (void)unarchiverDidFinish:(SUUnarchiver *)ua;
- (void)unarchiverDidFail:(SUUnarchiver *)ua;
+- (void)failedToApplyDeltaUpdate;
- (void)installUpdate;
- (void)installerFinishedForHost:(SUHost *)host;
View
@@ -91,6 +91,12 @@ - (void)appcastDidFinishLoading:(SUAppcast *)ac
do {
item = [updateEnumerator nextObject];
} while (item && ![self hostSupportsItem:item]);
+
+ SUAppcastItem *deltaUpdateItem = [[item deltaUpdates] objectForKey:[host version]];
+ if (deltaUpdateItem && [self hostSupportsItem:deltaUpdateItem]) {
+ nonDeltaUpdateItem = [item retain];
+ item = deltaUpdateItem;
+ }
}
updateItem = [item retain];
@@ -200,7 +206,7 @@ - (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSS
- (void)extractUpdate
{
- SUUnarchiver *unarchiver = [SUUnarchiver unarchiverForPath:downloadPath];
+ SUUnarchiver *unarchiver = [SUUnarchiver unarchiverForPath:downloadPath updatingHost:host];
if (!unarchiver)
{
NSLog(@"Sparkle Error: No valid unarchiver for %@!", downloadPath);
@@ -212,6 +218,16 @@ - (void)extractUpdate
[unarchiver start];
}
+- (void)failedToApplyDeltaUpdate
+{
+ // When a delta update fails to apply we fall back on updating via a full install.
+ [updateItem release];
+ updateItem = nonDeltaUpdateItem;
+ nonDeltaUpdateItem = nil;
+
+ [self downloadUpdate];
+}
+
- (void)unarchiverDidFinish:(SUUnarchiver *)ua
{
if (ua) { CFRelease(ua); }
@@ -221,6 +237,12 @@ - (void)unarchiverDidFinish:(SUUnarchiver *)ua
- (void)unarchiverDidFail:(SUUnarchiver *)ua
{
if (ua) { CFRelease(ua); }
+
+ if ([updateItem isDeltaUpdate]) {
+ [self failedToApplyDeltaUpdate];
+ return;
+ }
+
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUUnarchivingError userInfo:[NSDictionary dictionaryWithObject:SULocalizedString(@"An error occurred while extracting the archive. Please try again later.", nil) forKey:NSLocalizedDescriptionKey]]];
}
@@ -328,6 +350,7 @@ - (void)abortUpdateWithError:(NSError *)error
- (void)dealloc
{
[updateItem release];
+ [nonDeltaUpdateItem release];
[download release];
[downloadPath release];
[relaunchPath release];
View
@@ -0,0 +1,15 @@
+//
+// SUBinaryDeltaApply.h
+// Sparkle
+//
+// Created by Mark Rowe on 2009-06-01.
+// Copyright 2009 Mark Rowe. All rights reserved.
+//
+
+#ifndef SUBINARYDELTAAPPLY_H
+#define SUBINARYDELTAAPPLY_H
+
+@class NSString;
+int applyBinaryDelta(NSString *source, NSString *destination, NSString *patchFile);
+
+#endif
Oops, something went wrong.

0 comments on commit 9bc63cc

Please sign in to comment.