added XMLGraph and XMLParser JS/XML glue

git-svn-id: svn://10.0.0.236/trunk@7054 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
shaver%netscape.com
1998-08-01 19:08:05 +00:00
parent 8f1df79429
commit eedb2202bc
14 changed files with 2230 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH = ../../..
REQUIRES = xmlparse xmltok expat js
CSRCS = jsxparse.c \
jsxgraph.c \
xmljs.c \
$(NULL)
EXPORTS = xmljs.h
LIBRARY_NAME = xmljs
MODULE = xmljs
include $(DEPTH)/config/rules.mk

View File

@@ -0,0 +1,10 @@
Some primitive JS/XML glue. Contact shaver@netscape.com.
XMLParser: a thin wrapper around the parser APIs of James Clark's `expat'
XML parser.
XMLGraph: JSClass that generates a simple JS object graph from XML. This is
NOT W3C Level 1 DOM compliant by any stretch of even my vivid
imagination.
These objects may never show up in Mozilla, of course.

View File

@@ -0,0 +1,264 @@
#define XMLJS_INTERNAL
#include "xmljs.h"
#undef XMLJS_INTERNAL
#if DEBUG_shaver
#include <stdio.h>
#endif
/**
* An XMLGraph JS object produces an object graph in response
* to XML parser events.
*/
typedef struct {
XMLCallback cb;
JSObject *current;
char *nameBy;
} XMLGraphCallback;
static char
xmlg_up_str[] = "__up__";
static void
StartElementHandler(void *userdata, const char *name, const char **atts)
{
XMLGraphCallback * cb = (XMLGraphCallback *)userdata;
int i;
JSObject *element, *attobj, *array;
JSContext *cx = cb->cb.cx;
jsval rval;
if (!cb->current) {
if (!JS_EvaluateScript(cx, JS_GetGlobalObject(cx), xmljs_newObj_str,
xmljs_newObj_size,
"XMLGraph internal", 0, &rval)) {
JS_ReportError(cx, "failed to create new Object");
return;
}
element = JSVAL_TO_OBJECT(rval);
cb->current = element;
if (!JS_DefineProperty(cx, cb->cb.obj, "graph", rval,
NULL, NULL, JSPROP_ENUMERATE)) {
JS_ReportError(cx, "failed to define graph prop");
return;
}
}
if (!JS_EvaluateScript(cx, JS_GetGlobalObject(cx), xmljs_newObj_str,
xmljs_newObj_size,
"XMLGraph internal", 0, &rval)) {
JS_ReportError(cx, "failed to create new Object");
return;
}
element = JSVAL_TO_OBJECT(rval);
/* populate and set __attributes__ */
if (atts[0]) {
JSString *attstr;
if (!JS_EvaluateScript(cx, JS_GetGlobalObject(cx), xmljs_newObj_str,
xmljs_newObj_size,
"XMLGraph internal", 0, &rval))
return;
attobj = JSVAL_TO_OBJECT(rval);
for (i = 0; atts[i]; i+=2) {
/*
* if we have an attribute that matches nameBy, use
* the value of that attribute to name the node
*/
if (cb->nameBy && !strcmp(cb->nameBy, atts[i]))
name = atts[i+1];
attstr = JS_NewStringCopyZ(cx, atts[i+1]);
if (!attstr ||
!JS_DefineProperty(cx, attobj, atts[i],
STRING_TO_JSVAL(attstr),
NULL, NULL, JSPROP_ENUMERATE))
return;
}
if (!JS_DefineProperty(cx, element, "__attributes__",
OBJECT_TO_JSVAL(attobj), NULL, NULL,
0))
return;
}
/* Check for existing property with this name */
if (!JS_GetProperty(cx, cb->current, name, &rval))
return;
if (JSVAL_IS_OBJECT(rval)) {
JSObject *existing = JSVAL_TO_OBJECT(rval);
if (JS_IsArrayObject(cx, existing)) {
/* already an array, so append */
jsuint length;
if (!JS_GetArrayLength(cx, existing, &length) ||
!JS_DefineElement(cx, existing, (jsint)length,
OBJECT_TO_JSVAL(element), NULL, NULL,
JSPROP_ENUMERATE))
return;
} else {
/* replace with an array [current, new] */
jsval vector[2];
vector[0] = OBJECT_TO_JSVAL(existing);
vector[1] = OBJECT_TO_JSVAL(element);
array = JS_NewArrayObject(cx, 2, vector);
if (!array ||
!JS_DefineProperty(cx, cb->current, name,
OBJECT_TO_JSVAL(array), NULL, NULL,
JSPROP_ENUMERATE))
return;
}
} else if (!JS_DefineProperty(cx, cb->current, name,
OBJECT_TO_JSVAL(element), NULL, NULL,
JSPROP_ENUMERATE))
return;
/* define backpointer __up__ */
if (!JS_DefineProperty(cx, element, xmlg_up_str,
OBJECT_TO_JSVAL(cb->current),
NULL, NULL, 0))
return;
/*
* XXX DefineProperty(element, "__element__", elementstr)
*/
cb->current = element;
}
static void
EndElementHandler(void *userdata, const char *name)
{
/* XXX check to be sure that it's the right one ending! */
XMLGraphCallback *cb = (XMLGraphCallback *)userdata;
JSContext *cx = cb->cb.cx;
jsval rval;
if (!JS_GetProperty(cx, cb->current, xmlg_up_str, &rval))
return;
cb->current = JSVAL_TO_OBJECT(rval);
}
static void
CharacterDataHandler(void *userdata, const char *s, int len)
{
XMLGraphCallback *cb = (XMLGraphCallback *)userdata;
JSString *str;
JSContext *cx = cb->cb.cx;
str = JS_NewStringCopyN(cx, s, len);
if (!str)
return;
JS_DefineProperty(cx, cb->current, "__cdata__", STRING_TO_JSVAL(str),
NULL, NULL, 0);
}
static void
ProcessingInstructionHandler(void *userdata, const char *target,
const char *data)
{
/*
* (cb->obj).processingInstruction(element, target, data)
*/
}
static JSBool
PreParse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
XMLGraphCallback *cb;
if (!JS_DeleteProperty(cx, obj, "graph"))
return JS_FALSE;
cb = (XMLGraphCallback *)JS_GetPrivate(cx, obj);
if (!cb)
return JS_FALSE;
cb->current = NULL;
return JS_TRUE;
}
static JSBool
XMLGraph(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
XMLGraphCallback *cb = JS_malloc(cx, sizeof(XMLGraphCallback));
if (!cb)
return JS_FALSE;
cb->cb.xml = NULL;
cb->cb.obj = obj;
cb->cb.cx = cx;
cb->current = NULL;
cb->nameBy = NULL;
cb->cb.start = StartElementHandler;
cb->cb.end = EndElementHandler;
cb->cb.cdata = CharacterDataHandler;
cb->cb.processing = ProcessingInstructionHandler;
cb->cb.preParse = PreParse;
cb->cb.postParse = NULL;
return JS_SetPrivate(cx, obj, (void *)cb);
}
static void
xmlgraph_finalize(JSContext *cx, JSObject *obj)
{
XMLGraphCallback *cb;
cb = (XMLGraphCallback *)JS_GetPrivate(cx, obj);
if (!cb)
return;
if (cb->nameBy)
JS_free(cx, cb->nameBy);
JS_free(cx, cb);
}
static JSBool
xmlgraph_nameBySetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JSString *namestr;
XMLGraphCallback *cb = JS_GetPrivate(cx, obj);
if (!cb)
return JS_TRUE;
if (*vp == JSVAL_NULL) {
if (cb->nameBy)
JS_free(cx, cb->nameBy);
cb->nameBy = NULL;
return JS_TRUE;
}
namestr = JS_ValueToString(cx, *vp);
if (!namestr)
return JS_FALSE;
if (cb->nameBy)
JS_free(cx, cb->nameBy);
cb->nameBy = JS_strdup(cx, JS_GetStringBytes(namestr));
if (!cb->nameBy)
return JS_FALSE;
return JS_TRUE;
}
JSClass XMLGraph_class = {
"XMLGraph", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, xmlgraph_finalize
};
JSFunctionSpec xmlgraph_funcs[] = {
{0}
};
JSPropertySpec xmlgraph_props[] = {
{"nameBy", -1, JSPROP_ENUMERATE, NULL, xmlgraph_nameBySetter},
{0}
};
JSBool
XMLGraph_Init(JSContext *cx, JSObject *obj, JSObject *parent_proto)
{
jsval v = JSVAL_NULL;
JSObject *proto = JS_InitClass(cx, obj, parent_proto, &XMLGraph_class,
XMLGraph, 1,
xmlgraph_props, xmlgraph_funcs,
NULL, NULL);
if (!proto)
return JS_FALSE;
if (!JS_SetProperty(cx, proto, "nameBy", &v)) {
JS_ReportError(cx, "failed to set XMLGraph.prototype.nameBy = null");
return JS_FALSE;
}
return JS_TRUE;
}

