cog/Frameworks/Sparkle/SUUtilities.m

199 lines
6.0 KiB
Objective-C
Executable File

//
// SUUtilities.m
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUUtilities.h"
@interface SUUtilities : NSObject
+(NSString *)localizedStringForKey:(NSString *)key withComment:(NSString *)comment;
@end
id SUInfoValueForKey(NSString *key)
{
return [[NSBundle mainBundle] objectForInfoDictionaryKey:key];
}
NSString *SUHostAppName()
{
if (SUInfoValueForKey(@"CFBundleName")) { return SUInfoValueForKey(@"CFBundleName"); }
return [[[NSFileManager defaultManager] displayNameAtPath:[[NSBundle mainBundle] bundlePath]] stringByDeletingPathExtension];
}
NSString *SUHostAppDisplayName()
{
if (SUInfoValueForKey(@"CFBundleDisplayName")) { return SUInfoValueForKey(@"CFBundleDisplayName"); }
return SUHostAppName();
}
NSString *SUHostAppVersion()
{
return SUInfoValueForKey(@"CFBundleVersion");
}
NSString *SUHostAppVersionString()
{
NSString *shortVersionString = SUInfoValueForKey(@"CFBundleShortVersionString");
if (shortVersionString)
{
if (![shortVersionString isEqualToString:SUHostAppVersion()])
shortVersionString = [shortVersionString stringByAppendingFormat:@"/%@", SUHostAppVersion()];
return shortVersionString;
}
else
return SUHostAppVersion(); // fall back on CFBundleVersion
}
NSString *SULocalizedString(NSString *key, NSString *comment) {
return [SUUtilities localizedStringForKey:key withComment:comment];
}
enum {
kNumberType,
kStringType,
kPeriodType
};
// The version comparison code here is courtesy of Kevin Ballard, adapted from MacPAD. Thanks, Kevin!
int SUGetCharType(NSString *character)
{
if ([character isEqualToString:@"."]) {
return kPeriodType;
} else if ([character isEqualToString:@"0"] || [character intValue] != 0) {
return kNumberType;
} else {
return kStringType;
}
}
NSArray *SUSplitVersionString(NSString *version)
{
NSString *character;
NSMutableString *s;
int i, n, oldType, newType;
NSMutableArray *parts = [NSMutableArray array];
if ([version length] == 0) {
// Nothing to do here
return parts;
}
s = [[[version substringToIndex:1] mutableCopy] autorelease];
oldType = SUGetCharType(s);
n = [version length] - 1;
for (i = 1; i <= n; ++i) {
character = [version substringWithRange:NSMakeRange(i, 1)];
newType = SUGetCharType(character);
if (oldType != newType || oldType == kPeriodType) {
// We've reached a new segment
NSString *aPart = [[NSString alloc] initWithString:s];
[parts addObject:aPart];
[aPart release];
[s setString:character];
} else {
// Add character to string and continue
[s appendString:character];
}
oldType = newType;
}
// Add the last part onto the array
[parts addObject:[NSString stringWithString:s]];
return parts;
}
NSComparisonResult SUStandardVersionComparison(NSString *versionA, NSString *versionB)
{
NSArray *partsA = SUSplitVersionString(versionA);
NSArray *partsB = SUSplitVersionString(versionB);
NSString *partA, *partB;
int i, n, typeA, typeB, intA, intB;
n = MIN([partsA count], [partsB count]);
for (i = 0; i < n; ++i) {
partA = [partsA objectAtIndex:i];
partB = [partsB objectAtIndex:i];
typeA = SUGetCharType(partA);
typeB = SUGetCharType(partB);
// Compare types
if (typeA == typeB) {
// Same type; we can compare
if (typeA == kNumberType) {
intA = [partA intValue];
intB = [partB intValue];
if (intA > intB) {
return NSOrderedAscending;
} else if (intA < intB) {
return NSOrderedDescending;
}
} else if (typeA == kStringType) {
NSComparisonResult result = [partA compare:partB];
if (result != NSOrderedSame) {
return result;
}
}
} else {
// Not the same type? Now we have to do some validity checking
if (typeA != kStringType && typeB == kStringType) {
// typeA wins
return NSOrderedAscending;
} else if (typeA == kStringType && typeB != kStringType) {
// typeB wins
return NSOrderedDescending;
} else {
// One is a number and the other is a period. The period is invalid
if (typeA == kNumberType) {
return NSOrderedAscending;
} else {
return NSOrderedDescending;
}
}
}
}
// The versions are equal up to the point where they both still have parts
// Lets check to see if one is larger than the other
if ([partsA count] != [partsB count]) {
// Yep. Lets get the next part of the larger
// n holds the value we want
NSString *missingPart;
int missingType, shorterResult, largerResult;
if ([partsA count] > [partsB count]) {
missingPart = [partsA objectAtIndex:n];
shorterResult = NSOrderedDescending;
largerResult = NSOrderedAscending;
} else {
missingPart = [partsB objectAtIndex:n];
shorterResult = NSOrderedAscending;
largerResult = NSOrderedDescending;
}
missingType = SUGetCharType(missingPart);
// Check the type
if (missingType == kStringType) {
// It's a string. Shorter version wins
return shorterResult;
} else {
// It's a number/period. Larger version wins
return largerResult;
}
}
// The 2 strings are identical
return NSOrderedSame;
}
@implementation SUUtilities
+ (NSString *)localizedStringForKey:(NSString *)key withComment:(NSString *)comment
{
return NSLocalizedStringFromTableInBundle(key, @"Sparkle", [NSBundle bundleForClass:[self class]], comment);
}
@end