Как использовать JSExport и JavascriptCore в переполнении стека

Я работаю с JavascriptCore в проекте C ++, и я не знаю, как представить класс C ++ для javascript. Например, в Objective-C это что-то вроде этого:

@protocol MyPointExports <JSExport>
@property double x;
@property double y;
- (NSString *)description;
- (instancetype)initWithX:(double)x y:(double)y;
+ (MyPoint *)makePointWithX:(double)x y:(double)y;
@end

@interface MyPoint : NSObject <MyPointExports>
- (void)myPrivateMethod;  // Not in the MyPointExports protocol, so not visible to JavaScript code.
@end

@implementation MyPoint
// ...
@end

JSContext *context = [[JSContext alloc] init];

// export MyPoint class
context[@"MyPoint"] = [MyPoint class];

Но я не знаю, как перевести JSExport и протокол на C ++.

1

Решение

Похоже, вам нужно использовать C API для этого. Увидеть Эта статья для деталей. В частности, раздел «Определение нативных объектов в JavaScript».

Перечисление из ссылочной статьи выглядит очень похоже на то, что вы хотите достичь:

#include <iostream>
#include <JavaScriptCore/JavaScriptCore.h>
#include <sys/stat.h>

using namespace std;

struct FilesystemPrivate {
string path;
bool is_directory;
bool is_file;
bool is_symlink;
size_t size;
bool exists;
};

std::string JSStringToStdString(JSStringRef jsString) {
size_t maxBufferSize = JSStringGetMaximumUTF8CStringSize(jsString);
char* utf8Buffer = new char[maxBufferSize];
size_t bytesWritten = JSStringGetUTF8CString(jsString, utf8Buffer, maxBufferSize);
std::string utf_string = std::string (utf8Buffer, bytesWritten -1); // the last byte is a null \0 which std::string doesn't need.
delete [] utf8Buffer;
return utf_string;
}

JSValueRef ObjectCallAsFunctionCallback(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) {
for (size_t i=0; i<argumentCount; i++) {
JSStringRef pathString = JSValueToStringCopy(ctx, arguments[i], nullptr);
cout << JSStringToStdString(pathString);
}
cout << endl ;
return JSValueMakeUndefined(ctx);
}

void setAttributes(FilesystemPrivate *fs, std::string path) {
fs->path = path;

struct stat statbuf;

if (lstat(path.c_str(), &statbuf) != -1) {
switch (statbuf.st_mode & S_IFMT){
case S_IFREG:
fs->is_file = true;
break;
case S_IFLNK:
fs->is_symlink = true;
break;
case S_IFDIR:
fs->is_directory = true;
break;
}
fs->size = statbuf.st_size;
fs->exists = true;
}else{
fs->exists = false;
fs->is_file = false;
fs->is_directory = false;
fs->is_symlink = false;
fs->size = 0;
}
}

/* callbacks */

void Filesystem_Finalize(JSObjectRef object){
FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
delete fs;
}

JSObjectRef Filesystem_CallAsConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
FilesystemPrivate *fs = new FilesystemPrivate();

JSStringRef pathString = JSValueToStringCopy(ctx, arguments[0], nullptr);
setAttributes(fs, JSStringToStdString(pathString));
JSObjectSetPrivate(constructor, static_cast<void*>(fs));

return constructor;
}

/* static values */

JSValueRef Filesystem_getPath(JSContextRef ctx, JSObjectRef object,JSStringRef propertyName, JSValueRef* exception) {
FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
JSStringRef pathString = JSStringCreateWithUTF8CString(fs->path.c_str());

return JSValueMakeString(ctx, pathString);
}

bool Filesystem_setPath(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) {
FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
JSStringRef pathString = JSValueToStringCopy(ctx, value, nullptr);

setAttributes(fs, JSStringToStdString(pathString));

return true;
}

JSValueRef Filesystem_getType(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) {
FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
JSStringRef pathType;

if (fs->is_file) {
pathType = JSStringCreateWithUTF8CString("File");
}else if (fs->is_directory) {
pathType = JSStringCreateWithUTF8CString("Directory");
}else if (fs->is_symlink) {
pathType = JSStringCreateWithUTF8CString("Symlink");
}else{
pathType = JSStringCreateWithUTF8CString("Unknown");
}

return JSValueMakeString(ctx, pathType);
}

JSValueRef Filesystem_getExist(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) {
FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));

return JSValueMakeBoolean(ctx, fs->exists);
}

JSValueRef Filesystem_getSize(JSContextRef ctx, JSObjectRef object,JSStringRef propertyName, JSValueRef* exception) {
FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));

return JSValueMakeNumber(ctx, static_cast<double>(fs->size));
}

JSValueRef Filesystem_remove(JSContextRef ctx, JSObjectRef function, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
remove(fs->path.c_str());

return JSValueMakeUndefined(ctx);
}

JSClassRef FilesystemClass() {
static JSClassRef filesystem_class;
if (!filesystem_class) {
JSClassDefinition classDefinition = kJSClassDefinitionEmpty;

static JSStaticFunction staticFunctions[] = {
{ "remove", Filesystem_remove, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0 }
};

static JSStaticValue staticValues[] = {
{ "path", Filesystem_getPath, Filesystem_setPath, kJSPropertyAttributeDontDelete },
{ "type", Filesystem_getType, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "exists", Filesystem_getExist, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "size", Filesystem_getSize, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0, 0 }
};

classDefinition.className = "Filesystem";
classDefinition.attributes = kJSClassAttributeNone;
classDefinition.staticFunctions = staticFunctions;
classDefinition.staticValues = staticValues;
classDefinition.finalize = Filesystem_Finalize;
classDefinition.callAsConstructor = Filesystem_CallAsConstructor;

filesystem_class = JSClassCreate(&classDefinition);
}
return filesystem_class;
}

int main(int argc, const char * argv[]) {

JSContextGroupRef contextGroup = JSContextGroupCreate();
JSGlobalContextRef globalContext = JSGlobalContextCreateInGroup(contextGroup, nullptr);
JSObjectRef globalObject = JSContextGetGlobalObject(globalContext);

JSObjectRef functionObject = JSObjectMakeFunctionWithCallback(globalContext, JSStringCreateWithUTF8CString("log"), ObjectCallAsFunctionCallback);
JSObjectSetProperty(globalContext, globalObject, JSStringCreateWithUTF8CString("log"), functionObject, kJSPropertyAttributeNone, nullptr);

JSObjectRef filesystemObject = JSObjectMake(globalContext, FilesystemClass(), nullptr);
JSObjectSetProperty(globalContext, globalObject, JSStringCreateWithUTF8CString("Filesystem"), filesystemObject, kJSPropertyAttributeNone, nullptr);

JSEvaluateScript(globalContext, JSStringCreateWithUTF8CString("var fs = new Filesystem('/Users/{user}/Desktop/file');log(fs.exists);"), nullptr, nullptr, 1, nullptr);

return 0;
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]