]> git.saurik.com Git - cycript.git/blobdiff - ObjectiveC/Library.mm
Add String::toCYON, toString_s, and bridge NSString via String.prototype.
[cycript.git] / ObjectiveC / Library.mm
index 1613eea25738db0011e754b023be3554c932454f..c1cacf86062bcea5c4123c0cf8e658f1d562914b 100644 (file)
@@ -281,6 +281,7 @@ static Class NSBoolNumber_;
 
 static Class NSArray_;
 static Class NSDictionary_;
+static Class NSString_;
 static Class Object_;
 
 static Type_privateData *Object_type;
@@ -294,6 +295,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"));
@@ -312,16 +315,22 @@ JSValueRef CYGetClassPrototype(JSContextRef context, id self) {
     JSClassRef _class(NULL);
     JSValueRef prototype;
 
+    JSObjectRef object(JSObjectMake(context, _class, NULL));
+
     if (self == NSArray_)
         prototype = CYGetCachedObject(context, CYJSString("Array_prototype"));
     else if (self == NSDictionary_)
         prototype = CYGetCachedObject(context, CYJSString("Object_prototype"));
-    else
+    else if (self == NSString_) {
+        prototype = CYGetCachedObject(context, CYJSString("String_prototype"));
+
+        CYSetProperty(context, object, toString_s, &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete);
+    } 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 +770,10 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
     }
 }
 
++ (bool) cy$hasImplicitProperties {
+    return false;
+}
+
 @end
 /* }}} */
 /* Bridge: NSBoolNumber {{{ */
@@ -1044,6 +1057,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 {{{ */
@@ -1747,19 +1803,20 @@ static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object,
     }
 #endif
 
-    if (CYHasImplicitProperties(_class)) {
+    if (CYHasImplicitProperties(_class))
+        for (Class current(_class); current != nil; current = class_getSuperclass(current)) {
 #if OBJC_API_VERSION >= 2
-        unsigned int size;
-        objc_method **data(class_copyMethodList(_class, &size));
-        for (size_t i(0); i != size; ++i)
-            Instance_getPropertyNames_message(names, data[i]);
-        free(data);
+            unsigned int size;
+            objc_method **data(class_copyMethodList(current, &size));
+            for (size_t i(0); i != size; ++i)
+                Instance_getPropertyNames_message(names, data[i]);
+            free(data);
 #else
-        for (objc_method_list *methods(_class->methods); methods != NULL; methods = methods->method_next)
-            for (int i(0); i != methods->method_count; ++i)
-                Instance_getPropertyNames_message(names, &methods->method_list[i]);
+            for (objc_method_list *methods(current->methods); methods != NULL; methods = methods->method_next)
+                for (int i(0); i != methods->method_count; ++i)
+                    Instance_getPropertyNames_message(names, &methods->method_list[i]);
 #endif
-    }
+        }
 
     CYPoolTry {
         // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
@@ -2355,6 +2412,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;