View File

@@ -0,0 +1,218 @@
#define XMLJS_INTERNAL
#include "xmljs.h"
#undef XMLJS_INTERNAL
static void
StartElementHandler(void *userdata, const char *name, const char **atts)
{
XMLCallback *cb = (XMLCallback *)userdata;
int i;
JSString *namestr = NULL, *attstr = NULL;
JSObject *attobj = NULL;
JSContext *cx = cb->cx;
jsval argv[2];
jsval rval;
JSFunction *fun;
if (!JS_GetProperty(cx, cb->obj, "startElement", &rval) ||
JSVAL_IS_VOID(rval) || JSVAL_IS_NULL(rval))
return;
fun = JS_ValueToFunction(cx, rval);
if (!fun)
return;
/* oh, for local roots */
JS_AddRoot(cx, &namestr);
JS_AddRoot(cx, &attobj);
JS_AddRoot(cx, &attstr);
namestr = JS_NewStringCopyZ(cx, name);
if (atts[0]) {
if (!JS_EvaluateScript(cx, JS_GetGlobalObject(cx), xmljs_newObj_str,
xmljs_newObj_size,
"XMLParser internal", 0, &rval)) {
JS_ReportError(cx, "failed to create attobj");
goto out;
}
attobj = JSVAL_TO_OBJECT(rval);
for (i = 0; atts[i]; i+=2) {
attstr = JS_NewStringCopyZ(cx, atts[i+1]);
if (!attstr ||
!JS_DefineProperty(cx, attobj, atts[i],
STRING_TO_JSVAL(attstr),
NULL, NULL, JSPROP_ENUMERATE)) {
JS_ReportError(cx, "defining att prop %s failed", atts[i]);
goto out;
}
}
}
argv[0] = STRING_TO_JSVAL(namestr);
argv[1] = OBJECT_TO_JSVAL(attobj);
JS_CallFunction(cx, cb->obj, fun, 2, argv, &rval);
out:
JS_RemoveRoot(cx, &namestr);
JS_RemoveRoot(cx, &attstr);
JS_RemoveRoot(cx, &attobj);
}
static void
EndElementHandler(void *userdata, const char *name)
{
XMLCallback *cb = (XMLCallback *)userdata;
JSString *namestr = NULL;
JSContext *cx = cb->cx;
jsval argv[1];
jsval rval;
JSFunction *fun;
if (!JS_GetProperty(cx, cb->obj, "endElement", &rval) ||
JSVAL_IS_VOID(rval) || JSVAL_IS_NULL(rval))
return;
fun = JS_ValueToFunction(cx, rval);
if (!fun)
return;
/* oh, for local roots */
JS_AddRoot(cx, &namestr);
namestr = JS_NewStringCopyZ(cx, name);
if (!namestr)
goto out;
argv[0] = STRING_TO_JSVAL(namestr);
JS_CallFunction(cx, cb->obj, fun, 1, argv, &rval);
out:
JS_RemoveRoot(cx, &namestr);
}
static void
CharacterDataHandler(void *userdata, const char *s, int len)
{
XMLCallback *cb = (XMLCallback *)userdata;
JSString *cdatastr = NULL;
JSContext *cx = cb->cx;
jsval argv[1];
jsval rval;
JSFunction *fun;
if (!JS_GetProperty(cx, cb->obj, "characterData", &rval) ||
JSVAL_IS_VOID(rval) || JSVAL_IS_NULL(rval))
return;
fun = JS_ValueToFunction(cx, rval);
if (!fun)
return;
/* oh, for local roots */
JS_AddRoot(cx, &cdatastr);
cdatastr = JS_NewStringCopyZ(cx, s);
if (!cdatastr)
goto out;
argv[0] = STRING_TO_JSVAL(cdatastr);
JS_CallFunction(cx, cb->obj, fun, 1, argv, &rval);
out:
JS_RemoveRoot(cx, &cdatastr);
}
static void
ProcessingInstructionHandler(void *userdata, const char *target,
const char *data)
{
XMLCallback *cb = (XMLCallback *)userdata;
JSString *targetstr = NULL, *datastr = NULL;
JSContext *cx = cb->cx;
jsval argv[2];
jsval rval;
JSFunction *fun;
if (!JS_GetProperty(cx, cb->obj, "processingInstruction", &rval) ||
JSVAL_IS_VOID(rval) || JSVAL_IS_NULL(rval))
return;
fun = JS_ValueToFunction(cx, rval);
if (!fun)
return;
JS_AddRoot(cx, &targetstr);
JS_AddRoot(cx, &datastr);
targetstr = JS_NewStringCopyZ(cx, target);
if (!targetstr)
goto out;
datastr = JS_NewStringCopyZ(cx, data);
if (!datastr)
goto out;
argv[0] = STRING_TO_JSVAL(targetstr);
argv[1] = STRING_TO_JSVAL(datastr);
JS_CallFunction(cx, cb->obj, fun, 2, argv, &rval);
out:
JS_RemoveRoot(cx, &targetstr);
JS_RemoveRoot(cx, &datastr);
}
static JSBool
XMLParser(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
XMLCallback *cb = JS_malloc(cx, sizeof(XMLCallback));
if (!cb)
return JS_FALSE;
cb->start = StartElementHandler;
cb->end = EndElementHandler;
cb->cdata = CharacterDataHandler;
cb->processing = ProcessingInstructionHandler;
cb->xml = NULL;
cb->obj = obj;
cb->preParse = cb->postParse = NULL;
cb->cx = cx; /* XXX obj can persist longer than cx *sigh* */
return JS_SetPrivate(cx, obj, (void *)cb);
}
static void
xmlparser_finalize(JSContext *cx, JSObject *obj)
{
XMLCallback *cb;
cb = (XMLCallback *)JS_GetPrivate(cx, obj);
if (!cb)
return;
JS_free(cx, cb);
}
JSClass XMLParser_class = {
"XMLParser", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, xmlparser_finalize
};
JSFunctionSpec xmlparser_funcs[] = {
{0}
};
JSPropertySpec xmlparser_props[] = {
{0}
};
JSBool
XMLParser_Init(JSContext *cx, JSObject *obj, JSObject *parent_proto)
{
JSObject *proto = JS_InitClass(cx, obj, parent_proto, &XMLParser_class,
XMLParser, 1,
xmlparser_props, xmlparser_funcs,
NULL, NULL);
return proto &&
JS_DefineProperty(cx, proto, "startElement", JSVAL_NULL, NULL, NULL,
JSPROP_ENUMERATE) &&
JS_DefineProperty(cx, proto, "endElement", JSVAL_NULL, NULL, NULL,
JSPROP_ENUMERATE) &&
JS_DefineProperty(cx, proto, "characterData", JSVAL_NULL, NULL, NULL,
JSPROP_ENUMERATE) &&
JS_DefineProperty(cx, proto, "processingInstruction", JSVAL_NULL,
NULL, NULL, JSPROP_ENUMERATE);
}

