2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
12 * The Original Code is the Sablotron XSLT Processor.
14 * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15 * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16 * Ginger Alliance Ltd. All Rights Reserved.
18 * Contributor(s): Han Qi
20 * Alternatively, the contents of this file may be used under the
21 * terms of the GNU General Public License Version 2 or later (the
22 * "GPL"), in which case the provisions of the GPL are applicable
23 * instead of those above. If you wish to allow use of your
24 * version of this file only under the terms of the GPL and not to
25 * allow others to use your version of this file under the MPL,
26 * indicate your decision by deleting the provisions above and
27 * replace them with the notice and other provisions required by
28 * the GPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under either the MPL or the
41 #include "domprovider.h"
44 /************* extern constants ******************/
45 const char* theArrayProtoRoot = "_array_prototype_root_";
47 /*************** JS error reporter ******************/
49 void SJSErrorReporter(JSContext *cx, const char *message,
50 JSErrorReport *report)
52 JSContextItem *item = (JSContextItem*)JS_GetContextPrivate(cx);
54 if (item -> errInfo.message) delete item -> errInfo.message;
55 if (item -> errInfo.token) delete item -> errInfo.token;
56 item -> errInfo.message = NULL;
57 item -> errInfo.token = NULL;
59 item -> errInfo.message = new char[strlen(message) + 1];
60 strcpy(item -> errInfo.message, message);
62 if (report -> tokenptr) {
63 item -> errInfo.token = new char[strlen(report -> tokenptr) + 1];
64 strcpy(item -> errInfo.token, report -> tokenptr);
66 item -> errInfo.line = report -> lineno;
67 item -> errInfo.errNumber = report -> errorNumber;
71 /************************ MANAGER *******************/
73 JSRuntime_Sab* gJSRuntime;
75 JSRuntime_Sab* JSManager::getRuntime()
78 gJSRuntime = JS_NewRuntime(JS_RUNTIME_SIZE);
83 JSContext_Sab* JSManager::createContext(int size /* =JS_CONTEXT_SIZE */)
85 return JS_NewContext(getRuntime(), size);
89 void JSManager::finalize()
91 if ( gJSRuntime ) JS_DestroyRuntime(gJSRuntime);
94 /******************************delegates etc. ******************/
96 JS_METHOD(jsglobalLog) {
97 JSContextItem *item = (JSContextItem*)JS_GetContextPrivate(cx);
98 Situation *sit = item -> proc -> recallSituation();
99 JSString *str = JS_ValueToString(cx, argv[0]);
100 char *msg = JS_GetStringBytes(str);
101 sit -> message(MT_LOG, L_JS_LOG, (const char*) msg, (const char*)NULL);
105 /****************************************************************
109 ****************************************************************/
111 JSContextItem::JSContextItem(JSContext_Sab *cx_, Str &uri_, Processor *proc_)
112 : cx(cx_), uri(uri_), proc(proc_)
115 errInfo.message = NULL;
116 errInfo.token = NULL;
124 JSContextItem::~JSContextItem()
126 names.freeall(FALSE);
127 if (errInfo.message) delete errInfo.message;
128 if (errInfo.token) delete errInfo.token;
131 if (array_proto) JS_RemoveRoot(cx, &array_proto);
133 JS_DestroyContext(cx);
135 //if (cls) delete cls;
138 //js class for global object
139 JSClass sabGlobalClass = {
142 JS_PropertyStub, JS_PropertyStub,
145 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
146 JS_FinalizeStub, 0, 0, NULL, NULL, NULL, NULL, 0, 0
149 JSContextItem* JSContextList::find(Str uri, Bool canCreate /*TRUE*/)
151 JSContextItem *item = NULL;
152 for (int i = 0; i < number(); i++)
154 if ((*this)[i] -> uri == uri) item = (*this)[i];
156 if (!item && canCreate)
159 cx = JSManager::createContext();
160 item = new JSContextItem(cx, uri, proc);
163 //JSClass *cls = SJSGetGlobalClass();
165 JSObject *global = JS_NewObject(cx, &sabGlobalClass, NULL, NULL);
166 JS_InitStandardClasses(cx, global);
167 //set debugging globals
168 JS_DefineFunction(cx, global, "log", jsglobalLog, 1, 0);
169 //private data and error handling
170 JS_SetContextPrivate(cx, (void*)item);
171 JS_SetErrorReporter(cx, SJSErrorReporter);
172 //create persistent objects
173 jsdom_delegateDOM(cx);
178 /************************************************************/
180 /************************************************************/
182 JSExternalPrivate::JSExternalPrivate(void *p_, void *v_)
183 : priv(p_), value(v_), refcnt(1)
187 JS_AddRoot((JSContext*)priv, &value);
191 JSExternalPrivate::~JSExternalPrivate()
195 JS_RemoveRoot((JSContext*)priv, &value);
199 /**************** ordinary functions */
201 Bool sjs_instanceOf(JSContext_Sab *cx, JSObject_Sab *obj, JSClass_Sab *cls)
206 JSClass *c = JS_GET_CLASS(cx, o);
207 if (c && c == cls) return TRUE;
208 o = JS_GetPrototype(cx, o);
213 // const char* gClassName = "global";
215 // JSClass* SJSGetGlobalClass()
217 // #ifdef HAVE_JSAPI_H
218 // JSClass *ret = new JSClass();
219 // ret -> name = gClassName;
221 // ret -> addProperty = JS_PropertyStub;
222 // ret -> delProperty = JS_PropertyStub;
223 // ret -> getProperty = JS_PropertyStub;
224 // ret -> setProperty = JS_PropertyStub;
225 // ret -> enumerate = JS_EnumerateStub;
226 // ret -> resolve = JS_ResolveStub;
227 // ret -> convert = JS_ConvertStub;
228 // ret -> finalize = JS_FinalizeStub;
236 Bool SJSEvaluate(JSContextItem &item, DStr &script)
240 JSContext *cx = item.cx;
243 int len = utf8StrLength((const char*) script);
244 wchar_t *ucscript = new wchar_t[len + 1];
245 utf8ToUtf16(ucscript, (const char*) script);
247 status = JS_EvaluateUCScript(cx, JS_GetGlobalObject(cx),
248 (jschar*)ucscript, len,
249 "stylesheet", 0, &rval);
253 char *scr = (char *) script;
254 status = JS_EvaluateScript(cx, JS_GetGlobalObject(cx),
256 "stylesheet", 0, &rval);
257 if ( JS_IsExceptionPending(cx) )
259 JS_ClearPendingException(cx);
264 JSIdArray *arr = JS_Enumerate(cx, JS_GetGlobalObject(cx));
265 item.names.freeall(FALSE);
267 for (int i = 0; i < arr -> length; i++) {
269 jsid id = arr -> vector[i];
270 JS_IdToValue(cx, id, &propname);
272 JSString *str = JS_ValueToString(cx, propname);
274 JS_GetProperty(cx, JS_GetGlobalObject(cx),
275 JS_GetStringBytes(str), &prop);
277 JSFunction *func = JS_ValueToFunction(cx, prop);
279 const char* fname = JS_GetFunctionName(func);
280 item.names.append(new Str(fname));
283 JS_DestroyIdArray(cx, arr);
286 else { //error occured
292 /************** XSLTContext *******************/
294 struct XSLTContextPrivate {
299 void ctxFinalize(JSContext *cx, JSObject *obj)
301 XSLTContextPrivate *priv = (XSLTContextPrivate*)JS_GetPrivate(cx, obj);
302 if (priv) delete priv;
305 JS_PROP(ctxGetPosition)
307 XSLTContextPrivate *priv = (XSLTContextPrivate*)JS_GetPrivate(cx, obj);
309 *rval = INT_TO_JSVAL(priv -> ctx -> getPosition() + 1);
319 XSLTContextPrivate *priv = (XSLTContextPrivate*)JS_GetPrivate(cx, obj);
321 *rval = INT_TO_JSVAL(priv -> ctx -> getSize());
329 JS_PROP(ctxGetContextNode)
331 XSLTContextPrivate *priv = (XSLTContextPrivate*)JS_GetPrivate(cx, obj);
333 JSObject *obj = jsdom_wrapNode(*(priv->situa), cx, priv->ctx->current());
334 *rval = OBJECT_TO_JSVAL(obj);
341 JS_PROP(ctxGetCurrentNode)
343 XSLTContextPrivate *priv = (XSLTContextPrivate*)JS_GetPrivate(cx, obj);
345 JSObject *obj = jsdom_wrapNode(*(priv->situa), cx,
346 priv->ctx->getCurrentNode());
347 *rval = OBJECT_TO_JSVAL(obj);
354 JS_PROP(ctxGetOwnerDocument)
356 XSLTContextPrivate *priv = (XSLTContextPrivate*)JS_GetPrivate(cx, obj);
358 Tree &tree = toV(priv->ctx->current())->getOwner();
359 JSObject *obj = jsdom_wrapNode(*(priv -> situa), cx,
361 *rval = OBJECT_TO_JSVAL(obj);
368 JS_METHOD(ctxSystemProperty)
370 JSString *str = JS_NewStringCopyN(cx, "not supported", 13);
371 *rval = STRING_TO_JSVAL(str);
375 JS_METHOD(ctxStringValue)
377 // if (argc > 0 && JSVAL_IS_OBJECT(argv[0])
378 // && sjs_instanceOf(cx, JSVAL_TO_OBJECT(argv[0]), &nodeClass))
380 // JSObject *node = JSVAL_TO_OBJECT(argv[0]);
381 // NodePrivate *np = (NodePrivate*)JS_GetPrivate(cx, obj);
384 // np->situa->dom().constructStringValue(np->node, val);
385 // JSString *str = JS_NewStringCopyZ(cx, (char*)val);
386 // *rval = STRING_TO_JSVAL(str);
398 JS_PropertyStub, JS_PropertyStub,
399 JS_PropertyStub, JS_PropertyStub,
400 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
401 ctxFinalize, 0, 0, NULL, NULL, NULL, NULL, 0, 0
404 JSPropertySpec ctxProps[] =
406 {"contextPosition", 0, PROP_OPT, ctxGetPosition, NULL},
407 {"contextSize", 0, PROP_OPT, ctxGetSize, NULL},
408 {"contextNode", 0, PROP_OPT, ctxGetContextNode, NULL},
409 {"currentNode", 0, PROP_OPT, ctxGetCurrentNode, NULL},
410 {"ownerDocument", 0, PROP_OPT, ctxGetOwnerDocument, NULL},
414 JSFunctionSpec ctxFunctions[] =
416 {"systemProperty", ctxSystemProperty, 0, 0, 0},
417 {"stringValue", ctxStringValue, 0, 0, 0},
421 void sjs_PublishContext(Sit S, JSContext_Sab *cx, Context *c)
423 JSObject *obj = JS_DefineObject(cx, JS_GetGlobalObject(cx), "XSLTContext",
428 XSLTContextPrivate *priv = new XSLTContextPrivate;
431 JS_SetPrivate(cx, obj, priv);
432 JS_DefineProperties(cx, obj, ctxProps);
433 JS_DefineFunctions(cx, obj, ctxFunctions);
436 /************* function call ******************/
437 Bool SJSCallFunction(Sit S, Context *c, JSContextItem &item, Str &name,
438 ExprList &atoms, Expression &retxpr)
440 JSContext *cx = item.cx;
443 sjs_PublishContext(S, cx, c);
446 int argc = atoms.number();
447 jsval *args = new jsval[argc];
448 for (int i = 0; i < argc; i++) {
449 switch (atoms[i] -> type) {
452 jsdouble d = (double)(atoms[i]->tonumber(S));
453 JS_NewDoubleValue(cx, d, &args[i]);
457 args[i] = BOOLEAN_TO_JSVAL(atoms[i]->tobool());
462 atoms[i]->tostring(S, str);
463 char *p = (char*)str;
464 JSString *s = JS_NewStringCopyN(cx, p, strlen(p));
465 args[i] = STRING_TO_JSVAL(s);
469 const Context &ctx = atoms[i]->tonodesetRef();
470 int num = ctx.getSize();
471 JSObject *arr = jsdom_createNodeList(cx, num);
472 args[i] = OBJECT_TO_JSVAL(arr);
474 for (int j = 0; j < num; j++) {
475 NodeHandle node = ctx[j];
476 jsval val;// = new jsval;
477 val = OBJECT_TO_JSVAL(jsdom_wrapNode(S, cx, node));
478 JS_SetElement(cx, arr, j, &val);
484 e.assign(atoms[i]->toexternal(S));
485 JSObject *o = (JSObject*)e.getValue();
488 args[i] = OBJECT_TO_JSVAL(o);
492 args[i] = JSVAL_NULL;
499 atoms[i]->tostring(S, str);
500 char *p = (char*)str;
501 JSString *s = JS_NewStringCopyN(cx, p, strlen(p));
502 args[i] = STRING_TO_JSVAL(s);
509 JSBool status = JS_CallFunctionName(cx, JS_GetGlobalObject(cx),
510 (char*)name, argc, args, &rval);
511 if ( JS_IsExceptionPending(cx) )
513 JS_ClearPendingException(cx);
516 //remove XSLT context
517 JS_DeleteProperty(cx, JS_GetGlobalObject(cx), "XSLTContext");
522 if (JSVAL_IS_VOID(rval))
524 //return an emtpy nodeset
525 GP( Context ) newc = new Context(c->getCurrentNode());
526 retxpr.setAtom(newc.keep());
528 if (JSVAL_IS_NULL(rval))
530 External e(cx, NULL);
533 if (JSVAL_IS_OBJECT(rval))
535 JSObject *obj = JSVAL_TO_OBJECT(rval);
537 if (sjs_instanceOf(cx, obj, &nlistClass))
540 JS_GetArrayLength(cx, obj, &len);
541 GP( Context ) newc = new Context(c->getCurrentNode());
542 for (unsigned int i = 0; i < len; i++)
545 JS_GetElement(cx, obj, i, &jnode);
546 JSObject *onode = JSVAL_TO_OBJECT(jnode);
547 if (onode && sjs_instanceOf(cx, onode, &nodeClass))
549 NodePrivate *priv = (NodePrivate*)JS_GetPrivate(cx, onode);
551 (*newc).append(priv -> node);
554 retxpr.setAtom(newc.keep());
557 else if (sjs_instanceOf(cx, obj, &nodeClass))
559 GP( Context ) newc = new Context(c->getCurrentNode());
561 NodePrivate *priv = (NodePrivate*)JS_GetPrivate(cx, obj);
563 (*newc).append(priv -> node);
565 retxpr.setAtom(newc.keep());
575 else if (JSVAL_IS_STRING(rval))
577 JSString *str = JS_ValueToString(cx, rval);
578 Str rstr = (char*) JS_GetStringBytes(str);
579 retxpr.setAtom(rstr);
581 else if (JSVAL_IS_NUMBER(rval))
584 JS_ValueToNumber(cx, rval, &d);
585 Number num((double)d);
588 else if (JSVAL_IS_BOOLEAN(rval))
590 retxpr.setAtom(JSVAL_TO_BOOLEAN(rval));
594 //all other types are treated as strings (shouldn't happen)
595 JSString *str = JS_ValueToString(cx, rval);
596 Str rstr = (char*) JS_GetStringBytes(str);
597 retxpr.setAtom(rstr);