]> git.saurik.com Git - cydia.git/blobdiff - Cydia.mm
Fixed an abbreviation in French.
[cydia.git] / Cydia.mm
index 3daeb4547cd78673dfa2347389fe6c474cd87f1e..60067ebe34277d35864e4aa21d09aa5275bb4dc6 100644 (file)
--- a/Cydia.mm
+++ b/Cydia.mm
 #include <GraphicsServices/GraphicsServices.h>
 #include <Foundation/Foundation.h>
 
+#if 0
+#define DEPLOYMENT_TARGET_MACOSX 1
+#define CF_BUILDING_CF 1
+#include <CoreFoundation/CFInternal.h>
+#endif
+
+#include <CoreFoundation/CFPriv.h>
+#include <CoreFoundation/CFUniChar.h>
+
 #import <QuartzCore/CALayer.h>
 #import <UIKit/UIKit.h>
 
 #include <WebCore/WebCoreThread.h>
 #import <WebKit/WebDefaultUIKitDelegate.h>
 
+#include <algorithm>
 #include <iomanip>
 #include <sstream>
 #include <string>
@@ -254,8 +264,9 @@ void NSLogRect(const char *fix, const CGRect &rect) {
     /* XXX: deal with exceptions */
     id value([self performSelector:selector withObject:object]);
 
+    NSMethodSignature *signature([self methodSignatureForSelector:selector]);
     [context removeAllObjects];
-    if (value != nil)
+    if ([signature methodReturnLength] != 0 && value != nil)
         [context addObject:value];
 
     stopped = true;
@@ -302,9 +313,8 @@ void NSLogRect(const char *fix, const CGRect &rect) {
 
 /* 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;
+static const NSStringCompareOptions LaxCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSCaseInsensitiveSearch;
+static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareCaseInsensitive | kCFCompareNonliteral | kCFCompareLocalized | kCFCompareNumerically | kCFCompareWidthInsensitive | kCFCompareForcedOrdering;
 
 /* iPhoneOS 2.0 Compatibility {{{ */
 #ifdef __OBJC2__
@@ -388,7 +398,8 @@ extern NSString * const kCAFilterNearest;
 
 #define ForRelease 0
 #define ForSaurik (0 && !ForRelease)
-#define LogBrowser (1 && !ForRelease)
+#define LogBrowser (0 && !ForRelease)
+#define TrackResize (0 && !ForRelease)
 #define ManualRefresh (1 && !ForRelease)
 #define ShowInternals (0 && !ForRelease)
 #define IgnoreInstall (0 && !ForRelease)
@@ -468,11 +479,22 @@ static void RadixSort_(NSMutableArray *self, size_t count, struct RadixItem_ *sw
 @implementation NSMutableArray (Radix)
 
 - (void) radixSortUsingSelector:(SEL)selector withObject:(id)object {
+    size_t count([self count]);
+    if (count == 0)
+        return;
+
+#if 0
     NSInvocation *invocation([NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:"L12@0:4@8"]]);
     [invocation setSelector:selector];
     [invocation setArgument:&object atIndex:2];
+#else
+    /* XXX: this is an unsafe optimization of doomy hell */
+    Method method(class_getInstanceMethod([[self objectAtIndex:0] class], selector));
+    _assert(method != NULL);
+    uint32_t (*imp)(id, SEL, id) = reinterpret_cast<uint32_t (*)(id, SEL, id)>(method_getImplementation(method));
+    _assert(imp != NULL);
+#endif
 
-    size_t count([self count]);
     struct RadixItem_ *swap(new RadixItem_[count * 2]);
 
     for (size_t i(0); i != count; ++i) {
@@ -480,10 +502,14 @@ static void RadixSort_(NSMutableArray *self, size_t count, struct RadixItem_ *sw
         item.index = i;
 
         id object([self objectAtIndex:i]);
-        [invocation setTarget:object];
 
+#if 0
+        [invocation setTarget:object];
         [invocation invoke];
         [invocation getReturnValue:&item.key];
+#else
+        item.key = imp(object, selector, object);
+#endif
     }
 
     RadixSort_(self, count, swap);
@@ -505,6 +531,42 @@ static void RadixSort_(NSMutableArray *self, size_t count, struct RadixItem_ *sw
 }
 
 @end
+/* }}} */
+/* Insertion Sort {{{ */
+
+CFIndex CFBSearch_(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) {
+    const char *ptr = (const char *)list;
+    while (0 < count) {
+        CFIndex half = count / 2;
+        const char *probe = ptr + elementSize * half;
+        CFComparisonResult cr = comparator(element, probe, context);
+       if (0 == cr) return (probe - (const char *)list) / elementSize;
+        ptr = (cr < 0) ? ptr : probe + elementSize;
+        count = (cr < 0) ? half : (half + (count & 1) - 1);
+    }
+    return (ptr - (const char *)list) / elementSize;
+}
+
+void CFArrayInsertionSortValues(CFMutableArrayRef array, CFRange range, CFComparatorFunction comparator, void *context) {
+    if (range.length == 0)
+        return;
+    const void **values(new const void *[range.length]);
+    CFArrayGetValues(array, range, values);
+
+    for (CFIndex index(1); index != range.length; ++index) {
+        const void *value(values[index]);
+        CFIndex correct(CFBSearch_(&value, sizeof(const void *), values, index, comparator, context));
+        //NSLog(@"%u %u", index, correct);
+        if (correct != index) {
+            memmove(values + correct + 1, values + correct, sizeof(const void *) * (index - correct));
+            values[correct] = value;
+        }
+    }
+
+    CFArrayReplaceValues(array, range, values, range.length);
+    delete [] values;
+}
+
 /* }}} */
 
 /* Apple Bug Fixes {{{ */
@@ -701,8 +763,9 @@ class CYString {
         else {
             clear_();
 
-            char *temp(reinterpret_cast<char *>(apr_palloc(pool, size)));
+            char *temp(reinterpret_cast<char *>(apr_palloc(pool, size + 1)));
             memcpy(temp, data, size);
+            temp[size] = '\0';
             data_ = temp;
             size_ = size;
         }
@@ -966,6 +1029,7 @@ static const NSString *Product_ = nil;
 static const NSString *Safari_ = nil;
 
 CFLocaleRef Locale_;
+NSArray *Languages_;
 CGColorSpaceRef space_;
 
 bool bootstrap_;
@@ -1021,6 +1085,13 @@ NSString *SizeString(double size) {
     return [NSString stringWithFormat:@"%s%.1f %s", (negative ? "-" : ""), size, powers_[power]];
 }
 
+NSString *StripVersion(const char *version) {
+    const char *colon(strchr(version, ':'));
+    if (colon != NULL)
+        version = colon + 1;
+    return [NSString stringWithUTF8String:version];
+}
+
 NSString *StripVersion(NSString *version) {
     NSRange colon = [version rangeOfString:@":"];
     if (colon.location != NSNotFound)
@@ -1029,7 +1100,18 @@ NSString *StripVersion(NSString *version) {
 }
 
 NSString *LocalizeSection(NSString *section) {
-    return section;
+    static Pcre title_r("^(.*?) \\((.*)\\)$");
+    if (title_r(section)) {
+        NSString *parent(title_r[1]);
+        NSString *child(title_r[2]);
+
+        return [NSString stringWithFormat:CYLocalize("PARENTHETICAL"),
+            LocalizeSection(parent),
+            LocalizeSection(child)
+        ];
+    }
+
+    return [[NSBundle mainBundle] localizedStringForKey:section value:nil table:@"Sections"];
 }
 
 NSString *Simplify(NSString *title) {
@@ -1044,17 +1126,21 @@ NSString *Simplify(NSString *title) {
     if (paren_r(data, size))
         return Simplify(paren_r[1]);
 
-    static Pcre title_r("^(.*?) \\(.*\\)$");
+    static Pcre title_r("^(.*?) \\((.*)\\)$");
     if (title_r(data, size))
         return Simplify(title_r[1]);
 
     return title;
 }
+
+_finline static void Stifle(char &value) {
+    value = (value & 0xdf) ^ 0x40;
+}
 /* }}} */
 
 bool isSectionVisible(NSString *section) {
-    NSDictionary *metadata = [Sections_ objectForKey:section];
-    NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
+    NSDictionary *metadata([Sections_ objectForKey:section]);
+    NSNumber *hidden(metadata == nil ? nil : [metadata objectForKey:@"Hidden"]);
     return hidden == nil || ![hidden boolValue];
 }
 
@@ -1540,11 +1626,12 @@ class Progress :
     CYString section_;
     NSString *section$_;
     bool essential_;
+    bool visible_;
 
     NSString *latest_;
     NSString *installed_;
 
-    NSString *id_;
+    CYString id_;
     CYString name_;
     CYString tagline_;
     CYString icon_;
@@ -1562,7 +1649,11 @@ class Progress :
     NSString *role_;
 
     NSArray *relationships_;
+
     NSMutableDictionary *metadata_;
+    _transient NSDate *firstSeen_;
+    _transient NSDate *lastSeen_;
+    bool subscribed_;
 }
 
 - (Package *) initWithVersion:(pkgCache::VerIterator)version withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database;
@@ -1580,7 +1671,8 @@ class Progress :
 
 - (Address *) maintainer;
 - (size_t) size;
-- (NSString *) description;
+- (NSString *) longDescription;
+- (NSString *) shortDescription;
 - (unichar) index;
 
 - (NSMutableDictionary *) metadata;
@@ -1606,7 +1698,6 @@ class Progress :
 
 - (NSString *) id;
 - (NSString *) name;
-- (NSString *) tagline;
 - (UIImage *) icon;
 - (NSString *) homepage;
 - (NSString *) depiction;
@@ -1631,7 +1722,6 @@ class Progress :
 - (bool) isCommercial;
 
 - (uint32_t) compareByPrefix;
-- (NSComparisonResult) compareByName:(Package *)package;
 - (uint32_t) compareBySection:(NSArray *)sections;
 
 - (uint32_t) compareForChanges;
@@ -1673,6 +1763,53 @@ uint32_t PackageChangesRadix(Package *self, void *) {
     return _not(uint32_t) - value.key;
 }
 
+CFStringRef (*PackageName)(Package *self, SEL sel);
+
+CFComparisonResult PackageNameCompare(Package *lhs, Package *rhs, void *arg) {
+    _profile(PackageNameCompare)
+        CFStringRef lhn, rhn;
+        CFIndex length;
+
+        _profile(PackageNameCompare$Setup)
+            lhn = PackageName(lhs, @selector(name));
+            rhn = PackageName(rhs, @selector(name));
+        _end
+
+        _profile(PackageNameCompare$Nothing)
+        _end
+
+        _profile(PackageNameCompare$Length)
+            length = CFStringGetLength(lhn);
+        _end
+
+        _profile(PackageNameCompare$NumbersLast)
+            if (length != 0 && CFStringGetLength(rhn) != 0) {
+                UniChar lhc(CFStringGetCharacterAtIndex(lhn, 0));
+                UniChar rhc(CFStringGetCharacterAtIndex(rhn, 0));
+                bool lha(CFUniCharIsMemberOf(lhc, kCFUniCharLetterCharacterSet));
+                if (lha != CFUniCharIsMemberOf(rhc, kCFUniCharLetterCharacterSet))
+                    return lha ? NSOrderedAscending : NSOrderedDescending;
+            }
+        _end
+
+        _profile(PackageNameCompare$Compare)
+            return CFStringCompareWithOptionsAndLocale(lhn, rhn, CFRangeMake(0, length), LaxCompareFlags_, Locale_);
+        _end
+    _end
+}
+
+CFComparisonResult PackageNameCompare_(Package **lhs, Package **rhs, void *context) {
+    return PackageNameCompare(*lhs, *rhs, context);
+}
+
+struct PackageNameOrdering :
+    std::binary_function<Package *, Package *, bool>
+{
+    _finline bool operator ()(Package *lhs, Package *rhs) const {
+        return PackageNameCompare(lhs, rhs, NULL) == NSOrderedAscending;
+    }
+};
+
 @implementation Package
 
 - (void) dealloc {
@@ -1686,8 +1823,6 @@ uint32_t PackageChangesRadix(Package *self, void *) {
     if (installed_ != nil)
         [installed_ release];
 
-    if (id_ != nil)
-        [id_ release];
     if (sponsor$_ != nil)
         [sponsor$_ release];
     if (author$_ != nil)
@@ -1717,7 +1852,7 @@ uint32_t PackageChangesRadix(Package *self, void *) {
 }
 
 + (NSArray *) _attributeKeys {
-    return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"longSection", @"maintainer", @"mode", @"name", @"purposes", @"section", @"shortSection", @"simpleSection", @"size", @"source", @"sponsor", @"support", @"tagline", @"warnings", nil];
+    return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"longDescription", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"longSection", @"maintainer", @"mode", @"name", @"purposes", @"section", @"shortDescription", @"shortSection", @"simpleSection", @"size", @"source", @"sponsor", @"support", @"warnings", nil];
 }
 
 - (NSArray *) attributeKeys {
@@ -1739,32 +1874,22 @@ uint32_t PackageChangesRadix(Package *self, void *) {
         database_ = database;
 
         _profile(Package$initWithVersion$Latest)
-            latest_ = [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
+            latest_ = [StripVersion(version_.VerStr()) retain];
         _end
 
-        pkgCache::VerIterator current;
-        NSString *installed;
-
-        _profile(Package$initWithVersion$Current)
-            current = iterator_.CurrentVer();
-            installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()];
-        _end
-
-        _profile(Package$initWithVersion$Installed)
-            installed_ = [StripVersion(installed) retain];
-        _end
+        pkgCache::VerIterator current(iterator_.CurrentVer());
+        if (!current.end())
+            installed_ = [StripVersion(current.VerStr()) retain];
 
-        _profile(Package$initWithVersion$File)
-            if (!version_.end())
-                file_ = version_.FileList();
-            else {
-                pkgCache &cache([database_ cache]);
-                file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
-            }
-        _end
+        if (!version_.end())
+            file_ = version_.FileList();
+        else {
+            pkgCache &cache([database_ cache]);
+            file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
+        }
 
         _profile(Package$initWithVersion$Name)
-            id_ = [[NSString stringWithUTF8String:iterator_.Name()] retain];
+            id_.set(pool, iterator_.Name());
         _end
 
         if (!file_.end())
@@ -1780,63 +1905,36 @@ uint32_t PackageChangesRadix(Package *self, void *) {
                     parser = &[database_ records]->Lookup(file_);
                 _end
 
-                const char *begin, *end;
-                parser->GetRec(begin, end);
-
                 CYString website;
                 CYString tag;
 
-                struct {
-                    const char *name_;
-                    CYString *value_;
-                } names[] = {
-                    {"name", &name_},
-                    {"icon", &icon_},
-                    {"depiction", &depiction_},
-                    {"homepage", &homepage_},
-                    {"website", &website},
-                    {"support", &support_},
-                    {"sponsor", &sponsor_},
-                    {"author", &author_},
-                    {"tag", &tag},
-                };
-
-                while (begin != end)
-                    if (*begin == '\n') {
-                        ++begin;
-                        continue;
-                    } else if (isblank(*begin)) next: {
-                        begin = static_cast<char *>(memchr(begin + 1, '\n', end - begin - 1));
-                        if (begin == NULL)
-                            break;
-                    } else if (const char *colon = static_cast<char *>(memchr(begin, ':', end - begin))) {
-                        const char *name(begin);
-                        size_t size(colon - begin);
-
-                        begin = static_cast<char *>(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) {
-                                    CYString &value(*names[i].value_);
-
-                                    _profile(Package$initWithVersion$Parse$Value)
-                                        value.set(pool, colon, stop - colon);
-                                    _end
-
-                                    break;
-                                }
+                _profile(Package$initWithVersion$Parse$Find)
+                    struct {
+                        const char *name_;
+                        CYString *value_;
+                    } names[] = {
+                        {"name", &name_},
+                        {"icon", &icon_},
+                        {"depiction", &depiction_},
+                        {"homepage", &homepage_},
+                        {"website", &website},
+                        {"support", &support_},
+                        {"sponsor", &sponsor_},
+                        {"author", &author_},
+                        {"tag", &tag},
+                    };
+
+                    for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i) {
+                        const char *start, *end;
+
+                        if (parser->Find(names[i].name_, start, end)) {
+                            CYString &value(*names[i].value_);
+                            _profile(Package$initWithVersion$Parse$Value)
+                                value.set(pool, start, end - start);
+                            _end
                         }
-
-                        if (begin == NULL)
-                            break;
-                        ++begin;
-                    } else goto next;
+                    }
+                _end
 
                 _profile(Package$initWithVersion$Parse$Tagline)
                     tagline_.set(pool, parser->ShortDesc());
@@ -1866,21 +1964,28 @@ uint32_t PackageChangesRadix(Package *self, void *) {
 
         _profile(Package$initWithVersion$Metadata)
             metadata_ = [Packages_ objectForKey:key];
+
             if (metadata_ == nil) {
+                firstSeen_ = [now_ retain];
+
                 metadata_ = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
-                    now_, @"FirstSeen",
+                    firstSeen_, @"FirstSeen",
+                    latest_, @"LastVersion",
                 nil] mutableCopy];
 
-                [metadata_ setObject:latest_ forKey:@"LastVersion"];
                 changed = true;
             } else {
-                NSDate *first([metadata_ objectForKey:@"FirstSeen"]);
-                NSDate *last([metadata_ objectForKey:@"LastSeen"]);
+                firstSeen_ = [metadata_ objectForKey:@"FirstSeen"];
+                lastSeen_ = [metadata_ objectForKey:@"LastSeen"];
+
+                if (NSNumber *subscribed = [metadata_ objectForKey:@"IsSubscribed"])
+                    subscribed_ = [subscribed boolValue];
+
                 NSString *version([metadata_ objectForKey:@"LastVersion"]);
 
-                if (first == nil) {
-                    first = last == nil ? now_ : last;
-                    [metadata_ setObject:first forKey:@"FirstSeen"];
+                if (firstSeen_ == nil) {
+                    firstSeen_ = lastSeen_ == nil ? now_ : lastSeen_;
+                    [metadata_ setObject:firstSeen_ forKey:@"FirstSeen"];
                     changed = true;
                 }
 
@@ -1889,8 +1994,8 @@ uint32_t PackageChangesRadix(Package *self, void *) {
                     changed = true;
                 } else if (![version isEqualToString:latest_]) {
                     [metadata_ setObject:latest_ forKey:@"LastVersion"];
-                    last = now_;
-                    [metadata_ setObject:last forKey:@"LastSeen"];
+                    lastSeen_ = now_;
+                    [metadata_ setObject:lastSeen_ forKey:@"LastSeen"];
                     changed = true;
                 }
             }
@@ -1908,13 +2013,20 @@ uint32_t PackageChangesRadix(Package *self, void *) {
         _end
 
         essential_ = ((iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES) || [self hasTag:@"cydia::essential"];
+        visible_ = [self hasSupportingRole] && [self unfiltered];
     } _end } return self;
 }
 
 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database {
-    pkgCache::VerIterator version([database policy]->GetCandidateVer(iterator));
+    pkgCache::VerIterator version;
+
+    _profile(Package$packageWithIterator$GetCandidateVer)
+        version = [database policy]->GetCandidateVer(iterator);
+    _end
+
     if (version.end())
         return nil;
+
     return [[[Package alloc]
         initWithVersion:version
         withZone:zone
@@ -1986,7 +2098,7 @@ uint32_t PackageChangesRadix(Package *self, void *) {
     return version_.end() ? 0 : version_->InstalledSize;
 }
 
-- (NSString *) description {
+- (NSString *) longDescription {
     if (file_.end())
         return nil;
     pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
@@ -2006,38 +2118,34 @@ uint32_t PackageChangesRadix(Package *self, void *) {
     return [trimmed componentsJoinedByString:@"\n"];
 }
 
+- (NSString *) shortDescription {
+    return tagline_;
+}
+
 - (unichar) index {
     _profile(Package$index)
-        NSString *name([self name]);
-        if ([name length] == 0)
+        CFStringRef name((CFStringRef) [self name]);
+        if (CFStringGetLength(name) == 0)
             return '#';
-        unichar character([name characterAtIndex:0]);
-        if (!isalpha(character))
+        UniChar character(CFStringGetCharacterAtIndex(name, 0));
+        if (!CFUniCharIsMemberOf(character, kCFUniCharLetterCharacterSet))
             return '#';
         return toupper(character);
     _end
 }
 
 - (NSMutableDictionary *) metadata {
-    if (metadata_ == nil)
-        metadata_ = [[Packages_ objectForKey:[id_ lowercaseString]] retain];
     return metadata_;
 }
 
 - (NSDate *) seen {
-    NSDictionary *metadata([self metadata]);
-    if ([self subscribed])
-        if (NSDate *last = [metadata objectForKey:@"LastSeen"])
-            return last;
-    return [metadata objectForKey:@"FirstSeen"];
+    if (subscribed_ && lastSeen_ != nil)
+        return lastSeen_;
+    return firstSeen_;
 }
 
 - (BOOL) subscribed {
-    NSDictionary *metadata([self metadata]);
-    if (NSNumber *subscribed = [metadata objectForKey:@"IsSubscribed"])
-        return [subscribed boolValue];
-    else
-        return false;
+    return subscribed_;
 }
 
 - (BOOL) ignored {
@@ -2061,14 +2169,13 @@ uint32_t PackageChangesRadix(Package *self, void *) {
 }
 
 - (BOOL) upgradableAndEssential:(BOOL)essential {
-    pkgCache::VerIterator current = iterator_.CurrentVer();
-
-    bool value;
-    if (current.end())
-        value = essential && [self essential] && [self visible];
-    else
-        value = !version_.end() && version_ != current;// && (!essential || ![database_ cache][iterator_].Keep());
-    return value;
+    _profile(Package$upgradableAndEssential)
+        pkgCache::VerIterator current(iterator_.CurrentVer());
+        if (current.end())
+            return essential && essential_ && visible_;
+        else
+            return !version_.end() && version_ != current;// && (!essential || ![database_ cache][iterator_].Keep());
+    _end
 }
 
 - (BOOL) essential {
@@ -2080,16 +2187,16 @@ uint32_t PackageChangesRadix(Package *self, void *) {
 }
 
 - (BOOL) unfiltered {
-    NSString *section = [self section];
+    NSString *section([self section]);
     return section == nil || isSectionVisible(section);
 }
 
 - (BOOL) visible {
-    return [self hasSupportingRole] && [self unfiltered];
+    return visible_;
 }
 
 - (BOOL) half {
-    unsigned char current = iterator_->CurrentState;
+    unsigned char current(iterator_->CurrentState);
     return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
 }
 
@@ -2147,11 +2254,7 @@ uint32_t PackageChangesRadix(Package *self, void *) {
 }
 
 - (NSString *) name {
-    return name_ == nil ? id_ : name_;
-}
-
-- (NSString *) tagline {
-    return tagline_;
+    return name_.empty() ? id_ : name_;
 }
 
 - (UIImage *) icon {
@@ -2200,7 +2303,7 @@ uint32_t PackageChangesRadix(Package *self, void *) {
 }
 
 - (NSArray *) files {
-    NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", id_];
+    NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", static_cast<NSString *>(id_)];
     NSMutableArray *files = [NSMutableArray arrayWithCapacity:128];
 
     std::ifstream fin;
@@ -2334,7 +2437,7 @@ uint32_t PackageChangesRadix(Package *self, void *) {
     if (range.location != NSNotFound)
         return YES;
 
-    range = [[self tagline] rangeOfString:text options:MatchCompareOptions_];
+    range = [[self shortDescription] rangeOfString:text options:MatchCompareOptions_];
     if (range.location != NSNotFound)
         return YES;
 
@@ -2383,24 +2486,28 @@ uint32_t PackageChangesRadix(Package *self, void *) {
 }
 
 - (uint32_t) compareByPrefix {
-    return 0;
-}
-
-- (NSComparisonResult) compareByName:(Package *)package {
-    NSString *lhs = [self name];
-    NSString *rhs = [package name];
+    size_t offset(0);
 
-    if ([lhs length] != 0 && [rhs length] != 0) {
-        unichar lhc = [lhs characterAtIndex:0];
-        unichar rhc = [rhs characterAtIndex:0];
+    CYString &name(name_.empty() ? id_ : name_);
+    if (name.size() <= offset)
+        return 0;
+    size_t size(name.size() - offset);
 
-        if (isalpha(lhc) && !isalpha(rhc))
-            return NSOrderedAscending;
-        else if (!isalpha(lhc) && isalpha(rhc))
-            return NSOrderedDescending;
+    char data[4];
+    if (size >= 4)
+        memcpy(data, name.data() + offset, 4);
+    else {
+        memcpy(data, name.data() + offset, size);
+        memset(data + size, 0, 4 - size);
     }
 
-    return [lhs compare:rhs options:LaxCompareOptions_];
+    Stifle(data[0]);
+    Stifle(data[1]);
+    Stifle(data[2]);
+    Stifle(data[3]);
+
+    /* XXX: ntohl may be more honest */
+    return OSSwapInt32(*reinterpret_cast<uint32_t *>(data));
 }
 
 - (uint32_t) compareBySection:(NSArray *)sections {
@@ -2512,9 +2619,10 @@ uint32_t PackageChangesRadix(Package *self, void *) {
     NSString *localized_;
 }
 
-- (NSComparisonResult) compareByName:(Section *)section;
-- (Section *) initWithName:(NSString *)name;
-- (Section *) initWithName:(NSString *)name row:(size_t)row;
+- (NSComparisonResult) compareByLocalized:(Section *)section;
+- (Section *) initWithName:(NSString *)name localized:(NSString *)localized;
+- (Section *) initWithName:(NSString *)name localize:(BOOL)localize;
+- (Section *) initWithName:(NSString *)name row:(size_t)row localize:(BOOL)localize;
 - (Section *) initWithIndex:(unichar)index row:(size_t)row;
 - (NSString *) name;
 - (unichar) index;
@@ -2526,6 +2634,7 @@ uint32_t PackageChangesRadix(Package *self, void *) {
 - (void) addToCount;
 
 - (void) setCount:(size_t)count;
+- (NSString *) localized;
 
 @end
 
@@ -2538,11 +2647,11 @@ uint32_t PackageChangesRadix(Package *self, void *) {
     [super dealloc];
 }
 
-- (NSComparisonResult) compareByName:(Section *)section {
-    NSString *lhs = [self name];
-    NSString *rhs = [section name];
+- (NSComparisonResult) compareByLocalized:(Section *)section {
+    NSString *lhs(localized_);
+    NSString *rhs([section localized]);
 
-    if ([lhs length] != 0 && [rhs length] != 0) {
+    /*if ([lhs length] != 0 && [rhs length] != 0) {
         unichar lhc = [lhs characterAtIndex:0];
         unichar rhc = [rhs characterAtIndex:0];
 
@@ -2550,21 +2659,29 @@ uint32_t PackageChangesRadix(Package *self, void *) {
             return NSOrderedAscending;
         else if (!isalpha(lhc) && isalpha(rhc))
             return NSOrderedDescending;
-    }
+    }*/
 
     return [lhs compare:rhs options:LaxCompareOptions_];
 }
 
-- (Section *) initWithName:(NSString *)name {
-    return [self initWithName:name row:0];
+- (Section *) initWithName:(NSString *)name localized:(NSString *)localized {
+    if ((self = [self initWithName:name localize:NO]) != nil) {
+        if (localized != nil)
+            localized_ = [localized retain];
+    } return self;
+}
+
+- (Section *) initWithName:(NSString *)name localize:(BOOL)localize {
+    return [self initWithName:name row:0 localize:localize];
 }
 
-- (Section *) initWithName:(NSString *)name row:(size_t)row {
+- (Section *) initWithName:(NSString *)name row:(size_t)row localize:(BOOL)localize {
     if ((self = [super init]) != nil) {
         name_ = [name retain];
         index_ = '\0';
         row_ = row;
-        localized_ = [LocalizeSection(name_) retain];
+        if (localize)
+            localized_ = [LocalizeSection(name_) retain];
     } return self;
 }
 
@@ -2739,7 +2856,7 @@ static NSArray *Finishes_;
         apr_pool_create(&pool_, NULL);
 
         sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
-        packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
+        packages_ = [[NSMutableArray alloc] init];
 
         int fds[2];
 
@@ -2971,17 +3088,49 @@ static NSArray *Finishes_;
     }
     _trace();
 
-    [packages_ removeAllObjects];
-    _trace();
-    for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
-        if (Package *package = [Package packageWithIterator:iterator withZone:zone_ inPool:pool_ database:self])
-            [packages_ addObject:package];
-    _trace();
-    [packages_ sortUsingSelector:@selector(compareByName:)];
-    _trace();
+    {
+        /*std::vector<Package *> packages;
+        packages.reserve(std::max(10000U, [packages_ count] + 1000));
+        [packages_ release];
+        packages_ = nil;*/
 
-    _config->Set("Acquire::http::Timeout", 15);
-    _config->Set("Acquire::http::MaxParallel", 4);
+        [packages_ removeAllObjects];
+
+        _trace();
+
+        for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
+            if (Package *package = [Package packageWithIterator:iterator withZone:zone_ inPool:pool_ database:self])
+                //packages.push_back(package);
+                [packages_ addObject:package];
+
+        _trace();
+
+        /*if (packages.empty())
+            packages_ = [[NSArray alloc] init];
+        else
+            packages_ = [[NSArray alloc] initWithObjects:&packages.front() count:packages.size()];
+        _trace();*/
+
+        [packages_ radixSortUsingSelector:@selector(compareByPrefix) withObject:NULL];
+
+        /*_trace();
+        PrintTimes();
+        _trace();*/
+
+        _trace();
+
+        /*if (!packages.empty())
+            CFQSortArray(&packages.front(), packages.size(), sizeof(packages.front()), reinterpret_cast<CFComparatorFunction>(&PackageNameCompare_), NULL);*/
+        //std::sort(packages.begin(), packages.end(), PackageNameOrdering());
+
+        //CFArraySortValues((CFMutableArrayRef) packages_, CFRangeMake(0, [packages_ count]), reinterpret_cast<CFComparatorFunction>(&PackageNameCompare), NULL);
+
+        CFArrayInsertionSortValues((CFMutableArrayRef) packages_, CFRangeMake(0, [packages_ count]), reinterpret_cast<CFComparatorFunction>(&PackageNameCompare_), NULL);
+
+        //[packages_ sortUsingFunction:reinterpret_cast<NSComparisonResult (*)(id, id, void *)>(&PackageNameCompare) context:NULL];
+
+        _trace();
+    }
 }
 
 - (void) configure {
@@ -4102,7 +4251,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     icon_ = [[package icon] retain];
     name_ = [[package name] retain];
-    description_ = [[package tagline] retain];
+    description_ = [[package shortDescription] retain];
     commercial_ = [package isCommercial];
 
     package_ = [package retain];
@@ -4227,7 +4376,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 + (int) heightForPackage:(Package *)package {
-    NSString *tagline([package tagline]);
+    NSString *tagline([package shortDescription]);
     int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
 #ifdef USE_BADGES
     if ([package hasMode] || [package half])
@@ -4315,7 +4464,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         name_ = [CYLocalize("ALL_PACKAGES") retain];
         count_ = nil;
     } else {
-        section_ = [section name];
+        section_ = [section localized];
         if (section_ != nil)
             section_ = [section_ retain];
         name_  = [(section_ == nil ? CYLocalize("NO_SECTION") : section_) retain];
@@ -4652,6 +4801,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             [self setPopupHook:nil];
             WebThreadUnlock();
 
+            //[self yieldToSelector:@selector(callFunction:) withObject:special_];
             [super callFunction:special_];
         }
     }
@@ -4893,6 +5043,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         /* XXX: this is an unsafe optimization of doomy hell */
         Method method = class_getInstanceMethod([Package class], filter);
+        _assert(method != NULL);
         imp_ = method_getImplementation(method);
         _assert(imp_ != NULL);
 
@@ -5767,7 +5918,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [cancel_ addTarget:self action:@selector(_onCancel) forControlEvents:UIControlEventTouchUpInside];
 
         CGRect frame = [cancel_ frame];
-        frame.size.width = 65;
         frame.origin.x = ovrrect.size.width - frame.size.width - 5;
         frame.origin.y = (ovrrect.size.height - frame.size.height) / 2;
         [cancel_ setFrame:frame];
@@ -5795,7 +5945,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
-    [prompt_ setText:[NSString stringWithFormat:CYLocalize("ERROR_MESSAGE"), error]];
+    [prompt_ setText:[NSString stringWithFormat:CYLocalize("COLON_DELIMITED"), CYLocalize("ERROR"), error]];
 }
 
 - (void) setProgressTitle:(NSString *)title {
@@ -6100,7 +6250,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             section = &sections[key];
             if (*section == nil) {
                 _profile(SectionsView$reloadData$Section$Allocate)
-                    *section = [[[Section alloc] initWithName:name] autorelease];
+                    *section = [[[Section alloc] initWithName:name localize:YES] autorelease];
                 _end
             }
         _end
@@ -6120,7 +6270,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             section = [sections objectForKey:key];
             if (section == nil) {
                 _profile(SectionsView$reloadData$Section$Allocate)
-                    section = [[[Section alloc] initWithName:name] autorelease];
+                    section = [[[Section alloc] initWithName:name localize:YES] autorelease];
                     [sections setObject:section forKey:key];
                 _end
             }
@@ -6145,14 +6295,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [sections_ addObjectsFromArray:[sections allValues]];
 #endif
 
-    [sections_ sortUsingSelector:@selector(compareByName:)];
+    [sections_ sortUsingSelector:@selector(compareByLocalized:)];
 
     for (Section *section in sections_) {
         size_t count([section row]);
-        if ([section row] == 0)
+        if (count == 0)
             continue;
 
-        section = [[[Section alloc] initWithName:[section name]] autorelease];
+        section = [[[Section alloc] initWithName:[section name] localized:[section localized]] autorelease];
         [section setCount:count];
         [filtered_ addObject:section];
     }
@@ -6329,24 +6479,20 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [packages_ radixSortUsingFunction:reinterpret_cast<uint32_t (*)(id, void *)>(&PackageChangesRadix) withArgument:NULL];
     _trace();
 
-    Section *upgradable = [[[Section alloc] initWithName:CYLocalize("AVAILABLE_UPGRADES")] autorelease];
-    Section *ignored = [[[Section alloc] initWithName:CYLocalize("IGNORED_UPGRADES")] autorelease];
+    Section *upgradable = [[[Section alloc] initWithName:CYLocalize("AVAILABLE_UPGRADES") localize:NO] autorelease];
+    Section *ignored = [[[Section alloc] initWithName:CYLocalize("IGNORED_UPGRADES") localize:NO] autorelease];
     Section *section = nil;
     NSDate *last = nil;
 
     upgrades_ = 0;
     bool unseens = false;
 
-    CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
+    CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle));
 
-    _trace();
     for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
         Package *package = [packages_ objectAtIndex:offset];
 
-        BOOL uae;
-        _profile(ChangesView$reloadData$Upgrade)
-            uae = [package upgradableAndEssential:YES];
-        _end
+        BOOL uae = [package upgradableAndEssential:YES];
 
         if (!uae) {
             unseens = true;
@@ -6356,28 +6502,20 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                 seen = [package seen];
             _end
 
-            bool different;
-            _profile(ChangesView$reloadData$Compare)
-                different = section == nil || last != seen && (seen == nil || [seen compare:last] != NSOrderedSame);
-            _end
-
-            if (different) {
+            if (section == nil || last != seen && (seen == nil || [seen compare:last] != NSOrderedSame)) {
                 last = seen;
 
                 NSString *name;
                 if (seen == nil)
                     name = CYLocalize("UNKNOWN");
                 else {
-                    _profile(ChangesView$reloadData$Format)
-                        name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
-                    _end
-
+                    name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
                     [name autorelease];
                 }
 
                 _profile(ChangesView$reloadData$Allocate)
                     name = [NSString stringWithFormat:CYLocalize("NEW_AT"), name];
-                    section = [[[Section alloc] initWithName:name row:offset] autorelease];
+                    section = [[[Section alloc] initWithName:name row:offset localize:NO] autorelease];
                     [sections_ addObject:section];
                 _end
             }
@@ -7390,7 +7528,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             @"home-dn.png", kUIButtonBarButtonSelectedInfo,
             [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
             self, kUIButtonBarButtonTarget,
-            CYLocalize("HOME"), kUIButtonBarButtonTitle,
+            @"Cydia", kUIButtonBarButtonTitle,
             @"0", kUIButtonBarButtonType,
         nil],
 
@@ -7744,9 +7882,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
     Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
 
-    _assert(pkgInitConfig(*_config));
-    _assert(pkgInitSystem(*_config, _system));
-
     tag_ = 1;
 
     essential_ = [[NSMutableArray alloc] initWithCapacity:4];
@@ -7894,6 +8029,8 @@ void $UIWebDocumentView$_setUIKitDelegate$(UIWebDocumentView *self, SEL sel, id
 int main(int argc, char *argv[]) { _pooled
     _trace();
 
+    PackageName = reinterpret_cast<CFStringRef (*)(Package *, SEL)>(method_getImplementation(class_getInstanceMethod([Package class], @selector(name))));
+
     /* Library Hacks {{{ */
     class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16");
 
@@ -7906,9 +8043,17 @@ int main(int argc, char *argv[]) { _pooled
     /* }}} */
     /* Set Locale {{{ */
     Locale_ = CFLocaleCopyCurrent();
-
-    CFStringRef locale(CFLocaleGetIdentifier(Locale_));
-    setenv("LANG", [(NSString *) locale UTF8String], true);
+    Languages_ = [NSLocale preferredLanguages];
+    //CFStringRef locale(CFLocaleGetIdentifier(Locale_));
+    //NSLog(@"%@", [Languages_ description]);
+    const char *lang;
+    if (Languages_ == nil || [Languages_ count] == 0)
+        lang = NULL;
+    else
+        lang = [[Languages_ objectAtIndex:0] UTF8String];
+    setenv("LANG", lang, true);
+    //std::setlocale(LC_ALL, lang);
+    NSLog(@"Setting Language: %s", lang);
     /* }}} */
 
     // XXX: apr_app_initialize?
@@ -8057,6 +8202,14 @@ int main(int argc, char *argv[]) { _pooled
             _assert(errno == ENOENT);
     }
 
+    _assert(pkgInitConfig(*_config));
+    _assert(pkgInitSystem(*_config, _system));
+
+    if (lang != NULL)
+        _config->Set("APT::Acquire::Translation", lang);
+    _config->Set("Acquire::http::Timeout", 15);
+    _config->Set("Acquire::http::MaxParallel", 4);
+
     /* Color Choices {{{ */
     space_ = CGColorSpaceCreateDeviceRGB();