From a19b95f20c7919334652101131f54bbed756587e Mon Sep 17 00:00:00 2001 From: "nobody@earth.com" Date: Mon, 22 Feb 2021 23:27:19 +0100 Subject: [PATCH] [smjs local storage] spider monkey local storage --- configure.ac | 6 +- src/ecmascript/ecmascript.c | 11 + src/ecmascript/ecmascript.h | 4 + src/ecmascript/spidermonkey.c | 13 +- src/ecmascript/spidermonkey/Makefile | 2 +- src/ecmascript/spidermonkey/localstorage-db.c | 207 +++++++++++++++++ src/ecmascript/spidermonkey/localstorage-db.h | 16 ++ src/ecmascript/spidermonkey/localstorage.c | 208 ++++++++++++++++++ src/ecmascript/spidermonkey/localstorage.h | 12 + src/ecmascript/spidermonkey/meson.build | 2 +- test/ecmascript/local_storage.html | 32 +++ 11 files changed, 508 insertions(+), 5 deletions(-) create mode 100644 src/ecmascript/spidermonkey/localstorage-db.c create mode 100644 src/ecmascript/spidermonkey/localstorage-db.h create mode 100644 src/ecmascript/spidermonkey/localstorage.c create mode 100644 src/ecmascript/spidermonkey/localstorage.h create mode 100644 test/ecmascript/local_storage.html diff --git a/configure.ac b/configure.ac index 41a4e4ef..f819e137 100644 --- a/configure.ac +++ b/configure.ac @@ -666,8 +666,10 @@ for package in mozjs-52; do else AC_MSG_CHECKING([for SpiderMonkey (mozjs-52) in pkg-config $package]) if $PKG_CONFIG $pkg_config_static --cflags --libs $package > /dev/null 2>&AS_MESSAGE_LOG_FD; then - SPIDERMONKEY_LIBS="$($PKG_CONFIG $pkg_config_static --libs $package)" - SPIDERMONKEY_CFLAGS="$($PKG_CONFIG $pkg_config_static --cflags $package)" + DB_LOCALSTORAGE_LIBS="$($PKG_CONFIG $pkg_config_static --libs sqlite3)" + SPIDERMONKEY_LIBS="$($PKG_CONFIG $pkg_config_static --libs $package) $DB_LOCALSTORAGE_LIBS" + DB_LOCALSTORAGE_CFLAGS="$($PKG_CONFIG $pkg_config_static --cflags sqlite3)" + SPIDERMONKEY_CFLAGS="$($PKG_CONFIG $pkg_config_static --cflags $package) $DB_LOCALSTORAGE_CFLAGS" LIBS="$SPIDERMONKEY_LIBS $LIBS_X" CFLAGS="$CFLAGS_X $SPIDERMONKEY_CFLAGS" CPPFLAGS="$CPPFLAGS_X $SPIDERMONKEY_CFLAGS" diff --git a/src/ecmascript/ecmascript.c b/src/ecmascript/ecmascript.c index 72fbb187..0168fe1e 100644 --- a/src/ecmascript/ecmascript.c +++ b/src/ecmascript/ecmascript.c @@ -77,6 +77,10 @@ static INIT_LIST_OF(struct string_list_item, allowed_urls); char *console_log_filename; +char *local_storage_filename; + +int local_storage_ready; + static int is_prefix(char *prefix, char *url, int dl) { @@ -456,9 +460,15 @@ init_ecmascript_module(struct module *module) { read_url_list(); + /* ecmascript console log */ if (elinks_home) { console_log_filename = straconcat(elinks_home, "/console.log", NULL); } + + /* ecmascript local storage db location */ + if (elinks_home) { + local_storage_filename = straconcat(elinks_home, "/elinks_ls.db", NULL); + } } static void @@ -466,6 +476,7 @@ done_ecmascript_module(struct module *module) { free_string_list(&allowed_urls); mem_free_if(console_log_filename); + mem_free_if(local_storage_filename); } static struct module *ecmascript_modules[] = { diff --git a/src/ecmascript/ecmascript.h b/src/ecmascript/ecmascript.h index 2457f0e6..06592723 100644 --- a/src/ecmascript/ecmascript.h +++ b/src/ecmascript/ecmascript.h @@ -110,6 +110,10 @@ void ecmascript_set_timeout2(struct ecmascript_interpreter *interpreter, JS::Han int get_ecmascript_enable(struct ecmascript_interpreter *interpreter); extern char *console_log_filename; + +extern char *local_storage_filename; +extern int local_storage_ready; + extern struct module ecmascript_module; #endif diff --git a/src/ecmascript/spidermonkey.c b/src/ecmascript/spidermonkey.c index f9a08fe2..ee109639 100644 --- a/src/ecmascript/spidermonkey.c +++ b/src/ecmascript/spidermonkey.c @@ -30,6 +30,7 @@ #include "ecmascript/spidermonkey/form.h" #include "ecmascript/spidermonkey/heartbeat.h" #include "ecmascript/spidermonkey/location.h" +#include "ecmascript/spidermonkey/localstorage.h" #include "ecmascript/spidermonkey/navigator.h" #include "ecmascript/spidermonkey/unibar.h" #include "ecmascript/spidermonkey/window.h" @@ -214,7 +215,7 @@ spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter) { JSContext *ctx; JSObject *console_obj, *document_obj, *forms_obj, *history_obj, *location_obj, - *statusbar_obj, *menubar_obj, *navigator_obj; + *statusbar_obj, *menubar_obj, *navigator_obj, *localstorage_obj; static int initialized = 0; @@ -333,6 +334,16 @@ spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter) goto release_and_fail; } + localstorage_obj = spidermonkey_InitClass(ctx, window_obj, NULL, + &localstorage_class, NULL, 0, + localstorage_props, + localstorage_funcs, + NULL, NULL); + if (!localstorage_obj) { + goto release_and_fail; + } + + JS_SetCompartmentPrivate(js::GetContextCompartment(ctx), interpreter); return ctx; diff --git a/src/ecmascript/spidermonkey/Makefile b/src/ecmascript/spidermonkey/Makefile index aefffcc9..b5b95e1e 100644 --- a/src/ecmascript/spidermonkey/Makefile +++ b/src/ecmascript/spidermonkey/Makefile @@ -2,6 +2,6 @@ top_builddir=../../.. include $(top_builddir)/Makefile.config INCLUDES += $(SPIDERMONKEY_CFLAGS) -OBJS = console.o document.o form.o heartbeat.o location.o navigator.o unibar.o window.o +OBJS = console.o document.o form.o heartbeat.o location.o localstorage.o localstorage-db.o navigator.o unibar.o window.o include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/spidermonkey/localstorage-db.c b/src/ecmascript/spidermonkey/localstorage-db.c new file mode 100644 index 00000000..31485cb9 --- /dev/null +++ b/src/ecmascript/spidermonkey/localstorage-db.c @@ -0,0 +1,207 @@ +/* The SpiderMonkey localstorage database helper implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "elinks.h" +#include "src/ecmascript/ecmascript.h" + +extern const int +db_prepare_structure(char *db_name) +{ + sqlite3_stmt *stmt; + sqlite3 *db; + + int rc; + char *sqlbuffer; + + rc = sqlite3_open(db_name, &db); + if (rc) + { + //DBG("Error opening localStorage database."); + rc=sqlite3_close(db); + return(-1); + } + sqlite3_busy_timeout(db, 5000); + sqlbuffer=stracpy("CREATE TABLE storage (key TEXT, value TEXT);"); + rc=sqlite3_prepare_v2(db, sqlbuffer, strlen(sqlbuffer) + 1, &stmt, NULL); + rc=sqlite3_step(stmt); + rc=sqlite3_finalize(stmt); + rc=sqlite3_close(db); + return(0); +} + +extern const int +db_delete_from(char *db_name, char *key) +{ + + sqlite3_stmt *stmt; + sqlite3 *db; + + int rc; + char *sqlbuffer; + int affected_rows = 0; + + rc = sqlite3_open(db_name, &db); + if (rc) + { + //DBG("Error opening localStorage database."); + rc=sqlite3_close(db); + return(-1); + } + sqlite3_busy_timeout(db, 5000); + sqlbuffer=stracpy("DELETE FROM storage WHERE key = ?;"); + rc=sqlite3_prepare_v2(db, sqlbuffer, strlen(sqlbuffer) + 1, &stmt, NULL); + rc=sqlite3_bind_text(stmt, 1, key, strlen(key), SQLITE_STATIC); + rc=sqlite3_step(stmt); + rc=sqlite3_finalize(stmt); + affected_rows=sqlite3_changes(db); + rc=sqlite3_close(db); + return(affected_rows); + +} + + +extern const int +db_insert_into(char *db_name, char *key, char *value) +{ + sqlite3_stmt *stmt; + sqlite3 *db; + + int rc; + char *sqlbuffer; + int affected_rows = 0; + + rc = sqlite3_open(db_name, &db); + if (rc) { + //DBG("Error opening localStorage database."); + rc=sqlite3_close(db); + return(""); + } + sqlite3_busy_timeout(db, 5000); + sqlbuffer=stracpy("INSERT INTO storage (value,key) VALUES (?,?);"); + rc=sqlite3_prepare_v2(db, sqlbuffer, strlen(sqlbuffer) + 1, &stmt, NULL); + rc=sqlite3_bind_text(stmt, 1, value, strlen(value), SQLITE_STATIC); + rc=sqlite3_bind_text(stmt, 2, key, strlen(key), SQLITE_STATIC); + rc=sqlite3_step(stmt); + rc=sqlite3_finalize(stmt); + affected_rows=sqlite3_changes(db); + rc=sqlite3_close(db); + return(affected_rows); + +} + +extern const int +db_update_set(char *db_name, char *key, char *value) +{ + + sqlite3_stmt *stmt; + sqlite3 *db; + + int rc; + char sqlbuffer[8192]; + char result[8192]; + int affected_rows = 0; + + rc = sqlite3_open(db_name, &db); + if (rc) { + //DBG("Error opening localStorage database."); + rc=sqlite3_close(db); + return(""); + } + sqlite3_busy_timeout(db, 5000); + snprintf(sqlbuffer, 256, "UPDATE storage SET value = ? where key = ?;"); + rc=sqlite3_prepare_v2(db, sqlbuffer, strlen(sqlbuffer) + 1, &stmt, NULL); + rc=sqlite3_bind_text(stmt, 1, value, strlen(value), SQLITE_STATIC); + rc=sqlite3_bind_text(stmt, 2, key, strlen(key), SQLITE_STATIC); + rc=sqlite3_step(stmt); + rc=sqlite3_finalize(stmt); + affected_rows=sqlite3_changes(db); + rc=sqlite3_close(db); + return(affected_rows); + +} + +extern const char * +db_query_by_value(char *db_name, char *value) +{ + + sqlite3_stmt *stmt; + sqlite3 *db; + + int rc; + char *sqlbuffer; + char *result; + + rc = sqlite3_open(db_name, &db); + if (rc) { + //DBG("Error opening localStorage database."); + rc=sqlite3_close(db); + return(""); + } + rc = sqlite3_open(db_name, &db); + if (rc) + { + //DBG("Error opening localStorage database."); + rc=sqlite3_close(db); + return(""); + } + sqlite3_busy_timeout(db, 2000); + sqlbuffer=stracpy("SELECT * FROM storage WHERE value like ?;"); + rc=sqlite3_prepare_v2(db, sqlbuffer, strlen(sqlbuffer) + 1, &stmt, NULL); + rc=sqlite3_bind_text(stmt, 1, value, strlen(value) + 1, SQLITE_STATIC); + while (sqlite3_step(stmt) == SQLITE_ROW) { + if ((const char*) sqlite3_column_text(stmt,1)!= NULL) { + result=stracpy((const char *)sqlite3_column_text(stmt, 1)); + //DBG("%s",result); + } else { + result=stracpy(""); + } + } + rc=sqlite3_finalize(stmt); + rc=sqlite3_close(db); + return(result); + +} + +extern const char * +db_query_by_key(char *db_name, char *key) +{ + + sqlite3_stmt *stmt; + sqlite3 *db; + + int rc; + char *sqlbuffer; + char *result; + + rc = sqlite3_open(db_name, &db); + if (rc) + { + //DBG("Error opening localStorage database."); + rc=sqlite3_close(db); + return(""); + } + sqlite3_busy_timeout(db, 2000); + sqlbuffer=stracpy("SELECT * FROM storage WHERE key like ?;"); + rc=sqlite3_prepare_v2(db, sqlbuffer, strlen(sqlbuffer) + 1, &stmt, NULL); + rc=sqlite3_bind_text(stmt, 1, key, strlen(key) + 1, SQLITE_STATIC); + while (sqlite3_step(stmt) == SQLITE_ROW) { + if ((const char*) sqlite3_column_text(stmt,1)!= NULL) { + result=stracpy((const char *)sqlite3_column_text(stmt, 1)); + //DBG("%s",result); + } else { + result=stracpy(""); + } + } + rc=sqlite3_finalize(stmt); + rc=sqlite3_close(db); + return(result); + +} diff --git a/src/ecmascript/spidermonkey/localstorage-db.h b/src/ecmascript/spidermonkey/localstorage-db.h new file mode 100644 index 00000000..6de343a6 --- /dev/null +++ b/src/ecmascript/spidermonkey/localstorage-db.h @@ -0,0 +1,16 @@ +#ifndef EL__ECMASCRIPT_SPIDERMONKEY_LOCALSTORAGE_DB_H +#define EL__ECMASCRIPT_SPIDERMONKEY_LOCALSTORAGE_DB_H + +#include +#include +#include +#include + +extern const int db_prepare_structure(char *db_name); +extern const int db_delete_from(char *db_name, char *key); +extern const int db_insert_into(char *db_name, char *key, char *value); +extern const int db_update_set(char *db_name, char *key, char *value); +extern const char * db_query_by_key(char *db_name, char *key); +extern const char * db_qry_by_value(char *db_name, char *val); + +#endif diff --git a/src/ecmascript/spidermonkey/localstorage.c b/src/ecmascript/spidermonkey/localstorage.c new file mode 100644 index 00000000..c299349e --- /dev/null +++ b/src/ecmascript/spidermonkey/localstorage.c @@ -0,0 +1,208 @@ +/* The SpiderMonkey localstorage object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include "ecmascript/spidermonkey/util.h" + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "config/home.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/spidermonkey/form.h" +#include "ecmascript/spidermonkey/location.h" +#include "ecmascript/spidermonkey/localstorage.h" +#include "ecmascript/spidermonkey/localstorage-db.h" +#include "ecmascript/spidermonkey/document.h" +#include "ecmascript/spidermonkey/window.h" +#include "intl/gettext/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +#include +#include "document/renderer.h" +#include "document/refresh.h" +#include "terminal/screen.h" + +/* IMPLEMENTS READ FROM STORAGE USING SQLITE DATABASE */ +static unsigned char * +readFromStorage(unsigned char *key) +{ + + char * val = ""; + val = (unsigned char *) malloc (32384); + + if (local_storage_ready==0) + { + db_prepare_structure(local_storage_filename); + local_storage_ready=1; + } + + val = db_query_by_key(local_storage_filename, key); + + // DBG(log,"Read: %s %s %s",local_storage_filename, key, val); + + return (val); +} + +/* IMPLEMENTS SAVE TO STORAGE USING SQLITE DATABASE */ +static void +saveToStorage(unsigned char *key, unsigned char *val) +{ + + if (local_storage_ready==0) { + db_prepare_structure(local_storage_filename); + local_storage_ready=1; + } + + int rows_affected=0; + + rows_affected=db_update_set(local_storage_filename, key, val); + + if (rows_affected==0) { + rows_affected=db_insert_into(local_storage_filename, key, val); + } + + // DBG(log, "UPD ROWS: %d KEY: %s VAL: %s",rows_affected,key,val); + +} + +static bool localstorage_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); + +JSClassOps localstorage_ops = { + JS_PropertyStub, nullptr, + localstorage_get_property, JS_StrictPropertyStub, + nullptr, nullptr, nullptr +}; + +/* Each @localstorage_class object must have a @window_class parent. */ +const JSClass localstorage_class = { + "localStorage", + JSCLASS_HAS_PRIVATE, + &localstorage_ops +}; + +const JSPropertySpec localstorage_props[] = { + { NULL } +}; + +///* @localstorage_class.getProperty */ +static bool +localstorage_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp) +{ + JSObject *parent_win; /* instance of @window_class */ + + return(true); +} + +static bool localstorage_setitem(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool localstorage_getitem(JSContext *ctx, unsigned int argc, JS::Value *vp); + +const spidermonkeyFunctionSpec localstorage_funcs[] = { + { "setItem", localstorage_setitem, 2 }, + { "getItem", localstorage_getitem, 1 }, + { NULL } +}; + +static bool +localstorage_getitem(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ + //jsval val; + JSCompartment *comp = js::GetContextCompartment(ctx); + + if (!comp) + { + return false; + } + + struct ecmascript_interpreter *interpreter = JS_GetCompartmentPrivate(comp); + JS::CallArgs args = CallArgsFromVp(argc, vp); + unsigned char *key = JS_EncodeString(ctx, args[0].toString()); + //DBG("localstorage get by key: %s\n", args); + + if (argc != 1) + { + args.rval().setBoolean(false); + return(true); + } + + unsigned char *val; + val = (unsigned char * ) malloc(32000); + val = readFromStorage(key); + + //DBG("%s %s\n", key, val); + + if (strlen(val)>0) + { + args.rval().setString(JS_NewStringCopyZ(ctx, val)); + } else { + args.rval().setString(JS_NewStringCopyZ(ctx, "")); + + } + + return(true); + +} + +/* @localstorage_funcs{"setItem"} */ +static bool +localstorage_setitem(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ + JSCompartment *comp = js::GetContextCompartment(ctx); + + if (!comp) + { + return false; + } + struct ecmascript_interpreter *interpreter = JS_GetCompartmentPrivate(comp); + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 2) + { + args.rval().setBoolean(false); + return(true); + } + + unsigned char *key = JS_EncodeString(ctx, args[0].toString()); + unsigned char *val = JS_EncodeString(ctx, args[1].toString()); + saveToStorage(key,val); + //DBG("%s %s\n", key, val); + + +#ifdef CONFIG_LEDS + set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J'); +#endif + args.rval().setBoolean(true); + + return(true); +} diff --git a/src/ecmascript/spidermonkey/localstorage.h b/src/ecmascript/spidermonkey/localstorage.h new file mode 100644 index 00000000..e6516eec --- /dev/null +++ b/src/ecmascript/spidermonkey/localstorage.h @@ -0,0 +1,12 @@ + +#ifndef EL__ECMASCRIPT_SPIDERMONKEY_LOCALSTORAGE_H +#define EL__ECMASCRIPT_SPIDERMONKEY_LOCALSTORAGE_H + +#include "ecmascript/spidermonkey/util.h" +#include "ecmascript/spidermonkey/localstorage-db.h" + +extern const JSClass localstorage_class; +extern const spidermonkeyFunctionSpec localstorage_funcs[]; +extern const JSPropertySpec localstorage_props[]; + +#endif diff --git a/src/ecmascript/spidermonkey/meson.build b/src/ecmascript/spidermonkey/meson.build index fbd79014..015060b8 100644 --- a/src/ecmascript/spidermonkey/meson.build +++ b/src/ecmascript/spidermonkey/meson.build @@ -1,3 +1,3 @@ #INCLUDES += $(SPIDERMONKEY_CFLAGS) -srcs += files('console.c', 'document.c', 'form.c', 'heartbeat.c', 'location.c', 'navigator.c', 'unibar.c', 'window.c') +srcs += files('console.c', 'document.c', 'form.c', 'heartbeat.c', 'location.c', 'localstorage.c', 'localstorage-db.c', 'navigator.c', 'unibar.c', 'window.c') diff --git a/test/ecmascript/local_storage.html b/test/ecmascript/local_storage.html new file mode 100644 index 00000000..770b5469 --- /dev/null +++ b/test/ecmascript/local_storage.html @@ -0,0 +1,32 @@ + + + +
+
+You'll find the result of storage at sqlite database:
+
+e.g. ~/.elinks/lc_storage.db
+
+Ensure You have the storage table in there:
+
+CREATE TABLE storage (key text, value text);
+
+For the result of this code see:
+
+e.g. ~/.elinks/console.log
+
+
+
+ +