root/trunk/Update Checker Sources/SUUtilities.m

Revision 269, 6.3 kB (checked in by durin42, 2 years ago)

Initial non-working updater app - it gets as far as downloading an update, but
it doesn't know how to unarchive yet. I've grabbed a bunch of sources from
Sparkle (duh from the filenames) but this is all we'll use from there, as from
here on out our mission is quite different from theirs. I've not yet tested
the appcast support very thoroughly, but it seems to be working in my initial
tests. I need to change it from NSUserDefaults to CFPreferencesCopyAppValue,
and fix the appcast URL in the Info.plist (note to other devs: the current URL
resolves to a nonroutable IP - you've been warned!).
I'll do unarchiving in a bit - but first I need to think about some things. I
think the solution Graham offered of using a shell script and exec() will be best.

Line 
1 //
2 //  SUUtilities.m
3 //  Sparkle
4 //
5 //  Created by Andy Matuschak on 3/12/06.
6 //  Copyright 2006 Andy Matuschak. All rights reserved.
7 //
8
9 #import "SUUtilities.h"
10
11 @interface SUUtilities : NSObject
12         +(NSString *)localizedStringForKey:(NSString *)key withComment:(NSString *)comment;
13 @end
14
15 id SUUnlocalizedInfoValueForKey(NSString *key)
16 {
17         // Okay, but if it isn't there, let's use the general one.
18         id value = [[[NSBundle mainBundle] infoDictionary] valueForKey:key];
19         if (!value)
20                 return SUInfoValueForKey(key);
21         return value;
22 }
23
24 id SUInfoValueForKey(NSString *key)
25 {
26         return [[NSBundle mainBundle] objectForInfoDictionaryKey:key];
27 }
28
29 NSString *SUHostAppName()
30 {
31         if (SUInfoValueForKey(@"CFBundleName")) { return SUInfoValueForKey(@"CFBundleName"); }
32         return [[[NSFileManager defaultManager] displayNameAtPath:[[NSBundle mainBundle] bundlePath]] stringByDeletingPathExtension];
33 }
34
35 NSString *SUHostAppDisplayName()
36 {
37         if (SUInfoValueForKey(@"CFBundleDisplayName")) { return SUInfoValueForKey(@"CFBundleDisplayName"); }
38         return SUHostAppName();
39 }
40
41 NSString *SUHostAppVersion()
42 {
43         return SUInfoValueForKey(@"CFBundleVersion");
44 }
45
46 NSString *SUHostAppVersionString()
47 {
48         NSString *shortVersionString = SUInfoValueForKey(@"CFBundleShortVersionString");
49         if (shortVersionString)
50         {
51                 if (![shortVersionString isEqualToString:SUHostAppVersion()])
52                         shortVersionString = [shortVersionString stringByAppendingFormat:@"/%@", SUHostAppVersion()];
53                 return shortVersionString;
54         }
55         else
56                 return SUHostAppVersion(); // fall back on CFBundleVersion
57 }
58
59 NSString *SULocalizedString(NSString *key, NSString *comment) {
60         return [SUUtilities localizedStringForKey:key withComment:comment];
61 }
62
63 enum {
64     kNumberType,
65     kStringType,
66     kPeriodType
67 };
68
69 // The version comparison code here is courtesy of Kevin Ballard, adapted from MacPAD. Thanks, Kevin!
70
71 int SUGetCharType(NSString *character)
72 {
73     if ([character isEqualToString:@"."]) {
74         return kPeriodType;
75     } else if ([character isEqualToString:@"0"] || [character intValue] != 0) {
76         return kNumberType;
77     } else {
78         return kStringType;
79     }   
80 }
81
82 NSArray *SUSplitVersionString(NSString *version)
83 {
84     NSString *character;
85     NSMutableString *s;
86     int i, n, oldType, newType;
87     NSMutableArray *parts = [NSMutableArray array];
88     if ([version length] == 0) {
89         // Nothing to do here
90         return parts;
91     }
92     s = [[[version substringToIndex:1] mutableCopy] autorelease];
93     oldType = SUGetCharType(s);
94     n = [version length] - 1;
95     for (i = 1; i <= n; ++i) {
96         character = [version substringWithRange:NSMakeRange(i, 1)];
97         newType = SUGetCharType(character);
98         if (oldType != newType || oldType == kPeriodType) {
99             // We've reached a new segment
100                         NSString *aPart = [[NSString alloc] initWithString:s];
101             [parts addObject:aPart];
102                         [aPart release];
103             [s setString:character];
104         } else {
105             // Add character to string and continue
106             [s appendString:character];
107         }
108         oldType = newType;
109     }
110    
111     // Add the last part onto the array
112     [parts addObject:[NSString stringWithString:s]];
113     return parts;
114 }
115
116 NSComparisonResult SUStandardVersionComparison(NSString *versionA, NSString *versionB)
117 {
118         NSArray *partsA = SUSplitVersionString(versionA);
119     NSArray *partsB = SUSplitVersionString(versionB);
120    
121     NSString *partA, *partB;
122     int i, n, typeA, typeB, intA, intB;
123    
124     n = MIN([partsA count], [partsB count]);
125     for (i = 0; i < n; ++i) {
126         partA = [partsA objectAtIndex:i];
127         partB = [partsB objectAtIndex:i];
128        
129         typeA = SUGetCharType(partA);
130         typeB = SUGetCharType(partB);
131        
132         // Compare types
133         if (typeA == typeB) {
134             // Same type; we can compare
135             if (typeA == kNumberType) {
136                 intA = [partA intValue];
137                 intB = [partB intValue];
138                 if (intA > intB) {
139                     return NSOrderedAscending;
140                 } else if (intA < intB) {
141                     return NSOrderedDescending;
142                 }
143             } else if (typeA == kStringType) {
144                 NSComparisonResult result = [partA compare:partB];
145                 if (result != NSOrderedSame) {
146                     return result;
147                 }
148             }
149         } else {
150             // Not the same type? Now we have to do some validity checking
151             if (typeA != kStringType && typeB == kStringType) {
152                 // typeA wins
153                 return NSOrderedAscending;
154             } else if (typeA == kStringType && typeB != kStringType) {
155                 // typeB wins
156                 return NSOrderedDescending;
157             } else {
158                 // One is a number and the other is a period. The period is invalid
159                 if (typeA == kNumberType) {
160                     return NSOrderedAscending;
161                 } else {
162                     return NSOrderedDescending;
163                 }
164             }
165         }
166     }
167     // The versions are equal up to the point where they both still have parts
168     // Lets check to see if one is larger than the other
169     if ([partsA count] != [partsB count]) {
170         // Yep. Lets get the next part of the larger
171         // n holds the value we want
172         NSString *missingPart;
173         int missingType, shorterResult, largerResult;
174        
175         if ([partsA count] > [partsB count]) {
176             missingPart = [partsA objectAtIndex:n];
177             shorterResult = NSOrderedDescending;
178             largerResult = NSOrderedAscending;
179         } else {
180             missingPart = [partsB objectAtIndex:n];
181             shorterResult = NSOrderedAscending;
182             largerResult = NSOrderedDescending;
183         }
184        
185         missingType = SUGetCharType(missingPart);
186         // Check the type
187         if (missingType == kStringType) {
188             // It's a string. Shorter version wins
189             return shorterResult;
190         } else {
191             // It's a number/period. Larger version wins
192             return largerResult;
193         }
194     }
195    
196     // The 2 strings are identical
197     return NSOrderedSame;
198 }
199
200 @implementation SUUtilities
201
202 + (NSString *)localizedStringForKey:(NSString *)key withComment:(NSString *)comment
203 {
204         return NSLocalizedStringFromTableInBundle(key, @"Sparkle", [NSBundle bundleForClass:[self class]], comment);
205 }
206
207 @end
Note: See TracBrowser for help on using the browser.