View File

@@ -0,0 +1,38 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH = ../../../..
REQUIRES = xmlparse xmltok expat js xmljs nspr
CSRCS = js.c \
$(NULL)
PROGRAM = xmljs
include $(DEPTH)/config/rules.mk
CFLAGS += -DJSFILE -I.
MYLIBS = -lxmljs -lexpat -lxmltok -ljs $(LIBNSPR) -ldl -lm
js:
rm -f $(PROGRAM)
@make $(PROGRAM)
$(PROGRAM): $(OBJS)
@$(MAKE_OBJDIR)
$(CC) -o $@ $(LDFLAGS) $(OBJS) -L$(DIST)/bin $(MYLIBS)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
/*stddef inclusion here to first declare ptrdif as a signed long instead of a signed int*/
#ifdef _WINDOWS
# ifndef XP_WIN
# define XP_WIN
# endif
#if defined(_WIN32) || defined(WIN32)
# ifndef XP_WIN32
# define XP_WIN32
# endif
#else
# ifndef XP_WIN16
# define XP_WIN16
# endif
#endif
#endif
#ifdef XP_WIN16
#ifndef _PTRDIFF_T_DEFINED
typedef long ptrdiff_t;
/*
* The Win16 compiler treats pointer differences as 16-bit signed values.
* This macro allows us to treat them as 17-bit signed values, stored in
* a 32-bit type.
*/
#define PTRDIFF(p1, p2, type) \
((((unsigned long)(p1)) - ((unsigned long)(p2))) / sizeof(type))
#define _PTRDIFF_T_DEFINED
#endif /*_PTRDIFF_T_DEFINED*/
#else /*WIN16*/
#define PTRDIFF(p1, p2, type) \
((p1) - (p2))
#endif
#include <stddef.h>

