| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- //
- // LNStandardVersionComparator.m
- // Sparkle
- //
- // Created by Andy Matuschak on 12/21/07.
- // Copyright 2007 Andy Matuschak. All rights reserved.
- //
- #import <Cocoa/Cocoa.h>
- #import "LNStandardVersionComparator.h"
- @implementation LNStandardVersionComparator
- +(LNStandardVersionComparator*) defaultComparator {
- static LNStandardVersionComparator* defaultComparator = nil;
- if (defaultComparator == nil) defaultComparator = [[LNStandardVersionComparator alloc] init];
- return defaultComparator;
- }
- typedef enum {
- kNumberType,
- kStringType,
- kPeriodType
- } SUCharacterType;
- -(SUCharacterType) typeOfCharacter:(NSString*)character {
- if ([character isEqualToString:@"."]) {
- return kPeriodType;
- } else if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[character characterAtIndex:0]]) {
- return kNumberType;
- } else {
- return kStringType;
- }
- }
- -(NSArray*) splitVersionString:(NSString*)version {
- NSString* character;
- NSMutableString* s;
- NSUInteger i, n;
- SUCharacterType oldType, newType;
- NSMutableArray* parts = [NSMutableArray array];
- if ([version length] == 0) {
- // Nothing to do here
- return parts;
- }
- s = [[[version substringToIndex:1] mutableCopy] autorelease];
- oldType = [self typeOfCharacter:s];
- n = [version length] - 1;
- for (i = 1; i <= n; ++i) {
- character = [version substringWithRange:NSMakeRange(i, 1)];
- newType = [self typeOfCharacter:character];
- if ((oldType != newType) || (oldType == kPeriodType)) {
- // We've reached a new segment
- NSString* aPart = [[[NSString alloc] initWithString:s] autorelease];
- [parts addObject:aPart];
- [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) compareVersion:(NSString*)versionA toVersion:(NSString*)versionB;
- {
- NSArray* partsA = [self splitVersionString:versionA];
- NSArray* partsB = [self splitVersionString:versionB];
- NSString* partA, * partB;
- NSUInteger i, n;
- int intA, intB;
- SUCharacterType typeA, typeB;
- n = MIN([partsA count], [partsB count]);
- for (i = 0; i < n; ++i) {
- partA = [partsA objectAtIndex:i];
- partB = [partsB objectAtIndex:i];
- typeA = [self typeOfCharacter:partA];
- typeB = [self typeOfCharacter:partB];
- // Compare types
- if (typeA == typeB) {
- // Same type; we can compare
- if (typeA == kNumberType) {
- intA = [partA intValue];
- intB = [partB intValue];
- if (intA > intB) {
- return NSOrderedDescending;
- } else if (intA < intB) {
- return NSOrderedAscending;
- }
- } 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 NSOrderedDescending;
- } else if ((typeA == kStringType) && (typeB != kStringType)) {
- // typeB wins
- return NSOrderedAscending;
- } else {
- // One is a number and the other is a period. The period is invalid
- if (typeA == kNumberType) {
- return NSOrderedDescending;
- } else {
- return NSOrderedAscending;
- }
- }
- }
- }
- // 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 index of the part we want.
- NSString* missingPart;
- SUCharacterType missingType;
- NSComparisonResult shorterResult, largerResult;
- if ([partsA count] > [partsB count]) {
- missingPart = [partsA objectAtIndex:n];
- shorterResult = NSOrderedAscending;
- largerResult = NSOrderedDescending;
- } else {
- missingPart = [partsB objectAtIndex:n];
- shorterResult = NSOrderedDescending;
- largerResult = NSOrderedAscending;
- }
- missingType = [self typeOfCharacter: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;
- }
- @end
|