Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
379 lines (309 sloc) 10.3 KB
#include <node.h>
#include <node_version.h>
#include <node_object_wrap.h>
#include <node_buffer.h>
extern "C" {
#include <expat.h>
}
using namespace v8;
using namespace node;
static Persistent<String> sym_startElement, sym_endElement,
sym_startCdata, sym_endCdata,
sym_text, sym_processingInstruction,
sym_comment, sym_xmlDecl, sym_entityDecl,
sym_emit;
class Parser : public ObjectWrap {
public:
static void Initialize(Handle<Object> target)
{
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
NODE_SET_PROTOTYPE_METHOD(t, "parse", Parse);
NODE_SET_PROTOTYPE_METHOD(t, "setEncoding", SetEncoding);
NODE_SET_PROTOTYPE_METHOD(t, "getError", GetError);
NODE_SET_PROTOTYPE_METHOD(t, "stop", Stop);
NODE_SET_PROTOTYPE_METHOD(t, "resume", Resume);
target->Set(String::NewSymbol("Parser"), t->GetFunction());
sym_startElement = NODE_PSYMBOL("startElement");
sym_endElement = NODE_PSYMBOL("endElement");
sym_startCdata = NODE_PSYMBOL("startCdata");
sym_endCdata = NODE_PSYMBOL("endCdata");
sym_text = NODE_PSYMBOL("text");
sym_processingInstruction = NODE_PSYMBOL("processingInstruction");
sym_comment = NODE_PSYMBOL("comment");
sym_xmlDecl = NODE_PSYMBOL("xmlDecl");
sym_entityDecl = NODE_PSYMBOL("entityDecl");
sym_emit = NODE_PSYMBOL("emit");
}
protected:
/*** Constructor ***/
static Handle<Value> New(const Arguments& args)
{
HandleScope scope;
XML_Char *encoding = NULL;
if (args.Length() == 1 && args[0]->IsString())
{
encoding = new XML_Char[32];
args[0]->ToString()->WriteAscii(encoding, 0, 32);
}
Parser *parser = new Parser(encoding);
if (encoding)
delete[] encoding;
parser->Wrap(args.This());
return args.This();
}
Parser(const XML_Char *encoding)
: ObjectWrap()
{
parser = XML_ParserCreate(encoding);
assert(parser != NULL);
XML_SetUserData(parser, this);
XML_SetElementHandler(parser, StartElement, EndElement);
XML_SetCharacterDataHandler(parser, Text);
XML_SetCdataSectionHandler(parser, StartCdata, EndCdata);
XML_SetProcessingInstructionHandler(parser, ProcessingInstruction);
XML_SetCommentHandler(parser, Comment);
XML_SetXmlDeclHandler(parser, XmlDecl);
XML_SetEntityDeclHandler(parser, EntityDecl);
}
~Parser()
{
XML_ParserFree(parser);
}
/*** parse() ***/
static Handle<Value> Parse(const Arguments& args)
{
Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
HandleScope scope;
Local<String> str;
int isFinal = 0;
/* Argument 2: isFinal :: Bool */
if (args.Length() >= 2)
{
isFinal = args[1]->IsTrue();
}
/* Argument 1: buf :: String or Buffer */
if (args.Length() >= 1 && args[0]->IsString())
{
str = args[0]->ToString();
return scope.Close(parser->parseString(**str, isFinal) ? True() : False());
}
else if (args.Length() >= 1 && args[0]->IsObject())
{
Local<Object> obj = args[0]->ToObject();
if (Buffer::HasInstance(obj))
{
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
return scope.Close(parser->parseBuffer(*buffer, isFinal) ? True() : False());
#else
return scope.Close(parser->parseBuffer(obj, isFinal) ? True() : False());
#endif
}
else
return ThrowException(
Exception::TypeError(
String::New("Parse buffer must be String or Buffer")));
}
else
return ThrowException(
Exception::TypeError(
String::New("Parse buffer must be String or Buffer")));
}
/** Parse a v8 String by first writing it to the expat parser's
buffer */
bool parseString(String &str, int isFinal)
{
int len = str.Utf8Length();
if (len == 0)
return true;
void *buf = XML_GetBuffer(parser, len);
assert(buf != NULL);
assert(str.WriteUtf8(static_cast<char *>(buf), len) == len);
return XML_ParseBuffer(parser, len, isFinal) != XML_STATUS_ERROR;
}
/** Parse a node.js Buffer directly */
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
bool parseBuffer(Buffer &buffer, int isFinal)
{
return XML_Parse(parser, buffer.data(), buffer.length(), isFinal) != XML_STATUS_ERROR;
}
#else
bool parseBuffer(Local<Object> buffer, int isFinal)
{
return XML_Parse(parser, Buffer::Data(buffer), Buffer::Length(buffer), isFinal) != XML_STATUS_ERROR;
}
#endif
/*** setEncoding() ***/
static Handle<Value> SetEncoding(const Arguments& args)
{
Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
HandleScope scope;
if (args.Length() == 1 && args[0]->IsString())
{
XML_Char *encoding = new XML_Char[32];
args[0]->ToString()->WriteAscii(encoding, 0, 32);
int status = parser->setEncoding(encoding);
delete[] encoding;
return scope.Close(status ? True() : False());
}
else
return False();
}
int setEncoding(XML_Char *encoding)
{
return XML_SetEncoding(parser, encoding) != 0;
}
/*** getError() ***/
static Handle<Value> GetError(const Arguments& args)
{
HandleScope scope;
Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
const XML_LChar *error = parser->getError();
if (error)
return scope.Close(String::New(error));
else
return scope.Close(Null());
}
/*** stop() ***/
static Handle<Value> Stop(const Arguments& args)
{
Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
HandleScope scope;
int status = parser->stop();
return scope.Close(status ? True() : False());
}
int stop()
{
return XML_StopParser(parser, XML_TRUE) != 0;
}
/*** resume() ***/
static Handle<Value> Resume(const Arguments& args)
{
Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
HandleScope scope;
int status = parser->resume();
return scope.Close(status ? True() : False());
}
int resume()
{
return XML_ResumeParser(parser) != 0;
}
const XML_LChar *getError()
{
enum XML_Error code;
code = XML_GetErrorCode(parser);
return XML_ErrorString(code);
}
private:
/* expat instance */
XML_Parser parser;
/* no default ctor */
Parser();
/*** SAX callbacks ***/
/* Should a local HandleScope be used in those callbacks? */
static void StartElement(void *userData,
const XML_Char *name, const XML_Char **atts)
{
Parser *parser = reinterpret_cast<Parser *>(userData);
/* Collect atts into JS object */
Local<Object> attr = Object::New();
for(const XML_Char **atts1 = atts; *atts1; atts1 += 2)
attr->Set(String::New(atts1[0]), String::New(atts1[1]));
/* Trigger event */
Handle<Value> argv[3] = { sym_startElement,
String::New(name),
attr };
parser->Emit(3, argv);
}
static void EndElement(void *userData,
const XML_Char *name)
{
Parser *parser = reinterpret_cast<Parser *>(userData);
/* Trigger event */
Handle<Value> argv[2] = { sym_endElement, String::New(name) };
parser->Emit(2, argv);
}
static void StartCdata(void *userData)
{
Parser *parser = reinterpret_cast<Parser *>(userData);
/* Trigger event */
Handle<Value> argv[1] = { sym_startCdata };
parser->Emit(1, argv);
}
static void EndCdata(void *userData)
{
Parser *parser = reinterpret_cast<Parser *>(userData);
/* Trigger event */
Handle<Value> argv[1] = { sym_endCdata };
parser->Emit(1, argv);
}
static void Text(void *userData,
const XML_Char *s, int len)
{
Parser *parser = reinterpret_cast<Parser *>(userData);
/* Trigger event */
Handle<Value> argv[2] = { sym_text,
String::New(s, len) };
parser->Emit(2, argv);
}
static void ProcessingInstruction(void *userData,
const XML_Char *target, const XML_Char *data)
{
Parser *parser = reinterpret_cast<Parser *>(userData);
/* Trigger event */
Handle<Value> argv[3] = { sym_processingInstruction,
String::New(target),
String::New(data) };
parser->Emit(3, argv);
}
static void Comment(void *userData,
const XML_Char *data)
{
Parser *parser = reinterpret_cast<Parser *>(userData);
/* Trigger event */
Handle<Value> argv[2] = { sym_comment, String::New(data) };
parser->Emit(2, argv);
}
static void XmlDecl(void *userData,
const XML_Char *version, const XML_Char *encoding,
int standalone)
{
Parser *parser = reinterpret_cast<Parser *>(userData);
/* Trigger event */
Handle<Value> argv[4] = { sym_xmlDecl,
version ? String::New(version) : Null(),
encoding ? String::New(encoding) : Null(),
Boolean::New(standalone) };
parser->Emit(4, argv);
}
static void EntityDecl(void *userData, const XML_Char *entityName, int is_parameter_entity,
const XML_Char *value, int value_length, const XML_Char *base,
const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName)
{
Parser *parser = reinterpret_cast<Parser *>(userData);
/* Trigger event */
Handle<Value> argv[8] = { sym_entityDecl,
entityName ? String::New(entityName) : Null(),
Boolean::New(is_parameter_entity),
value ? String::New(value) : Null(),
base ? String::New(base) : Null(),
systemId ? String::New(systemId) : Null(),
publicId ? String::New(publicId) : Null(),
notationName ? String::New(notationName) : Null(),
};
parser->Emit(8, argv);
}
void Emit(int argc, Handle<Value> argv[])
{
HandleScope scope;
Local<Function> emit = Local<Function>::Cast(handle_->Get(sym_emit));
emit->Call(handle_, argc, argv);
}
};
extern "C" void init(Handle<Object> target)
{
HandleScope scope;
Parser::Initialize(target);
}
Jump to Line
Something went wrong with that request. Please try again.