View File

@@ -0,0 +1,54 @@
<RDF:RDF>
<Topic id="root" name="Mozilla.Org">
<child href="http://www.mozilla.org/mission.html" name="Our Mission"/>
<child>
<Topic id="WhoWeAre" name="Who We Are">
<child href="http://www.mozilla.org/about.html" name="About Us"/>
<child>
<Topic id="FAQ" name="FAQ">
<child href="http://www.mozilla.org/faq.html" name="FAQs"/>
<child href="http://www.mozilla.org/free-faq.html" name="Free Navigator FAQ"/>
<child href="http://www.mozilla.org/src-faq.html" name="Open Source FAQ"/>
<child href="http://home.netscape.com/newsref/pr/newsrelease577.html"
name="Press Release"/>
</Topic>
</child>
</Topic>
</child>
<child href="http://www.mozilla.org/news.html" name="News"/>
<child href="http://www.mozilla.org/community.html" name="Community"/>
<child href="http://www.mozilla.org/get-involved.html" name="Get Involved"/>
<child href="http://www.mozilla.org/projects.html" name="Projects"/>
<child href="http://www.mozilla.org/blue-sky.html" name="Blue Sky"/>
<child href="http://www.mozilla.org/advocacy.html" name="Advocacy"/>
<child>
<Topic id="DC" name="Documentation">
<child href="http://www.mozilla.org/docs.html" name="Documentation"/>
<child href="http://www.mozilla.org/library.html" name="Library"/>
</Topic>
</child>
<child>
<Topic id="dl" name="Downloads">
<child href="http://www.mozilla.org/download.html" name="Downloads"/>
<child href="http://www.mozilla.org/mirrors.html" name="Mirrors"/>
</Topic>
</child>
<child>
<Topic id="bg" name="Bugs">
<child href="http://www.mozilla.org/report.html" name="Reporting Bugs"/>
<child href="http://www.mozilla.org/bugs.html" name="Bug Database"/>
</Topic>
</child>
<child href="http://www.mozilla.org/search" name="Search"/>
<child href="http://www.mozilla.org/feedback.html" name="Feedback"/>
<child href="http://developer.netscape.com/index_moz.html" name="DevEdge"/>
</Topic>
</RDF:RDF>

