Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2007-2019
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / JavaScript Storage bindings
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : /*
27 : ANY CHANGE TO THE API MUST BE REFLECTED IN THE DOCUMENTATION IN gpac/share/doc/idl/storage.js
28 : (no way to define inline JS doc with doxygen)
29 : */
30 :
31 : #include <gpac/setup.h>
32 :
33 : #ifdef GPAC_HAS_QJS
34 :
35 : #include <gpac/config_file.h>
36 : #include "../scenegraph/qjs_common.h"
37 :
38 :
39 : static JSClassID storage_class_id = 0;
40 : GF_List *all_storages = NULL;
41 :
42 9 : static void storage_finalize(JSRuntime *rt, JSValue obj)
43 : {
44 9 : GF_Config *cfg = JS_GetOpaque(obj, storage_class_id);
45 9 : if (!cfg) return;
46 5 : if (all_storages) {
47 4 : gf_list_del_item(all_storages, cfg);
48 4 : if (!gf_list_count(all_storages)) {
49 4 : gf_list_del(all_storages);
50 4 : all_storages = NULL;
51 : }
52 : }
53 5 : gf_cfg_del(cfg);
54 : }
55 :
56 : JSClassDef storageClass = {
57 : "Storage",
58 : .finalizer = storage_finalize,
59 : };
60 :
61 :
62 13 : static JSValue js_storage_get_option(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
63 : {
64 : const char *opt = NULL;
65 : const char *sec_name, *key_name;
66 13 : s32 idx = -1;
67 13 : GF_Config *config = JS_GetOpaque(this_val, storage_class_id);
68 13 : if (!config) return JS_EXCEPTION;
69 13 : if (argc < 2) return JS_EXCEPTION;
70 :
71 26 : if (!JS_IsString(argv[0])) return JS_EXCEPTION;
72 26 : if (!JS_IsString(argv[1]) && !JS_IsInteger(argv[1])) return JS_EXCEPTION;
73 :
74 : sec_name = JS_ToCString(ctx, argv[0]);
75 13 : if (!strcmp(sec_name, "GPAC")) {
76 0 : JS_FreeCString(ctx, sec_name);
77 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "Cannot access section 'GPAC' from script\n");
78 : }
79 :
80 : key_name = NULL;
81 26 : if (JS_IsInteger(argv[1])) {
82 0 : JS_ToInt32(ctx, &idx, argv[1]);
83 13 : } else if (JS_IsString(argv[1]) ) {
84 : key_name = JS_ToCString(ctx, argv[1]);
85 : }
86 :
87 13 : if (key_name) {
88 13 : opt = gf_cfg_get_key(config, sec_name, key_name);
89 0 : } else if (idx>=0) {
90 0 : opt = gf_cfg_get_key_name(config, sec_name, idx);
91 : } else {
92 : opt = NULL;
93 : }
94 :
95 13 : JS_FreeCString(ctx, key_name);
96 13 : JS_FreeCString(ctx, sec_name);
97 :
98 13 : if (opt) {
99 1 : return JS_NewString(ctx, opt);
100 : }
101 12 : return JS_NULL;
102 : }
103 :
104 14 : static JSValue js_storage_set_option(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
105 : {
106 : const char *sec_name, *key_name, *key_val;
107 14 : GF_Config *config = JS_GetOpaque(this_val, storage_class_id);
108 14 : if (!config) return JS_EXCEPTION;
109 14 : if (argc < 3) return JS_EXCEPTION;
110 :
111 28 : if (!JS_IsString(argv[0])) return JS_EXCEPTION;
112 28 : if (!JS_IsString(argv[1])) return JS_EXCEPTION;
113 :
114 : sec_name = JS_ToCString(ctx, argv[0]);
115 14 : if (!strcmp(sec_name, "GPAC")) {
116 0 : JS_FreeCString(ctx, sec_name);
117 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "Cannot access section 'GPAC' from script\n");
118 : }
119 : key_name = JS_ToCString(ctx, argv[1]);
120 : key_val = NULL;
121 28 : if (JS_IsString(argv[2]))
122 : key_val = JS_ToCString(ctx, argv[2]);
123 :
124 14 : gf_cfg_set_key(config, sec_name, key_name, key_val);
125 :
126 14 : JS_FreeCString(ctx, sec_name);
127 14 : JS_FreeCString(ctx, key_name);
128 14 : JS_FreeCString(ctx, key_val);
129 14 : return JS_UNDEFINED;
130 : }
131 :
132 14 : static JSValue js_storage_save(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
133 : {
134 14 : GF_Config *config = JS_GetOpaque(this_val, storage_class_id);
135 14 : if (!config) return JS_EXCEPTION;
136 14 : gf_cfg_save(config);
137 14 : return JS_UNDEFINED;
138 : }
139 :
140 : static const JSCFunctionListEntry storage_funcs[] = {
141 : JS_CFUNC_DEF("get_option", 0, js_storage_get_option),
142 : JS_CFUNC_DEF("set_option", 0, js_storage_set_option),
143 : JS_CFUNC_DEF("save", 0, js_storage_save),
144 : };
145 :
146 5 : static JSValue storage_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv)
147 : {
148 : char szFile[GF_MAX_PATH];
149 : JSValue anobj;
150 : GF_Config *storage = NULL;
151 : const char *storage_url = NULL;
152 : u32 i, count;
153 : u8 hash[20];
154 : char temp[3];
155 :
156 10 : if (!JS_IsString(argv[0]) )
157 0 : return JS_EXCEPTION;
158 :
159 : storage_url = JS_ToCString(ctx, argv[0]);
160 5 : if (!storage_url) return JS_NULL;
161 :
162 5 : szFile[0]=0;
163 5 : gf_sha1_csum((u8 *)storage_url, (u32) strlen(storage_url), hash);
164 105 : for (i=0; i<20; i++) {
165 100 : sprintf(temp, "%02X", hash[i]);
166 : strcat(szFile, temp);
167 : }
168 : strcat(szFile, ".cfg");
169 :
170 5 : count = gf_list_count(all_storages);
171 5 : for (i=0; i<count; i++) {
172 0 : GF_Config *a_cfg = gf_list_get(all_storages, i);
173 0 : const char *cfg_name = gf_cfg_get_filename(a_cfg);
174 :
175 0 : if (strstr(cfg_name, szFile)) {
176 : storage = a_cfg;
177 : break;
178 : }
179 : }
180 :
181 5 : if (!storage) {
182 5 : const char *storage_dir = gf_opts_get_key("core", "store-dir");
183 :
184 5 : storage = gf_cfg_force_new(storage_dir, szFile);
185 5 : if (storage) {
186 5 : gf_cfg_set_key(storage, "GPAC", "StorageURL", storage_url);
187 5 : gf_list_add(all_storages, storage);
188 : }
189 : }
190 :
191 5 : JS_FreeCString(ctx, storage_url);
192 :
193 5 : anobj = JS_NewObjectClass(ctx, storage_class_id);
194 5 : if (JS_IsException(anobj)) return anobj;
195 5 : JS_SetOpaque(anobj, storage);
196 5 : return anobj;
197 : }
198 :
199 4 : static int js_storage_init(JSContext *c, JSModuleDef *m)
200 : {
201 4 : if (!storage_class_id) {
202 4 : JS_NewClassID(&storage_class_id);
203 4 : JS_NewClass(JS_GetRuntime(c), storage_class_id, &storageClass);
204 :
205 : assert(!all_storages);
206 4 : all_storages = gf_list_new();
207 : }
208 :
209 4 : JSValue proto = JS_NewObjectClass(c, storage_class_id);
210 4 : JS_SetPropertyFunctionList(c, proto, storage_funcs, countof(storage_funcs));
211 4 : JS_SetClassProto(c, storage_class_id, proto);
212 :
213 4 : JSValue ctor = JS_NewCFunction2(c, storage_constructor, "Storage", 1, JS_CFUNC_constructor, 0);
214 4 : JS_SetModuleExport(c, m, "Storage", ctor);
215 4 : return 0;
216 : }
217 :
218 :
219 468 : void qjs_module_init_storage(JSContext *ctx)
220 : {
221 : JSModuleDef *m;
222 468 : m = JS_NewCModule(ctx, "storage", js_storage_init);
223 468 : if (!m) return;
224 :
225 468 : JS_AddModuleExport(ctx, m, "Storage");
226 468 : return;
227 : }
228 :
229 :
230 : #endif
231 :
|