summaryrefslogtreecommitdiff
path: root/Expat/Expat.xs
diff options
context:
space:
mode:
Diffstat (limited to 'Expat/Expat.xs')
-rw-r--r--Expat/Expat.xs2214
1 files changed, 2214 insertions, 0 deletions
diff --git a/Expat/Expat.xs b/Expat/Expat.xs
new file mode 100644
index 0000000..497b64f
--- /dev/null
+++ b/Expat/Expat.xs
@@ -0,0 +1,2214 @@
+/*****************************************************************
+** Expat.xs
+**
+** Copyright 1998 Larry Wall and Clark Cooper
+** All rights reserved.
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the same terms as Perl itself.
+**
+*/
+
+#include <expat.h>
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#undef convert
+
+#include "patchlevel.h"
+#include "encoding.h"
+
+
+/* Version 5.005_5x (Development version for 5.006) doesn't like sv_...
+ anymore, but 5.004 doesn't know about PL_sv..
+ Don't want to push up required version just for this. */
+
+#if PATCHLEVEL < 5
+#define PL_sv_undef sv_undef
+#define PL_sv_no sv_no
+#define PL_sv_yes sv_yes
+#define PL_na na
+#endif
+
+#define BUFSIZE 32768
+
+#define NSDELIM '|'
+
+/* Macro to update handler fields. Used in the various handler setting
+ XSUBS */
+
+#define XMLP_UPD(fld) \
+ RETVAL = cbv->fld ? newSVsv(cbv->fld) : &PL_sv_undef;\
+ if (cbv->fld) {\
+ if (cbv->fld != fld)\
+ sv_setsv(cbv->fld, fld);\
+ }\
+ else\
+ cbv->fld = newSVsv(fld)
+
+/* Macro to push old handler value onto return stack. This is done here
+ to get around a bug in 5.004 sv_2mortal function. */
+
+#define PUSHRET \
+ ST(0) = RETVAL;\
+ if (RETVAL != &PL_sv_undef && SvREFCNT(RETVAL)) sv_2mortal(RETVAL)
+
+typedef struct {
+ SV* self_sv;
+ XML_Parser p;
+
+ AV* context;
+ AV* new_prefix_list;
+ HV *nstab;
+ AV *nslst;
+
+ unsigned int st_serial;
+ unsigned int st_serial_stackptr;
+ unsigned int st_serial_stacksize;
+ unsigned int * st_serial_stack;
+
+ unsigned int skip_until;
+
+ SV *recstring;
+ char * delim;
+ STRLEN delimlen;
+
+ unsigned ns:1;
+ unsigned no_expand:1;
+ unsigned parseparam:1;
+
+ /* Callback handlers */
+
+ SV* start_sv;
+ SV* end_sv;
+ SV* char_sv;
+ SV* proc_sv;
+ SV* cmnt_sv;
+ SV* dflt_sv;
+
+ SV* entdcl_sv;
+ SV* eledcl_sv;
+ SV* attdcl_sv;
+ SV* doctyp_sv;
+ SV* doctypfin_sv;
+ SV* xmldec_sv;
+
+ SV* unprsd_sv;
+ SV* notation_sv;
+
+ SV* extent_sv;
+ SV* extfin_sv;
+
+ SV* startcd_sv;
+ SV* endcd_sv;
+} CallbackVector;
+
+
+static HV* EncodingTable = NULL;
+
+static XML_Char nsdelim[] = {NSDELIM, '\0'};
+
+static char *QuantChar[] = {"", "?", "*", "+"};
+
+/* Forward declarations */
+
+static void suspend_callbacks(CallbackVector *);
+static void resume_callbacks(CallbackVector *);
+
+#if PATCHLEVEL < 5 && SUBVERSION < 5
+
+/* ================================================================
+** This is needed where the length is explicitly given. The expat
+** library may sometimes give us zero-length strings. Perl's newSVpv
+** interprets a zero length as a directive to do a strlen. This
+** function is used when we want to force length to mean length, even
+** if zero.
+*/
+
+static SV *
+newSVpvn(char *s, STRLEN len)
+{
+ register SV *sv;
+
+ sv = newSV(0);
+ sv_setpvn(sv, s, len);
+ return sv;
+} /* End newSVpvn */
+
+#define ERRSV GvSV(errgv)
+#endif
+
+#ifdef SvUTF8_on
+
+static SV *
+newUTF8SVpv(char *s, STRLEN len) {
+ register SV *sv;
+
+ sv = newSVpv(s, len);
+ SvUTF8_on(sv);
+ return sv;
+} /* End new UTF8SVpv */
+
+static SV *
+newUTF8SVpvn(char *s, STRLEN len) {
+ register SV *sv;
+
+ sv = newSV(0);
+ sv_setpvn(sv, s, len);
+ SvUTF8_on(sv);
+ return sv;
+}
+
+#else /* SvUTF8_on not defined */
+
+#define newUTF8SVpv newSVpv
+#define newUTF8SVpvn newSVpvn
+
+#endif
+
+static void*
+mymalloc(size_t size) {
+#ifndef LEAKTEST
+ return safemalloc(size);
+#else
+ return safexmalloc(328,size);
+#endif
+}
+
+static void*
+myrealloc(void *p, size_t s) {
+#ifndef LEAKTEST
+ return saferealloc(p, s);
+#else
+ return safexrealloc(p, s);
+#endif
+}
+
+static void
+myfree(void *p) {
+ Safefree(p);
+}
+
+static XML_Memory_Handling_Suite ms = {mymalloc, myrealloc, myfree};
+
+static void
+append_error(XML_Parser parser, char * err)
+{
+ dSP;
+ CallbackVector * cbv;
+ SV ** errstr;
+
+ cbv = (CallbackVector*) XML_GetUserData(parser);
+ errstr = hv_fetch((HV*)SvRV(cbv->self_sv),
+ "ErrorMessage", 12, 0);
+
+ if (errstr && SvPOK(*errstr)) {
+ SV ** errctx = hv_fetch((HV*) SvRV(cbv->self_sv),
+ "ErrorContext", 12, 0);
+ int dopos = !err && errctx && SvOK(*errctx);
+
+ if (! err)
+ err = (char *) XML_ErrorString(XML_GetErrorCode(parser));
+
+ sv_catpvf(*errstr, "\n%s at line %d, column %d, byte %d%s",
+ err,
+ XML_GetCurrentLineNumber(parser),
+ XML_GetCurrentColumnNumber(parser),
+ XML_GetCurrentByteIndex(parser),
+ dopos ? ":\n" : "");
+
+ if (dopos)
+ {
+ int count;
+
+ ENTER ;
+ SAVETMPS ;
+ PUSHMARK(sp);
+ XPUSHs(cbv->self_sv);
+ XPUSHs(*errctx);
+ PUTBACK ;
+
+ count = perl_call_method("position_in_context", G_SCALAR);
+
+ SPAGAIN ;
+
+ if (count >= 1) {
+ sv_catsv(*errstr, POPs);
+ }
+
+ PUTBACK ;
+ FREETMPS ;
+ LEAVE ;
+ }
+ }
+} /* End append_error */
+
+static SV *
+generate_model(XML_Content *model) {
+ HV * hash = newHV();
+ SV * obj = newRV_noinc((SV *) hash);
+
+ sv_bless(obj, gv_stashpv("XML::Parser::ContentModel", 1));
+
+ hv_store(hash, "Type", 4, newSViv(model->type), 0);
+ if (model->quant != XML_CQUANT_NONE) {
+ hv_store(hash, "Quant", 5, newSVpv(QuantChar[model->quant], 1), 0);
+ }
+
+ switch(model->type) {
+ case XML_CTYPE_NAME:
+ hv_store(hash, "Tag", 3, newUTF8SVpv((char *)model->name, 0), 0);
+ break;
+
+ case XML_CTYPE_MIXED:
+ case XML_CTYPE_CHOICE:
+ case XML_CTYPE_SEQ:
+ if (model->children && model->numchildren)
+ {
+ AV * children = newAV();
+ int i;
+
+ for (i = 0; i < model->numchildren; i++) {
+ av_push(children, generate_model(&model->children[i]));
+ }
+
+ hv_store(hash, "Children", 8, newRV_noinc((SV *) children), 0);
+ }
+ break;
+ }
+
+ return obj;
+} /* End generate_model */
+
+static int
+parse_stream(XML_Parser parser, SV * ioref)
+{
+ dSP;
+ SV * tbuff;
+ SV * tsiz;
+ char * linebuff;
+ STRLEN lblen;
+ STRLEN br = 0;
+ int buffsize;
+ int done = 0;
+ int ret = 1;
+ char * msg = NULL;
+ CallbackVector * cbv;
+ char *buff = (char *) 0;
+
+ cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ ENTER;
+ SAVETMPS;
+
+ if (cbv->delim) {
+ int cnt;
+ SV * tline;
+
+ PUSHMARK(SP);
+ XPUSHs(ioref);
+ PUTBACK ;
+
+ cnt = perl_call_method("getline", G_SCALAR);
+
+ SPAGAIN;
+
+ if (cnt != 1)
+ croak("getline method call failed");
+
+ tline = POPs;
+
+ if (! SvOK(tline)) {
+ lblen = 0;
+ }
+ else {
+ char * chk;
+ linebuff = SvPV(tline, lblen);
+ chk = &linebuff[lblen - cbv->delimlen - 1];
+
+ if (lblen > cbv->delimlen + 1
+ && *chk == *cbv->delim
+ && chk[cbv->delimlen] == '\n'
+ && strnEQ(++chk, cbv->delim + 1, cbv->delimlen - 1))
+ lblen -= cbv->delimlen + 1;
+ }
+
+ PUTBACK ;
+ buffsize = lblen;
+ done = lblen == 0;
+ }
+ else {
+ tbuff = newSV(0);
+ tsiz = newSViv(BUFSIZE);
+ buffsize = BUFSIZE;
+ }
+
+ while (! done)
+ {
+ char *buffer = XML_GetBuffer(parser, buffsize);
+
+ if (! buffer)
+ croak("Ran out of memory for input buffer");
+
+ SAVETMPS;
+
+ if (cbv->delim) {
+ Copy(linebuff, buffer, lblen, char);
+ br = lblen;
+ done = 1;
+ }
+ else {
+ int cnt;
+ SV * rdres;
+ char * tb;
+
+ PUSHMARK(SP);
+ EXTEND(SP, 3);
+ PUSHs(ioref);
+ PUSHs(tbuff);
+ PUSHs(tsiz);
+ PUTBACK ;
+
+ cnt = perl_call_method("read", G_SCALAR);
+
+ SPAGAIN ;
+
+ if (cnt != 1)
+ croak("read method call failed");
+
+ rdres = POPs;
+
+ if (! SvOK(rdres))
+ croak("read error");
+
+ tb = SvPV(tbuff, br);
+ if (br > 0)
+ Copy(tb, buffer, br, char);
+ else
+ done = 1;
+
+ PUTBACK ;
+ }
+
+ ret = XML_ParseBuffer(parser, br, done);
+
+ SPAGAIN; /* resync local SP in case callbacks changed global stack */
+
+ if (! ret)
+ break;
+
+ FREETMPS;
+ }
+
+ if (! ret)
+ append_error(parser, msg);
+
+ if (! cbv->delim) {
+ SvREFCNT_dec(tsiz);
+ SvREFCNT_dec(tbuff);
+ }
+
+ FREETMPS;
+ LEAVE;
+
+ return ret;
+} /* End parse_stream */
+
+static SV *
+gen_ns_name(const char * name, HV * ns_table, AV * ns_list)
+{
+ char *pos = strchr(name, NSDELIM);
+ SV * ret;
+
+ if (pos && pos > name)
+ {
+ SV ** name_ent = hv_fetch(ns_table, (char *) name,
+ pos - name, TRUE);
+ ret = newUTF8SVpv(&pos[1], 0);
+
+ if (name_ent)
+ {
+ int index;
+
+ if (SvOK(*name_ent))
+ {
+ index = SvIV(*name_ent);
+ }
+ else
+ {
+ av_push(ns_list, newUTF8SVpv((char *) name, pos - name));
+ index = av_len(ns_list);
+ sv_setiv(*name_ent, (IV) index);
+ }
+
+ sv_setiv(ret, (IV) index);
+ SvPOK_on(ret);
+ }
+ }
+ else
+ ret = newUTF8SVpv((char *) name, 0);
+
+ return ret;
+} /* End gen_ns_name */
+
+static void
+characterData(void *userData, const char *s, int len)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpvn((char*)s,len)));
+ PUTBACK;
+ perl_call_sv(cbv->char_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End characterData */
+
+static void
+startElement(void *userData, const char *name, const char **atts)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+ SV ** pcontext;
+ unsigned do_ns = cbv->ns;
+ unsigned skipping = 0;
+ SV ** pnstab;
+ SV ** pnslst;
+ SV * elname;
+
+ cbv->st_serial++;
+
+ if (cbv->skip_until) {
+ skipping = cbv->st_serial < cbv->skip_until;
+ if (! skipping) {
+ resume_callbacks(cbv);
+ cbv->skip_until = 0;
+ }
+ }
+
+ if (cbv->st_serial_stackptr >= cbv->st_serial_stacksize) {
+ unsigned int newsize = cbv->st_serial_stacksize + 512;
+
+ Renew(cbv->st_serial_stack, newsize, unsigned int);
+ cbv->st_serial_stacksize = newsize;
+ }
+
+ cbv->st_serial_stack[++cbv->st_serial_stackptr] = cbv->st_serial;
+
+ if (do_ns)
+ elname = gen_ns_name(name, cbv->nstab, cbv->nslst);
+ else
+ elname = newUTF8SVpv((char *)name, 0);
+
+ if (! skipping && SvTRUE(cbv->start_sv))
+ {
+ const char **attlim = atts;
+
+ while (*attlim)
+ attlim++;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, attlim - atts + 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(elname);
+ while (*atts)
+ {
+ SV * attname;
+
+ attname = (do_ns ? gen_ns_name(*atts, cbv->nstab, cbv->nslst)
+ : newUTF8SVpv((char *) *atts, 0));
+
+ atts++;
+ PUSHs(sv_2mortal(attname));
+ if (*atts)
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)*atts++,0)));
+ }
+ PUTBACK;
+ perl_call_sv(cbv->start_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+ }
+
+ av_push(cbv->context, elname);
+
+ if (cbv->ns) {
+ av_clear(cbv->new_prefix_list);
+ }
+} /* End startElement */
+
+static void
+endElement(void *userData, const char *name)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+ SV *elname;
+
+ elname = av_pop(cbv->context);
+
+ if (! cbv->st_serial_stackptr) {
+ croak("endElement: Start tag serial number stack underflow");
+ }
+
+ if (! cbv->skip_until && SvTRUE(cbv->end_sv))
+ {
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(elname);
+ PUTBACK;
+ perl_call_sv(cbv->end_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+ }
+
+ cbv->st_serial_stackptr--;
+
+ SvREFCNT_dec(elname);
+} /* End endElement */
+
+static void
+processingInstruction(void *userData, const char *target, const char *data)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 3);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)target,0)));
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)data,0)));
+ PUTBACK;
+ perl_call_sv(cbv->proc_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End processingInstruction */
+
+static void
+commenthandle(void *userData, const char *string)
+{
+ dSP;
+ CallbackVector * cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) string, 0)));
+ PUTBACK;
+ perl_call_sv(cbv->cmnt_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End commenthandler */
+
+static void
+startCdata(void *userData)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ if (cbv->startcd_sv) {
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ XPUSHs(cbv->self_sv);
+ PUTBACK;
+ perl_call_sv(cbv->startcd_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+ }
+} /* End startCdata */
+
+static void
+endCdata(void *userData)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ if (cbv->endcd_sv) {
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ XPUSHs(cbv->self_sv);
+ PUTBACK;
+ perl_call_sv(cbv->endcd_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+ }
+} /* End endCdata */
+
+static void
+nsStart(void *userdata, const XML_Char *prefix, const XML_Char *uri){
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userdata;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 3);
+ PUSHs(cbv->self_sv);
+ PUSHs(prefix ? sv_2mortal(newUTF8SVpv((char *)prefix, 0)) : &PL_sv_undef);
+ PUSHs(uri ? sv_2mortal(newUTF8SVpv((char *)uri, 0)) : &PL_sv_undef);
+ PUTBACK;
+ perl_call_method("NamespaceStart", G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End nsStart */
+
+static void
+nsEnd(void *userdata, const XML_Char *prefix) {
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userdata;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(prefix ? sv_2mortal(newUTF8SVpv((char *)prefix, 0)) : &PL_sv_undef);
+ PUTBACK;
+ perl_call_method("NamespaceEnd", G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End nsEnd */
+
+static void
+defaulthandle(void *userData, const char *string, int len)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpvn((char*)string, len)));
+ PUTBACK;
+ perl_call_sv(cbv->dflt_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End defaulthandle */
+
+static void
+elementDecl(void *data,
+ const char *name,
+ XML_Content *model) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) data;
+ SV *cmod;
+
+ ENTER;
+ SAVETMPS;
+
+
+ cmod = generate_model(model);
+
+ Safefree(model);
+ PUSHMARK(sp);
+ EXTEND(sp, 3);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char *)name, 0)));
+ PUSHs(sv_2mortal(cmod));
+ PUTBACK;
+ perl_call_sv(cbv->eledcl_sv, G_DISCARD);
+ FREETMPS;
+ LEAVE;
+
+} /* End elementDecl */
+
+static void
+attributeDecl(void *data,
+ const char * elname,
+ const char * attname,
+ const char * att_type,
+ const char * dflt,
+ int reqorfix) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) data;
+ SV * dfltsv;
+
+ if (dflt) {
+ dfltsv = newUTF8SVpv("'", 1);
+ sv_catpv(dfltsv, (char *) dflt);
+ sv_catpv(dfltsv, "'");
+ }
+ else {
+ dfltsv = newUTF8SVpv(reqorfix ? "#REQUIRED" : "#IMPLIED", 0);
+ }
+
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(sp);
+ EXTEND(sp, 5);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char *)elname, 0)));
+ PUSHs(sv_2mortal(newUTF8SVpv((char *)attname, 0)));
+ PUSHs(sv_2mortal(newUTF8SVpv((char *)att_type, 0)));
+ PUSHs(sv_2mortal(dfltsv));
+ if (dflt && reqorfix)
+ XPUSHs(&PL_sv_yes);
+ PUTBACK;
+ perl_call_sv(cbv->attdcl_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End attributeDecl */
+
+static void
+entityDecl(void *data,
+ const char *name,
+ int isparam,
+ const char *value,
+ int vlen,
+ const char *base,
+ const char *sysid,
+ const char *pubid,
+ const char *notation) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) data;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 6);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)name, 0)));
+ PUSHs(value ? sv_2mortal(newUTF8SVpvn((char*)value, vlen)) : &PL_sv_undef);
+ PUSHs(sysid ? sv_2mortal(newUTF8SVpv((char *)sysid, 0)) : &PL_sv_undef);
+ PUSHs(pubid ? sv_2mortal(newUTF8SVpv((char *)pubid, 0)) : &PL_sv_undef);
+ PUSHs(notation ? sv_2mortal(newUTF8SVpv((char *)notation, 0)) : &PL_sv_undef);
+ if (isparam)
+ XPUSHs(&PL_sv_yes);
+ PUTBACK;
+ perl_call_sv(cbv->entdcl_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End entityDecl */
+
+static void
+doctypeStart(void *userData,
+ const char* name,
+ const char* sysid,
+ const char* pubid,
+ int hasinternal) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 5);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)name, 0)));
+ PUSHs(sysid ? sv_2mortal(newUTF8SVpv((char*)sysid, 0)) : &PL_sv_undef);
+ PUSHs(pubid ? sv_2mortal(newUTF8SVpv((char*)pubid, 0)) : &PL_sv_undef);
+ PUSHs(hasinternal ? &PL_sv_yes : &PL_sv_no);
+ PUTBACK;
+ perl_call_sv(cbv->doctyp_sv, G_DISCARD);
+ FREETMPS;
+ LEAVE;
+} /* End doctypeStart */
+
+static void
+doctypeEnd(void *userData) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 1);
+ PUSHs(cbv->self_sv);
+ PUTBACK;
+ perl_call_sv(cbv->doctypfin_sv, G_DISCARD);
+ FREETMPS;
+ LEAVE;
+} /* End doctypeEnd */
+
+static void
+xmlDecl(void *userData,
+ const char *version,
+ const char *encoding,
+ int standalone) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 4);
+ PUSHs(cbv->self_sv);
+ PUSHs(version ? sv_2mortal(newUTF8SVpv((char *)version, 0))
+ : &PL_sv_undef);
+ PUSHs(encoding ? sv_2mortal(newUTF8SVpv((char *)encoding, 0))
+ : &PL_sv_undef);
+ PUSHs(standalone == -1 ? &PL_sv_undef
+ : (standalone ? &PL_sv_yes : &PL_sv_no));
+ PUTBACK;
+ perl_call_sv(cbv->xmldec_sv, G_DISCARD);
+ FREETMPS;
+ LEAVE;
+} /* End xmlDecl */
+
+static void
+unparsedEntityDecl(void *userData,
+ const char* entity,
+ const char* base,
+ const char* sysid,
+ const char* pubid,
+ const char* notation)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 6);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) entity, 0)));
+ PUSHs(base ? sv_2mortal(newUTF8SVpv((char*) base, 0)) : &PL_sv_undef);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) sysid, 0)));
+ PUSHs(pubid ? sv_2mortal(newUTF8SVpv((char*) pubid, 0)) : &PL_sv_undef);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) notation, 0)));
+ PUTBACK;
+ perl_call_sv(cbv->unprsd_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End unparsedEntityDecl */
+
+static void
+notationDecl(void *userData,
+ const char *name,
+ const char *base,
+ const char *sysid,
+ const char *pubid)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ PUSHMARK(sp);
+ XPUSHs(cbv->self_sv);
+ XPUSHs(sv_2mortal(newUTF8SVpv((char*) name, 0)));
+ if (base)
+ {
+ XPUSHs(sv_2mortal(newUTF8SVpv((char *) base, 0)));
+ }
+ else if (sysid || pubid)
+ {
+ XPUSHs(&PL_sv_undef);
+ }
+
+ if (sysid)
+ {
+ XPUSHs(sv_2mortal(newUTF8SVpv((char *) sysid, 0)));
+ }
+ else if (pubid)
+ {
+ XPUSHs(&PL_sv_undef);
+ }
+
+ if (pubid)
+ XPUSHs(sv_2mortal(newUTF8SVpv((char *) pubid, 0)));
+
+ PUTBACK;
+ perl_call_sv(cbv->notation_sv, G_DISCARD);
+} /* End notationDecl */
+
+static int
+externalEntityRef(XML_Parser parser,
+ const char* open,
+ const char* base,
+ const char* sysid,
+ const char* pubid)
+{
+ dSP;
+#if defined(USE_THREADS) && PATCHLEVEL==6
+ dTHX;
+#endif
+
+ int count;
+ int ret = 0;
+ int parse_done = 0;
+
+ CallbackVector* cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ if (! cbv->extent_sv)
+ return 0;
+
+ ENTER ;
+ SAVETMPS ;
+ PUSHMARK(sp);
+ EXTEND(sp, pubid ? 4 : 3);
+ PUSHs(cbv->self_sv);
+ PUSHs(base ? sv_2mortal(newUTF8SVpv((char*) base, 0)) : &PL_sv_undef);
+ PUSHs(sv_2mortal(newSVpv((char*) sysid, 0)));
+ if (pubid)
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) pubid, 0)));
+ PUTBACK ;
+ count = perl_call_sv(cbv->extent_sv, G_SCALAR);
+
+ SPAGAIN ;
+
+ if (count >= 1) {
+ SV * result = POPs;
+ int type;
+
+ if (result && (type = SvTYPE(result)) > 0) {
+ SV **pval = hv_fetch((HV*) SvRV(cbv->self_sv), "Parser", 6, 0);
+
+ if (! pval || ! SvIOK(*pval))
+ append_error(parser, "Can't find parser entry in XML::Parser object");
+ else {
+ XML_Parser entpar;
+ char *errmsg = (char *) 0;
+
+ entpar = XML_ExternalEntityParserCreate(parser, open, 0);
+
+ XML_SetBase(entpar, XML_GetBase(parser));
+
+ sv_setiv(*pval, (IV) entpar);
+
+ cbv->p = entpar;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(*pval);
+ PUSHs(result);
+ PUTBACK;
+ count = perl_call_pv("XML::Parser::Expat::Do_External_Parse",
+ G_SCALAR | G_EVAL);
+ SPAGAIN;
+
+ if (SvTRUE(ERRSV)) {
+ char *hold;
+ STRLEN len;
+
+ POPs;
+ hold = SvPV(ERRSV, len);
+ New(326, errmsg, len + 1, char);
+ if (len)
+ Copy(hold, errmsg, len, char);
+ goto Extparse_Cleanup;
+ }
+
+ if (count > 0)
+ ret = POPi;
+
+ parse_done = 1;
+
+ Extparse_Cleanup:
+ cbv->p = parser;
+ sv_setiv(*pval, (IV) parser);
+ XML_ParserFree(entpar);
+
+ if (cbv->extfin_sv) {
+ PUSHMARK(sp);
+ PUSHs(cbv->self_sv);
+ PUTBACK;
+ perl_call_sv(cbv->extfin_sv, G_DISCARD);
+ SPAGAIN;
+ }
+
+ if (SvTRUE(ERRSV))
+ append_error(parser, SvPV(ERRSV, PL_na));
+ }
+ }
+ }
+
+ if (! ret && ! parse_done)
+ append_error(parser, "Handler couldn't resolve external entity");
+
+ PUTBACK ;
+ FREETMPS ;
+ LEAVE ;
+
+ return ret;
+} /* End externalEntityRef */
+
+/*================================================================
+** This is the function that expat calls to convert multi-byte sequences
+** for external encodings. Each byte in the sequence is used to index
+** into the current map to either set the next map or, in the case of
+** the final byte, to get the corresponding Unicode scalar, which is
+** returned.
+*/
+
+static int
+convert_to_unicode(void *data, const char *seq) {
+ Encinfo *enc = (Encinfo *) data;
+ PrefixMap *curpfx;
+ int count;
+ int index = 0;
+
+ for (count = 0; count < 4; count++) {
+ unsigned char byte = (unsigned char) seq[count];
+ unsigned char bndx;
+ unsigned char bmsk;
+ int offset;
+
+ curpfx = &enc->prefixes[index];
+ offset = ((int) byte) - curpfx->min;
+ if (offset < 0)
+ break;
+ if (offset >= curpfx->len && curpfx->len != 0)
+ break;
+
+ bndx = byte >> 3;
+ bmsk = 1 << (byte & 0x7);
+
+ if (curpfx->ispfx[bndx] & bmsk) {
+ index = enc->bytemap[curpfx->bmap_start + offset];
+ }
+ else if (curpfx->ischar[bndx] & bmsk) {
+ return enc->bytemap[curpfx->bmap_start + offset];
+ }
+ else
+ break;
+ }
+
+ return -1;
+} /* End convert_to_unicode */
+
+static int
+unknownEncoding(void *unused, const char *name, XML_Encoding *info)
+{
+ SV ** encinfptr;
+ Encinfo *enc;
+ int namelen;
+ int i;
+ char buff[42];
+
+ namelen = strlen(name);
+ if (namelen > 40)
+ return 0;
+
+ /* Make uppercase */
+ for (i = 0; i < namelen; i++) {
+ char c = name[i];
+ if (c >= 'a' && c <= 'z')
+ c -= 'a' - 'A';
+ buff[i] = c;
+ }
+
+ if (! EncodingTable) {
+ EncodingTable = perl_get_hv("XML::Parser::Expat::Encoding_Table", FALSE);
+ if (! EncodingTable)
+ croak("Can't find XML::Parser::Expat::Encoding_Table");
+ }
+
+ encinfptr = hv_fetch(EncodingTable, buff, namelen, 0);
+
+ if (! encinfptr || ! SvOK(*encinfptr)) {
+ /* Not found, so try to autoload */
+ dSP;
+ int count;
+
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(sp);
+ XPUSHs(sv_2mortal(newSVpvn(buff,namelen)));
+ PUTBACK;
+ perl_call_pv("XML::Parser::Expat::load_encoding", G_DISCARD);
+
+ encinfptr = hv_fetch(EncodingTable, buff, namelen, 0);
+ FREETMPS;
+ LEAVE;
+
+ if (! encinfptr || ! SvOK(*encinfptr))
+ return 0;
+ }
+
+ if (! sv_derived_from(*encinfptr, "XML::Parser::Encinfo"))
+ croak("Entry in XML::Parser::Expat::Encoding_Table not an Encinfo object");
+
+ enc = (Encinfo *) SvIV((SV*)SvRV(*encinfptr));
+ Copy(enc->firstmap, info->map, 256, int);
+ info->release = NULL;
+ if (enc->prefixes_size) {
+ info->data = (void *) enc;
+ info->convert = convert_to_unicode;
+ }
+ else {
+ info->data = NULL;
+ info->convert = NULL;
+ }
+
+ return 1;
+} /* End unknownEncoding */
+
+
+static void
+recString(void *userData, const char *string, int len)
+{
+ CallbackVector *cbv = (CallbackVector*) userData;
+
+ if (cbv->recstring) {
+ sv_catpvn(cbv->recstring, (char *) string, len);
+ }
+ else {
+ cbv->recstring = newUTF8SVpvn((char *) string, len);
+ }
+} /* End recString */
+
+static void
+suspend_callbacks(CallbackVector *cbv) {
+ if (SvTRUE(cbv->char_sv)) {
+ XML_SetCharacterDataHandler(cbv->p,
+ (XML_CharacterDataHandler) 0);
+ }
+
+ if (SvTRUE(cbv->proc_sv)) {
+ XML_SetProcessingInstructionHandler(cbv->p,
+ (XML_ProcessingInstructionHandler) 0);
+ }
+
+ if (SvTRUE(cbv->cmnt_sv)) {
+ XML_SetCommentHandler(cbv->p,
+ (XML_CommentHandler) 0);
+ }
+
+ if (SvTRUE(cbv->startcd_sv)
+ || SvTRUE(cbv->endcd_sv)) {
+ XML_SetCdataSectionHandler(cbv->p,
+ (XML_StartCdataSectionHandler) 0,
+ (XML_EndCdataSectionHandler) 0);
+ }
+
+ if (SvTRUE(cbv->unprsd_sv)) {
+ XML_SetUnparsedEntityDeclHandler(cbv->p,
+ (XML_UnparsedEntityDeclHandler) 0);
+ }
+
+ if (SvTRUE(cbv->notation_sv)) {
+ XML_SetNotationDeclHandler(cbv->p,
+ (XML_NotationDeclHandler) 0);
+ }
+
+ if (SvTRUE(cbv->extent_sv)) {
+ XML_SetExternalEntityRefHandler(cbv->p,
+ (XML_ExternalEntityRefHandler) 0);
+ }
+
+} /* End suspend_callbacks */
+
+static void
+resume_callbacks(CallbackVector *cbv) {
+ if (SvTRUE(cbv->char_sv)) {
+ XML_SetCharacterDataHandler(cbv->p, characterData);
+ }
+
+ if (SvTRUE(cbv->proc_sv)) {
+ XML_SetProcessingInstructionHandler(cbv->p, processingInstruction);
+ }
+
+ if (SvTRUE(cbv->cmnt_sv)) {
+ XML_SetCommentHandler(cbv->p, commenthandle);
+ }
+
+ if (SvTRUE(cbv->startcd_sv)
+ || SvTRUE(cbv->endcd_sv)) {
+ XML_SetCdataSectionHandler(cbv->p, startCdata, endCdata);
+ }
+
+ if (SvTRUE(cbv->unprsd_sv)) {
+ XML_SetUnparsedEntityDeclHandler(cbv->p, unparsedEntityDecl);
+ }
+
+ if (SvTRUE(cbv->notation_sv)) {
+ XML_SetNotationDeclHandler(cbv->p, notationDecl);
+ }
+
+ if (SvTRUE(cbv->extent_sv)) {
+ XML_SetExternalEntityRefHandler(cbv->p, externalEntityRef);
+ }
+
+} /* End resume_callbacks */
+
+
+MODULE = XML::Parser::Expat PACKAGE = XML::Parser::Expat PREFIX = XML_
+
+XML_Parser
+XML_ParserCreate(self_sv, enc_sv, namespaces)
+ SV * self_sv
+ SV * enc_sv
+ int namespaces
+ CODE:
+ {
+ CallbackVector *cbv;
+ enum XML_ParamEntityParsing pep = XML_PARAM_ENTITY_PARSING_NEVER;
+ char *enc = (char *) (SvTRUE(enc_sv) ? SvPV(enc_sv,PL_na) : 0);
+ SV ** spp;
+
+ Newz(320, cbv, 1, CallbackVector);
+ cbv->self_sv = SvREFCNT_inc(self_sv);
+ Newz(325, cbv->st_serial_stack, 1024, unsigned int);
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "NoExpand", 8, 0);
+ if (spp && SvTRUE(*spp))
+ cbv->no_expand = 1;
+
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "Context", 7, 0);
+ if (! spp || ! *spp || !SvROK(*spp))
+ croak("XML::Parser instance missing Context");
+
+ cbv->context = (AV*) SvRV(*spp);
+
+ cbv->ns = (unsigned) namespaces;
+ if (namespaces)
+ {
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "New_Prefixes", 12, 0);
+ if (! spp || ! *spp || !SvROK(*spp))
+ croak("XML::Parser instance missing New_Prefixes");
+
+ cbv->new_prefix_list = (AV *) SvRV(*spp);
+
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "Namespace_Table",
+ 15, FALSE);
+ if (! spp || ! *spp || !SvROK(*spp))
+ croak("XML::Parser instance missing Namespace_Table");
+
+ cbv->nstab = (HV *) SvRV(*spp);
+
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "Namespace_List",
+ 14, FALSE);
+ if (! spp || ! *spp || !SvROK(*spp))
+ croak("XML::Parser instance missing Namespace_List");
+
+ cbv->nslst = (AV *) SvRV(*spp);
+
+ RETVAL = XML_ParserCreate_MM(enc, &ms, nsdelim);
+ XML_SetNamespaceDeclHandler(RETVAL,nsStart, nsEnd);
+ }
+ else
+ {
+ RETVAL = XML_ParserCreate_MM(enc, &ms, NULL);
+ }
+
+ cbv->p = RETVAL;
+ XML_SetUserData(RETVAL, (void *) cbv);
+ XML_SetElementHandler(RETVAL, startElement, endElement);
+ XML_SetUnknownEncodingHandler(RETVAL, unknownEncoding, 0);
+
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "ParseParamEnt",
+ 13, FALSE);
+
+ if (spp && SvTRUE(*spp)) {
+ pep = XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE;
+ cbv->parseparam = 1;
+ }
+
+ XML_SetParamEntityParsing(RETVAL, pep);
+ }
+ OUTPUT:
+ RETVAL
+
+void
+XML_ParserRelease(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ SvREFCNT_dec(cbv->self_sv);
+ }
+
+void
+XML_ParserFree(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ Safefree(cbv->st_serial_stack);
+
+
+ /* Clean up any SVs that we have */
+ /* (Note that self_sv must already be taken care of
+ or we couldn't be here */
+
+ if (cbv->recstring)
+ SvREFCNT_dec(cbv->recstring);
+
+ if (cbv->start_sv)
+ SvREFCNT_dec(cbv->start_sv);
+
+ if (cbv->end_sv)
+ SvREFCNT_dec(cbv->end_sv);
+
+ if (cbv->char_sv)
+ SvREFCNT_dec(cbv->char_sv);
+
+ if (cbv->proc_sv)
+ SvREFCNT_dec(cbv->proc_sv);
+
+ if (cbv->cmnt_sv)
+ SvREFCNT_dec(cbv->cmnt_sv);
+
+ if (cbv->dflt_sv)
+ SvREFCNT_dec(cbv->dflt_sv);
+
+ if (cbv->entdcl_sv)
+ SvREFCNT_dec(cbv->entdcl_sv);
+
+ if (cbv->eledcl_sv)
+ SvREFCNT_dec(cbv->eledcl_sv);
+
+ if (cbv->attdcl_sv)
+ SvREFCNT_dec(cbv->attdcl_sv);
+
+ if (cbv->doctyp_sv)
+ SvREFCNT_dec(cbv->doctyp_sv);
+
+ if (cbv->doctypfin_sv)
+ SvREFCNT_dec(cbv->doctypfin_sv);
+
+ if (cbv->xmldec_sv)
+ SvREFCNT_dec(cbv->xmldec_sv);
+
+ if (cbv->unprsd_sv)
+ SvREFCNT_dec(cbv->unprsd_sv);
+
+ if (cbv->notation_sv)
+ SvREFCNT_dec(cbv->notation_sv);
+
+ if (cbv->extent_sv)
+ SvREFCNT_dec(cbv->extent_sv);
+
+ if (cbv->extfin_sv)
+ SvREFCNT_dec(cbv->extfin_sv);
+
+ if (cbv->startcd_sv)
+ SvREFCNT_dec(cbv->startcd_sv);
+
+ if (cbv->endcd_sv)
+ SvREFCNT_dec(cbv->endcd_sv);
+
+ /* ================ */
+
+ Safefree(cbv);
+ XML_ParserFree(parser);
+ }
+
+int
+XML_ParseString(parser, sv)
+ XML_Parser parser
+ SV * sv
+ CODE:
+ {
+ CallbackVector * cbv;
+ STRLEN len;
+ char *s = SvPV(sv, len);
+
+ cbv = (CallbackVector *) XML_GetUserData(parser);
+
+
+ RETVAL = XML_Parse(parser, s, len, 1);
+ SPAGAIN; /* XML_Parse might have changed stack pointer */
+ if (! RETVAL)
+ append_error(parser, NULL);
+ }
+
+ OUTPUT:
+ RETVAL
+
+int
+XML_ParseStream(parser, ioref, delim)
+ XML_Parser parser
+ SV * ioref
+ SV * delim
+ CODE:
+ {
+ SV **delimsv;
+ CallbackVector * cbv;
+
+ cbv = (CallbackVector *) XML_GetUserData(parser);
+ if (SvOK(delim)) {
+ cbv->delim = SvPV(delim, cbv->delimlen);
+ }
+ else {
+ cbv->delim = (char *) 0;
+ }
+
+ RETVAL = parse_stream(parser, ioref);
+ SPAGAIN; /* parse_stream might have changed stack pointer */
+ }
+
+ OUTPUT:
+ RETVAL
+
+int
+XML_ParsePartial(parser, sv)
+ XML_Parser parser
+ SV * sv
+ CODE:
+ {
+ STRLEN len;
+ char *s = SvPV(sv, len);
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ RETVAL = XML_Parse(parser, s, len, 0);
+ if (! RETVAL)
+ append_error(parser, NULL);
+ }
+
+ OUTPUT:
+ RETVAL
+
+
+int
+XML_ParseDone(parser)
+ XML_Parser parser
+ CODE:
+ {
+ RETVAL = XML_Parse(parser, "", 0, 1);
+ if (! RETVAL)
+ append_error(parser, NULL);
+ }
+
+ OUTPUT:
+ RETVAL
+
+SV *
+XML_SetStartElementHandler(parser, start_sv)
+ XML_Parser parser
+ SV * start_sv
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+ XMLP_UPD(start_sv);
+ PUSHRET;
+ }
+
+SV *
+XML_SetEndElementHandler(parser, end_sv)
+ XML_Parser parser
+ SV * end_sv
+ CODE:
+ {
+ CallbackVector *cbv = (CallbackVector*) XML_GetUserData(parser);
+ XMLP_UPD(end_sv);
+ PUSHRET;
+ }
+
+SV *
+XML_SetCharacterDataHandler(parser, char_sv)
+ XML_Parser parser
+ SV * char_sv
+ CODE:
+ {
+ XML_CharacterDataHandler charhndl = (XML_CharacterDataHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(char_sv);
+ if (SvTRUE(char_sv))
+ charhndl = characterData;
+
+ XML_SetCharacterDataHandler(parser, charhndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetProcessingInstructionHandler(parser, proc_sv)
+ XML_Parser parser
+ SV * proc_sv
+ CODE:
+ {
+ XML_ProcessingInstructionHandler prochndl =
+ (XML_ProcessingInstructionHandler) 0;
+ CallbackVector* cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(proc_sv);
+ if (SvTRUE(proc_sv))
+ prochndl = processingInstruction;
+
+ XML_SetProcessingInstructionHandler(parser, prochndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetCommentHandler(parser, cmnt_sv)
+ XML_Parser parser
+ SV * cmnt_sv
+ CODE:
+ {
+ XML_CommentHandler cmnthndl = (XML_CommentHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(cmnt_sv);
+ if (SvTRUE(cmnt_sv))
+ cmnthndl = commenthandle;
+
+ XML_SetCommentHandler(parser, cmnthndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetDefaultHandler(parser, dflt_sv)
+ XML_Parser parser
+ SV * dflt_sv
+ CODE:
+ {
+ XML_DefaultHandler dflthndl = (XML_DefaultHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(dflt_sv);
+ if (SvTRUE(dflt_sv))
+ dflthndl = defaulthandle;
+
+ if (cbv->no_expand)
+ XML_SetDefaultHandler(parser, dflthndl);
+ else
+ XML_SetDefaultHandlerExpand(parser, dflthndl);
+
+ PUSHRET;
+ }
+
+SV *
+XML_SetUnparsedEntityDeclHandler(parser, unprsd_sv)
+ XML_Parser parser
+ SV * unprsd_sv
+ CODE:
+ {
+ XML_UnparsedEntityDeclHandler unprsdhndl =
+ (XML_UnparsedEntityDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(unprsd_sv);
+ if (SvTRUE(unprsd_sv))
+ unprsdhndl = unparsedEntityDecl;
+
+ XML_SetUnparsedEntityDeclHandler(parser, unprsdhndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetNotationDeclHandler(parser, notation_sv)
+ XML_Parser parser
+ SV * notation_sv
+ CODE:
+ {
+ XML_NotationDeclHandler nothndlr = (XML_NotationDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(notation_sv);
+ if (SvTRUE(notation_sv))
+ nothndlr = notationDecl;
+
+ XML_SetNotationDeclHandler(parser, nothndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetExternalEntityRefHandler(parser, extent_sv)
+ XML_Parser parser
+ SV * extent_sv
+ CODE:
+ {
+ XML_ExternalEntityRefHandler exthndlr =
+ (XML_ExternalEntityRefHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(extent_sv);
+ if (SvTRUE(extent_sv))
+ exthndlr = externalEntityRef;
+
+ XML_SetExternalEntityRefHandler(parser, exthndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetExtEntFinishHandler(parser, extfin_sv)
+ XML_Parser parser
+ SV * extfin_sv
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ /* There is no corresponding handler for this in expat. This is
+ called from the externalEntityRef function above after parsing
+ the external entity. */
+
+ XMLP_UPD(extfin_sv);
+ PUSHRET;
+ }
+
+
+SV *
+XML_SetEntityDeclHandler(parser, entdcl_sv)
+ XML_Parser parser
+ SV * entdcl_sv
+ CODE:
+ {
+ XML_EntityDeclHandler enthndlr =
+ (XML_EntityDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(entdcl_sv);
+ if (SvTRUE(entdcl_sv))
+ enthndlr = entityDecl;
+
+ XML_SetEntityDeclHandler(parser, enthndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetElementDeclHandler(parser, eledcl_sv)
+ XML_Parser parser
+ SV * eledcl_sv
+ CODE:
+ {
+ XML_ElementDeclHandler eldeclhndlr =
+ (XML_ElementDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(eledcl_sv);
+ if (SvTRUE(eledcl_sv))
+ eldeclhndlr = elementDecl;
+
+ XML_SetElementDeclHandler(parser, eldeclhndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetAttListDeclHandler(parser, attdcl_sv)
+ XML_Parser parser
+ SV * attdcl_sv
+ CODE:
+ {
+ XML_AttlistDeclHandler attdeclhndlr =
+ (XML_AttlistDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(attdcl_sv);
+ if (SvTRUE(attdcl_sv))
+ attdeclhndlr = attributeDecl;
+
+ XML_SetAttlistDeclHandler(parser, attdeclhndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetDoctypeHandler(parser, doctyp_sv)
+ XML_Parser parser
+ SV * doctyp_sv
+ CODE:
+ {
+ XML_StartDoctypeDeclHandler dtsthndlr =
+ (XML_StartDoctypeDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+ int set = 0;
+
+ XMLP_UPD(doctyp_sv);
+ if (SvTRUE(doctyp_sv))
+ dtsthndlr = doctypeStart;
+
+ XML_SetStartDoctypeDeclHandler(parser, dtsthndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetEndDoctypeHandler(parser, doctypfin_sv)
+ XML_Parser parser
+ SV * doctypfin_sv
+ CODE:
+ {
+ XML_EndDoctypeDeclHandler dtendhndlr =
+ (XML_EndDoctypeDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(doctypfin_sv);
+ if (SvTRUE(doctypfin_sv))
+ dtendhndlr = doctypeEnd;
+
+ XML_SetEndDoctypeDeclHandler(parser, dtendhndlr);
+ PUSHRET;
+ }
+
+
+SV *
+XML_SetXMLDeclHandler(parser, xmldec_sv)
+ XML_Parser parser
+ SV * xmldec_sv
+ CODE:
+ {
+ XML_XmlDeclHandler xmldechndlr =
+ (XML_XmlDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ XMLP_UPD(xmldec_sv);
+ if (SvTRUE(xmldec_sv))
+ xmldechndlr = xmlDecl;
+
+ XML_SetXmlDeclHandler(parser, xmldechndlr);
+ PUSHRET;
+ }
+
+
+void
+XML_SetBase(parser, base)
+ XML_Parser parser
+ SV * base
+ CODE:
+ {
+ char * b;
+
+ if (! SvOK(base)) {
+ b = (char *) 0;
+ }
+ else {
+ b = SvPV(base, PL_na);
+ }
+
+ XML_SetBase(parser, b);
+ }
+
+
+SV *
+XML_GetBase(parser)
+ XML_Parser parser
+ CODE:
+ {
+ const char *ret = XML_GetBase(parser);
+ if (ret) {
+ ST(0) = sv_newmortal();
+ sv_setpv(ST(0), ret);
+ }
+ else {
+ ST(0) = &PL_sv_undef;
+ }
+ }
+
+void
+XML_PositionContext(parser, lines)
+ XML_Parser parser
+ int lines
+ PREINIT:
+ int parsepos;
+ int size;
+ const char *pos = XML_GetInputContext(parser, &parsepos, &size);
+ const char *markbeg;
+ const char *limit;
+ const char *markend;
+ int length, relpos;
+ int cnt;
+
+ PPCODE:
+ if (! pos)
+ return;
+
+ for (markbeg = &pos[parsepos], cnt = 0; markbeg >= pos; markbeg--)
+ {
+ if (*markbeg == '\n')
+ {
+ cnt++;
+ if (cnt > lines)
+ break;
+ }
+ }
+
+ markbeg++;
+
+ relpos = 0;
+ limit = &pos[size];
+ for (markend = &pos[parsepos + 1], cnt = 0;
+ markend < limit;
+ markend++)
+ {
+ if (*markend == '\n')
+ {
+ if (cnt == 0)
+ relpos = (markend - markbeg) + 1;
+ cnt++;
+ if (cnt > lines)
+ {
+ markend++;
+ break;
+ }
+ }
+ }
+
+ length = markend - markbeg;
+ if (relpos == 0)
+ relpos = length;
+
+ EXTEND(sp, 2);
+ PUSHs(sv_2mortal(newSVpvn((char *) markbeg, length)));
+ PUSHs(sv_2mortal(newSViv(relpos)));
+
+SV *
+GenerateNSName(name, xml_namespace, table, list)
+ SV * name
+ SV * xml_namespace
+ SV * table
+ SV * list
+ CODE:
+ {
+ STRLEN nmlen, nslen;
+ char * nmstr;
+ char * nsstr;
+ char * buff;
+ char * bp;
+ char * blim;
+
+ nmstr = SvPV(name, nmlen);
+ nsstr = SvPV(xml_namespace, nslen);
+
+ /* Form a namespace-name string that looks like expat's */
+ New(321, buff, nmlen + nslen + 2, char);
+ bp = buff;
+ blim = bp + nslen;
+ while (bp < blim)
+ *bp++ = *nsstr++;
+ *bp++ = NSDELIM;
+ blim = bp + nmlen;
+ while (bp < blim)
+ *bp++ = *nmstr++;
+ *bp = '\0';
+
+ RETVAL = gen_ns_name(buff, (HV *) SvRV(table), (AV *) SvRV(list));
+ Safefree(buff);
+ }
+ OUTPUT:
+ RETVAL
+
+void
+XML_DefaultCurrent(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ XML_DefaultCurrent(parser);
+ }
+
+SV *
+XML_RecognizedString(parser)
+ XML_Parser parser
+ CODE:
+ {
+ XML_DefaultHandler dflthndl = (XML_DefaultHandler) 0;
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ if (cbv->dflt_sv) {
+ dflthndl = defaulthandle;
+ }
+
+ if (cbv->recstring) {
+ sv_setpvn(cbv->recstring, "", 0);
+ }
+
+ if (cbv->no_expand)
+ XML_SetDefaultHandler(parser, recString);
+ else
+ XML_SetDefaultHandlerExpand(parser, recString);
+
+ XML_DefaultCurrent(parser);
+
+ if (cbv->no_expand)
+ XML_SetDefaultHandler(parser, dflthndl);
+ else
+ XML_SetDefaultHandlerExpand(parser, dflthndl);
+
+ RETVAL = newSVsv(cbv->recstring);
+ }
+ OUTPUT:
+ RETVAL
+
+int
+XML_GetErrorCode(parser)
+ XML_Parser parser
+
+int
+XML_GetCurrentLineNumber(parser)
+ XML_Parser parser
+
+
+int
+XML_GetCurrentColumnNumber(parser)
+ XML_Parser parser
+
+long
+XML_GetCurrentByteIndex(parser)
+ XML_Parser parser
+
+int
+XML_GetSpecifiedAttributeCount(parser)
+ XML_Parser parser
+
+char *
+XML_ErrorString(code)
+ int code
+ CODE:
+ const char *ret = XML_ErrorString(code);
+ ST(0) = sv_newmortal();
+ sv_setpv((SV*)ST(0), ret);
+
+SV *
+XML_LoadEncoding(data, size)
+ char * data
+ int size
+ CODE:
+ {
+ Encmap_Header *emh = (Encmap_Header *) data;
+ unsigned pfxsize, bmsize;
+
+ if (size < sizeof(Encmap_Header)
+ || ntohl(emh->magic) != ENCMAP_MAGIC) {
+ RETVAL = &PL_sv_undef;
+ }
+ else {
+ Encinfo *entry;
+ SV *sv;
+ PrefixMap *pfx;
+ unsigned short *bm;
+ int namelen;
+ int i;
+
+ pfxsize = ntohs(emh->pfsize);
+ bmsize = ntohs(emh->bmsize);
+
+ if (size != (sizeof(Encmap_Header)
+ + pfxsize * sizeof(PrefixMap)
+ + bmsize * sizeof(unsigned short))) {
+ RETVAL = &PL_sv_undef;
+ }
+ else {
+ /* Convert to uppercase and get name length */
+
+ for (i = 0; i < sizeof(emh->name); i++) {
+ char c = emh->name[i];
+
+ if (c == (char) 0)
+ break;
+
+ if (c >= 'a' && c <= 'z')
+ emh->name[i] -= 'a' - 'A';
+ }
+ namelen = i;
+
+ RETVAL = newSVpvn(emh->name, namelen);
+
+ New(322, entry, 1, Encinfo);
+ entry->prefixes_size = pfxsize;
+ entry->bytemap_size = bmsize;
+ for (i = 0; i < 256; i++) {
+ entry->firstmap[i] = ntohl(emh->map[i]);
+ }
+
+ pfx = (PrefixMap *) &data[sizeof(Encmap_Header)];
+ bm = (unsigned short *) (((char *) pfx)
+ + sizeof(PrefixMap) * pfxsize);
+
+ New(323, entry->prefixes, pfxsize, PrefixMap);
+ New(324, entry->bytemap, bmsize, unsigned short);
+
+ for (i = 0; i < pfxsize; i++, pfx++) {
+ PrefixMap *dest = &entry->prefixes[i];
+
+ dest->min = pfx->min;
+ dest->len = pfx->len;
+ dest->bmap_start = ntohs(pfx->bmap_start);
+ Copy(pfx->ispfx, dest->ispfx,
+ sizeof(pfx->ispfx) + sizeof(pfx->ischar), unsigned char);
+ }
+
+ for (i = 0; i < bmsize; i++)
+ entry->bytemap[i] = ntohs(bm[i]);
+
+ sv = newSViv(0);
+ sv_setref_pv(sv, "XML::Parser::Encinfo", (void *) entry);
+
+ if (! EncodingTable) {
+ EncodingTable
+ = perl_get_hv("XML::Parser::Expat::Encoding_Table",
+ FALSE);
+ if (! EncodingTable)
+ croak("Can't find XML::Parser::Expat::Encoding_Table");
+ }
+
+ hv_store(EncodingTable, emh->name, namelen, sv, 0);
+ }
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+void
+XML_FreeEncoding(enc)
+ Encinfo * enc
+ CODE:
+ Safefree(enc->bytemap);
+ Safefree(enc->prefixes);
+ Safefree(enc);
+
+SV *
+XML_OriginalString(parser)
+ XML_Parser parser
+ CODE:
+ {
+ int parsepos, size;
+ const char *buff = XML_GetInputContext(parser, &parsepos, &size);
+ if (buff) {
+ RETVAL = newSVpvn((char *) &buff[parsepos],
+ XML_GetCurrentByteCount(parser));
+ }
+ else {
+ RETVAL = newSVpv("", 0);
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+SV *
+XML_SetStartCdataHandler(parser, startcd_sv)
+ XML_Parser parser
+ SV * startcd_sv
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+ XML_StartCdataSectionHandler scdhndl =
+ (XML_StartCdataSectionHandler) 0;
+
+ XMLP_UPD(startcd_sv);
+ if (SvTRUE(startcd_sv))
+ scdhndl = startCdata;
+
+ XML_SetStartCdataSectionHandler(parser, scdhndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetEndCdataHandler(parser, endcd_sv)
+ XML_Parser parser
+ SV * endcd_sv
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+ XML_EndCdataSectionHandler ecdhndl =
+ (XML_EndCdataSectionHandler) 0;
+
+ XMLP_UPD(endcd_sv);
+ if (SvTRUE(endcd_sv))
+ ecdhndl = endCdata;
+
+ XML_SetEndCdataSectionHandler(parser, ecdhndl);
+ PUSHRET;
+ }
+
+void
+XML_UnsetAllHandlers(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ suspend_callbacks(cbv);
+ if (cbv->ns) {
+ XML_SetNamespaceDeclHandler(cbv->p,
+ (XML_StartNamespaceDeclHandler) 0,
+ (XML_EndNamespaceDeclHandler) 0);
+ }
+
+ XML_SetElementHandler(parser,
+ (XML_StartElementHandler) 0,
+ (XML_EndElementHandler) 0);
+
+ XML_SetUnknownEncodingHandler(parser,
+ (XML_UnknownEncodingHandler) 0,
+ (void *) 0);
+ }
+
+int
+XML_ElementIndex(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+ RETVAL = cbv->st_serial_stack[cbv->st_serial_stackptr];
+ }
+ OUTPUT:
+ RETVAL
+
+void
+XML_SkipUntil(parser, index)
+ XML_Parser parser
+ unsigned int index
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+ if (index <= cbv->st_serial)
+ return;
+ cbv->skip_until = index;
+ suspend_callbacks(cbv);
+ }
+
+int
+XML_Do_External_Parse(parser, result)
+ XML_Parser parser
+ SV * result
+ CODE:
+ {
+ int type;
+
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ if (SvROK(result) && SvOBJECT(SvRV(result))) {
+ RETVAL = parse_stream(parser, result);
+ }
+ else if (isGV(result)) {
+ RETVAL = parse_stream(parser,
+ sv_2mortal(newRV((SV*) GvIOp(result))));
+ }
+ else if (SvPOK(result)) {
+ STRLEN eslen;
+ int pret;
+ char *entstr = SvPV(result, eslen);
+
+ RETVAL = XML_Parse(parser, entstr, eslen, 1);
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+