View File

@@ -0,0 +1,64 @@
<RDF:RDF>
<Topic id="NC:NavCenter">
<child>
<Topic id="NC:Bookmarks" name="Bookmarks"/>
</child>
<child href="NC:Search" largeIcon="icon/large:workspace,search" name="Srch"/>
<child>
<Topic id="NC:History" largeIcon="icon/large:workspace,history" name="History" />
</child>
<child>
<Topic id="NC:Sitemaps" name="Site Tools" htmlURL="http://rdf.netscape.com/rdf/navcntradvert.html" />
</child>
<child>
<Topic id="NC:LocalFiles" name="Files" largeIcon="http://rdf.netscape.com/rdf/heabou.gif"/>
</child>
<child>
<Topic id="http://www.netscape.com/netcenter.rdf#root" name="Netcenter"/>
</child>
<child>
<Topic id="http://www.ilrt.bris.ac.uk/discovery/demos/rdf/webcat.rdf#ilrtroot" name="WebCat"/>
<child>
<child>
<Topic id="NC:NavInternals" name="Navigator Internals">
<child href="NC:SmartBrowsingProviders" name="SmartBrowsing Providers"/>
</Topic>
</child>
</Topic>
<Topic id="NC:SmartBrowsingProviders">
<child href="http://altavista.digital.com/cgi-bin/query?q=link%3A"
name="Who points to me?"
resultType="TEXT/HTML"/>
<child href="http://www-rl1.netscape.com/wtgn?" name="Related Links"
resultType="TEXT/RDF" />
</Topic>
</RDF:RDF>

