X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/326a9dbad829e7d77335fae6274dc364770c1b1f..da2af935087da0e425bbfb06fe1cc24107e3f32d:/ObjectiveC/Library.mm diff --git a/ObjectiveC/Library.mm b/ObjectiveC/Library.mm index 6a8c0eb..b8699cd 100644 --- a/ObjectiveC/Library.mm +++ b/ObjectiveC/Library.mm @@ -1,40 +1,22 @@ -/* Cycript - Inlining/Optimizing JavaScript Compiler - * Copyright (C) 2009 Jay Freeman (saurik) +/* Cycript - Optimizing JavaScript Compiler/Runtime + * Copyright (C) 2009-2010 Jay Freeman (saurik) */ -/* Modified BSD License {{{ */ +/* GNU Lesser General Public License, Version 3 {{{ */ /* - * Redistribution and use in source and binary - * forms, with or without modification, are permitted - * provided that the following conditions are met: + * Cycript is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * 1. Redistributions of source code must retain the - * above copyright notice, this list of conditions - * and the following disclaimer. - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions - * and the following disclaimer in the documentation - * and/or other materials provided with the - * distribution. - * 3. The name of the author may not be used to endorse - * or promote products derived from this software - * without specific prior written permission. + * Cycript 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 Lesser General Public + * License for more details. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + * You should have received a copy of the GNU Lesser General Public License + * along with Cycript. If not, see . +**/ /* }}} */ #if defined(__APPLE__) && defined(__arm__) @@ -131,6 +113,7 @@ #define object_getInstanceVariable(object, name, value) ({ \ objc_ivar *ivar(class_getInstanceVariable(object_getClass(object), name)); \ + _assert(value != NULL); \ if (ivar != NULL) \ GSObjCGetVariable(object, ivar_getOffset(ivar), sizeof(void *), value); \ ivar; \ @@ -260,6 +243,7 @@ static JSClassRef Internal_; static JSClassRef Message_; static JSClassRef Messages_; static JSClassRef Selector_; +static JSClassRef StringInstance_; static JSClassRef Super_; static JSClassRef ObjectiveC_Classes_; @@ -281,6 +265,7 @@ static Class NSBoolNumber_; static Class NSArray_; static Class NSDictionary_; +static Class NSString_; static Class Object_; static Type_privateData *Object_type; @@ -294,6 +279,8 @@ Type_privateData *Selector_privateData::GetType() const { return Selector_type; } +static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception); + JSValueRef CYGetClassPrototype(JSContextRef context, id self) { if (self == nil) return CYGetCachedObject(context, CYJSString("Instance_prototype")); @@ -316,12 +303,15 @@ JSValueRef CYGetClassPrototype(JSContextRef context, id self) { prototype = CYGetCachedObject(context, CYJSString("Array_prototype")); else if (self == NSDictionary_) prototype = CYGetCachedObject(context, CYJSString("Object_prototype")); + else if (self == NSString_) + prototype = CYGetCachedObject(context, CYJSString("StringInstance_prototype")); else prototype = CYGetClassPrototype(context, class_getSuperclass(self)); JSObjectRef object(JSObjectMake(context, _class, NULL)); JSObjectSetPrototype(context, object, prototype); CYSetProperty(context, cy, name, object); + return object; } @@ -761,6 +751,10 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu } } ++ (bool) cy$hasImplicitProperties { + return false; +} + @end /* }}} */ /* Bridge: NSBoolNumber {{{ */ @@ -1044,6 +1038,49 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu return [self cy$toCYON]; } +- (bool) cy$hasProperty:(NSString *)name { + if ([name isEqualToString:@"length"]) + return true; + + size_t index(CYGetIndex(name)); + if (index == _not(size_t) || index >= [self length]) + return [super cy$hasProperty:name]; + else + return true; +} + +- (NSObject *) cy$getProperty:(NSString *)name { + if ([name isEqualToString:@"length"]) { + NSUInteger count([self length]); +#ifdef __APPLE__ + return [NSNumber numberWithUnsignedInteger:count]; +#else + return [NSNumber numberWithUnsignedInt:count]; +#endif + } + + size_t index(CYGetIndex(name)); + if (index == _not(size_t) || index >= [self length]) + return [super cy$getProperty:name]; + else + return [self substringWithRange:NSMakeRange(index, 1)]; +} + +- (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context { + [super cy$getPropertyNames:names inContext:context]; + + for (size_t index(0), length([self length]); index != length; ++index) { + char name[32]; + sprintf(name, "%zu", index); + JSPropertyNameAccumulatorAddName(names, CYJSString(name)); + } +} + +// XXX: this might be overly restrictive for NSString; I think I need a half-way between /injecting/ implicit properties and /accepting/ implicit properties ++ (bool) cy$hasImplicitProperties { + return false; +} + @end /* }}} */ /* Bridge: WebUndefined {{{ */ @@ -2339,6 +2376,12 @@ static JSStaticFunction Selector_staticFunctions[5] = { {NULL, NULL, 0} }; +static JSStaticFunction StringInstance_staticFunctions[2] = { + //{"valueOf", &Instance_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"toString", &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {NULL, NULL, 0} +}; + void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry { apr_pool_t *pool(CYGetGlobalPool()); @@ -2356,6 +2399,7 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry { NSArray_ = objc_getClass("NSArray"); NSDictionary_ = objc_getClass("NSDictionary"); + NSString_ = objc_getClass("NSString"); Object_ = objc_getClass("Object"); JSClassDefinition definition; @@ -2411,6 +2455,11 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry { definition.finalize = &CYFinalize; Selector_ = JSClassCreate(&definition); + definition = kJSClassDefinitionEmpty; + definition.className = "StringInstance"; + definition.staticFunctions = StringInstance_staticFunctions; + StringInstance_ = JSClassCreate(&definition); + definition = kJSClassDefinitionEmpty; definition.className = "Super"; definition.staticFunctions = Internal_staticFunctions; @@ -2471,11 +2520,18 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry { JSObjectRef Instance(JSObjectMakeConstructor(context, Instance_, &Instance_new)); JSObjectRef Message(JSObjectMakeConstructor(context, Message_, NULL)); JSObjectRef Selector(JSObjectMakeConstructor(context, Selector_, &Selector_new)); + JSObjectRef StringInstance(JSObjectMakeConstructor(context, StringInstance_, NULL)); JSObjectRef Super(JSObjectMakeConstructor(context, Super_, &Super_new)); JSObjectRef Instance_prototype(CYCastJSObject(context, CYGetProperty(context, Instance, prototype_s))); CYSetProperty(context, cy, CYJSString("Instance_prototype"), Instance_prototype); + JSObjectRef StringInstance_prototype(CYCastJSObject(context, CYGetProperty(context, StringInstance, prototype_s))); + CYSetProperty(context, cy, CYJSString("StringInstance_prototype"), StringInstance_prototype); + + JSObjectRef String_prototype(CYGetCachedObject(context, CYJSString("String_prototype"))); + JSObjectSetPrototype(context, StringInstance_prototype, String_prototype); + CYSetProperty(context, cycript, CYJSString("Instance"), Instance); CYSetProperty(context, cycript, CYJSString("Selector"), Selector); CYSetProperty(context, cycript, CYJSString("Super"), Super);