/***************************************************************** ** 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 #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