View File

@@ -0,0 +1,13 @@
<toplevel>
<child id="foo">
<one/>
<two/>
<three/>
</child>
<child id="baz"/>
<child id="bar">
<four/>
<five/>
<six/>
</child>
</toplevel>

View File

@@ -0,0 +1,23 @@
prefix = "";
xml = new XMLGraph();
xml.parseFile("moz.rdf");
function dumpobj(o, name) {
print(prefix + "dumping " + name);
prefix += " ";
if (typeof(o) != "object") {
print(prefix + typeof(o) + " " + o + " is not an object!\n");
return;
}
for (i in o) {
if (typeof(o[i]) == "object")
dumpobj(o[i], i);
else
print(prefix + i + "=" + o[i]);
}
prefix = prefix.substring(2);
print(prefix + "done " + name);
}
dumpobj(xml.graph, "RDF:RDF");

View File

@@ -0,0 +1,29 @@
prefix = "";
function startElement(name, attr) {
print(prefix + 'starting "' + name + '"')
prefix += " ";
for (i in attr) {
print(prefix + i + '=' + attr[i]);
}
}
function endElement(name) {
prefix = prefix.substring(2);
print(prefix + 'ending "' + name + '"');
}
function characterData(cdata) {
print(prefix + 'CDATA: "' + cdata + '"');
}
function processingInstruction(target, data) {
print(prefix + 'processing insn for "' + target + '": "' + data + '"');
}
xml = new XMLParser();
xml.startElement = startElement;
xml.endElement = endElement;
xml.characterData = null; // characterData;
xml.parseFile("moz.rdf");

View File

