ELinks 0.12pre1
[elinks/elinks-j605.git] / src / scripting / smjs / cache_object.c
blob8d2a44d90213631f51d28b58bcab85a9183d9bf3
1 /* Exports struct cache_entry to the world of ECMAScript */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include "elinks.h"
9 #include "cache/cache.h"
10 #include "ecmascript/spidermonkey/util.h"
11 #include "protocol/uri.h"
12 #include "scripting/smjs/cache_object.h"
13 #include "scripting/smjs/core.h"
14 #include "util/error.h"
15 #include "util/memory.h"
17 static const JSClass cache_entry_class; /* defined below */
19 /* Tinyids of properties. Use negative values to distinguish these
20 * from array indexes (even though this object has no array elements).
21 * ECMAScript code should not use these directly as in cache_entry[-1];
22 * future versions of ELinks may change the numbers. */
23 enum cache_entry_prop {
24 CACHE_ENTRY_CONTENT = -1,
25 CACHE_ENTRY_TYPE = -2,
26 CACHE_ENTRY_LENGTH = -3,
27 CACHE_ENTRY_HEAD = -4,
28 CACHE_ENTRY_URI = -5,
31 static const JSPropertySpec cache_entry_props[] = {
32 { "content", CACHE_ENTRY_CONTENT, JSPROP_ENUMERATE },
33 { "type", CACHE_ENTRY_TYPE, JSPROP_ENUMERATE },
34 { "length", CACHE_ENTRY_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY },
35 { "head", CACHE_ENTRY_HEAD, JSPROP_ENUMERATE },
36 { "uri", CACHE_ENTRY_URI, JSPROP_ENUMERATE | JSPROP_READONLY },
37 { NULL }
40 /* @cache_entry_class.getProperty */
41 static JSBool
42 cache_entry_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
44 struct cache_entry *cached;
46 /* This can be called if @obj if not itself an instance of the
47 * appropriate class but has one in its prototype chain. Fail
48 * such calls. */
49 if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL))
50 return JS_FALSE;
52 cached = JS_GetInstancePrivate(ctx, obj,
53 (JSClass *) &cache_entry_class, NULL);
55 if (!cache_entry_is_valid(cached)) return JS_FALSE;
57 undef_to_jsval(ctx, vp);
59 if (!JSVAL_IS_INT(id))
60 return JS_FALSE;
62 switch (JSVAL_TO_INT(id)) {
63 case CACHE_ENTRY_CONTENT: {
64 struct fragment *fragment = get_cache_fragment(cached);
66 assert(fragment);
68 *vp = STRING_TO_JSVAL(JS_NewStringCopyN(smjs_ctx,
69 fragment->data,
70 fragment->length));
72 return JS_TRUE;
74 case CACHE_ENTRY_TYPE:
75 *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx,
76 cached->content_type));
78 return JS_TRUE;
79 case CACHE_ENTRY_HEAD:
80 *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx,
81 cached->head));
83 return JS_TRUE;
84 case CACHE_ENTRY_LENGTH:
85 *vp = INT_TO_JSVAL(cached->length);
87 return JS_TRUE;
88 case CACHE_ENTRY_URI:
89 *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx,
90 struri(cached->uri)));
92 return JS_TRUE;
93 default:
94 /* Unrecognized integer property ID; someone is using
95 * the object as an array. SMJS builtin classes (e.g.
96 * js_RegExpClass) just return JS_TRUE in this case
97 * and leave *@vp unchanged. Do the same here.
98 * (Actually not quite the same, as we already used
99 * @undef_to_jsval.) */
100 return JS_TRUE;
104 /* @cache_entry_class.setProperty */
105 static JSBool
106 cache_entry_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
108 struct cache_entry *cached;
110 /* This can be called if @obj if not itself an instance of the
111 * appropriate class but has one in its prototype chain. Fail
112 * such calls. */
113 if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL))
114 return JS_FALSE;
116 cached = JS_GetInstancePrivate(ctx, obj,
117 (JSClass *) &cache_entry_class, NULL);
119 if (!cache_entry_is_valid(cached)) return JS_FALSE;
121 if (!JSVAL_IS_INT(id))
122 return JS_FALSE;
124 switch (JSVAL_TO_INT(id)) {
125 case CACHE_ENTRY_CONTENT: {
126 JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
127 unsigned char *str = JS_GetStringBytes(jsstr);
128 size_t len = JS_GetStringLength(jsstr);
130 add_fragment(cached, 0, str, len);
131 normalize_cache_entry(cached, len);
133 return JS_TRUE;
135 case CACHE_ENTRY_TYPE: {
136 JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
137 unsigned char *str = JS_GetStringBytes(jsstr);
139 mem_free_set(&cached->content_type, stracpy(str));
141 return JS_TRUE;
143 case CACHE_ENTRY_HEAD: {
144 JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
145 unsigned char *str = JS_GetStringBytes(jsstr);
147 mem_free_set(&cached->head, stracpy(str));
149 return JS_TRUE;
151 default:
152 /* Unrecognized integer property ID; someone is using
153 * the object as an array. SMJS builtin classes (e.g.
154 * js_RegExpClass) just return JS_TRUE in this case.
155 * Do the same here. */
156 return JS_TRUE;
160 /* @cache_entry_class.finalize */
161 static void
162 cache_entry_finalize(JSContext *ctx, JSObject *obj)
164 struct cache_entry *cached;
166 assert(JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL));
167 if_assert_failed return;
169 cached = JS_GetInstancePrivate(ctx, obj,
170 (JSClass *) &cache_entry_class, NULL);
172 if (!cached) return;
174 object_unlock(cached);
177 static const JSClass cache_entry_class = {
178 "cache_entry",
179 JSCLASS_HAS_PRIVATE, /* struct cache_entry * */
180 JS_PropertyStub, JS_PropertyStub,
181 cache_entry_get_property, cache_entry_set_property,
182 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, cache_entry_finalize
185 JSObject *
186 smjs_get_cache_entry_object(struct cache_entry *cached)
188 JSObject *cache_entry_object;
190 assert(smjs_ctx);
192 cache_entry_object = JS_NewObject(smjs_ctx,
193 (JSClass *) &cache_entry_class,
194 NULL, NULL);
196 if (!cache_entry_object) return NULL;
198 if (JS_FALSE == JS_SetPrivate(smjs_ctx, cache_entry_object, cached)) /* to @cache_entry_class */
199 return NULL;
201 object_lock(cached);
203 if (JS_FALSE == JS_DefineProperties(smjs_ctx, cache_entry_object,
204 (JSPropertySpec *) cache_entry_props))
205 return NULL;
207 return cache_entry_object;