/* Cydia - iPhone UIKit Front-End for Debian APT
* Copyright (C) 2008-2015 Jay Freeman (saurik)
*/
/* GNU General Public License, Version 3 {{{ */
/*
* Cydia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Cydia is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cydia. If not, see .
**/
/* }}} */
// XXX: wtf/FastMalloc.h... wtf?
#define USE_SYSTEM_MALLOC 1
/* #include Directives {{{ */
#include "CyteKit/UCPlatform.h"
#include "CyteKit/Localize.h"
#include
#include
#include
#include
#include
#include
#if 0
#define DEPLOYMENT_TARGET_MACOSX 1
#define CF_BUILDING_CF 1
#include
#endif
#include
#include
#include
#include "iPhonePrivate.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include "fdstream.hpp"
#undef ABS
#include "apt.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
extern "C" {
#include
}
#include
#include
#include
#include
#include
#include "Sources.h"
#include "Substrate.hpp"
#include "Menes/Menes.h"
#include "CyteKit/CyteKit.h"
#include "CyteKit/RegEx.hpp"
#include "Cydia/MIMEAddress.h"
#include "Cydia/LoadingViewController.h"
#include "Cydia/ProgressEvent.h"
/* }}} */
/* Profiler {{{ */
struct timeval _ltv;
bool _itv;
#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(7) << count_ << ", " << std::setw(8) << 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 }
/* }}} */
extern NSString *Cydia_;
#define lprintf(args...) fprintf(stderr, args)
#define ForRelease 1
#define TraceLogging (1 && !ForRelease)
#define HistogramInsertionSort (0 && !ForRelease)
#define ProfileTimes (0 && !ForRelease)
#define ForSaurik (0 && !ForRelease)
#define LogBrowser (0 && !ForRelease)
#define TrackResize (0 && !ForRelease)
#define ManualRefresh (1 && !ForRelease)
#define ShowInternals (0 && !ForRelease)
#define AlwaysReload (0 && !ForRelease)
#if !TraceLogging
#undef _trace
#define _trace(args...)
#endif
#if !ProfileTimes
#undef _profile
#define _profile(name) {
#undef _end
#define _end }
#define PrintTimes() do {} while (false)
#endif
// Hash Functions/Structures {{{
extern "C" uint32_t hashlittle(const void *key, size_t length, uint32_t initval = 0);
union SplitHash {
uint32_t u32;
uint16_t u16[2];
};
// }}}
static NSString *Colon_;
NSString *Elision_;
static NSString *Error_;
static NSString *Warning_;
static void (*$SBSSetInterceptsMenuButtonForever)(bool);
static NSData *(*$SBSCopyIconImagePNGDataForDisplayIdentifier)(NSString *);
static CFStringRef (*$MGCopyAnswer)(CFStringRef);
static NSString *UniqueIdentifier(UIDevice *device = nil) {
if (kCFCoreFoundationVersionNumber < 800) // iOS 7.x
return [device ?: [UIDevice currentDevice] uniqueIdentifier];
else
return [(id)$MGCopyAnswer(CFSTR("UniqueDeviceID")) autorelease];
}
static const NSUInteger UIViewAutoresizingFlexibleBoth(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
static _finline NSString *CydiaURL(NSString *path) {
char page[26];
page[0] = 'h'; page[1] = 't'; page[2] = 't'; page[3] = 'p'; page[4] = 's';
page[5] = ':'; page[6] = '/'; page[7] = '/'; page[8] = 'c'; page[9] = 'y';
page[10] = 'd'; page[11] = 'i'; page[12] = 'a'; page[13] = '.'; page[14] = 's';
page[15] = 'a'; page[16] = 'u'; page[17] = 'r'; page[18] = 'i'; page[19] = 'k';
page[20] = '.'; page[21] = 'c'; page[22] = 'o'; page[23] = 'm'; page[24] = '/';
page[25] = '\0';
return [[NSString stringWithUTF8String:page] stringByAppendingString:path];
}
static NSString *ShellEscape(NSString *value) {
return [NSString stringWithFormat:@"'%@'", [value stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"]];
}
static _finline void UpdateExternalStatus(uint64_t newStatus) {
int notify_token;
if (notify_register_check("com.saurik.Cydia.status", ¬ify_token) == NOTIFY_STATUS_OK) {
notify_set_state(notify_token, newStatus);
notify_cancel(notify_token);
}
notify_post("com.saurik.Cydia.status");
}
/* NSForcedOrderingSearch doesn't work on the iPhone */
static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch;
static const NSStringCompareOptions LaxCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSCaseInsensitiveSearch;
static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareNumerically | kCFCompareWidthInsensitive | kCFCompareForcedOrdering;
/* Insertion Sort {{{ */
template
size_t CFBSearch_(const Type_ &element, const void *list, size_t count, CFComparisonResult (*comparator)(Type_, Type_, void *), void *context) {
const char *ptr = (const char *)list;
while (0 < count) {
size_t half = count / 2;
const char *probe = ptr + sizeof(Type_) * half;
CFComparisonResult cr = comparator(element, * (const Type_ *) probe, context);
if (0 == cr) return (probe - (const char *)list) / sizeof(Type_);
ptr = (cr < 0) ? ptr : probe + sizeof(Type_);
count = (cr < 0) ? half : (half + (count & 1) - 1);
}
return (ptr - (const char *)list) / sizeof(Type_);
}
template
void CYArrayInsertionSortValues(Type_ *values, size_t length, CFComparisonResult (*comparator)(Type_, Type_, void *), void *context) {
if (length == 0)
return;
#if HistogramInsertionSort > 0
uint32_t total(0), *offsets(new uint32_t[length]);
#endif
for (size_t index(1); index != length; ++index) {
Type_ value(values[index]);
#if 0
size_t correct(CFBSearch_(value, values, index, comparator, context));
#else
size_t correct(index);
while (comparator(value, values[correct - 1], context) == kCFCompareLessThan) {
#if HistogramInsertionSort > 1
NSLog(@"%@ < %@", value, values[correct - 1]);
#endif
if (--correct == 0)
break;
if (index - correct >= 8) {
correct = CFBSearch_(value, values, correct, comparator, context);
break;
}
}
#endif
if (correct != index) {
size_t offset(index - correct);
#if HistogramInsertionSort
total += offset;
++offsets[offset];
if (offset > 10)
NSLog(@"Heavy Insertion Displacement: %u = %@", offset, value);
#endif
memmove(values + correct + 1, values + correct, sizeof(const void *) * offset);
values[correct] = value;
}
}
#if HistogramInsertionSort > 0
for (size_t index(0); index != range.length; ++index)
if (offsets[index] != 0)
NSLog(@"Insertion Displacement [%u]: %u", index, offsets[index]);
NSLog(@"Average Insertion Displacement: %f", double(total) / range.length);
delete [] offsets;
#endif
}
/* }}} */
/* Cydia NSString Additions {{{ */
@interface NSString (Cydia)
- (NSComparisonResult) compareByPath:(NSString *)other;
- (NSString *) stringByAddingPercentEscapesIncludingReserved;
@end
@implementation NSString (Cydia)
- (NSComparisonResult) compareByPath:(NSString *)other {
NSString *prefix = [self commonPrefixWithString:other options:0];
size_t length = [prefix length];
NSRange lrange = NSMakeRange(length, [self length] - length);
NSRange rrange = NSMakeRange(length, [other length] - length);
lrange = [self rangeOfString:@"/" options:0 range:lrange];
rrange = [other rangeOfString:@"/" options:0 range:rrange];
NSComparisonResult value;
if (lrange.location == NSNotFound && rrange.location == NSNotFound)
value = NSOrderedSame;
else if (lrange.location == NSNotFound)
value = NSOrderedAscending;
else if (rrange.location == NSNotFound)
value = NSOrderedDescending;
else
value = NSOrderedSame;
NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
[self substringWithRange:NSMakeRange(length, lrange.location - length)];
NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
[other substringWithRange:NSMakeRange(length, rrange.location - length)];
NSComparisonResult result = [lpath compare:rpath];
return result == NSOrderedSame ? value : result;
}
- (NSString *) stringByAddingPercentEscapesIncludingReserved {
return [(id)CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(CFStringRef) self,
NULL,
CFSTR(";/?:@&=+$,"),
kCFStringEncodingUTF8
) autorelease];
}
@end
/* }}} */
/* C++ NSString Wrapper Cache {{{ */
static _finline CFStringRef CYStringCreate(const char *data, size_t size) {
return size == 0 ? NULL :
CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast(data), size, kCFStringEncodingUTF8, NO, kCFAllocatorNull) ?:
CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast(data), size, kCFStringEncodingISOLatin1, NO, kCFAllocatorNull);
}
static _finline CFStringRef CYStringCreate(const std::string &data) {
return CYStringCreate(data.data(), data.size());
}
static _finline CFStringRef CYStringCreate(const char *data) {
return CYStringCreate(data, strlen(data));
}
class CYString {
private:
char *data_;
size_t size_;
CFStringRef cache_;
_finline void clear_() {
if (cache_ != NULL) {
CFRelease(cache_);
cache_ = NULL;
}
}
public:
_finline bool empty() const {
return size_ == 0;
}
_finline size_t size() const {
return size_;
}
_finline char *data() const {
return data_;
}
_finline void clear() {
size_ = 0;
clear_();
}
_finline CYString() :
data_(0),
size_(0),
cache_(NULL)
{
}
_finline ~CYString() {
clear_();
}
void operator =(const CYString &rhs) {
data_ = rhs.data_;
size_ = rhs.size_;
if (rhs.cache_ == nil)
cache_ = NULL;
else
cache_ = reinterpret_cast(CFRetain(rhs.cache_));
}
void copy(CYPool *pool) {
char *temp(pool->malloc(size_ + 1));
memcpy(temp, data_, size_);
temp[size_] = '\0';
data_ = temp;
}
void set(CYPool *pool, const char *data, size_t size) {
if (size == 0)
clear();
else {
clear_();
data_ = const_cast(data);
size_ = size;
if (pool != NULL)
copy(pool);
}
}
_finline void set(CYPool *pool, const char *data) {
set(pool, data, data == NULL ? 0 : strlen(data));
}
_finline void set(CYPool *pool, const std::string &rhs) {
set(pool, rhs.data(), rhs.size());
}
bool operator ==(const CYString &rhs) const {
return size_ == rhs.size_ && memcmp(data_, rhs.data_, size_) == 0;
}
_finline operator CFStringRef() {
if (cache_ == NULL)
cache_ = CYStringCreate(data_, size_);
return cache_;
}
_finline operator id() {
return (NSString *) static_cast(*this);
}
_finline operator const char *() {
return reinterpret_cast(data_);
}
};
/* }}} */
/* C++ NSString Algorithm Adapters {{{ */
extern "C" {
CF_EXPORT CFHashCode CFStringHashNSString(CFStringRef str);
}
struct NSStringMapHash :
std::unary_function
{
_finline size_t operator ()(NSString *value) const {
return CFStringHashNSString((CFStringRef) value);
}
};
struct NSStringMapLess :
std::binary_function
{
_finline bool operator ()(NSString *lhs, NSString *rhs) const {
return [lhs compare:rhs] == NSOrderedAscending;
}
};
struct NSStringMapEqual :
std::binary_function
{
_finline bool operator ()(NSString *lhs, NSString *rhs) const {
return CFStringCompare((CFStringRef) lhs, (CFStringRef) rhs, 0) == kCFCompareEqualTo;
//CFEqual((CFTypeRef) lhs, (CFTypeRef) rhs);
//[lhs isEqualToString:rhs];
}
};
/* }}} */
/* CoreGraphics Primitives {{{ */
class CYColor {
private:
CGColorRef color_;
static CGColorRef Create_(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
CGFloat color[] = {red, green, blue, alpha};
return CGColorCreate(space, color);
}
public:
CYColor() :
color_(NULL)
{
}
CYColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
color_(Create_(space, red, green, blue, alpha))
{
Set(space, red, green, blue, alpha);
}
void Clear() {
if (color_ != NULL)
CGColorRelease(color_);
}
~CYColor() {
Clear();
}
void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
Clear();
color_ = Create_(space, red, green, blue, alpha);
}
operator CGColorRef() {
return color_;
}
};
/* }}} */
/* Random Global Variables {{{ */
static int PulseInterval_ = 500000;
static const NSString *UI_;
static int Finish_;
static bool RestartSubstrate_;
static NSArray *Finishes_;
#define SpringBoard_ "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
#define NotifyConfig_ "/etc/notify.conf"
static bool Queuing_;
static CYColor Blue_;
static CYColor Blueish_;
static CYColor Black_;
static CYColor Folder_;
static CYColor Off_;
static CYColor White_;
static CYColor Gray_;
static CYColor Green_;
static CYColor Purple_;
static CYColor Purplish_;
static UIColor *InstallingColor_;
static UIColor *RemovingColor_;
static NSString *App_;
static BOOL Advanced_;
static BOOL Ignored_;
static _H Font12_;
static _H Font12Bold_;
static _H Font14_;
static _H Font18_;
static _H Font18Bold_;
static _H Font22Bold_;
static _H UniqueID_;
static _H CollationLocale_;
static _H CollationThumbs_;
static std::vector CollationOffset_;
static _H CollationTitles_;
static _H CollationStarts_;
static UTransliterator *CollationTransl_;
//static Function CollationModify_;
typedef std::basic_string ustring;
static ustring CollationString_;
#define CUC const ustring &str(*reinterpret_cast(rep))
#define UC ustring &str(*reinterpret_cast(rep))
static struct UReplaceableCallbacks CollationUCalls_ = {
.length = [](const UReplaceable *rep) -> int32_t { CUC;
return str.size();
},
.charAt = [](const UReplaceable *rep, int32_t offset) -> UChar { CUC;
//fprintf(stderr, "charAt(%d) : %d\n", offset, str.size());
if (offset >= str.size())
return 0xffff;
return str[offset];
},
.char32At = [](const UReplaceable *rep, int32_t offset) -> UChar32 { CUC;
//fprintf(stderr, "char32At(%d) : %d\n", offset, str.size());
if (offset >= str.size())
return 0xffff;
UChar32 c;
U16_GET(str.data(), 0, offset, str.size(), c);
return c;
},
.replace = [](UReplaceable *rep, int32_t start, int32_t limit, const UChar *text, int32_t length) -> void { UC;
//fprintf(stderr, "replace(%d, %d, %d) : %d\n", start, limit, length, str.size());
str.replace(start, limit - start, text, length);
},
.extract = [](UReplaceable *rep, int32_t start, int32_t limit, UChar *dst) -> void { UC;
//fprintf(stderr, "extract(%d, %d) : %d\n", start, limit, str.size());
str.copy(dst, limit - start, start);
},
.copy = [](UReplaceable *rep, int32_t start, int32_t limit, int32_t dest) -> void { UC;
//fprintf(stderr, "copy(%d, %d, %d) : %d\n", start, limit, dest, str.size());
str.replace(dest, 0, str, start, limit - start);
},
};
static CFLocaleRef Locale_;
static NSArray *Languages_;
static CGColorSpaceRef space_;
#define CacheState_ Cache("CacheState.plist")
#define SavedState_ Cache("SavedState.plist")
static NSDictionary *SectionMap_;
static _H Backgrounded_;
static _transient NSMutableDictionary *Values_;
static _transient NSMutableDictionary *Sections_;
_H Sources_;
static _transient NSNumber *Version_;
static time_t now_;
static _H SessionData_;
static _H BridgedHosts_;
static _H InsecureHosts_;
static NSString *kCydiaProgressEventTypeError = @"Error";
static NSString *kCydiaProgressEventTypeInformation = @"Information";
static NSString *kCydiaProgressEventTypeStatus = @"Status";
static NSString *kCydiaProgressEventTypeWarning = @"Warning";
/* }}} */
/* Display Helpers {{{ */
static _finline const char *StripVersion_(const char *version) {
const char *colon(strchr(version, ':'));
return colon == NULL ? version : colon + 1;
}
NSString *LocalizeSection(NSString *section) {
static RegEx title_r("(.*?) \\((.*)\\)");
if (title_r(section)) {
NSString *parent(title_r[1]);
NSString *child(title_r[2]);
return [NSString stringWithFormat:UCLocalize("PARENTHETICAL"),
LocalizeSection(parent),
LocalizeSection(child)
];
}
return [[NSBundle mainBundle] localizedStringForKey:section value:nil table:@"Sections"];
}
NSString *Simplify(NSString *title) {
const char *data = [title UTF8String];
size_t size = [title lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
static RegEx square_r("\\[(.*)\\]");
if (square_r(data, size))
return Simplify(square_r[1]);
static RegEx paren_r("\\((.*)\\)");
if (paren_r(data, size))
return Simplify(paren_r[1]);
static RegEx title_r("(.*?) \\((.*)\\)");
if (title_r(data, size))
return Simplify(title_r[1]);
return title;
}
/* }}} */
bool isSectionVisible(NSString *section) {
NSDictionary *metadata([Sections_ objectForKey:(section ?: @"")]);
NSNumber *hidden(metadata == nil ? nil : [metadata objectForKey:@"Hidden"]);
return hidden == nil || ![hidden boolValue];
}
static NSString *VerifySource(NSString *href) {
static RegEx href_r("(http(s?)://|file:///)[^# ]*");
if (!href_r(href)) {
[[[[UIAlertView alloc]
initWithTitle:[NSString stringWithFormat:Colon_, Error_, UCLocalize("INVALID_URL")]
message:UCLocalize("INVALID_URL_EX")
delegate:nil
cancelButtonTitle:UCLocalize("OK")
otherButtonTitles:nil
] autorelease] show];
return nil;
}
if (![href hasSuffix:@"/"])
href = [href stringByAppendingString:@"/"];
return href;
}
@class Cydia;
/* Delegate Prototypes {{{ */
@class Package;
@class Source;
@class CydiaProgressEvent;
@protocol DatabaseDelegate
- (void) repairWithSelector:(SEL)selector;
- (void) setConfigurationData:(NSString *)data;
- (void) addProgressEventOnMainThread:(CydiaProgressEvent *)event forTask:(NSString *)task;
@end
@class CYPackageController;
@protocol SourceDelegate
- (void) setFetch:(NSNumber *)fetch;
@end
@protocol FetchDelegate
- (bool) isSourceCancelled;
- (void) startSourceFetch:(NSString *)uri;
- (void) stopSourceFetch:(NSString *)uri;
@end
@protocol CydiaDelegate
- (void) returnToCydia;
- (void) saveState;
- (void) retainNetworkActivityIndicator;
- (void) releaseNetworkActivityIndicator;
- (void) clearPackage:(Package *)package;
- (void) installPackage:(Package *)package;
- (void) installPackages:(NSArray *)packages;
- (void) removePackage:(Package *)package;
- (void) beginUpdate;
- (BOOL) updating;
- (bool) requestUpdate;
- (void) distUpgrade;
- (void) loadData;
- (void) updateData;
- (void) _saveConfig;
- (void) syncData;
- (void) addSource:(NSDictionary *)source;
- (BOOL) addTrivialSource:(NSString *)href;
- (UIProgressHUD *) addProgressHUD;
- (void) removeProgressHUD:(UIProgressHUD *)hud;
- (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item;
- (void) reloadDataWithInvocation:(NSInvocation *)invocation;
@end
/* }}} */
/* CancelStatus {{{ */
class CancelStatus :
public pkgAcquireStatus
{
private:
bool cancelled_;
public:
CancelStatus() :
cancelled_(false)
{
}
virtual bool MediaChange(std::string media, std::string drive) {
return false;
}
virtual void IMSHit(pkgAcquire::ItemDesc &desc) {
Done(desc);
}
virtual bool Pulse_(pkgAcquire *Owner) = 0;
virtual bool Pulse(pkgAcquire *Owner) {
if (pkgAcquireStatus::Pulse(Owner) && Pulse_(Owner))
return true;
else {
cancelled_ = true;
return false;
}
}
_finline bool WasCancelled() const {
return cancelled_;
}
};
/* }}} */
/* DelegateStatus {{{ */
class CydiaStatus :
public CancelStatus
{
private:
_transient NSObject *delegate_;
public:
CydiaStatus() :
delegate_(nil)
{
}
void setDelegate(NSObject *delegate) {
delegate_ = delegate;
}
virtual void Fetch(pkgAcquire::ItemDesc &desc) {
NSString *name([NSString stringWithUTF8String:desc.ShortDesc.c_str()]);
CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithFormat:UCLocalize("DOWNLOADING_"), name] ofType:kCydiaProgressEventTypeStatus forItemDesc:desc]);
[delegate_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES];
}
virtual void Done(pkgAcquire::ItemDesc &desc) {
NSString *name([NSString stringWithUTF8String:desc.ShortDesc.c_str()]);
CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithFormat:Colon_, UCLocalize("DONE"), name] ofType:kCydiaProgressEventTypeStatus forItemDesc:desc]);
[delegate_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES];
}
virtual void Fail(pkgAcquire::ItemDesc &desc) {
if (
desc.Owner->Status == pkgAcquire::Item::StatIdle ||
desc.Owner->Status == pkgAcquire::Item::StatDone
)
return;
std::string &error(desc.Owner->ErrorText);
if (error.empty())
return;
CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:kCydiaProgressEventTypeError forItemDesc:desc]);
[delegate_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES];
}
virtual bool Pulse_(pkgAcquire *Owner) {
double percent(
double(CurrentBytes + CurrentItems) /
double(TotalBytes + TotalItems)
);
[delegate_ performSelectorOnMainThread:@selector(setProgressStatus:) withObject:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:percent], @"Percent",
[NSNumber numberWithDouble:CurrentBytes], @"Current",
[NSNumber numberWithDouble:TotalBytes], @"Total",
[NSNumber numberWithDouble:CurrentCPS], @"Speed",
nil] waitUntilDone:YES];
return ![delegate_ isProgressCancelled];
}
virtual void Start() {
pkgAcquireStatus::Start();
[delegate_ performSelectorOnMainThread:@selector(setProgressCancellable:) withObject:[NSNumber numberWithBool:YES] waitUntilDone:YES];
}
virtual void Stop() {
pkgAcquireStatus::Stop();
[delegate_ performSelectorOnMainThread:@selector(setProgressCancellable:) withObject:[NSNumber numberWithBool:NO] waitUntilDone:YES];
[delegate_ performSelectorOnMainThread:@selector(setProgressStatus:) withObject:nil waitUntilDone:YES];
}
};
/* }}} */
/* Database Interface {{{ */
typedef std::map< unsigned long, _H