@@ -0,0 +1,147 @@
#define XMLJS_INTERNAL
#include "xmljs.h"
#undef XMLJS_INTERNAL
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/**
* Parse a given string of XML.
* If we fail, we (try to) set an error property on the given obj, and
* return JSVAL_FALSE.
* If all is well, we return JSVAL_TRUE.
*/
JSBool
xmljs_parse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
XMLCallback *cb;
XML_Parser xml;
JSString *str;
JSBool ok;
cb = (XMLCallback *)JS_GetPrivate(cx, obj);
if (!cb) {
JS_ReportError(cx, "XMLParser object has no parser!");
return JS_FALSE;
}
if (cb->preParse &&
!cb->preParse(cx, obj, argc, argv, rval))
return JS_FALSE;
if (argc < 1) {
*rval = JSVAL_TRUE;
return JS_TRUE;
}
xml = XML_ParserCreate(NULL);
if (!xml)
return JS_FALSE; /* XXX report error */
/* after this point, have to leave via out: */
XML_SetElementHandler(xml, cb->start, cb->end);
XML_SetCharacterDataHandler(xml, cb->cdata);
XML_SetProcessingInstructionHandler(xml, cb->processing);
XML_SetUserData(xml, (void *)cb);
cb->xml = xml;
str = JS_ValueToString(cx, argv[0]);
if (!XML_Parse(xml, JS_GetStringBytes(str), JS_GetStringLength(str), 1)) {
str = JS_NewStringCopyZ(cx, XML_ErrorString(XML_GetErrorCode(xml)));
if (!str) {
ok = JS_FALSE;
goto out;
}
if (!JS_DefineProperty(cx, obj, "error", STRING_TO_JSVAL(str),
NULL, NULL, JSPROP_ENUMERATE)) {
ok = JS_FALSE;
goto out;
}
*rval = JSVAL_FALSE;
} else {
*rval = JSVAL_TRUE;
}
out:
XML_ParserFree(xml);
cb->xml = NULL;
return ok;
}
/**
* Get a file into a string and call the above.
* XXX when File object is present, we don't need this mess.
*/
static JSBool
xmljs_parseFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSString *str, *filename;
struct stat sbuf;
char * buf;
int fd, len;
*rval = JSVAL_TRUE;
if (argc < 1)
return JS_TRUE;
filename = JS_ValueToString(cx, argv[0]);
if (!filename)
return JS_TRUE;
argv[0] = STRING_TO_JSVAL(filename);
fd = open(JS_GetStringBytes(filename), O_RDONLY);
if (fd < 0) {
JS_ReportError(cx,
"XMLParser.prototype.parseFile: open of %s failed!\n",
JS_GetStringBytes(filename));
return JS_FALSE;
}
if (fstat(fd, &sbuf) < 0) {
JS_ReportError(cx,
"XMLParser.prototype.parseFile: stat of %s failed!\n",
JS_GetStringBytes(filename));
close(fd);
return JS_FALSE;
}
len = sbuf.st_size;
buf = (char *)JS_malloc(cx, len);
if (read(fd, (void *)buf, (size_t)len) < len) {
JS_ReportError(cx,
"XMLParser.prototype.parseFile: read of %s failed!\n",
JS_GetStringBytes(filename));
JS_free(cx, buf);
close(fd);
return JS_FALSE;
}
close(fd);
str = JS_NewString(cx, buf, len); /* hand buf off to engine; don't free! */
if (!str) {
JS_free(cx, buf);
return JS_FALSE;
}
argv[0] = STRING_TO_JSVAL(str);
return JS_CallFunctionName(cx, obj, "parse", argc, argv, rval);
}
JSBool
XML_Init(JSContext *cx, JSObject *obj)
{
jsval rval;
JSObject *proto;
if (!JS_EvaluateScript(cx, JS_GetGlobalObject(cx), xmljs_newObj_str,
xmljs_newObj_size,
"XMLJS internal", 0, &rval))
return JS_FALSE;
proto = JSVAL_TO_OBJECT(rval);
if (!JS_DefineFunction(cx, proto, "parse", xmljs_parse,
1, 0) ||
!JS_DefineFunction(cx, proto, "parseFile", xmljs_parseFile,
1, 0))
return JS_FALSE;
return XMLParser_Init(cx, obj, proto) && XMLGraph_Init(cx, obj, proto);
}

View File

@@ -0,0 +1,34 @@
#ifndef XMLJS_H
#define XMLJS_H
#include <xmlparse.h>
#include <jsapi.h>
extern JSBool
XML_Init(JSContext *cx, JSObject *obj);
#ifdef XMLJS_INTERNAL
typedef struct {
JSContext *cx;
JSObject *obj;
XML_Parser xml;
XML_StartElementHandler start;
XML_EndElementHandler end;
XML_CharacterDataHandler cdata;
XML_ProcessingInstructionHandler processing;
JSNative preParse;
JSNative postParse;
} XMLCallback;
extern JSBool
XMLParser_Init(JSContext *cx, JSObject *obj, JSObject *parent_proto);
extern JSBool
XMLGraph_Init(JSContext *cx, JSObject *obj, JSObject *parent_proto);
#define xmljs_newObj_str "new Object();"
#define xmljs_newObj_size (sizeof(xmljs_newObj_str) - 1)
#endif /* XMLJS_INTERNAL */
#endif /* XMLJS_H */