+MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
+ MSOldCall([UIColor clearColor]);
+ [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
+}
+
+// iOS >= 5.0
+MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
+ if ((self = MSOldCall(style, reuse)) != nil) {
+ [self setBackgroundColor:[UIColor clearColor]];
+ [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
+ } return self;
+}
+
+// iOS << 5.0
+MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
+ if ((self = MSOldCall(style, reuse)) != nil) {
+ [self setBackgroundColor:[UIColor clearColor]];
+ [[self contentView] setBackgroundColor:[UIColor clearColor]];
+ } return self;
+}
+
+MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
+ if ((self = MSOldCall(style, reuse)) != nil) {
+ UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
+ [_label setBackgroundColor:[UIColor clearColor]];
+ } return self;
+}
+
+MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
+ MSOldCall(UITableViewCellSeparatorStyleNone);
+}
+
+MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
+ if ((self = MSOldCall(frame, style)) != nil) {
+ [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
+ } return self;
+}
+
+MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
+ MSOldCall();
+
+ if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
+ if (UIImage *image = $getImage$(path)) {
+ SMSBackgrounded_ = true;
+
+ UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
+ UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
+ UIView *table;
+ if (&_transcriptTable != NULL)
+ table = _transcriptTable;
+ else if (&_transcriptLayer != NULL)
+ table = _transcriptLayer;
+ else
+ table = nil;
+
+ UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
+ UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
+
+ if (table == nil)
+ [placard insertSubview:background atIndex:0];
+ else {
+ [table setBackgroundColor:[UIColor clearColor]];
+ [placard insertSubview:background belowSubview:table];
+ }
+ }
+}
+// }}}
+
+template <typename Original_>
+static UIImage *WBCacheUIImage(NSBundle *bundle, const Original_ &original, NSString *name, NSString *key) {
+ if (name == nil)
+ return original();
+ NSUInteger period([name rangeOfString:@"."].location);
+ NSUInteger length([name length]);
+ if (period == NSNotFound || length < 4 || period > length - 4)
+ name = [name stringByAppendingString:@".png"];
+
+ return WBCacheImage([bundle, &original, name](){
+ UIImage *image(original());
+ if (image != nil && UIDebug_) {
+ NSString *path([@"/tmp/WBImages/" stringByAppendingString:[bundle bundleIdentifier]]);
+ [Manager_ createDirectoryAtPath:path withIntermediateDirectories:YES attributes:@{NSFilePosixPermissions: @0777} error:NULL];
+ path = [NSString stringWithFormat:@"%@/%@", path, name];
+ if (![Manager_ fileExistsAtPath:path])
+ [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
+ } return image;
+ }, [=](){ return $pathForFile$inBundle$(name, bundle, true); }, key);
+}
+
+// %hook _UIImageWithName() {{{
+MSHook(UIImage *, _UIImageWithName, NSString *name) {
+ if (name == nil)
+ return nil;
+ if (Debug_)
+ NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
+ return WBCacheUIImage(_UIKitBundle(),
+ [=](){ return __UIImageWithName(name); },
+ name, [NSString stringWithFormat:@"I:%@", name]);
+}
+// }}}
+// %hook _UIImageWithNameInDomain() {{{
+MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
+ if (Debug_)
+ NSLog(@"WB:Debug: _UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
+ return WBCacheImage(
+ [=](){ return __UIImageWithNameInDomain(name, domain); },
+ [=](){ return $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])); },
+ [NSString stringWithFormat:@"D:%zu:%@%@", size_t([domain length]), domain, name]);
+}
+// }}}
+
+// UISharedArtwork (iOS 6) {{{
+MSInstanceMessageHook2(UISharedArtwork *, UISharedArtwork, initWithName,inBundle, NSString *, name, NSBundle *, bundle) {
+ if ((self = MSOldCall(name, bundle)) != nil) {
+ $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ } return self;
+}
+
+MSInstanceMessageHook2(UIImage *, UISharedArtwork, imageNamed,device, NSString *, name, NSInteger, device) {
+ NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
+ if (Debug_)
+ NSLog(@"WB:Debug: -[UISharedArtwork(%@) imageNamed:@\"%@\" device:%li]", [bundle bundleIdentifier], name, (long) device);
+ return WBCacheUIImage(bundle,
+ [=](){ return MSOldCall(name, device); },
+ name, [NSString stringWithFormat:@"M:%p:%@:%li", self, name, (long) device]);
+}
+// }}}
+// _UIAssetManager (iOS 7) {{{
+MSInstanceMessageHook3(_UIAssetManager *, _UIAssetManager, initWithName,inBundle,idiom, NSString *, name, NSBundle *, bundle, NSInteger, idiom) {
+ if ((self = MSOldCall(name, bundle, idiom)) != nil) {
+ $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ } return self;
+}
+
+MSInstanceMessageHook5(UIImage *, _UIAssetManager, imageNamed,scale,idiom,subtype,cachingOptions, NSString *, name, CGFloat, scale, NSInteger, idiom, NSUInteger, subtype, NSUInteger, caching) {
+ NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
+ if (Debug_)
+ NSLog(@"WB:Debug: -[_UIAssetManager(%@/%@) imageNamed:@\"%@\" scale:%g idiom:%li subtype:%lu cachingOptions:%lu]",
+ [bundle bundleIdentifier], [self carFileName],
+ name, scale, (long) idiom,
+ (unsigned long) subtype,
+ (unsigned long) caching
+ );
+
+ if (bundle == _UIKitBundle()) {
+ NSString *name([self carFileName]);
+ if (false);
+ else if ([name isEqualToString:@"UIKit_NewArtwork"])
+ bundle = [WBBundle bundleWithIdentifier:@"com.apple.uikit.Artwork"];
+ else if ([name isEqualToString:@"UIKit_OriginalArtwork"])
+ bundle = [WBBundle bundleWithIdentifier:@"com.apple.uikit.LegacyArtwork"];
+ }
+
+ return WBCacheUIImage(bundle,
+ [=](){ return MSOldCall(name, scale, idiom, subtype, caching); },
+ name, [NSString stringWithFormat:@"M:%p:%@:%g:%li:%lu", self, name, scale, (long) idiom, (unsigned long) subtype]);
+}
+// }}}
+// _UIAssetManager (iOS 8) {{{
+struct SizeClassPair {
+ NSInteger first;
+ NSInteger second;
+};
+
+MSInstanceMessageHook7(UIImage *, _UIAssetManager, imageNamed,scale,idiom,subtype,cachingOptions,sizeClassPair,attachCatalogImage, NSString *, name, CGFloat, scale, NSInteger, idiom, NSUInteger, subtype, NSUInteger, caching, SizeClassPair, size, BOOL, attach) {
+ NSBundle *bundle([self bundle]);
+ if (Debug_)
+ NSLog(@"WB:Debug: -[_UIAssetManager(%@/%@) imageNamed:@\"%@\" scale:%g idiom:%li subtype:%lu cachingOptions:%lu sizeClassPair:[%li %li] attachCatalogImage:%s]",
+ [bundle bundleIdentifier], [self carFileName],
+ name, scale, (long) idiom,
+ (unsigned long) subtype,
+ (unsigned long) caching,
+ (long) size.first, (long) size.second,
+ attach ? "YES" : "NO"
+ );
+ return WBCacheUIImage(bundle,
+ [=](){ return MSOldCall(name, scale, idiom, subtype, caching, size, attach); },
+ name, [NSString stringWithFormat:@"M:%p:%@:%g:%li:%lu:%li:%li:%c", self, name, scale, (long) idiom, (unsigned long) subtype, (long) size.first, (long) size.second, attach ? 'Y' : 'N']);
+}
+// }}}
+
+// %hook GSFontCreateWithName() {{{
+MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
+ if (Debug_)
+ NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
+ if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
+ name = [font UTF8String];
+ //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
+ // size *= [scale floatValue];
+ return _GSFontCreateWithName(name, traits, size);
+}
+// }}}
+
+#define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"