// Workaround bug in cycript-0.9.259-1
this.objc_msgSend = Cycript.all.objc_msgSend;
// include other .cy files
function include(fn) {
var t = [new NSTask init]; [t setLaunchPath:@"/usr/bin/cycript"]; [t setArguments:["-c", fn]];
var p = [NSPipe pipe]; [t setStandardOutput:p]; [t launch]; [t waitUntilExit]; [t release];
var s = [new NSString initWithData:[[p fileHandleForReading] readDataToEndOfFile] encoding:4];
with(this) { var r = eval(s.toString()); } [s release]; return r;
}
// Standard C functions
function CGPointMake(x, y) { return {x:x, y:y}; }
function CGSizeMake(w, h) { return {width:w, height:h}; }
function CGRectMake(x, y, w, h) { return {origin:CGPointMake(x,y), size:CGSizeMake(w, h)}; }
function NSMakeRange(loc, len) { return {location:loc, length:len}; }
var CFRangeMake = NSMakeRange;
// Standard C types
var IMP = new Type("^?"), SEL = new Type(":"), unsigned = new Type("I");
var int8_t = char, int16_t = short, int32_t = long, int64_t = new Type("q");
var uint8_t = new Type("C"), uint16_t = new Type("S"), uint32_t = new Type("L"), uint64_t = new Type("Q");
var SInt8 = int8_t, SInt16 = int16_t, SInt32 = int32_t, SInt64 = int64_t;
var UInt8 = uint8_t, UInt16 = uint16_t, UInt32 = uint32_t, UInt64 = uint64_t;
var unichar = int16_t, UniChar = int16_t, wchar_t = int32_t;
var size_t = NSUInteger, intptr_t = NSInteger;
var BOOL = char, bool = new Type("B");
var mach_port_t = int, pid_t = int32_t;
var CGRect = new Type("{CGRect}"), CGSize = new Type("{CGSize}"), CGPoint = new Type("{CGPoint}");
var NSRange = new Type("{NSRange}"), CFRange = new Type("{CFRange}");
var CGAffineTransform = new Type("{CGAffineTransform}"), UIEdgeInsets = new Type("{UIEdgeInsets}");
// Standard enum values
var UIControlStateNormal = 0, UIControlStateHighlighted = 1 << 0, UIControlStateDisabled = 1 << 1,
UIControlStateSelected = 1 << 2, UIControlStateApplication = 0x00FF0000, UIControlStateReserved = 0xFF000000;
// Usage: dlfun("notify_post", "I*")
function dlfun(fn, encoding, altname) { var f = new Functor(dlsym(RTLD_DEFAULT, fn), encoding); if (f) this[altname || fn] = f; return f; }
// MobileSubstrate
dlfun("MSHookMessageEx", "v#:^?^^?");
dlfun("MSHookMessage", "^?#:^?*");
dlfun("MSHookFunction", "v^v^v^^v");
dlfun("_Z8MSLogHexPKvmPKc", "v^vL*", "MSLogHex");
// Declare a struct
// e.g. var CGSize = struct(CGFloat, CGFloat);
function struct(n) {
var typestr = ["{?="];
for (var i = 0; i < arguments.length; ++ i) {
var arg = arguments[i];
typestr.push(arguments[i].toString());
}
typestr.push("}");
return new Type(typestr.join(""));
}
// Hack!
function quit() { MSHookFunction(dlsym(RTLD_DEFAULT, "readline"), new Functor(function(x){return null;}, "**"), null); }
// Usage: $encode("int*") --> new Type("^i").
// Cannot handle structs, unions and function pointers yet.
function $encode(ss, dontKeepClassName) {
function _encode(s) {
s = s.replace(/\s{2,}/g, " ").replace(/^\s|\s$/g, "").replace(/(\W)\s|\s(\W)/g, "$1$2")
var m;
if ((m = /\((\*+)\)\[(\d*)\]/.exec(s))) {
var left = s.substr(0, m.index), right = s.substr(m.index + m[0].length);
var t = _encode(left+right), px = m[1].replace(/\*/g, "^");
if (m[2]) return px + "[" + m[2] + t + "]";
else return px + "^" + t;
} else if ((m = /\[(\d*)\]$/.exec(s))) {
var t = _encode(s.substr(0, m.index));
if (m[1]) return "[" + m[1] + t + "]";
else return "^" + t;
} else if ((m = /\*+$/.exec(s))) {
var t = _encode(s.substr(0, m.index));
var px = m[0].replace(/\*/g, "^");
if (t[0] == '1') { px = px.substr(1); t = t.substr(1); }
return px+t;
} else if ((m = /:(\d+)$/.exec(s))) {
return "b" + m[1];
} else {
var prefix = "", longcount = 0, isunsigned = null, theType = "";
for each (comp in s.split(/\s/)) {
if ((mod = _encode.modifiers[comp])) prefix += mod;
else if (comp == "unsigned") isunsigned = true;
else if (comp == "signed") isunsigned = false;
else if (comp == "long") ++ longcount;
else if (comp == "short") -- longcount;
else if (comp == "void") theType = "v";
else if ((typ = this[comp])) {
if (typ instanceof Type) theType = typ.toString();
else theType = dontKeepClassName ? "1@" : "1@\"" + typ.toString() + "\"";
} else theType = "{" + comp + "}";
}
if (theType == "" || theType == "i") {
if (longcount < 0) theType = "s";
else if (longcount == 1) theType = "l";
else if (longcount >= 2) theType = "q";
}
if (isunsigned !== null && theType[0] !== '1' && theType[0] !== '{')
theType = theType[isunsigned ? 'toUpperCase' : 'toLowerCase']();
return prefix + theType;
}
}
_encode.modifiers = {
"inout": "N", "bycopy": "O", "byref": "R", "oneway": "V",
"_Complex": "j", "in": "n", "out": "o", "const": "r"
};
return ss instanceof Type ? ss : new Type(_encode(ss).replace(/\^c/g, "*"));
}
/*
Usage:
addMethod(UIWindow, "-(void)setAutorotates:(BOOL)autorotates forceUpdateInterfaceOrientation:(BOOL)orientation", function(autorotates, orientation){});
Bug: [super xxx] doesn't work by default. You need to call
$cyr = new Super(this, @selector(...));
yourself.
*/
function addMethod(cls, decl, func) {
if (/^\s*\+/.test(decl)) cls = cls->isa;
var typeMatcher = /\(([^)]+)\)/g, selMatcher = /[\s\)]([^:\s]+)\s*:/g
var typestr = "", typecount = 0;
var selname = "";
var m;
while ((m = typeMatcher.exec(decl))) {
typestr += $encode(m[1], true).toString();
if (++typecount == 1) typestr += "@:";
}
if (typecount == 1) selname = /\)(.+)$/.exec(decl)[0];
else {
while ((m = selMatcher.exec(decl))) selname += m[1] + ":";
}
selname = selname.replace(/\s/g, "");
return class_addMethod(cls, new Selector(selname), new Functor(function(self,_cmd){
return func.apply(self,Array.prototype.slice.call(arguments,2));
}, typestr), typestr);
}