/src/gpac/src/jsmods/storage.c
Line | Count | Source |
1 | | /* |
2 | | * GPAC - Multimedia Framework C SDK |
3 | | * |
4 | | * Authors: Jean Le Feuvre |
5 | | * Copyright (c) Telecom ParisTech 2007-2023 |
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 | | static void storage_finalize(JSRuntime *rt, JSValue obj) |
43 | 0 | { |
44 | 0 | GF_Config *cfg = JS_GetOpaque(obj, storage_class_id); |
45 | 0 | if (!cfg) return; |
46 | 0 | if (all_storages) { |
47 | 0 | gf_list_del_item(all_storages, cfg); |
48 | 0 | if (!gf_list_count(all_storages)) { |
49 | 0 | gf_list_del(all_storages); |
50 | 0 | all_storages = NULL; |
51 | 0 | } |
52 | 0 | } |
53 | 0 | gf_cfg_del(cfg); |
54 | 0 | } |
55 | | |
56 | | JSClassDef storageClass = { |
57 | | "Storage", |
58 | | .finalizer = storage_finalize, |
59 | | }; |
60 | | |
61 | | |
62 | | static JSValue js_storage_get_option(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
63 | 0 | { |
64 | 0 | const char *opt = NULL; |
65 | 0 | const char *sec_name, *key_name; |
66 | 0 | s32 idx = -1; |
67 | 0 | GF_Config *config = JS_GetOpaque(this_val, storage_class_id); |
68 | 0 | if (!config) return GF_JS_EXCEPTION(ctx); |
69 | 0 | if (argc < 2) return GF_JS_EXCEPTION(ctx); |
70 | | |
71 | 0 | if (!JS_IsString(argv[0])) return GF_JS_EXCEPTION(ctx); |
72 | 0 | if (!JS_IsString(argv[1]) && !JS_IsInteger(argv[1])) return GF_JS_EXCEPTION(ctx); |
73 | | |
74 | 0 | sec_name = JS_ToCString(ctx, argv[0]); |
75 | 0 | 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 | 0 | } |
79 | | |
80 | 0 | key_name = NULL; |
81 | 0 | if (JS_IsInteger(argv[1])) { |
82 | 0 | JS_ToInt32(ctx, &idx, argv[1]); |
83 | 0 | } else if (JS_IsString(argv[1]) ) { |
84 | 0 | key_name = JS_ToCString(ctx, argv[1]); |
85 | 0 | } |
86 | |
|
87 | 0 | if (key_name) { |
88 | 0 | 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 | 0 | } else { |
92 | 0 | opt = NULL; |
93 | 0 | } |
94 | |
|
95 | 0 | JS_FreeCString(ctx, key_name); |
96 | 0 | JS_FreeCString(ctx, sec_name); |
97 | |
|
98 | 0 | if (opt) { |
99 | 0 | return JS_NewString(ctx, opt); |
100 | 0 | } |
101 | 0 | return JS_NULL; |
102 | 0 | } |
103 | | |
104 | | static JSValue js_storage_set_option(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
105 | 0 | { |
106 | 0 | const char *sec_name, *key_name, *key_val; |
107 | 0 | GF_Config *config = JS_GetOpaque(this_val, storage_class_id); |
108 | 0 | if (!config) return GF_JS_EXCEPTION(ctx); |
109 | 0 | if (argc < 3) return GF_JS_EXCEPTION(ctx); |
110 | | |
111 | 0 | if (!JS_IsString(argv[0])) return GF_JS_EXCEPTION(ctx); |
112 | 0 | if (!JS_IsString(argv[1])) return GF_JS_EXCEPTION(ctx); |
113 | | |
114 | 0 | sec_name = JS_ToCString(ctx, argv[0]); |
115 | 0 | 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 | 0 | } |
119 | 0 | key_name = JS_ToCString(ctx, argv[1]); |
120 | 0 | key_val = NULL; |
121 | 0 | if (JS_IsString(argv[2])) |
122 | 0 | key_val = JS_ToCString(ctx, argv[2]); |
123 | |
|
124 | 0 | gf_cfg_set_key(config, sec_name, key_name, key_val); |
125 | |
|
126 | 0 | JS_FreeCString(ctx, sec_name); |
127 | 0 | JS_FreeCString(ctx, key_name); |
128 | 0 | JS_FreeCString(ctx, key_val); |
129 | 0 | return JS_UNDEFINED; |
130 | 0 | } |
131 | | |
132 | | static JSValue js_storage_save(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
133 | 0 | { |
134 | 0 | GF_Config *config = JS_GetOpaque(this_val, storage_class_id); |
135 | 0 | if (!config) return GF_JS_EXCEPTION(ctx); |
136 | 0 | gf_cfg_save(config); |
137 | 0 | return JS_UNDEFINED; |
138 | 0 | } |
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 | | static JSValue storage_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) |
147 | 0 | { |
148 | 0 | char szFile[GF_MAX_PATH]; |
149 | 0 | JSValue anobj; |
150 | 0 | GF_Config *storage = NULL; |
151 | 0 | const char *storage_url = NULL; |
152 | 0 | u32 i, count; |
153 | 0 | u8 hash[20]; |
154 | 0 | char temp[3]; |
155 | |
|
156 | 0 | if (!JS_IsString(argv[0]) ) |
157 | 0 | return GF_JS_EXCEPTION(ctx); |
158 | | |
159 | 0 | storage_url = JS_ToCString(ctx, argv[0]); |
160 | 0 | if (!storage_url) return JS_NULL; |
161 | | |
162 | 0 | szFile[0]=0; |
163 | 0 | gf_sha1_csum((u8 *)storage_url, (u32) strlen(storage_url), hash); |
164 | 0 | for (i=0; i<20; i++) { |
165 | 0 | sprintf(temp, "%02X", hash[i]); |
166 | 0 | strcat(szFile, temp); |
167 | 0 | } |
168 | 0 | strcat(szFile, ".cfg"); |
169 | |
|
170 | 0 | count = gf_list_count(all_storages); |
171 | 0 | 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 | 0 | storage = a_cfg; |
177 | 0 | break; |
178 | 0 | } |
179 | 0 | } |
180 | |
|
181 | 0 | if (!storage) { |
182 | 0 | const char *storage_dir = gf_opts_get_key("core", "store-dir"); |
183 | |
|
184 | 0 | storage = gf_cfg_force_new(storage_dir, szFile); |
185 | 0 | if (storage) { |
186 | 0 | gf_cfg_set_key(storage, "GPAC", "StorageURL", storage_url); |
187 | 0 | gf_list_add(all_storages, storage); |
188 | 0 | } |
189 | 0 | } |
190 | |
|
191 | 0 | JS_FreeCString(ctx, storage_url); |
192 | |
|
193 | 0 | anobj = JS_NewObjectClass(ctx, storage_class_id); |
194 | 0 | if (JS_IsException(anobj)) return anobj; |
195 | 0 | JS_SetOpaque(anobj, storage); |
196 | 0 | return anobj; |
197 | 0 | } |
198 | | |
199 | | static int js_storage_init(JSContext *c, JSModuleDef *m) |
200 | 0 | { |
201 | 0 | if (!storage_class_id) { |
202 | 0 | JS_NewClassID(&storage_class_id); |
203 | 0 | JS_NewClass(JS_GetRuntime(c), storage_class_id, &storageClass); |
204 | |
|
205 | 0 | gf_assert(!all_storages); |
206 | 0 | all_storages = gf_list_new(); |
207 | 0 | } |
208 | |
|
209 | 0 | JSValue proto = JS_NewObjectClass(c, storage_class_id); |
210 | 0 | JS_SetPropertyFunctionList(c, proto, storage_funcs, countof(storage_funcs)); |
211 | 0 | JS_SetClassProto(c, storage_class_id, proto); |
212 | |
|
213 | 0 | JSValue ctor = JS_NewCFunction2(c, storage_constructor, "Storage", 1, JS_CFUNC_constructor, 0); |
214 | 0 | JS_SetModuleExport(c, m, "Storage", ctor); |
215 | 0 | return 0; |
216 | 0 | } |
217 | | |
218 | | |
219 | | void qjs_module_init_storage(JSContext *ctx) |
220 | 0 | { |
221 | 0 | JSModuleDef *m; |
222 | 0 | m = JS_NewCModule(ctx, "storage", js_storage_init); |
223 | 0 | if (!m) return; |
224 | | |
225 | 0 | JS_AddModuleExport(ctx, m, "Storage"); |
226 | 0 | return; |
227 | 0 | } |
228 | | |
229 | | |
230 | | #endif |
231 | | |