JSWrappers.m
/* |
File: JSWrappers.m |
Abstract: Conveience class used to gather |
commonly called sequences into some simple class methods for calling |
the JavaScriptCore Framework. The methods defined in this class |
are used again and again throughout the sample. |
Version: 1.1 |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
Inc. ("Apple") in consideration of your agreement to the following |
terms, and your use, installation, modification or redistribution of |
this Apple software constitutes acceptance of these terms. If you do |
not agree with these terms, please do not use, install, modify or |
redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and |
subject to these terms, Apple grants you a personal, non-exclusive |
license, under Apple's copyrights in this original Apple software (the |
"Apple Software"), to use, reproduce, modify and redistribute the Apple |
Software, with or without modifications, in source and/or binary forms; |
provided that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the following |
text and disclaimers in all such redistributions of the Apple Software. |
Neither the name, trademarks, service marks or logos of Apple Inc. may |
be used to endorse or promote products derived from the Apple Software |
without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or |
implied, are granted by Apple herein, including but not limited to any |
patent rights that may be infringed by your derivative works or by other |
works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
Copyright (C) 2011 Apple Inc. All Rights Reserved. |
*/ |
#import "JSWrappers.h" |
#import "NSStringExtras.h" |
@implementation JSWrappers |
@synthesize jsContext; |
- (id)initWithContext:(JSGlobalContextRef)theContext { |
if ((self = [super init]) != nil) { |
self.jsContext = theContext; |
} |
return self; |
} |
- (void)dealloc { |
self.jsContext = NULL; |
[super dealloc]; |
} |
/* -vsCallJSFunction:withParameters: is much like the vsprintf function in that |
it receives a va_list rather than a variable length argument list. This |
is a simple utility for calling JavaScript functions in a JavaScriptContext |
that is called by the other call*JSFunction methods in this file to do the |
actual work. The caller provides a function name and the parameter va_list, |
and -vsCallJSFunction:withParameters: uses those to call the function in the |
JavaScriptCore context. Only NSString and NSNumber values can be provided |
as parameters. The result returned is the same as the value returned by |
the function, or NULL if an error occured. */ |
- (JSValueRef)vsCallJSFunction:(NSString *)name withArg:(id)firstParameter andArgList:(va_list)args { |
/* default result */ |
JSValueRef theResult = NULL; |
/* try to find the named function defined as a property on the global object */ |
JSStringRef functionNameString = [name jsStringValue]; |
if ( functionNameString != NULL ) { |
/* retrieve the function object from the global object. */ |
JSValueRef jsFunctionObject = |
JSObjectGetProperty( self.jsContext, |
JSContextGetGlobalObject( self.jsContext ), functionNameString, NULL ); |
/* if we found a property, verify that it's a function */ |
if ( ( jsFunctionObject != NULL ) && JSValueIsObject( self.jsContext, jsFunctionObject ) ) { |
const size_t kMaxArgCount = 20; |
id nthID; |
BOOL argsOK = YES; |
size_t argumentCount = 0; |
JSValueRef arguments[kMaxArgCount]; |
/* convert the function reference to a function object */ |
JSObjectRef jsFunction = JSValueToObject( self.jsContext, jsFunctionObject, NULL ); |
/* index through the parameters until we find a nil one, |
or exceed our maximu argument count */ |
for ( nthID = firstParameter; |
argsOK && ( nthID != nil ) && ( argumentCount < kMaxArgCount ); |
nthID = va_arg( args, id ) ) { |
if ( [nthID isKindOfClass: [NSNumber class]] ) { |
arguments[argumentCount++] = JSValueMakeNumber( self.jsContext, [nthID doubleValue] ); |
} else if ( [nthID isKindOfClass: [NSString class]] ) { |
JSStringRef argString = [nthID jsStringValue]; |
if ( argString != NULL ) { |
arguments[argumentCount++] = |
JSValueMakeString( self.jsContext, argString ); |
JSStringRelease( argString ); |
} else { |
argsOK = NO; |
} |
} else { |
NSLog(@"bad parameter type for item %lu (%@) in vsCallJSFunction:withArg:andArgList:", |
argumentCount, nthID); |
argsOK = NO; /* unknown parameter type */ |
} |
} |
/* call through to the function */ |
if ( argsOK ) { |
theResult = JSObjectCallAsFunction(self.jsContext, jsFunction, |
NULL, argumentCount, arguments, NULL); |
} |
} |
JSStringRelease( functionNameString ); |
} |
return theResult; |
} |
/* -callJSFunction:withParameters: is a simple utility for calling JavaScript |
functions in a JavaScriptContext. The caller provides a function |
name and a nil terminated list of parameters, and callJSFunction |
uses those to call the function in the JavaScriptCore context. Only |
NSString and NSNumber values can be provided as parameters. The |
result returned is the same as the value returned by the function, |
or NULL if an error occured. */ |
- (JSValueRef)callJSFunction:(NSString *)name withParameters:(id)firstParameter,... { |
JSValueRef theResult = NULL; |
va_list args; |
va_start( args, firstParameter ); |
theResult = [self vsCallJSFunction: name withArg: firstParameter andArgList: args]; |
va_end( args ); |
return theResult; |
} |
/* -callBooleanJSFunction:withParameters: is similar to -callJSFunction:withParameters: |
except it returns a BOOL result. It will return NO if the function is not |
defined in the context or if an error occurs. */ |
- (BOOL)callBooleanJSFunction:(NSString *)name withParameters:(id)firstParameter,... { |
BOOL theResult; |
va_list args; |
/* call the function */ |
va_start( args, firstParameter ); |
JSValueRef functionResult = [self vsCallJSFunction: name withArg: firstParameter andArgList: args]; |
va_end( args ); |
/* convert the result, if there is one, into the objective-c type */ |
if ( ( functionResult != NULL ) && JSValueIsBoolean( self.jsContext, functionResult ) ) { |
theResult = ( JSValueToBoolean(self.jsContext, functionResult ) ? YES : NO ); |
} else { |
theResult = NO; |
} |
return theResult; |
} |
/* -callNumericJSFunction:withParameters: is similar to -callJSFunction:withParameters: |
except it returns a NSNumber * result. It will return nil if the function is not |
defined in the context, if the result returned by the function cannot be converted |
into a number, or if an error occurs. */ |
- (NSNumber *)callNumericJSFunction:(NSString*)name withParameters:(id)firstParameter,... { |
NSNumber *theResult; |
va_list args; |
/* call the function */ |
va_start( args, firstParameter ); |
JSValueRef functionResult = [self vsCallJSFunction: name withArg: firstParameter andArgList: args]; |
va_end( args ); |
/* convert the result, if there is one, into the objective-c type */ |
if ( ( functionResult != NULL ) && JSValueIsNumber( self.jsContext, functionResult ) ) { |
theResult = [NSNumber numberWithDouble: JSValueToNumber( self.jsContext, functionResult, NULL )]; |
} else { |
theResult = nil; |
} |
return theResult; |
} |
/* -callStringJSFunction:withParameters: is similar to -callJSFunction:withParameters: |
except it returns a NSNumber * result. It will return nil if the function is not |
defined in the context, if the result returned by the function cannot be converted |
into a string, or if an error occurs. */ |
- (NSString *)callStringJSFunction:(NSString *)name withParameters:(id)firstParameter,... { |
NSString *theResult = nil; |
va_list args; |
/* call the function */ |
va_start( args, firstParameter ); |
JSValueRef functionResult = [self vsCallJSFunction: name withArg: firstParameter andArgList: args]; |
va_end( args ); |
/* convert the result, if there is one, into the objective-c type */ |
if ( functionResult != NULL ) { |
/* attempt to convert the result into a NSString */ |
theResult = [NSString stringWithJSValue:functionResult fromContext: self.jsContext]; |
} |
return theResult; |
} |
/* -addGlobalObject:ofClass:withPrivateData: adds an object of the given class |
and name to the global object of the JavaScriptContext. After this call, scripts |
running in the context will be able to access the object using the name. */ |
- (void)addGlobalObject:(NSString *)objectName ofClass:(JSClassRef)theClass |
withPrivateData:(void *)theData { |
/* create a new object of the given class */ |
JSObjectRef theObject = JSObjectMake( self.jsContext, theClass, theData ); |
if ( theObject != NULL ) { |
/* protect the value so it isn't eligible for garbage collection */ |
JSValueProtect( self.jsContext, theObject ); |
/* convert the name to a JavaScript string */ |
JSStringRef objectJSName = [objectName jsStringValue]; |
if ( objectJSName != NULL ) { |
/* add the object as a property of the context's global object */ |
JSObjectSetProperty( self.jsContext, JSContextGetGlobalObject( self.jsContext ), |
objectJSName, theObject, kJSPropertyAttributeReadOnly, NULL ); |
/* done with our reference to the name */ |
JSStringRelease( objectJSName ); |
} |
} |
} |
/* -addGlobalStringProperty:withValue: adds a string with the given name to the |
global object of the JavaScriptContext. After this call, scripts running in |
the context will be able to access the string using the name. */ |
- (void)addGlobalStringProperty:(NSString *)name withValue:(NSString *)theValue { |
/* convert the name to a JavaScript string */ |
JSStringRef propertyName = [name jsStringValue]; |
if ( propertyName != NULL ) { |
/* convert the property value into a JavaScript string */ |
JSStringRef propertyValue = [theValue jsStringValue]; |
if ( propertyValue != NULL ) { |
/* copy the property value into the JavaScript context */ |
JSValueRef valueInContext = JSValueMakeString( self.jsContext, propertyValue ); |
if ( valueInContext != NULL ) { |
/* add the property into the context's global object */ |
JSObjectSetProperty( self.jsContext, JSContextGetGlobalObject( self.jsContext ), |
propertyName, valueInContext, kJSPropertyAttributeReadOnly, NULL ); |
} |
/* done with our reference to the property value */ |
JSStringRelease( propertyValue ); |
} |
/* done with our reference to the property name */ |
JSStringRelease( propertyName ); |
} |
} |
/* -addGlobalFunctionProperty:withCallback: adds a function with the given name to the |
global object of the JavaScriptContext. After this call, scripts running in |
the context will be able to call the function using the name. */ |
- (void)addGlobalFunctionProperty:(NSString *)name |
withCallback:(JSObjectCallAsFunctionCallback)theFunction { |
/* convert the name to a JavaScript string */ |
JSStringRef functionName = [name jsStringValue]; |
if ( functionName != NULL ) { |
/* create a function object in the context with the function pointer. */ |
JSObjectRef functionObject = |
JSObjectMakeFunctionWithCallback( self.jsContext, functionName, theFunction ); |
if ( functionObject != NULL ) { |
/* add the function object as a property of the global object */ |
JSObjectSetProperty( self.jsContext, JSContextGetGlobalObject( self.jsContext ), |
functionName, functionObject, kJSPropertyAttributeReadOnly, NULL ); |
} |
/* done with our reference to the function name */ |
JSStringRelease( functionName ); |
} |
} |
/* -evaluateJavaScript: evaluates a string containing a JavaScript in the |
JavaScriptCore context and returns the result as a string. If an error |
occurs or the result returned by the script cannot be converted into a |
string, then nil is returned. */ |
- (NSString *)evaluateJavaScript:(NSString *)theJavaScript { |
NSString *resultString = nil; |
/* coerce the contents of the script edit text field in the window into |
a string inside of the JavaScript context. */ |
JSStringRef scriptJS = [theJavaScript jsStringValue]; |
if ( scriptJS != NULL ) { |
/* evaluate the string as a JavaScript inside of the JavaScript context. */ |
JSValueRef result = JSEvaluateScript( self.jsContext, scriptJS, NULL, NULL, 0, NULL ); |
if ( result != NULL) { |
/* attempt to convert the result into a NSString */ |
resultString = [NSString stringWithJSValue:result fromContext: self.jsContext]; |
} |
/* done with our reference to the script string */ |
JSStringRelease( scriptJS ); |
} |
return resultString; |
} |
@end |
Copyright © 2011 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2011-08-03