diff --git a/native/linux/atom.cpp b/native/linux/atom.cpp index d11f36d5e..15301cfc0 100644 --- a/native/linux/atom.cpp +++ b/native/linux/atom.cpp @@ -13,7 +13,6 @@ #include "include/cef_runnable.h" #include "client_handler.h" #include "onig_regexp_extension.h" -#include "atom_handler.h" #include "io_utils.h" char* szWorkingDir; // The current working directory diff --git a/native/linux/atom.gyp b/native/linux/atom.gyp index eae84318c..1f8e157d1 100644 --- a/native/linux/atom.gyp +++ b/native/linux/atom.gyp @@ -15,11 +15,15 @@ 'include_dirs': [ '../../cef', '..', + '../v8_extensions', + '.', ], 'sources': [ + '../v8_extensions/atom_linux.cpp', + '../v8_extensions/native_linux.cpp', + '../v8_extensions/onig_reg_exp_linux.cpp', 'atom.cpp', 'atom_cef_render_process_handler.cpp', - 'atom_handler.cpp', 'client_handler.cpp', 'io_utils.cpp', 'message_translation.cpp', diff --git a/native/linux/atom_cef_render_process_handler.cpp b/native/linux/atom_cef_render_process_handler.cpp index 957fdb8d1..5502ec9df 100644 --- a/native/linux/atom_cef_render_process_handler.cpp +++ b/native/linux/atom_cef_render_process_handler.cpp @@ -1,15 +1,15 @@ #include "atom_cef_render_process_handler.h" -#include "atom_handler.h" -#include "native_handler.h" -#include "onig_regexp_extension.h" +#include "atom_linux.h" +#include "native_linux.h" +#include "onig_reg_exp_linux.h" #include "io_utils.h" #include "message_translation.h" #include void AtomCefRenderProcessHandler::OnWebKitInitialized() { - new AtomHandler(); - new NativeHandler(); - new OnigRegexpExtension(); + new v8_extensions::AtomHandler(); + new v8_extensions::NativeHandler(); + new v8_extensions::OnigRegexpExtension(); } void AtomCefRenderProcessHandler::OnContextCreated( diff --git a/native/linux/atom_handler.cpp b/native/v8_extensions/atom_linux.cpp similarity index 96% rename from native/linux/atom_handler.cpp rename to native/v8_extensions/atom_linux.cpp index aa576f9c8..981562c61 100644 --- a/native/linux/atom_handler.cpp +++ b/native/v8_extensions/atom_linux.cpp @@ -1,4 +1,4 @@ -#include "atom_handler.h" +#include "atom_linux.h" #include "include/cef_base.h" #include "include/cef_runnable.h" #include @@ -8,6 +8,8 @@ using namespace std; +namespace v8_extensions { + AtomHandler::AtomHandler() : CefV8Handler() { string realFilePath = io_utils_real_app_path("/native/v8_extensions/atom.js"); @@ -42,3 +44,4 @@ bool AtomHandler::Execute(const CefString& name, CefRefPtr object, } return false; } +} diff --git a/native/linux/atom_handler.h b/native/v8_extensions/atom_linux.h similarity index 82% rename from native/linux/atom_handler.h rename to native/v8_extensions/atom_linux.h index a11c9a7f9..b26fe3e0b 100644 --- a/native/linux/atom_handler.h +++ b/native/v8_extensions/atom_linux.h @@ -1,9 +1,11 @@ -#ifndef ATOM_HANDLER_H_ -#define ATOM_HANDLER_H_ +#ifndef ATOM_LINUX_H_ +#define ATOM_LINUX_H_ #include "include/cef_base.h" #include "include/cef_v8.h" +namespace v8_extensions { + class AtomHandler: public CefV8Handler { public: @@ -17,5 +19,6 @@ IMPLEMENT_REFCOUNTING(AtomHandler) ; }; +} #endif diff --git a/native/v8_extensions/native_linux.cpp b/native/v8_extensions/native_linux.cpp new file mode 100644 index 000000000..d3e09a827 --- /dev/null +++ b/native/v8_extensions/native_linux.cpp @@ -0,0 +1,529 @@ +#include "native_linux.h" +#include "include/cef_base.h" +#include "include/cef_runnable.h" +#include "client_handler.h" +#include "io_utils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 8192 + +using namespace std; + +namespace v8_extensions { + +void *NotifyWatchersCallback(void* pointer) { + NativeHandler* handler = (NativeHandler*) pointer; + handler->NotifyWatchers(); + return NULL; +} + +void ExecuteWatchCallback(NotifyContext notifyContext) { + map callbacks = + notifyContext.callbacks[notifyContext.descriptor]; + map::iterator callback; + for (callback = callbacks.begin(); callback != callbacks.end(); callback++) { + CallbackContext callbackContext = callback->second; + CefRefPtr context = callbackContext.context; + CefRefPtr function = callbackContext.function; + + context->Enter(); + + CefV8ValueList args; + CefRefPtr retval; + CefRefPtr e; + args.push_back(callbackContext.eventTypes); + function->ExecuteFunction(retval, args); + + context->Exit(); + } +} + +NativeHandler::NativeHandler() : + CefV8Handler() { + string nativePath = io_utils_real_app_path("/native/v8_extensions/native.js"); + if (!nativePath.empty()) { + string extensionCode; + if (io_utils_read(nativePath, &extensionCode) > 0) + CefRegisterExtension("v8/native", extensionCode, this); + } + + notifyFd = inotify_init(); + if (notifyFd != -1) + g_thread_create_full(NotifyWatchersCallback, this, 0, true, false, + G_THREAD_PRIORITY_NORMAL, NULL); +} + +void NativeHandler::NotifyWatchers() { + char buffer[BUFFER_SIZE]; + ssize_t bufferRead; + size_t eventSize; + ssize_t bufferIndex; + struct inotify_event *event; + bufferRead = read(notifyFd, buffer, BUFFER_SIZE); + while (bufferRead > 0) { + bufferIndex = 0; + while (bufferIndex < bufferRead) { + event = (struct inotify_event *) &buffer[bufferIndex]; + eventSize = offsetof (struct inotify_event, name) + event->len; + + NotifyContext context; + context.descriptor = event->wd; + context.callbacks = pathCallbacks; + CefPostTask(TID_UI, + NewCefRunnableFunction(&ExecuteWatchCallback, context)); + + bufferIndex += eventSize; + } + bufferRead = read(notifyFd, buffer, BUFFER_SIZE); + } +} + +void NativeHandler::Exists(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + struct stat statInfo; + int result = stat(path.c_str(), &statInfo); + retval = CefV8Value::CreateBool(result == 0); +} + +void NativeHandler::Read(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + string value; + io_utils_read(path, &value); + retval = CefV8Value::CreateString(value); +} + +void NativeHandler::Absolute(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + string relativePath; + if (path[0] != '~') + relativePath.append(path); + else { + relativePath.append(getenv("HOME")); + relativePath.append(path, 1, path.length() - 1); + } + + vector < string > segments; + char allSegments[relativePath.length() + 1]; + strcpy(allSegments, relativePath.c_str()); + const char* segment; + for (segment = strtok(allSegments, "/"); segment; + segment = strtok(NULL, "/")) { + if (strcmp(segment, ".") == 0) + continue; + if (strcmp(segment, "..") == 0) { + if (segments.empty()) { + retval = CefV8Value::CreateString("/"); + return; + } + segments.pop_back(); + } else + segments.push_back(segment); + } + + string absolutePath; + unsigned int i; + for (i = 0; i < segments.size(); i++) { + absolutePath.append("/"); + absolutePath.append(segments.at(i)); + } + retval = CefV8Value::CreateString(absolutePath); +} + +void ListDirectory(string path, vector* paths, bool recursive) { + dirent **children; + int childrenCount = scandir(path.c_str(), &children, 0, alphasort); + struct stat statInfo; + int result; + + for (int i = 0; i < childrenCount; i++) { + if (strcmp(children[i]->d_name, ".") == 0 + || strcmp(children[i]->d_name, "..") == 0) { + free(children[i]); + continue; + } + string entryPath(path + "/" + children[i]->d_name); + paths->push_back(entryPath); + if (recursive) { + result = stat(entryPath.c_str(), &statInfo); + if (result == 0 && S_ISDIR(statInfo.st_mode)) + ListDirectory(entryPath, paths, recursive); + } + free(children[i]); + } + free(children); +} + +void DeleteContents(string path) { + dirent **children; + const char* dirPath = path.c_str(); + int childrenCount = scandir(dirPath, &children, 0, alphasort); + struct stat statInfo; + + for (int i = 0; i < childrenCount; i++) { + if (strcmp(children[i]->d_name, ".") == 0 + || strcmp(children[i]->d_name, "..") == 0) { + free(children[i]); + continue; + } + + string entryPath(path + "/" + children[i]->d_name); + if (stat(entryPath.c_str(), &statInfo) != 0) { + free(children[i]); + continue; + } + + if (S_ISDIR(statInfo.st_mode)) + DeleteContents(entryPath); + else if (S_ISREG(statInfo.st_mode)) + remove(entryPath.c_str()); + } + free(children); + rmdir(dirPath); +} + +void NativeHandler::List(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + bool recursive = arguments[1]->GetBoolValue(); + vector < string > *paths = new vector; + ListDirectory(path, paths, recursive); + + retval = CefV8Value::CreateArray(paths->size()); + for (uint i = 0; i < paths->size(); i++) + retval->SetValue(i, CefV8Value::CreateString(paths->at(i))); + free (paths); +} + +void NativeHandler::IsFile(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + struct stat statInfo; + int result = stat(path.c_str(), &statInfo); + retval = CefV8Value::CreateBool(result == 0 && S_ISREG(statInfo.st_mode)); +} + +void NativeHandler::IsDirectory(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + struct stat statInfo; + int result = stat(path.c_str(), &statInfo); + retval = CefV8Value::CreateBool(result == 0 && S_ISDIR(statInfo.st_mode)); +} + +void NativeHandler::OpenDialog(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + GtkWidget *dialog; + dialog = gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(window), + GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *filename; + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + retval = CefV8Value::CreateString(filename); + g_free(filename); + } else + retval = CefV8Value::CreateNull(); + + gtk_widget_destroy(dialog); +} + +void NativeHandler::Open(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + path = arguments[0]->GetStringValue().ToString(); + CefV8Context::GetCurrentContext()->GetBrowser()->Reload(); +} + +void NativeHandler::Write(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + string content = arguments[1]->GetStringValue().ToString(); + + ofstream file; + file.open(path.c_str()); + file << content; + file.close(); +} + +void NativeHandler::WriteToPasteboard(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + string content = arguments[0]->GetStringValue().ToString(); + GtkClipboard* clipboard = gtk_clipboard_get_for_display( + gdk_display_get_default(), GDK_NONE); + gtk_clipboard_set_text(clipboard, content.c_str(), content.length()); + gtk_clipboard_store(clipboard); +} + +void NativeHandler::ReadFromPasteboard(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + GtkClipboard* clipboard = gtk_clipboard_get_for_display( + gdk_display_get_default(), GDK_NONE); + char* content = gtk_clipboard_wait_for_text(clipboard); + retval = CefV8Value::CreateString(content); +} + +void NativeHandler::AsyncList(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + bool recursive = arguments[1]->GetBoolValue(); + vector < string > *paths = new vector; + ListDirectory(path, paths, recursive); + + CefRefPtr callbackPaths = CefV8Value::CreateArray(paths->size()); + for (uint i = 0; i < paths->size(); i++) + callbackPaths->SetValue(i, CefV8Value::CreateString(paths->at(i))); + CefV8ValueList args; + args.push_back(callbackPaths); + CefRefPtr e; + arguments[2]->ExecuteFunction(retval, args); + if (e) + exception = e->GetMessage(); + free (paths); +} + +void NativeHandler::MakeDirectory(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + string content = arguments[0]->GetStringValue().ToString(); + mkdir(content.c_str(), S_IRWXU); +} + +void NativeHandler::Move(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + string from = arguments[0]->GetStringValue().ToString(); + string to = arguments[1]->GetStringValue().ToString(); + rename(from.c_str(), to.c_str()); +} + +void NativeHandler::Remove(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + string pathArgument = arguments[0]->GetStringValue().ToString(); + const char* path = pathArgument.c_str(); + + struct stat statInfo; + if (stat(path, &statInfo) != 0) + return; + + if (S_ISREG(statInfo.st_mode)) + remove(path); + else if (S_ISDIR(statInfo.st_mode)) + DeleteContents(pathArgument); +} + +void NativeHandler::Alert(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + CefRefPtr buttonNamesAndCallbacks; + if (arguments.size() < 3) + buttonNamesAndCallbacks = CefV8Value::CreateArray(0); + else + buttonNamesAndCallbacks = arguments[2]; + + GtkWidget *dialog; + dialog = gtk_dialog_new_with_buttons("atom", GTK_WINDOW(window), + GTK_DIALOG_DESTROY_WITH_PARENT, NULL); + for (int i = 0; i < buttonNamesAndCallbacks->GetArrayLength(); i++) { + string title = + buttonNamesAndCallbacks->GetValue(i)->GetValue(0)->GetStringValue().ToString(); + gtk_dialog_add_button(GTK_DIALOG(dialog), title.c_str(), i); + } + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + + string dialogMessage(arguments[0]->GetStringValue().ToString()); + dialogMessage.append("\n\n"); + dialogMessage.append(arguments[1]->GetStringValue().ToString()); + GtkWidget *label; + label = gtk_label_new(dialogMessage.c_str()); + + GtkWidget *contentArea; + contentArea = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_container_add(GTK_CONTAINER(contentArea), label); + + gtk_widget_show_all(dialog); + int result = gtk_dialog_run(GTK_DIALOG(dialog)); + if (result >= 0) { + CefRefPtr callback = + buttonNamesAndCallbacks->GetValue(result)->GetValue(1); + CefV8ValueList args; + CefRefPtr e; + callback->ExecuteFunction(retval, args); + if (e) + exception = e->GetMessage(); + } + gtk_widget_destroy(dialog); +} + +void NativeHandler::WatchPath(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + int descriptor = inotify_add_watch(notifyFd, path.c_str(), + IN_ALL_EVENTS & ~(IN_CLOSE | IN_OPEN | IN_ACCESS)); + if (descriptor == -1) + return; + + CallbackContext callbackContext; + callbackContext.context = CefV8Context::GetCurrentContext(); + callbackContext.function = arguments[1]; + CefRefPtr eventTypes = CefV8Value::CreateObject(NULL); + eventTypes->SetValue("modified", CefV8Value::CreateBool(true), + V8_PROPERTY_ATTRIBUTE_NONE); + callbackContext.eventTypes = eventTypes; + + stringstream idStream; + idStream << "counter"; + idStream << idCounter; + string id = idStream.str(); + idCounter++; + pathDescriptors[path] = descriptor; + pathCallbacks[descriptor][id] = callbackContext; + retval = CefV8Value::CreateString(id); +} + +void NativeHandler::UnwatchPath(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + + int descriptor = pathDescriptors[path]; + if (descriptor == -1) + return; + + map callbacks = pathCallbacks[descriptor]; + string id = arguments[1]->GetStringValue().ToString(); + callbacks.erase(id); + if (callbacks.empty()) + inotify_rm_watch(notifyFd, descriptor); +} + +void NativeHandler::Digest(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + + int fd = open(path.c_str(), O_RDONLY); + if (fd < 0) + return; + + const EVP_MD *md; + OpenSSL_add_all_digests(); + md = EVP_get_digestbyname("md5"); + if (!md) + return; + + EVP_MD_CTX context; + EVP_MD_CTX_init(&context); + EVP_DigestInit_ex(&context, md, NULL); + + char buffer[BUFFER_SIZE]; + int r; + while ((r = read(fd, buffer, sizeof buffer)) > 0) + EVP_DigestUpdate(&context, buffer, r); + close(fd); + + unsigned char value[EVP_MAX_MD_SIZE]; + unsigned int length; + EVP_DigestFinal_ex(&context, value, &length); + EVP_MD_CTX_cleanup(&context); + + stringstream md5; + char hex[3]; + for (uint i = 0; i < length; i++) { + sprintf(hex, "%02x", value[i]); + md5 << hex; + } + retval = CefV8Value::CreateString(md5.str()); +} + +void NativeHandler::LastModified(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + struct stat statInfo; + if (stat(path.c_str(), &statInfo) == 0) { + CefTime time(statInfo.st_mtime); + retval = CefV8Value::CreateDate(time); + } +} + +bool NativeHandler::Execute(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + if (name == "exists") + Exists(name, object, arguments, retval, exception); + else if (name == "read") + Read(name, object, arguments, retval, exception); + else if (name == "absolute") + Absolute(name, object, arguments, retval, exception); + else if (name == "list") + List(name, object, arguments, retval, exception); + else if (name == "isFile") + IsFile(name, object, arguments, retval, exception); + else if (name == "isDirectory") + IsDirectory(name, object, arguments, retval, exception); + else if (name == "openDialog") + OpenDialog(name, object, arguments, retval, exception); + else if (name == "open") + Open(name, object, arguments, retval, exception); + else if (name == "write") + Write(name, object, arguments, retval, exception); + else if (name == "writeToPasteboard") + WriteToPasteboard(name, object, arguments, retval, exception); + else if (name == "readFromPasteboard") + ReadFromPasteboard(name, object, arguments, retval, exception); + else if (name == "asyncList") + AsyncList(name, object, arguments, retval, exception); + else if (name == "makeDirectory") + MakeDirectory(name, object, arguments, retval, exception); + else if (name == "move") + Move(name, object, arguments, retval, exception); + else if (name == "remove") + Remove(name, object, arguments, retval, exception); + else if (name == "alert") + Alert(name, object, arguments, retval, exception); + else if (name == "watchPath") + WatchPath(name, object, arguments, retval, exception); + else if (name == "unwatchPath") + UnwatchPath(name, object, arguments, retval, exception); + else if (name == "md5ForPath") + Digest(name, object, arguments, retval, exception); + else if (name == "getPlatform") + retval = CefV8Value::CreateString("linux"); + else if (name == "lastModified") + LastModified(name, object, arguments, retval, exception); + else + cout << "Unhandled -> " + name.ToString() << " : " + << arguments[0]->GetStringValue().ToString() << endl; + return true; +} + +} diff --git a/native/v8_extensions/native_linux.h b/native/v8_extensions/native_linux.h new file mode 100644 index 000000000..442bc40ef --- /dev/null +++ b/native/v8_extensions/native_linux.h @@ -0,0 +1,131 @@ +#ifndef NATIVE_LINUX_H_ +#define NATIVE_LINUX_H_ + +#include "include/cef_base.h" +#include "include/cef_v8.h" +#include +#include + +namespace v8_extensions { + +struct CallbackContext { + CefRefPtr context; + CefRefPtr function; + CefRefPtr eventTypes; +}; + +struct NotifyContext { + int descriptor; + std::map > callbacks; +}; + +class NativeHandler: public CefV8Handler { +public: + NativeHandler(); + + GtkWidget* window; + + std::string path; + + virtual bool Execute(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void NotifyWatchers(); + +IMPLEMENT_REFCOUNTING(NativeHandler) + ; + +private: + + int notifyFd; + + unsigned long int idCounter; + + std::map > pathCallbacks; + + std::map pathDescriptors; + + void Exists(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void Read(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void Absolute(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void List(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void AsyncList(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void IsFile(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void IsDirectory(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void OpenDialog(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void Open(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void Write(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void WriteToPasteboard(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void ReadFromPasteboard(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void MakeDirectory(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void Move(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void Remove(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void Alert(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void WatchPath(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void UnwatchPath(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void Digest(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void LastModified(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); +}; + +} +#endif diff --git a/native/v8_extensions/onig_reg_exp_linux.cpp b/native/v8_extensions/onig_reg_exp_linux.cpp new file mode 100644 index 000000000..65101e6b0 --- /dev/null +++ b/native/v8_extensions/onig_reg_exp_linux.cpp @@ -0,0 +1,229 @@ +#include "onig_reg_exp_linux.h" +#include "include/cef_base.h" +#include "include/cef_runnable.h" +#include +#include +#include +#include "io_utils.h" + +using namespace std; + +namespace v8_extensions { + +class OnigRegexpUserData: public CefBase { +public: + OnigRegexpUserData(CefRefPtr source) { + OnigErrorInfo error; + string input = source->GetStringValue().ToString(); + int length = input.length(); + UChar* pattern = (UChar*) input.c_str(); + int code = onig_new(®ex, pattern, pattern + length, + ONIG_OPTION_SINGLELINE, ONIG_ENCODING_UTF8, ONIG_SYNTAX_DEFAULT, + &error); + if (code != ONIG_NORMAL) { + char errorText[ONIG_MAX_ERROR_MESSAGE_LEN]; + onig_error_code_to_str((OnigUChar*) errorText, code, &error); + cout << errorText << " for pattern: " << input << endl; + } + } + + ~OnigRegexpUserData() { + onig_free(regex); + } + + OnigRegion* SearchRegion(string input, int index) { + if (!regex) + return NULL; + + OnigRegion* region = onig_region_new(); + UChar* search = (UChar*) input.c_str(); + unsigned char* start = search + index; + unsigned char* end = search + input.length(); + int code = onig_search(regex, search, end, start, end, region, + ONIG_OPTION_NONE); + if (code >= 0) + return region; + else { + onig_region_free(region, 1); + return NULL; + } + } + + CefRefPtr Search(CefRefPtr argument, + CefRefPtr index) { + string input = argument->GetStringValue().ToString(); + OnigRegion* region = SearchRegion(input, index->GetIntValue()); + if (!region) + return CefV8Value::CreateNull(); + + CefRefPtr indices; + CefRefPtr resultArray = CefV8Value::CreateArray( + region->num_regs); + CefRefPtr indicesArray = CefV8Value::CreateArray( + region->num_regs); + for (int i = 0; i < region->num_regs; i++) { + int begin = region->beg[i]; + int end = region->end[i]; + resultArray->SetValue(i, + CefV8Value::CreateString(input.substr(begin, end - begin))); + indicesArray->SetValue(i, CefV8Value::CreateInt(begin)); + } + resultArray->SetValue("index", CefV8Value::CreateInt(region->beg[0]), + V8_PROPERTY_ATTRIBUTE_NONE); + resultArray->SetValue("indices", indicesArray, V8_PROPERTY_ATTRIBUTE_NONE); + onig_region_free(region, 1); + return resultArray; + } + + CefRefPtr Test(CefRefPtr argument, + CefRefPtr index) { + OnigRegion* region = SearchRegion(argument->GetStringValue().ToString(), + index->GetIntValue()); + CefRefPtr text = CefV8Value::CreateBool(region != NULL); + if (region) + onig_region_free(region, 1); + return text; + } + + CefRefPtr GetCaptureIndices(CefRefPtr argument, + CefRefPtr index) { + OnigRegion* region = SearchRegion(argument->GetStringValue().ToString(), + index->GetIntValue()); + CefRefPtr indices; + if (region) { + indices = BuildCaptureIndices(region); + onig_region_free(region, 1); + } else + indices = CefV8Value::CreateNull(); + return indices; + } + + CefRefPtr BuildCaptureIndices(OnigRegion *region) { + CefRefPtr array = CefV8Value::CreateArray(region->num_regs * 3); + int i = 0; + for (int index = 0; index < region->num_regs; index++) { + int begin = region->beg[index]; + int end = region->end[index]; + if (end - begin <= 0) + continue; + array->SetValue(i++, CefV8Value::CreateInt(index)); + array->SetValue(i++, CefV8Value::CreateInt(begin)); + array->SetValue(i++, CefV8Value::CreateInt(end)); + } + + return array; + } + + CefRefPtr CaptureCount() { + if (regex) + return CefV8Value::CreateInt(onig_number_of_captures(regex)); + else + return CefV8Value::CreateInt(0); + } + + regex_t* regex; + +IMPLEMENT_REFCOUNTING(OnigRegexpUserData) + ; +} +; + +OnigRegexpExtension::OnigRegexpExtension() : + CefV8Handler() { + string realFilePath = io_utils_real_app_path( + "/native/v8_extensions/onig_reg_exp.js"); + if (!realFilePath.empty()) { + string extensionCode; + if (io_utils_read(realFilePath, &extensionCode) > 0) + CefRegisterExtension("v8/onig-reg-exp", extensionCode, this); + } +} + +bool OnigRegexpExtension::Execute(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + if (name == "captureIndices") { + CefRefPtr string = arguments[0]; + CefRefPtr index = arguments[1]; + CefRefPtr regexes = arguments[2]; + + int bestIndex = -1; + CefRefPtr captureIndicesForBestIndex; + CefRefPtr captureIndices; + + retval = CefV8Value::CreateObject(NULL); + for (int i = 0; i < regexes->GetArrayLength(); i++) { + OnigRegexpUserData *userData = + (OnigRegexpUserData *) regexes->GetValue(i)->GetUserData().get(); + captureIndices = userData->GetCaptureIndices(string, index); + if (captureIndices->IsNull()) + continue; + + if (bestIndex == -1 + || captureIndices->GetValue(1)->GetIntValue() + < captureIndicesForBestIndex->GetValue(1)->GetIntValue()) { + bestIndex = i; + captureIndicesForBestIndex = captureIndices; + if (captureIndices->GetValue(1)->GetIntValue() == 0) + break; // If the match starts at 0, just use it! + } + } + + if (bestIndex != -1) { + retval->SetValue("index", CefV8Value::CreateInt(bestIndex), + V8_PROPERTY_ATTRIBUTE_NONE); + retval->SetValue("captureIndices", captureIndicesForBestIndex, + V8_PROPERTY_ATTRIBUTE_NONE); + } + + return true; + + } + + if (name == "getCaptureIndices") { + CefRefPtr string = arguments[0]; + CefRefPtr index = + arguments.size() > 1 ? arguments[1] : CefV8Value::CreateInt(0); + OnigRegexpUserData *userData = + (OnigRegexpUserData *) object->GetUserData().get(); + retval = userData->GetCaptureIndices(string, index); + return true; + } + + if (name == "search") { + CefRefPtr string = arguments[0]; + CefRefPtr index = + arguments.size() > 1 ? arguments[1] : CefV8Value::CreateInt(0); + OnigRegexpUserData *userData = + (OnigRegexpUserData *) object->GetUserData().get(); + retval = userData->Search(string, index); + return true; + } + + if (name == "test") { + CefRefPtr string = arguments[0]; + CefRefPtr index = + arguments.size() > 1 ? arguments[1] : CefV8Value::CreateInt(0); + OnigRegexpUserData *userData = + (OnigRegexpUserData *) object->GetUserData().get(); + retval = userData->Test(string, index); + return true; + } + + if (name == "buildOnigRegExp") { + CefRefPtr userData = new OnigRegexpUserData(arguments[0]); + retval = CefV8Value::CreateObject(NULL); + retval->SetUserData(userData); + return true; + } + + if (name == "getCaptureCount") { + OnigRegexpUserData *userData = + (OnigRegexpUserData *) object->GetUserData().get(); + retval = userData->CaptureCount(); + return true; + } + + return false; +} +} diff --git a/native/v8_extensions/onig_reg_exp_linux.h b/native/v8_extensions/onig_reg_exp_linux.h new file mode 100644 index 000000000..a6bc7eb76 --- /dev/null +++ b/native/v8_extensions/onig_reg_exp_linux.h @@ -0,0 +1,24 @@ +#ifndef ONIG_REG_EXP_LINUX_H_ +#define ONIG_REG_EXP_LINUX_H_ + +#include "include/cef_base.h" +#include "include/cef_v8.h" + +namespace v8_extensions { + +class OnigRegexpExtension: public CefV8Handler { + +public: + OnigRegexpExtension(); + + virtual bool Execute(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + +IMPLEMENT_REFCOUNTING(OnigRegexpExtension) + ; + +}; + +} +#endif