/* Cydia - iPhone UIKit Front-End for Debian APT
* Copyright (C) 2008-2014 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
#include
#undef ABS
#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/IndirectDelegate.h"
#include "CyteKit/PerlCompatibleRegEx.hpp"
#include "CyteKit/TableViewCell.h"
#include "CyteKit/TabBarController.h"
#include "CyteKit/WebScriptObject-Cyte.h"
#include "CyteKit/WebViewController.h"
#include "CyteKit/WebViewTableViewCell.h"
#include "CyteKit/stringWithUTF8Bytes.h"
#include "Cydia/MIMEAddress.h"
#include "Cydia/LoadingViewController.h"
#include "Cydia/ProgressEvent.h"
#include "SDURLCache/SDURLCache.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 }
/* }}} */
// XXX: I hate clang. Apple: please get over your petty hatred of GPL and fix your gcc fork
#define synchronized(lock) \
synchronized(static_cast(lock))
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 void setreugid(uid_t uid, gid_t gid) {
_assert(setreuid(uid, uid) != -1);
_assert(setregid(gid, gid) != -1);
}
static void setreguid(gid_t gid, uid_t uid) {
_assert(setregid(gid, gid) != -1);
_assert(setreuid(uid, uid) != -1);
}
struct Root {
Root() {
_trace();
setreugid(0, 0);
_assert(pthread_setugid_np(0, 0) != -1);
setreguid(501, 501);
}
~Root() {
_trace();
setreugid(0, 0);
_assert(pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) != -1);
setreguid(501, 501);
}
};
#define _root(code) \
({ Root _root; code; })
static NSString *Colon_;
NSString *Elision_;
static NSString *Error_;
static NSString *Warning_;
static NSString *Cache_;
#define Cache(file) \
[NSString stringWithFormat:@"%@/%s", Cache_, file]
static void (*$SBSSetInterceptsMenuButtonForever)(bool);
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 bool IsReachable(const char *name) {
SCNetworkReachabilityFlags flags; {
SCNetworkReachabilityRef reachability(SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, name));
SCNetworkReachabilityGetFlags(reachability, &flags);
CFRelease(reachability);
}
// XXX: this elaborate mess is what Apple is using to determine this? :(
// XXX: do we care if the user has to intervene? maybe that's ok?
return
(flags & kSCNetworkReachabilityFlagsReachable) != 0 && (
(flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0 || (
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0 ||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0
) && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0 ||
(flags & kSCNetworkReachabilityFlagsIsWWAN) != 0
)
;
}
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 void ReapZombie(pid_t pid) {
int status;
wait:
if (waitpid(pid, &status, 0) == -1)
if (errno == EINTR)
goto wait;
else _assert(false);
}
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");
}
static CGFloat CYStatusBarHeight() {
CGSize size([[UIApplication sharedApplication] statusBarFrame].size);
return UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]) ? size.height : size.width;
}
/* 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 {{{ */
CFIndex SKBSearch_(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;
}
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);
#if HistogramInsertionSort > 0
uint32_t total(0), *offsets(new uint32_t[range.length]);
#endif
for (CFIndex index(1); index != range.length; ++index) {
const void *value(values[index]);
//CFIndex correct(SKBSearch_(&value, sizeof(const void *), values, index, comparator, context));
CFIndex correct(index);
while (comparator(value, values[correct - 1], context) == kCFCompareLessThan) {
#if HistogramInsertionSort > 1
NSLog(@"%@ < %@", value, values[correct - 1]);
#endif
if (--correct == 0)
break;
}
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;
}
}
CFArrayReplaceValues(array, range, values, range.length);
delete [] values;
#if HistogramInsertionSort > 0
for (CFIndex 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
}
/* }}} */
/* Apple Bug Fixes {{{ */
@implementation UIWebDocumentView (Cydia)
- (void) _setScrollerOffset:(CGPoint)offset {
UIScroller *scroller([self _scroller]);
CGSize size([scroller contentSize]);
CGSize bounds([scroller bounds].size);
CGPoint max;
max.x = size.width - bounds.width;
max.y = size.height - bounds.height;
// wtf Apple?!
if (max.x < 0)
max.x = 0;
if (max.y < 0)
max.y = 0;
offset.x = offset.x < 0 ? 0 : offset.x > max.x ? max.x : offset.x;
offset.y = offset.y < 0 ? 0 : offset.y > max.y ? max.y : offset.y;
[scroller setOffset:offset];
}
@end
/* }}} */
NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *self, SEL sel, NSFastEnumerationState *state, id *objects, NSUInteger count) {
size_t length([self length] - state->state);
if (length <= 0)
return 0;
else if (length > count)
length = count;
for (size_t i(0); i != length; ++i)
objects[i] = [self item:state->state++];
state->itemsPtr = objects;
state->mutationsPtr = (unsigned long *) self;
return length;
}
/* 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 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(apr_pool_t *pool) {
char *temp(reinterpret_cast(apr_palloc(pool, size_ + 1)));
memcpy(temp, data_, size_);
temp[size_] = '\0';
data_ = temp;
}
void set(apr_pool_t *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(apr_pool_t *pool, const char *data) {
set(pool, data, data == NULL ? 0 : strlen(data));
}
_finline void set(apr_pool_t *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 bool UpgradeCydia_;
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 const char *Machine_ = NULL;
static _H System_;
static NSString *SerialNumber_ = nil;
static NSString *ChipID_ = nil;
static NSString *BBSNum_ = nil;
static _H Token_;
static _H UniqueID_;
static _H UserAgent_;
static _H Product_;
static _H Safari_;
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_;
static NSDictionary *SectionMap_;
static NSMutableDictionary *Metadata_;
static _transient NSMutableDictionary *Settings_;
static _transient NSMutableDictionary *Packages_;
static _transient NSMutableDictionary *Values_;
static _transient NSMutableDictionary *Sections_;
_H Sources_;
static _transient NSNumber *Version_;
bool Changed_;
static time_t now_;
bool IsWildcat_;
CGFloat ScreenScale_;
static NSString *Idiom_;
static _H Firmware_;
static NSString *Major_;
static _H SessionData_;
static _H HostConfig_;
static _H BridgedHosts_;
static _H TokenHosts_;
static _H InsecureHosts_;
static _H PipelinedHosts_;
static _H CachedURLs_;
static NSString *kCydiaProgressEventTypeError = @"Error";
static NSString *kCydiaProgressEventTypeInformation = @"Information";
static NSString *kCydiaProgressEventTypeStatus = @"Status";
static NSString *kCydiaProgressEventTypeWarning = @"Warning";
/* }}} */
/* Display Helpers {{{ */
inline float Interpolate(float begin, float end, float fraction) {
return (end - begin) * fraction + begin;
}
static inline double Retina(double value) {
value *= ScreenScale_;
value = round(value);
value /= ScreenScale_;
return value;
}
static inline CGRect Retina(CGRect value) {
value.origin.x *= ScreenScale_;
value.origin.y *= ScreenScale_;
value.size.width *= ScreenScale_;
value.size.height *= ScreenScale_;
value = CGRectIntegral(value);
value.origin.x /= ScreenScale_;
value.origin.y /= ScreenScale_;
value.size.width /= ScreenScale_;
value.size.height /= ScreenScale_;
return value;
}
static _finline const char *StripVersion_(const char *version) {
const char *colon(strchr(version, ':'));
return colon == NULL ? version : colon + 1;
}
NSString *LocalizeSection(NSString *section) {
static Pcre 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 Pcre square_r("^\\[(.*)\\]$");
if (square_r(data, size))
return Simplify(square_r[1]);
static Pcre paren_r("^\\((.*)\\)$");
if (paren_r(data, size))
return Simplify(paren_r[1]);
static Pcre title_r("^(.*?) \\((.*)\\)$");
if (title_r(data, size))
return Simplify(title_r[1]);
return title;
}
/* }}} */
NSString *GetLastUpdate() {
NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
if (update == nil)
return UCLocalize("NEVER_OR_UNKNOWN");
CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
CFRelease(formatter);
return [(NSString *) formatted autorelease];
}
bool isSectionVisible(NSString *section) {
NSDictionary *metadata([Sections_ objectForKey:(section ?: @"")]);
NSNumber *hidden(metadata == nil ? nil : [metadata objectForKey:@"Hidden"]);
return hidden == nil || ![hidden boolValue];
}
static NSObject *CYIOGetValue(const char *path, NSString *property) {
io_registry_entry_t entry(IORegistryEntryFromPath(kIOMasterPortDefault, path));
if (entry == MACH_PORT_NULL)
return nil;
CFTypeRef value(IORegistryEntryCreateCFProperty(entry, (CFStringRef) property, kCFAllocatorDefault, 0));
IOObjectRelease(entry);
if (value == NULL)
return nil;
return [(id) value autorelease];
}
static NSString *CYHex(NSData *data, bool reverse = false) {
if (data == nil)
return nil;
size_t length([data length]);
uint8_t bytes[length];
[data getBytes:bytes];
char string[length * 2 + 1];
for (size_t i(0); i != length; ++i)
sprintf(string + i * 2, "%.2x", bytes[reverse ? length - i - 1 : i]);
return [NSString stringWithUTF8String:string];
}
@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;
- (void) 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