X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/d6dad1b433cca3973dcb114c69e389b2ecb765fd..e124f5222a28c2a3e2081155cbaa02017b763b93:/Cydia.mm diff --git a/Cydia.mm b/Cydia.mm index d07e85f4..d898ef3a 100644 --- a/Cydia.mm +++ b/Cydia.mm @@ -41,6 +41,7 @@ /* #include Directives {{{ */ #import "UICaboodle.h" +#include #include #include @@ -55,6 +56,7 @@ // XXX: remove #import +#include #include #include @@ -114,14 +116,71 @@ bool _itv; exit(0); \ } while (false) -static uint64_t profile_; - #define _timestamp ({ \ struct timeval tv; \ gettimeofday(&tv, NULL); \ tv.tv_sec * 1000000 + tv.tv_usec; \ }) +typedef std::vector TimeList; +TimeList times_; + +class ProfileTime { + private: + const char *name_; + uint64_t total_; + uint64_t count_; + + public: + ProfileTime(const char *name) : + name_(name), + total_(0) + { + times_.push_back(this); + } + + void AddTime(uint64_t time) { + total_ += time; + ++count_; + } + + void Print() { + if (total_ != 0) + std::cerr << std::setw(5) << count_ << ", " << std::setw(7) << total_ << " : " << name_ << std::endl; + total_ = 0; + count_ = 0; + } +}; + +class ProfileTimer { + private: + ProfileTime &time_; + uint64_t start_; + + public: + ProfileTimer(ProfileTime &time) : + time_(time), + start_(_timestamp) + { + } + + ~ProfileTimer() { + time_.AddTime(_timestamp - start_); + } +}; + +void PrintTimes() { + for (TimeList::const_iterator i(times_.begin()); i != times_.end(); ++i) + (*i)->Print(); + std::cerr << "========" << std::endl; +} + +#define _profile(name) { \ + static ProfileTime name(#name); \ + ProfileTimer _ ## name(name); + +#define _end } + /* Objective-C Handle<> {{{ */ template class _H { @@ -172,7 +231,72 @@ void NSLogRect(const char *fix, const CGRect &rect) { NSLog(@"%s(%g,%g)+(%g,%g)", fix, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); } +@interface NSObject (Cydia) +- (id) yieldToSelector:(SEL)selector withObject:(id)object; +- (id) yieldToSelector:(SEL)selector; +@end + +@implementation NSObject (Cydia) + +- (void) doNothing { +} + +- (void) _yieldToContext:(NSMutableArray *)context { _pooled + SEL selector(reinterpret_cast([[context objectAtIndex:0] pointerValue])); + id object([[context objectAtIndex:1] nonretainedObjectValue]); + volatile bool &stopped(*reinterpret_cast([[context objectAtIndex:2] pointerValue])); + + /* XXX: deal with exceptions */ + id value([self performSelector:selector withObject:object]); + + [context removeAllObjects]; + if (value != nil) + [context addObject:value]; + + stopped = true; + + [self + performSelectorOnMainThread:@selector(doNothing) + withObject:nil + waitUntilDone:NO + ]; +} + +- (id) yieldToSelector:(SEL)selector withObject:(id)object { + /*return [self performSelector:selector withObject:object];*/ + + volatile bool stopped(false); + + NSMutableArray *context([NSMutableArray arrayWithObjects: + [NSValue valueWithPointer:selector], + [NSValue valueWithNonretainedObject:object], + [NSValue valueWithPointer:const_cast(&stopped)], + nil]); + + NSThread *thread([[[NSThread alloc] + initWithTarget:self + selector:@selector(_yieldToContext:) + object:context + ] autorelease]); + + [thread start]; + + NSRunLoop *loop([NSRunLoop currentRunLoop]); + NSDate *future([NSDate distantFuture]); + + while (!stopped && [loop runMode:NSDefaultRunLoopMode beforeDate:future]); + + return [context count] == 0 ? nil : [context objectAtIndex:0]; +} + +- (id) yieldToSelector:(SEL)selector { + return [self yieldToSelector:selector withObject:nil]; +} + +@end + /* NSForcedOrderingSearch doesn't work on the iPhone */ +static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch; static const NSStringCompareOptions BaseCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch; static const NSStringCompareOptions ForcedCompareOptions_ = BaseCompareOptions_; static const NSStringCompareOptions LaxCompareOptions_ = BaseCompareOptions_ | NSCaseInsensitiveSearch; @@ -257,8 +381,9 @@ extern NSString * const kCAFilterNearest; #define lprintf(args...) fprintf(stderr, args) -#define ForRelease 0 +#define ForRelease 1 #define ForSaurik (1 && !ForRelease) +#define ShowInternals (1 && !ForRelease) #define IgnoreInstall (0 && !ForRelease) #define RecycleWebViews 0 #define AlwaysReload (1 && !ForRelease) @@ -266,6 +391,11 @@ extern NSString * const kCAFilterNearest; #if ForRelease #undef _trace #define _trace(args...) +#undef _profile +#define _profile(name) { +#undef _end +#define _end } +#define PrintTimes() do {} while (false) #endif /* Radix Sort {{{ */ @@ -403,12 +533,19 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s @end @interface NSString (Cydia) ++ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length; + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length; - (NSComparisonResult) compareByPath:(NSString *)other; +- (NSString *) stringByCachingURLWithCurrentCDN; +- (NSString *) stringByAddingPercentEscapesIncludingReserved; @end @implementation NSString (Cydia) ++ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length { + return [[[NSString alloc] initWithBytesNoCopy:const_cast(bytes) length:length encoding:NSUTF8StringEncoding freeWhenDone:NO] autorelease]; +} + + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length { return [[[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding] autorelease]; } @@ -443,6 +580,26 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s return result == NSOrderedSame ? value : result; } +- (NSString *) stringByCachingURLWithCurrentCDN { + return [self + stringByReplacingOccurrencesOfString:@"://" + withString:@"://ne.edgecastcdn.net/8003A4/" + options:0 + /* XXX: this is somewhat inaccurate */ + range:NSMakeRange(0, 10) + ]; +} + +- (NSString *) stringByAddingPercentEscapesIncludingReserved { + return [(id)CFURLCreateStringByAddingPercentEscapes( + kCFAllocatorDefault, + (CFStringRef) self, + NULL, + CFSTR(";/?:@&=+$,"), + kCFStringEncodingUTF8 + ) autorelease]; +} + @end /* Perl-Compatible RegEx {{{ */ @@ -629,6 +786,8 @@ static UIFont *Font22Bold_; static const char *Machine_ = NULL; static const NSString *UniqueID_ = nil; static const NSString *Build_ = nil; +static const NSString *Product_ = nil; +static const NSString *Safari_ = nil; CFLocaleRef Locale_; CGColorSpaceRef space_; @@ -638,7 +797,6 @@ bool reload_; static NSDictionary *SectionMap_; static NSMutableDictionary *Metadata_; -static NSMutableDictionary *Indices_; static _transient NSMutableDictionary *Settings_; static _transient NSString *Role_; static _transient NSMutableDictionary *Packages_; @@ -760,6 +918,7 @@ bool isSectionVisible(NSString *section) { - (void) syncData; - (void) askForSettings; - (UIProgressHUD *) addProgressHUD; +- (void) removeProgressHUD:(UIProgressHUD *)hud; - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag; - (RVPage *) pageForPackage:(NSString *)name; - (void) openMailToURL:(NSURL *)url; @@ -852,8 +1011,8 @@ class Progress : protected: virtual void Update() { - [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]]; - [delegate_ setProgressPercent:(Percent / 100)]; + /*[delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]]; + [delegate_ setProgressPercent:(Percent / 100)];*/ } public: @@ -867,13 +1026,15 @@ class Progress : } virtual void Done() { - [delegate_ setProgressPercent:1]; + //[delegate_ setProgressPercent:1]; } }; /* }}} */ /* Database Interface {{{ */ @interface Database : NSObject { + unsigned era_; + pkgCacheFile cache_; pkgDepCache::Policy *policy_; pkgRecords *records_; @@ -896,6 +1057,7 @@ class Progress : } + (Database *) sharedInstance; +- (unsigned) era; - (void) _readCydia:(NSNumber *)fd; - (void) _readStatus:(NSNumber *)fd; @@ -1166,6 +1328,8 @@ class Progress : /* }}} */ /* Package Class {{{ */ @interface Package : NSObject { + unsigned era_; + pkgCache::PkgIterator iterator_; _transient Database *database_; pkgCache::VerIterator version_; @@ -1175,6 +1339,7 @@ class Progress : bool cached_; NSString *section_; + bool essential_; NSString *latest_; NSString *installed_; @@ -1206,7 +1371,7 @@ class Progress : - (Address *) maintainer; - (size_t) size; - (NSString *) description; -- (NSString *) index; +- (unichar) index; - (NSMutableDictionary *) metadata; - (NSDate *) seen; @@ -1244,7 +1409,6 @@ class Progress : - (Source *) source; - (NSString *) role; -- (NSString *) rating; - (BOOL) matches:(NSString *)text; @@ -1261,10 +1425,10 @@ class Progress : - (void) install; - (void) remove; -- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search; -- (NSNumber *) isInstalledAndVisible:(NSNumber *)number; -- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section; -- (NSNumber *) isVisibleInSource:(Source *)source; +- (bool) isUnfilteredAndSearchedForBy:(NSString *)search; +- (bool) isInstalledAndVisible:(NSNumber *)number; +- (bool) isVisiblyUninstalledInSection:(NSString *)section; +- (bool) isVisibleInSource:(Source *)source; @end @@ -1273,7 +1437,6 @@ class Progress : - (void) dealloc { if (source_ != nil) [source_ release]; - if (section_ != nil) [section_ release]; @@ -1307,7 +1470,7 @@ class Progress : } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"rating", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil]; + return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil]; } - (NSArray *) attributeKeys { @@ -1320,156 +1483,215 @@ class Progress : - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database { if ((self = [super init]) != nil) { + _profile(Package$initWithIterator) + @synchronized (database) { + era_ = [database era]; + iterator_ = iterator; database_ = database; - version_ = [database_ policy]->GetCandidateVer(iterator_); + _profile(Package$initWithIterator$Control) + _end + + _profile(Package$initWithIterator$Version) + version_ = [database_ policy]->GetCandidateVer(iterator_); + _end + NSString *latest = version_.end() ? nil : [NSString stringWithUTF8String:version_.VerStr()]; - latest_ = latest == nil ? nil : [StripVersion(latest) retain]; - pkgCache::VerIterator current = iterator_.CurrentVer(); - NSString *installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()]; - installed_ = [StripVersion(installed) retain]; + _profile(Package$initWithIterator$Latest) + latest_ = latest == nil ? nil : [StripVersion(latest) retain]; + _end - if (!version_.end()) - file_ = version_.FileList(); - else { - pkgCache &cache([database_ cache]); - file_ = pkgCache::VerFileIterator(cache, cache.VerFileP); - } + pkgCache::VerIterator current; + NSString *installed; - id_ = [[NSString stringWithUTF8String:iterator_.Name()] retain]; - - if (!file_.end()) { - pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); - - const char *begin, *end; - parser->GetRec(begin, end); - - NSString *website(nil); - NSString *sponsor(nil); - NSString *author(nil); - NSString *tag(nil); - - struct { - const char *name_; - NSString **value_; - } names[] = { - {"name", &name_}, - {"icon", &icon_}, - {"depiction", &depiction_}, - {"homepage", &homepage_}, - {"website", &website}, - {"sponsor", &sponsor}, - {"author", &author}, - {"tag", &tag}, - }; - - while (begin != end) - if (*begin == '\n') { - ++begin; - continue; - } else if (isblank(*begin)) next: { - begin = static_cast(memchr(begin + 1, '\n', end - begin - 1)); - if (begin == NULL) - break; - } else if (const char *colon = static_cast(memchr(begin, ':', end - begin))) { - const char *name(begin); - size_t size(colon - begin); - - begin = static_cast(memchr(begin, '\n', end - begin)); - - { - const char *stop(begin == NULL ? end : begin); - while (stop[-1] == '\r') - --stop; - while (++colon != stop && isblank(*colon)); - - for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i) - if (strncasecmp(names[i].name_, name, size) == 0) { - NSString *value([NSString stringWithUTF8Bytes:colon length:(stop - colon)]); - *names[i].value_ = value; - break; - } - } + _profile(Package$initWithIterator$Current) + current = iterator_.CurrentVer(); + installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()]; + _end - if (begin == NULL) - break; - ++begin; - } else goto next; - - if (name_ != nil) - name_ = [name_ retain]; - tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain]; - if (icon_ != nil) - icon_ = [icon_ retain]; - if (depiction_ != nil) - depiction_ = [depiction_ retain]; - if (homepage_ == nil) - homepage_ = website; - if ([homepage_ isEqualToString:depiction_]) - homepage_ = nil; - if (homepage_ != nil) - homepage_ = [homepage_ retain]; - if (sponsor != nil) - sponsor_ = [[Address addressWithString:sponsor] retain]; - if (author != nil) - author_ = [[Address addressWithString:author] retain]; - if (tag != nil) - tags_ = [[tag componentsSeparatedByString:@", "] retain]; - } + _profile(Package$initWithIterator$Installed) + installed_ = [StripVersion(installed) retain]; + _end - if (tags_ != nil) - for (int i(0), e([tags_ count]); i != e; ++i) { - NSString *tag = [tags_ objectAtIndex:i]; - if ([tag hasPrefix:@"role::"]) { - role_ = [[tag substringFromIndex:6] retain]; - break; - } + _profile(Package$initWithIterator$File) + if (!version_.end()) + file_ = version_.FileList(); + else { + pkgCache &cache([database_ cache]); + file_ = pkgCache::VerFileIterator(cache, cache.VerFileP); } + _end + + _profile(Package$initWithIterator$Name) + id_ = [[NSString stringWithUTF8String:iterator_.Name()] retain]; + _end + + if (!file_.end()) + _profile(Package$initWithIterator$Parse) + pkgRecords::Parser *parser; + + _profile(Package$initWithIterator$Parse$Lookup) + parser = &[database_ records]->Lookup(file_); + _end + + const char *begin, *end; + parser->GetRec(begin, end); + + NSString *website(nil); + NSString *sponsor(nil); + NSString *author(nil); + NSString *tag(nil); + + struct { + const char *name_; + NSString **value_; + } names[] = { + {"name", &name_}, + {"icon", &icon_}, + {"depiction", &depiction_}, + {"homepage", &homepage_}, + {"website", &website}, + {"sponsor", &sponsor}, + {"author", &author}, + {"tag", &tag}, + }; + + while (begin != end) + if (*begin == '\n') { + ++begin; + continue; + } else if (isblank(*begin)) next: { + begin = static_cast(memchr(begin + 1, '\n', end - begin - 1)); + if (begin == NULL) + break; + } else if (const char *colon = static_cast(memchr(begin, ':', end - begin))) { + const char *name(begin); + size_t size(colon - begin); + + begin = static_cast(memchr(begin, '\n', end - begin)); + + { + const char *stop(begin == NULL ? end : begin); + while (stop[-1] == '\r') + --stop; + while (++colon != stop && isblank(*colon)); + + for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i) + if (strncasecmp(names[i].name_, name, size) == 0) { + NSString *value; + + _profile(Package$initWithIterator$Parse$Value) + value = [NSString stringWithUTF8Bytes:colon length:(stop - colon)]; + _end + + *names[i].value_ = value; + break; + } + } + + if (begin == NULL) + break; + ++begin; + } else goto next; + + _profile(Package$initWithIterator$Parse$Retain) + if (name_ != nil) + name_ = [name_ retain]; + _profile(Package$initWithIterator$Parse$Tagline) + tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain]; + _end + if (icon_ != nil) + icon_ = [icon_ retain]; + if (depiction_ != nil) + depiction_ = [depiction_ retain]; + if (homepage_ == nil) + homepage_ = website; + if ([homepage_ isEqualToString:depiction_]) + homepage_ = nil; + if (homepage_ != nil) + homepage_ = [homepage_ retain]; + if (sponsor != nil) + sponsor_ = [[Address addressWithString:sponsor] retain]; + if (author != nil) + author_ = [[Address addressWithString:author] retain]; + if (tag != nil) + tags_ = [[tag componentsSeparatedByString:@", "] retain]; + _end + _end + + _profile(Package$initWithIterator$Tags) + if (tags_ != nil) + for (NSString *tag in tags_) + if ([tag hasPrefix:@"role::"]) { + role_ = [[tag substringFromIndex:6] retain]; + break; + } + _end NSString *solid(latest == nil ? installed : latest); bool changed(false); NSString *key([id_ lowercaseString]); - NSMutableDictionary *metadata = [Packages_ objectForKey:key]; - if (metadata == nil) { - metadata = [[NSMutableDictionary dictionaryWithObjectsAndKeys: - now_, @"FirstSeen", - nil] mutableCopy]; - - if (solid != nil) - [metadata setObject:solid forKey:@"LastVersion"]; - changed = true; - } else { - NSDate *first([metadata objectForKey:@"FirstSeen"]); - NSDate *last([metadata objectForKey:@"LastSeen"]); - NSString *version([metadata objectForKey:@"LastVersion"]); + _profile(Package$initWithIterator$Metadata) + NSMutableDictionary *metadata = [Packages_ objectForKey:key]; + if (metadata == nil) { + metadata = [[NSMutableDictionary dictionaryWithObjectsAndKeys: + now_, @"FirstSeen", + nil] mutableCopy]; - if (first == nil) { - first = last == nil ? now_ : last; - [metadata setObject:first forKey:@"FirstSeen"]; + if (solid != nil) + [metadata setObject:solid forKey:@"LastVersion"]; changed = true; + } else { + NSDate *first([metadata objectForKey:@"FirstSeen"]); + NSDate *last([metadata objectForKey:@"LastSeen"]); + NSString *version([metadata objectForKey:@"LastVersion"]); + + if (first == nil) { + first = last == nil ? now_ : last; + [metadata setObject:first forKey:@"FirstSeen"]; + changed = true; + } + + if (solid != nil) + if (version == nil) { + [metadata setObject:solid forKey:@"LastVersion"]; + changed = true; + } else if (![version isEqualToString:solid]) { + [metadata setObject:solid forKey:@"LastVersion"]; + last = now_; + [metadata setObject:last forKey:@"LastSeen"]; + changed = true; + } } - if (solid != nil) - if (version == nil) { - [metadata setObject:solid forKey:@"LastVersion"]; - changed = true; - } else if (![version isEqualToString:solid]) { - [metadata setObject:solid forKey:@"LastVersion"]; - last = now_; - [metadata setObject:last forKey:@"LastSeen"]; - changed = true; + if (changed) { + [Packages_ setObject:metadata forKey:key]; + Changed_ = true; + } + _end + + const char *section(iterator_.Section()); + if (section == NULL) + section_ = nil; + else { + NSString *name([[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_']); + + lookup: + if (NSDictionary *value = [SectionMap_ objectForKey:name]) + if (NSString *rename = [value objectForKey:@"Rename"]) { + name = rename; + goto lookup; } - } - if (changed) { - [Packages_ setObject:metadata forKey:key]; - Changed_ = true; + section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain]; } - } return self; + + essential_ = (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES; + } _end } return self; } + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database { @@ -1484,23 +1706,6 @@ class Progress : } - (NSString *) section { - if (section_ != nil) - return section_; - - const char *section = iterator_.Section(); - if (section == NULL) - return nil; - - NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_']; - - lookup: - if (NSDictionary *value = [SectionMap_ objectForKey:name]) - if (NSString *rename = [value objectForKey:@"Rename"]) { - name = rename; - goto lookup; - } - - section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain]; return section_; } @@ -1548,7 +1753,7 @@ class Progress : return nil; NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet]; - for (size_t i(1); i != [lines count]; ++i) { + for (size_t i(1), e([lines count]); i != e; ++i) { NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace]; [trimmed addObject:trim]; } @@ -1556,9 +1761,16 @@ class Progress : return [trimmed componentsJoinedByString:@"\n"]; } -- (NSString *) index { - NSString *index = [[[self name] substringToIndex:1] uppercaseString]; - return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123"; +- (unichar) index { + _profile(Package$index) + NSString *name([self name]); + if ([name length] == 0) + return '#'; + unichar character([name characterAtIndex:0]); + if (!isalpha(character)) + return '#'; + return toupper(character); + _end } - (NSMutableDictionary *) metadata { @@ -1606,14 +1818,14 @@ class Progress : bool value; if (current.end()) - value = essential && [self essential]; + value = essential && [self essential] && [self visible]; else value = !version_.end() && version_ != current;// && (!essential || ![database_ cache][iterator_].Keep()); return value; } - (BOOL) essential { - return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES; + return essential_; } - (BOOL) broken { @@ -1827,8 +2039,17 @@ class Progress : - (Source *) source { if (!cached_) { - source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain]; - cached_ = true; + @synchronized (database_) { + if ([database_ era] != era_ || file_.end()) + source_ = nil; + else { + source_ = [database_ getSource:file_.File()]; + if (source_ != nil) + [source_ retain]; + } + + cached_ = true; + } } return source_; @@ -1838,28 +2059,21 @@ class Progress : return role_; } -- (NSString *) rating { - if (NSString *rating = [Indices_ objectForKey:@"Rating"]) - return [rating stringByReplacingOccurrencesOfString:@"@P" withString:[id_ stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - else - return nil; -} - - (BOOL) matches:(NSString *)text { if (text == nil) return NO; NSRange range; - range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch]; + range = [[self id] rangeOfString:text options:MatchCompareOptions_]; if (range.location != NSNotFound) return YES; - range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch]; + range = [[self name] rangeOfString:text options:MatchCompareOptions_]; if (range.location != NSNotFound) return YES; - range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch]; + range = [[self tagline] rangeOfString:text options:MatchCompareOptions_]; if (range.location != NSNotFound) return YES; @@ -1982,33 +2196,40 @@ class Progress : [database_ cache]->MarkDelete(iterator_, true); } -- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search { - return [NSNumber numberWithBool:( - [self unfiltered] && [self matches:search] - )]; +- (bool) isUnfilteredAndSearchedForBy:(NSString *)search { + _profile(Package$isUnfilteredAndSearchedForBy) + bool value(true); + + _profile(Package$isUnfilteredAndSearchedForBy$Unfiltered) + value &= [self unfiltered]; + _end + + _profile(Package$isUnfilteredAndSearchedForBy$Match) + value &= [self matches:search]; + _end + + return value; + _end } -- (NSNumber *) isInstalledAndVisible:(NSNumber *)number { - return [NSNumber numberWithBool:( - (![number boolValue] || [self visible]) && [self installed] != nil - )]; +- (bool) isInstalledAndVisible:(NSNumber *)number { + return (![number boolValue] || [self visible]) && [self installed] != nil; } -- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name { +- (bool) isVisiblyUninstalledInSection:(NSString *)name { NSString *section = [self section]; - return [NSNumber numberWithBool:( + return [self visible] && [self installed] == nil && ( name == nil || section == nil && [name length] == 0 || [name isEqualToString:section] - ) - )]; + ); } -- (NSNumber *) isVisibleInSource:(Source *)source { - return [NSNumber numberWithBool:([self source] == source && [self visible])]; +- (bool) isVisibleInSource:(Source *)source { + return [self source] == source && [self visible]; } @end @@ -2016,6 +2237,7 @@ class Progress : /* Section Class {{{ */ @interface Section : NSObject { NSString *name_; + unichar index_; size_t row_; size_t count_; } @@ -2023,7 +2245,9 @@ class Progress : - (NSComparisonResult) compareByName:(Section *)section; - (Section *) initWithName:(NSString *)name; - (Section *) initWithName:(NSString *)name row:(size_t)row; +- (Section *) initWithIndex:(unichar)index row:(size_t)row; - (NSString *) name; +- (unichar) index; - (size_t) row; - (size_t) count; - (void) addToCount; @@ -2061,6 +2285,15 @@ class Progress : - (Section *) initWithName:(NSString *)name row:(size_t)row { if ((self = [super init]) != nil) { name_ = [name retain]; + index_ = '\0'; + row_ = row; + } return self; +} + +- (Section *) initWithIndex:(unichar)index row:(size_t)row { + if ((self = [super init]) != nil) { + name_ = [(index == '#' ? @"123" : [NSString stringWithCharacters:&index length:1]) retain]; + index_ = index; row_ = row; } return self; } @@ -2069,6 +2302,10 @@ class Progress : return name_; } +- (unichar) index { + return index_; +} + - (size_t) row { return row_; } @@ -2097,6 +2334,10 @@ static NSArray *Finishes_; return instance; } +- (unsigned) era { + return era_; +} + - (void) dealloc { _assert(false); [super dealloc]; @@ -2340,7 +2581,11 @@ static NSArray *Finishes_; return issues; } -- (void) reloadData { +- (void) reloadData { _pooled + @synchronized (self) { + ++era_; + } + _error->Discard(); delete list_; @@ -2412,13 +2657,15 @@ static NSArray *Finishes_; [packages_ removeAllObjects]; _trace(); - profile_ = 0; for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator) if (Package *package = [Package packageWithIterator:iterator database:self]) [packages_ addObject:package]; _trace(); [packages_ sortUsingSelector:@selector(compareByName:)]; _trace(); + + _config->Set("Acquire::http::Timeout", 15); + _config->Set("Acquire::http::MaxParallel", 4); } - (void) configure { @@ -2806,8 +3053,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { pkgCacheFile &cache([database_ cache]); NSArray *packages = [database_ packages]; - for (size_t i(0), e = [packages count]; i != e; ++i) { - Package *package = [packages objectAtIndex:i]; + for (Package *package in packages) { pkgCache::PkgIterator iterator = [package iterator]; pkgDepCache::StateCache &state(cache[iterator]); @@ -2891,11 +3137,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return @"Cancel"; } +- (id) rightButtonTitle { + return issues_ != nil ? nil : [super rightButtonTitle]; +} + - (id) _rightButtonTitle { #if AlwaysReload || IgnoreInstall - return @"Reload"; + return [super _rightButtonTitle]; #else - return issues_ == nil ? @"Confirm" : nil; + return @"Confirm"; #endif } @@ -2979,8 +3229,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { SHA1SumValue springlist_; SHA1SumValue notifyconf_; SHA1SumValue sandplate_; - size_t received_; - NSTimeInterval last_; } - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to; @@ -3080,6 +3328,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [status_ setCentersHorizontally:YES]; //[status_ setFont:font]; + _trace(); output_ = [[UITextView alloc] initWithFrame:CGRectMake( 10, @@ -3087,6 +3336,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { bounds.size.width - 20, bounds.size.height - navsize.height - 62 - navrect.size.height )]; + _trace(); //[output_ setTextFont:@"Courier New"]; [output_ setTextSize:12]; @@ -3290,9 +3540,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [output_ setText:@""]; [progress_ setProgress:0]; - received_ = 0; - last_ = 0;//[NSDate timeIntervalSinceReferenceDate]; - [close_ removeFromSuperview]; [overlay_ addSubview:progress_]; [overlay_ addSubview:status_]; @@ -3386,7 +3633,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) startProgress { - last_ = [NSDate timeIntervalSinceReferenceDate]; } - (void) addProgressOutput:(NSString *)output { @@ -3398,15 +3644,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (bool) isCancelling:(size_t)received { - if (last_ != 0) { - NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; - if (received_ != received) { - received_ = received; - last_ = now; - } else if (now - last_ > 30) - return true; - } - return false; } @@ -3940,6 +4177,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super webView:sender didClearWindowObject:window forFrame:frame]; } +- (bool) _allowJavaScriptPanel { + return false; +} + #if !AlwaysReload - (void) _rightButtonClicked { /*[super _rightButtonClicked]; @@ -4095,9 +4336,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return; Package *package = [packages_ objectAtIndex:row]; + package = [database_ packageWithName:[package id]]; PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease]; - [view setDelegate:delegate_]; [view setPackage:package]; + [view setDelegate:delegate_]; [book_ pushPage:view]; } @@ -4145,27 +4387,41 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [packages_ removeAllObjects]; [sections_ removeAllObjects]; - for (size_t i(0); i != [packages count]; ++i) { - Package *package([packages objectAtIndex:i]); - if ([self hasPackage:package]) - [packages_ addObject:package]; - } + _profile(PackageTable$reloadData$Filter) + for (Package *package in packages) + if ([self hasPackage:package]) + [packages_ addObject:package]; + _end Section *section = nil; - for (size_t offset(0); offset != [packages_ count]; ++offset) { - Package *package = [packages_ objectAtIndex:offset]; - NSString *name = [package index]; + _profile(PackageTable$reloadData$Section) + for (size_t offset(0), end([packages_ count]); offset != end; ++offset) { + Package *package; + unichar index; - if (section == nil || ![[section name] isEqualToString:name]) { - section = [[[Section alloc] initWithName:name row:offset] autorelease]; - [sections_ addObject:section]; - } + _profile(PackageTable$reloadData$Section$Package) + package = [packages_ objectAtIndex:offset]; + index = [package index]; + _end - [section addToCount]; - } + if (section == nil || [section index] != index) { + _profile(PackageTable$reloadData$Section$Allocate) + section = [[[Section alloc] initWithIndex:index row:offset] autorelease]; + _end - [list_ reloadData]; + _profile(PackageTable$reloadData$Section$Add) + [sections_ addObject:section]; + _end + } + + [section addToCount]; + } + _end + + _profile(PackageTable$reloadData$List) + [list_ reloadData]; + _end } - (NSString *) title { @@ -4193,6 +4449,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* Filtered Package Table {{{ */ @interface FilteredPackageTable : PackageTable { SEL filter_; + IMP imp_; id object_; } @@ -4220,7 +4477,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (bool) hasPackage:(Package *)package { - return [package valid] && [[package performSelector:filter_ withObject:object_] boolValue]; + _profile(FilteredPackageTable$hasPackage) + return [package valid] && (*reinterpret_cast(imp_))(package, filter_, object_); + _end } - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object { @@ -4228,6 +4487,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { filter_ = filter; object_ = object == nil ? nil : [object retain]; + /* XXX: this is an unsafe optimization of doomy hell */ + Method method = class_getInstanceMethod([Package class], filter); + imp_ = method_getImplementation(method); + _assert(imp_ != NULL); + [self reloadData]; } return self; } @@ -4456,6 +4720,35 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [delegate_ syncData]; } +- (void) complete { + [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys: + @"deb", @"Type", + href_, @"URI", + @"./", @"Distribution", + nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]]; + + [delegate_ syncData]; +} + +- (NSString *) getWarning { + NSString *href(href_); + NSRange colon([href rangeOfString:@"://"]); + if (colon.location != NSNotFound) + href = [href substringFromIndex:(colon.location + 3)]; + href = [href stringByAddingPercentEscapes]; + href = [@"http://cydia.saurik.com/api/repotag/" stringByAppendingString:href]; + href = [href stringByCachingURLWithCurrentCDN]; + + NSURL *url([NSURL URLWithString:href]); + + NSStringEncoding encoding; + NSError *error(nil); + + if (NSString *warning = [NSString stringWithContentsOfURL:url usedEncoding:&encoding error:&error]) + return [warning length] == 0 ? nil : warning; + return nil; +} + - (void) _endConnection:(NSURLConnection *)connection { NSURLConnection **field = NULL; if (connection == trivial_bz2_) @@ -4470,21 +4763,26 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { trivial_bz2_ == nil && trivial_gz_ == nil ) { - [delegate_ setStatusBarShowsProgress:NO]; - - [hud_ show:NO]; - [hud_ removeFromSuperview]; - [hud_ autorelease]; - hud_ = nil; + bool defer(false); if (trivial_) { - [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys: - @"deb", @"Type", - href_, @"URI", - @"./", @"Distribution", - nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]]; - - [delegate_ syncData]; + if (NSString *warning = [self yieldToSelector:@selector(getWarning)]) { + defer = true; + + UIActionSheet *sheet = [[[UIActionSheet alloc] + initWithTitle:@"Source Warning" + buttons:[NSArray arrayWithObjects:@"Add Anyway", @"Cancel", nil] + defaultButtonIndex:0 + delegate:self + context:@"warning" + ] autorelease]; + + [sheet setNumberOfRows:1]; + + [sheet setBodyText:warning]; + [sheet popupAlertAnimated:YES]; + } else + [self complete]; } else if (error_ != nil) { UIActionSheet *sheet = [[[UIActionSheet alloc] initWithTitle:@"Verification Error" @@ -4509,8 +4807,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [sheet popupAlertAnimated:YES]; } - [href_ release]; - href_ = nil; + [delegate_ setStatusBarShowsProgress:NO]; + [delegate_ removeProgressHUD:hud_]; + + [hud_ autorelease]; + hud_ = nil; + + if (!defer) { + [href_ release]; + href_ = nil; + } if (error_ != nil) { [error_ release]; @@ -4571,7 +4877,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { trivial_ = false; - hud_ = [delegate_ addProgressHUD]; + hud_ = [[delegate_ addProgressHUD] retain]; [hud_ setText:@"Verifying URL"]; } break; @@ -4587,6 +4893,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [sheet dismiss]; else if ([context isEqualToString:@"urlerror"]) [sheet dismiss]; + else if ([context isEqualToString:@"warning"]) { + switch (button) { + case 1: + [self complete]; + break; + + case 2: + break; + + default: + _assert(false); + } + + [href_ release]; + href_ = nil; + + [sheet dismiss]; + } } - (id) initWithBook:(RVBook *)book database:(Database *)database { @@ -4800,7 +5124,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ] autorelease]; [sheet setBodyText: - @"Copyright (C) 2008\n" + @"Copyright (C) 2008-2009\n" "Jay Freeman (saurik)\n" "saurik@saurik.com\n" "http://www.saurik.com/\n" @@ -4870,8 +5194,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIProgressBar *progress_; UINavigationButton *cancel_; bool updating_; - size_t received_; - NSTimeInterval last_; } - (id) initWithFrame:(CGRect)frame database:(Database *)database; @@ -4921,8 +5243,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [prompt_ setText:@"Updating Database"]; [progress_ setProgress:0]; - received_ = 0; - last_ = [NSDate timeIntervalSinceReferenceDate]; updating_ = true; [overlay_ addSubview:cancel_]; @@ -5086,12 +5406,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (bool) isCancelling:(size_t)received { - NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; - if (received_ != received) { - received_ = received; - last_ = now; - } else if (now - last_ > 15) - return true; return !updating_; } @@ -5350,8 +5664,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32]; _trace(); - for (size_t i(0); i != [packages count]; ++i) { - Package *package([packages objectAtIndex:i]); + for (Package *package in packages) { NSString *name([package section]); if (name != nil) { @@ -5375,8 +5688,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _trace(); Section *section = nil; - for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) { - Package *package = [filtered objectAtIndex:offset]; + for (Package *package in filtered) { NSString *name = [package section]; if (section == nil || name != nil && ![[section name] isEqualToString:name]) { @@ -5551,15 +5863,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [sections_ removeAllObjects]; _trace(); - for (size_t i(0); i != [packages count]; ++i) { - Package *package([packages objectAtIndex:i]); - + for (Package *package in packages) if ( [package installed] == nil && [package valid] && [package visible] || [package upgradableAndEssential:YES] ) [packages_ addObject:package]; - } _trace(); [packages_ radixSortUsingSelector:@selector(compareForChanges) withObject:nil]; @@ -5872,7 +6181,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (flipped_) [self flipPage]; [table_ setObject:[field_ text]]; - [table_ reloadData]; + _profile(SearchView$reloadData) + [table_ reloadData]; + _end + PrintTimes(); [table_ resetCursor]; } @@ -6201,12 +6513,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) _reloadData { - /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_]; - [hud setText:@"Reloading Data"]; - [overlay_ addSubview:hud]; - [hud show:YES];*/ + UIView *block(); - [database_ reloadData]; + static bool loaded(false); + UIProgressHUD *hud([self addProgressHUD]); + [hud setText:(loaded ? @"Reloading Data" : @"Loading Data")]; + loaded = true; + + [database_ yieldToSelector:@selector(reloadData) withObject:nil]; + _trace(); + + [self removeProgressHUD:hud]; size_t changes(0); @@ -6241,7 +6558,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { // XXX: what is this line of code for? if ([packages count] == 0); - else if (Loaded_) loaded: + else if (Loaded_ || ForSaurik) loaded: [self _loaded]; else { Loaded_ = YES; @@ -6254,9 +6571,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [book_ update]; } - - /*[hud show:NO]; - [hud removeFromSuperview];*/ } - (void) _saveConfig { @@ -6292,8 +6606,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSArray *keys = [Sources_ allKeys]; - for (int i(0), e([keys count]); i != e; ++i) { - NSString *key = [keys objectAtIndex:i]; + for (NSString *key in keys) { NSDictionary *source = [Sources_ objectForKey:key]; fprintf(file, "%s %s %s\n", @@ -6484,9 +6797,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) finish { if (hud_ != nil) { [self setStatusBarShowsProgress:NO]; + [self removeProgressHUD:hud_]; - [hud_ show:NO]; - [hud_ removeFromSuperview]; [hud_ autorelease]; hud_ = nil; @@ -6504,6 +6816,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return; } + _trace(); overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]]; CGRect screenrect = [UIHardware fullScreenApplicationContentRect]; @@ -6613,6 +6926,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { withClass:[ManageView class] ] retain]; + PrintTimes(); + if (bootstrap_) [self bootstrap]; else @@ -6628,8 +6943,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { switch (button) { case 1: @synchronized (self) { - for (int i = 0, e = [broken_ count]; i != e; ++i) { - Package *broken = [broken_ objectAtIndex:i]; + for (Package *broken in broken_) { [broken remove]; NSString *id = [broken id]; @@ -6685,10 +6999,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { switch (button) { case 1: @synchronized (self) { - for (int i = 0, e = [essential_ count]; i != e; ++i) { - Package *essential = [essential_ objectAtIndex:i]; + for (Package *essential in essential_) [essential install]; - } [self resolve]; [self perform]; @@ -6732,12 +7044,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (UIProgressHUD *) addProgressHUD { - UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_]; + UIProgressHUD *hud([[[UIProgressHUD alloc] initWithWindow:window_] autorelease]); + [window_ setUserInteractionEnabled:NO]; [hud show:YES]; - [underlay_ addSubview:hud]; + [progress_ addSubview:hud]; return hud; } +- (void) removeProgressHUD:(UIProgressHUD *)hud { + [hud show:NO]; + [hud removeFromSuperview]; + [window_ setUserInteractionEnabled:YES]; +} + - (void) openMailToURL:(NSURL *)url { // XXX: this makes me sad #if 0 @@ -6831,6 +7150,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) applicationDidFinishLaunching:(id)unused { + _trace(); Font12_ = [[UIFont systemFontOfSize:12] retain]; Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain]; Font14_ = [[UIFont systemFontOfSize:14] retain]; @@ -6875,7 +7195,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ) { [self setIdleTimerDisabled:YES]; - hud_ = [self addProgressHUD]; + hud_ = [[self addProgressHUD] retain]; [hud_ setText:@"Reorganizing\n\nWill Automatically\nClose When Done"]; [self setStatusBarShowsProgress:YES]; @@ -6931,8 +7251,7 @@ void AddPreferences(NSString *plist) { _pooled bool cydia(false); - for (size_t i(0); i != [items count]; ++i) { - NSMutableDictionary *item([items objectAtIndex:i]); + for (NSMutableDictionary *item in items) { NSString *label = [item objectForKey:@"label"]; if (label != nil && [label isEqualToString:@"Cydia"]) { cydia = true; @@ -7055,18 +7374,14 @@ int main(int argc, char *argv[]) { _pooled if (NSDictionary *system = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) Build_ = [system objectForKey:@"ProductBuildVersion"]; + if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:@"/Applications/MobileSafari.app/Info.plist"]) { + Product_ = [info objectForKey:@"SafariProductVersion"]; + Safari_ = [info objectForKey:@"CFBundleVersion"]; + } /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist"); AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/ - /*if ((Indices_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/indices.plist"]) == NULL) - Indices_ = [[NSMutableDictionary alloc] init];*/ - - Indices_ = [NSMutableDictionary dictionaryWithObjectsAndKeys: - @"http://"/*"cache.saurik.com/"*/"cydia.saurik.com/rating/@", @"Rating", - //@"http://"/*"cache.saurik.com/"*/"cydia.saurik.com/repotag/@", @"RepoTag", - nil]; - _trace(); Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]; _trace();