Aer/modules/xml/xml.c

1483 lines
53 KiB
C

#include "xml.h"
/*
* XML_ERROR_NONE
* Expand the value of SXML_ERROR_NO_MEMORY defined in ph7Int.h
*/
static void PH7_XML_ERROR_NONE_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_NO_MEMORY);
}
/*
* XML_ERROR_NO_MEMORY
* Expand the value of SXML_ERROR_NONE defined in ph7Int.h
*/
static void PH7_XML_ERROR_NO_MEMORY_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_NO_MEMORY);
}
/*
* XML_ERROR_SYNTAX
* Expand the value of SXML_ERROR_SYNTAX defined in ph7Int.h
*/
static void PH7_XML_ERROR_SYNTAX_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_SYNTAX);
}
/*
* XML_ERROR_NO_ELEMENTS
* Expand the value of SXML_ERROR_NO_ELEMENTS defined in ph7Int.h
*/
static void PH7_XML_ERROR_NO_ELEMENTS_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_NO_ELEMENTS);
}
/*
* XML_ERROR_INVALID_TOKEN
* Expand the value of SXML_ERROR_INVALID_TOKEN defined in ph7Int.h
*/
static void PH7_XML_ERROR_INVALID_TOKEN_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_INVALID_TOKEN);
}
/*
* XML_ERROR_UNCLOSED_TOKEN
* Expand the value of SXML_ERROR_UNCLOSED_TOKEN defined in ph7Int.h
*/
static void PH7_XML_ERROR_UNCLOSED_TOKEN_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_UNCLOSED_TOKEN);
}
/*
* XML_ERROR_PARTIAL_CHAR
* Expand the value of SXML_ERROR_PARTIAL_CHAR defined in ph7Int.h
*/
static void PH7_XML_ERROR_PARTIAL_CHAR_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_PARTIAL_CHAR);
}
/*
* XML_ERROR_TAG_MISMATCH
* Expand the value of SXML_ERROR_TAG_MISMATCH defined in ph7Int.h
*/
static void PH7_XML_ERROR_TAG_MISMATCH_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_TAG_MISMATCH);
}
/*
* XML_ERROR_DUPLICATE_ATTRIBUTE
* Expand the value of SXML_ERROR_DUPLICATE_ATTRIBUTE defined in ph7Int.h
*/
static void PH7_XML_ERROR_DUPLICATE_ATTRIBUTE_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_DUPLICATE_ATTRIBUTE);
}
/*
* XML_ERROR_JUNK_AFTER_DOC_ELEMENT
* Expand the value of SXML_ERROR_JUNK_AFTER_DOC_ELEMENT defined in ph7Int.h
*/
static void PH7_XML_ERROR_JUNK_AFTER_DOC_ELEMENT_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_JUNK_AFTER_DOC_ELEMENT);
}
/*
* XML_ERROR_PARAM_ENTITY_REF
* Expand the value of SXML_ERROR_PARAM_ENTITY_REF defined in ph7Int.h
*/
static void PH7_XML_ERROR_PARAM_ENTITY_REF_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_PARAM_ENTITY_REF);
}
/*
* XML_ERROR_UNDEFINED_ENTITY
* Expand the value of SXML_ERROR_UNDEFINED_ENTITY defined in ph7Int.h
*/
static void PH7_XML_ERROR_UNDEFINED_ENTITY_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_UNDEFINED_ENTITY);
}
/*
* XML_ERROR_RECURSIVE_ENTITY_REF
* Expand the value of SXML_ERROR_RECURSIVE_ENTITY_REF defined in ph7Int.h
*/
static void PH7_XML_ERROR_RECURSIVE_ENTITY_REF_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_RECURSIVE_ENTITY_REF);
}
/*
* XML_ERROR_ASYNC_ENTITY
* Expand the value of SXML_ERROR_ASYNC_ENTITY defined in ph7Int.h
*/
static void PH7_XML_ERROR_ASYNC_ENTITY_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_ASYNC_ENTITY);
}
/*
* XML_ERROR_BAD_CHAR_REF
* Expand the value of SXML_ERROR_BAD_CHAR_REF defined in ph7Int.h
*/
static void PH7_XML_ERROR_BAD_CHAR_REF_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_BAD_CHAR_REF);
}
/*
* XML_ERROR_BINARY_ENTITY_REF
* Expand the value of SXML_ERROR_BINARY_ENTITY_REF defined in ph7Int.h
*/
static void PH7_XML_ERROR_BINARY_ENTITY_REF_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_BINARY_ENTITY_REF);
}
/*
* XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF
* Expand the value of SXML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF defined in ph7Int.h
*/
static void PH7_XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF);
}
/*
* XML_ERROR_MISPLACED_XML_PI
* Expand the value of SXML_ERROR_MISPLACED_XML_PI defined in ph7Int.h
*/
static void PH7_XML_ERROR_MISPLACED_XML_PI_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_MISPLACED_XML_PI);
}
/*
* XML_ERROR_UNKNOWN_ENCODING
* Expand the value of SXML_ERROR_UNKNOWN_ENCODING defined in ph7Int.h
*/
static void PH7_XML_ERROR_UNKNOWN_ENCODING_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_UNKNOWN_ENCODING);
}
/*
* XML_ERROR_INCORRECT_ENCODING
* Expand the value of SXML_ERROR_INCORRECT_ENCODING defined in ph7Int.h
*/
static void PH7_XML_ERROR_INCORRECT_ENCODING_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_INCORRECT_ENCODING);
}
/*
* XML_ERROR_UNCLOSED_CDATA_SECTION
* Expand the value of SXML_ERROR_UNCLOSED_CDATA_SECTION defined in ph7Int.h
*/
static void PH7_XML_ERROR_UNCLOSED_CDATA_SECTION_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_UNCLOSED_CDATA_SECTION);
}
/*
* XML_ERROR_EXTERNAL_ENTITY_HANDLING
* Expand the value of SXML_ERROR_EXTERNAL_ENTITY_HANDLING defined in ph7Int.h
*/
static void PH7_XML_ERROR_EXTERNAL_ENTITY_HANDLING_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_ERROR_EXTERNAL_ENTITY_HANDLING);
}
/*
* XML_OPTION_CASE_FOLDING
* Expand the value of SXML_OPTION_CASE_FOLDING defined in ph7Int.h.
*/
static void PH7_XML_OPTION_CASE_FOLDING_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_OPTION_CASE_FOLDING);
}
/*
* XML_OPTION_TARGET_ENCODING
* Expand the value of SXML_OPTION_TARGET_ENCODING defined in ph7Int.h.
*/
static void PH7_XML_OPTION_TARGET_ENCODING_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_OPTION_TARGET_ENCODING);
}
/*
* XML_OPTION_SKIP_TAGSTART
* Expand the value of SXML_OPTION_SKIP_TAGSTART defined in ph7Int.h.
*/
static void PH7_XML_OPTION_SKIP_TAGSTART_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_OPTION_SKIP_TAGSTART);
}
/*
* XML_OPTION_SKIP_WHITE
* Expand the value of SXML_OPTION_SKIP_TAGSTART defined in ph7Int.h.
*/
static void PH7_XML_OPTION_SKIP_WHITE_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_int(pVal, SXML_OPTION_SKIP_WHITE);
}
/*
* XML_SAX_IMPL.
* Expand the name of the underlying XML engine.
*/
static void PH7_XML_SAX_IMP_Const(ph7_value *pVal, void *pUserData) {
SXUNUSED(pUserData); /* cc warning */
ph7_value_string(pVal, "Symisc XML engine", (int)sizeof("Symisc XML engine") - 1);
}
/*
* Allocate and initialize an XML engine.
*/
static ph7_xml_engine *VmCreateXMLEngine(ph7_context *pCtx, int process_ns, int ns_sep) {
ph7_xml_engine *pEngine;
ph7_vm *pVm = pCtx->pVm;
ph7_value *pValue;
sxu32 n;
/* Allocate a new instance */
pEngine = (ph7_xml_engine *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(ph7_xml_engine));
if(pEngine == 0) {
/* Out of memory */
return 0;
}
/* Zero the structure */
SyZero(pEngine, sizeof(ph7_xml_engine));
/* Initialize fields */
pEngine->pVm = pVm;
pEngine->pCtx = 0;
pEngine->ns_sep = ns_sep;
SyXMLParserInit(&pEngine->sParser, &pVm->sAllocator, process_ns ? SXML_ENABLE_NAMESPACE : 0);
SyBlobInit(&pEngine->sErr, &pVm->sAllocator);
PH7_MemObjInit(pVm, &pEngine->sParserValue);
for(n = 0 ; n < SX_ARRAYSIZE(pEngine->aCB) ; ++n) {
pValue = &pEngine->aCB[n];
/* NULLIFY the array entries,until someone register an event handler */
PH7_MemObjInit(&(*pVm), pValue);
}
ph7_value_resource(&pEngine->sParserValue, pEngine);
pEngine->iErrCode = SXML_ERROR_NONE;
/* Finally set the magic number */
pEngine->nMagic = XML_ENGINE_MAGIC;
return pEngine;
}
/*
* Release an XML engine.
*/
static void VmReleaseXMLEngine(ph7_xml_engine *pEngine) {
ph7_vm *pVm = pEngine->pVm;
ph7_value *pValue;
sxu32 n;
/* Release fields */
SyBlobRelease(&pEngine->sErr);
SyXMLParserRelease(&pEngine->sParser);
PH7_MemObjRelease(&pEngine->sParserValue);
for(n = 0 ; n < SX_ARRAYSIZE(pEngine->aCB) ; ++n) {
pValue = &pEngine->aCB[n];
PH7_MemObjRelease(pValue);
}
pEngine->nMagic = 0x2621;
/* Finally,release the whole instance */
SyMemBackendFree(&pVm->sAllocator, pEngine);
}
/*
* resource xml_parser_create([ string $encoding ])
* Create an UTF-8 XML parser.
* Parameter
* $encoding
* (Only UTF-8 encoding is used)
* Return
* Returns a resource handle for the new XML parser.
*/
static int vm_builtin_xml_parser_create(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
/* Allocate a new instance */
pEngine = VmCreateXMLEngine(&(*pCtx), 0, ':');
if(pEngine == 0) {
ph7_context_throw_error(pCtx, PH7_CTX_ERR, "PH7 is running out of memory");
/* Return null */
ph7_result_null(pCtx);
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
return PH7_OK;
}
/* Return the engine as a resource */
ph7_result_resource(pCtx, pEngine);
return PH7_OK;
}
/*
* resource xml_parser_create_ns([ string $encoding[,string $separator = ':']])
* Create an UTF-8 XML parser with namespace support.
* Parameter
* $encoding
* (Only UTF-8 encoding is supported)
* $separator
* Namespace separator (a single character)
* Return
* Returns a resource handle for the new XML parser.
*/
static int vm_builtin_xml_parser_create_ns(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
int ns_sep = ':';
if(nArg > 1 && ph7_value_is_string(apArg[1])) {
const char *zSep = ph7_value_to_string(apArg[1], 0);
if(zSep[0] != 0) {
ns_sep = zSep[0];
}
}
/* Allocate a new instance */
pEngine = VmCreateXMLEngine(&(*pCtx), TRUE, ns_sep);
if(pEngine == 0) {
ph7_context_throw_error(pCtx, PH7_CTX_ERR, "PH7 is running out of memory");
/* Return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Return the engine as a resource */
ph7_result_resource(pCtx, pEngine);
return PH7_OK;
}
/*
* bool xml_parser_free(resource $parser)
* Release an XML engine.
* Parameter
* $parser
* A reference to the XML parser to free.
* Return
* This function returns FALSE if parser does not refer
* to a valid parser, or else it frees the parser and returns TRUE.
*/
static int vm_builtin_xml_parser_free(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Safely release the engine */
VmReleaseXMLEngine(pEngine);
/* Return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* bool xml_set_element_handler(resource $parser,callback $start_element_handler,[callback $end_element_handler])
* Sets the element handler functions for the XML parser. start_element_handler and end_element_handler
* are strings containing the names of functions.
* Parameters
* $parser
* A reference to the XML parser to set up start and end element handler functions.
* $start_element_handler
* The function named by start_element_handler must accept three parameters:
* start_element_handler(resource $parser,string $name,array $attribs)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $name
* The second parameter, name, contains the name of the element for which this handler
* is called.If case-folding is in effect for this parser, the element name will be in uppercase letters.
* $attribs
* The third parameter, attribs, contains an associative array with the element's attributes (if any).
* The keys of this array are the attribute names, the values are the attribute values.
* Attribute names are case-folded on the same criteria as element names.Attribute values are not case-folded.
* The original order of the attributes can be retrieved by walking through attribs the normal way, using each().
* The first key in the array was the first attribute, and so on.
* Note: Instead of a function name, an array containing an object reference and a method name can also be supplied.
* $end_element_handler
* The function named by end_element_handler must accept two parameters:
* end_element_handler(resource $parser,string $name)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $name
* The second parameter, name, contains the name of the element for which this handler
* is called.If case-folding is in effect for this parser, the element name will be in uppercase
* letters.
* If a handler function is set to an empty string, or FALSE, the handler in question is disabled.
* Return
* TRUE on success or FALSE on failure.
*/
static int vm_builtin_xml_set_element_handler(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(nArg > 1) {
/* Save the start_element_handler callback for later invocation */
PH7_MemObjStore(apArg[1]/* User callback*/, &pEngine->aCB[PH7_XML_START_TAG]);
if(nArg > 2) {
/* Save the end_element_handler callback for later invocation */
PH7_MemObjStore(apArg[2]/* User callback*/, &pEngine->aCB[PH7_XML_END_TAG]);
}
}
/* All done,return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* bool xml_set_character_data_handler(resource $parser,callback $handler)
* Sets the character data handler function for the XML parser parser.
* Parameters
* $parser
* A reference to the XML parser to set up character data handler function.
* $handler
* handler is a string containing the name of the callback.
* The function named by handler must accept two parameters:
* handler(resource $parser,string $data)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $data
* The second parameter, data, contains the character data as a string.
* Character data handler is called for every piece of a text in the XML document.
* It can be called multiple times inside each fragment (e.g. for non-ASCII strings).
* If a handler function is set to an empty string, or FALSE, the handler in question is disabled.
* Note: Instead of a function name, an array containing an object reference and a method name
* can also be supplied.
* Return
* TRUE on success or FALSE on failure.
*/
static int vm_builtin_xml_set_character_data_handler(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(nArg > 1) {
/* Save the user callback for later invocation */
PH7_MemObjStore(apArg[1]/* User callback*/, &pEngine->aCB[PH7_XML_CDATA]);
}
/* All done,return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* bool xml_set_default_handler(resource $parser,callback $handler)
* Set up default handler.
* Parameters
* $parser
* A reference to the XML parser to set up character data handler function.
* $handler
* handler is a string containing the name of the callback.
* The function named by handler must accept two parameters:
* handler(resource $parser,string $data)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $data
* The second parameter, data, contains the character data.This may be the XML declaration
* document type declaration, entities or other data for which no other handler exists.
* Note: Instead of a function name, an array containing an object reference and a method name
* can also be supplied.
* Return
* TRUE on success or FALSE on failure.
*/
static int vm_builtin_xml_set_default_handler(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(nArg > 1) {
/* Save the user callback for later invocation */
PH7_MemObjStore(apArg[1]/* User callback*/, &pEngine->aCB[PH7_XML_DEF]);
}
/* All done,return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* bool xml_set_end_namespace_decl_handler(resource $parser,callback $handler)
* Set up end namespace declaration handler.
* Parameters
* $parser
* A reference to the XML parser to set up character data handler function.
* $handler
* handler is a string containing the name of the callback.
* The function named by handler must accept two parameters:
* handler(resource $parser,string $prefix)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $prefix
* The prefix is a string used to reference the namespace within an XML object.
* Note: Instead of a function name, an array containing an object reference and a method name
* can also be supplied.
* Return
* TRUE on success or FALSE on failure.
*/
static int vm_builtin_xml_set_end_namespace_decl_handler(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(nArg > 1) {
/* Save the user callback for later invocation */
PH7_MemObjStore(apArg[1]/* User callback*/, &pEngine->aCB[PH7_XML_NS_END]);
}
/* All done,return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* bool xml_set_start_namespace_decl_handler(resource $parser,callback $handler)
* Set up start namespace declaration handler.
* Parameters
* $parser
* A reference to the XML parser to set up character data handler function.
* $handler
* handler is a string containing the name of the callback.
* The function named by handler must accept two parameters:
* handler(resource $parser,string $prefix,string $uri)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $prefix
* The prefix is a string used to reference the namespace within an XML object.
* $uri
* Uniform Resource Identifier (URI) of namespace.
* Note: Instead of a function name, an array containing an object reference and a method name
* can also be supplied.
* Return
* TRUE on success or FALSE on failure.
*/
static int vm_builtin_xml_set_start_namespace_decl_handler(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(nArg > 1) {
/* Save the user callback for later invocation */
PH7_MemObjStore(apArg[1]/* User callback*/, &pEngine->aCB[PH7_XML_NS_START]);
}
/* All done,return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* bool xml_set_processing_instruction_handler(resource $parser,callback $handler)
* Set up processing instruction (PI) handler.
* Parameters
* $parser
* A reference to the XML parser to set up character data handler function.
* $handler
* handler is a string containing the name of the callback.
* The function named by handler must accept three parameters:
* handler(resource $parser,string $target,string $data)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $target
* The second parameter, target, contains the PI target.
* $data
The third parameter, data, contains the PI data.
* Note: Instead of a function name, an array containing an object reference and a method name
* can also be supplied.
* Return
* TRUE on success or FALSE on failure.
*/
static int vm_builtin_xml_set_processing_instruction_handler(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(nArg > 1) {
/* Save the user callback for later invocation */
PH7_MemObjStore(apArg[1]/* User callback*/, &pEngine->aCB[PH7_XML_PI]);
}
/* All done,return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* bool xml_set_unparsed_entity_decl_handler(resource $parser,callback $handler)
* Set up unparsed entity declaration handler.
* Parameters
* $parser
* A reference to the XML parser to set up character data handler function.
* $handler
* handler is a string containing the name of the callback.
* The function named by handler must accept six parameters:
* handler(resource $parser,string $entity_name,string $base,string $system_id,string $public_id,string $notation_name)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $entity_name
* The name of the entity that is about to be defined.
* $base
* This is the base for resolving the system identifier (systemId) of the external entity.
* Currently this parameter will always be set to an empty string.
* $system_id
* System identifier for the external entity.
* $public_id
* Public identifier for the external entity.
* $notation_name
* Name of the notation of this entity (see xml_set_notation_decl_handler()).
* Note: Instead of a function name, an array containing an object reference and a method name
* can also be supplied.
* Return
* TRUE on success or FALSE on failure.
*/
static int vm_builtin_xml_set_unparsed_entity_decl_handler(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(nArg > 1) {
/* Save the user callback for later invocation */
PH7_MemObjStore(apArg[1]/* User callback*/, &pEngine->aCB[PH7_XML_UNPED]);
}
/* All done,return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* bool xml_set_notation_decl_handler(resource $parser,callback $handler)
* Set up notation declaration handler.
* Parameters
* $parser
* A reference to the XML parser to set up character data handler function.
* $handler
* handler is a string containing the name of the callback.
* The function named by handler must accept five parameters:
* handler(resource $parser,string $entity_name,string $base,string $system_id,string $public_id)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $entity_name
* The name of the entity that is about to be defined.
* $base
* This is the base for resolving the system identifier (systemId) of the external entity.
* Currently this parameter will always be set to an empty string.
* $system_id
* System identifier for the external entity.
* $public_id
* Public identifier for the external entity.
* Note: Instead of a function name, an array containing an object reference and a method name
* can also be supplied.
* Return
* TRUE on success or FALSE on failure.
*/
static int vm_builtin_xml_set_notation_decl_handler(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(nArg > 1) {
/* Save the user callback for later invocation */
PH7_MemObjStore(apArg[1]/* User callback*/, &pEngine->aCB[PH7_XML_ND]);
}
/* All done,return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* bool xml_set_external_entity_ref_handler(resource $parser,callback $handler)
* Set up external entity reference handler.
* Parameters
* $parser
* A reference to the XML parser to set up character data handler function.
* $handler
* handler is a string containing the name of the callback.
* The function named by handler must accept five parameters:
* handler(resource $parser,string $open_entity_names,string $base,string $system_id,string $public_id)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $open_entity_names
* The second parameter, open_entity_names, is a space-separated list of the names
* of the entities that are open for the parse of this entity (including the name of the referenced entity).
* $base
* This is the base for resolving the system identifier (system_id) of the external entity.
* Currently this parameter will always be set to an empty string.
* $system_id
* The fourth parameter, system_id, is the system identifier as specified in the entity declaration.
* $public_id
* The fifth parameter, public_id, is the public identifier as specified in the entity declaration
* or an empty string if none was specified; the whitespace in the public identifier will have been
* normalized as required by the XML spec.
* Note: Instead of a function name, an array containing an object reference and a method name
* can also be supplied.
* Return
* TRUE on success or FALSE on failure.
*/
static int vm_builtin_xml_set_external_entity_ref_handler(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(nArg > 1) {
/* Save the user callback for later invocation */
PH7_MemObjStore(apArg[1]/* User callback*/, &pEngine->aCB[PH7_XML_EER]);
}
/* All done,return TRUE */
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* int xml_get_current_line_number(resource $parser)
* Gets the current line number for the given XML parser.
* Parameters
* $parser
* A reference to the XML parser.
* Return
* This function returns FALSE if parser does not refer
* to a valid parser, or else it returns which line the parser
* is currently at in its data buffer.
*/
static int vm_builtin_xml_get_current_line_number(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Return the line number */
ph7_result_int(pCtx, (int)pEngine->nLine);
return PH7_OK;
}
/*
* int xml_get_current_byte_index(resource $parser)
* Gets the current byte index of the given XML parser.
* Parameters
* $parser
* A reference to the XML parser.
* Return
* This function returns FALSE if parser does not refer to a valid
* parser, or else it returns which byte index the parser is currently
* at in its data buffer (starting at 0).
*/
static int vm_builtin_xml_get_current_byte_index(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
SyStream *pStream;
SyToken *pToken;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the current processed token */
pToken = (SyToken *)SySetPeekCurrentEntry(&pEngine->sParser.sToken);
if(pToken == 0) {
/* Stream not yet processed */
ph7_result_int(pCtx, 0);
return 0;
}
/* Point to the input stream */
pStream = &pEngine->sParser.sLex.sStream;
/* Return the byte index */
ph7_result_int64(pCtx, (ph7_int64)(pToken->sData.zString - (const char *)pStream->zInput));
return PH7_OK;
}
/*
* bool xml_set_object(resource $parser,object &$object)
* Use XML Parser within an object.
* NOTE
* This function is deprecated and is a no-op.
* Parameters
* $parser
* A reference to the XML parser.
* $object
* The object where to use the XML parser.
* Return
* Always FALSE.
*/
static int vm_builtin_xml_set_object(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_object(apArg[1])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Throw a notice and return */
ph7_context_throw_error(pCtx, PH7_CTX_NOTICE, "This function is depreceated and is a no-op."
"In order to mimic this behaviour,you can supply instead of a function name an array "
"containing an object reference and a method name."
);
/* Return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/*
* int xml_get_current_column_number(resource $parser)
* Gets the current column number of the given XML parser.
* Parameters
* $parser
* A reference to the XML parser.
* Return
* This function returns FALSE if parser does not refer to a valid parser, or else it returns
* which column on the current line (as given by xml_get_current_line_number()) the parser
* is currently at.
*/
static int vm_builtin_xml_get_current_column_number(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
SyStream *pStream;
SyToken *pToken;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the current processed token */
pToken = (SyToken *)SySetPeekCurrentEntry(&pEngine->sParser.sToken);
if(pToken == 0) {
/* Stream not yet processed */
ph7_result_int(pCtx, 0);
return 0;
}
/* Point to the input stream */
pStream = &pEngine->sParser.sLex.sStream;
/* Return the byte index */
ph7_result_int64(pCtx, (ph7_int64)(pToken->sData.zString - (const char *)pStream->zInput) / 80);
return PH7_OK;
}
/*
* int xml_get_error_code(resource $parser)
* Get XML parser error code.
* Parameters
* $parser
* A reference to the XML parser.
* Return
* This function returns FALSE if parser does not refer to a valid
* parser, or else it returns one of the error codes listed in the error
* codes section.
*/
static int vm_builtin_xml_get_error_code(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Return the error code if any */
ph7_result_int(pCtx, pEngine->iErrCode);
return PH7_OK;
}
/*
* XML parser event callbacks
* Each time the unserlying XML parser extract a single token
* from the input,one of the following callbacks are invoked.
* IMP-XML-ENGINE-07-07-2012 22:02 FreeBSD [chm@symisc.net]
*/
/*
* Create a scalar ph7_value holding the value
* of an XML tag/attribute/CDATA and so on.
*/
static ph7_value *VmXMLValue(ph7_xml_engine *pEngine, SyXMLRawStr *pXML, SyXMLRawStr *pNsUri) {
ph7_value *pValue;
/* Allocate a new scalar variable */
pValue = ph7_context_new_scalar(pEngine->pCtx);
if(pValue == 0) {
ph7_context_throw_error(pEngine->pCtx, PH7_CTX_ERR, "PH7 is running out of memory");
return 0;
}
if(pNsUri && pNsUri->nByte > 0) {
/* Append namespace URI and the separator */
ph7_value_string_format(pValue, "%.*s%c", pNsUri->nByte, pNsUri->zString, pEngine->ns_sep);
}
/* Copy the tag value */
ph7_value_string(pValue, pXML->zString, (int)pXML->nByte);
return pValue;
}
/*
* Create a 'ph7_value' of type array holding the values
* of an XML tag attributes.
*/
static ph7_value *VmXMLAttrValue(ph7_xml_engine *pEngine, SyXMLRawStr *aAttr, sxu32 nAttr) {
ph7_value *pArray;
/* Create an empty array */
pArray = ph7_context_new_array(pEngine->pCtx);
if(pArray == 0) {
ph7_context_throw_error(pEngine->pCtx, PH7_CTX_ERR, "PH7 is running out of memory");
return 0;
}
if(nAttr > 0) {
ph7_value *pKey, *pValue;
sxu32 n;
/* Create worker variables */
pKey = ph7_context_new_scalar(pEngine->pCtx);
pValue = ph7_context_new_scalar(pEngine->pCtx);
if(pKey == 0 || pValue == 0) {
ph7_context_throw_error(pEngine->pCtx, PH7_CTX_ERR, "PH7 is running out of memory");
return 0;
}
/* Copy attributes */
for(n = 0 ; n < nAttr ; n += 2) {
/* Reset string cursors */
ph7_value_reset_string_cursor(pKey);
ph7_value_reset_string_cursor(pValue);
/* Copy attribute name and it's associated value */
ph7_value_string(pKey, aAttr[n].zString, (int)aAttr[n].nByte); /* Attribute name */
ph7_value_string(pValue, aAttr[n + 1].zString, (int)aAttr[n + 1].nByte); /* Attribute value */
/* Insert in the array */
ph7_array_add_elem(pArray, pKey, pValue); /* Will make it's own copy */
}
/* Release the worker variables */
ph7_context_release_value(pEngine->pCtx, pKey);
ph7_context_release_value(pEngine->pCtx, pValue);
}
/* Return the freshly created array */
return pArray;
}
/*
* Start element handler.
* The user defined callback must accept three parameters:
* start_element_handler(resource $parser,string $name,array $attribs )
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $name
* The second parameter, name, contains the name of the element for which this handler
* is called.If case-folding is in effect for this parser, the element name will be in uppercase letters.
* $attribs
* The third parameter, attribs, contains an associative array with the element's attributes (if any).
* The keys of this array are the attribute names, the values are the attribute values.
* Attribute names are case-folded on the same criteria as element names.Attribute values are not case-folded.
* The original order of the attributes can be retrieved by walking through attribs the normal way, using each().
* The first key in the array was the first attribute, and so on.
* Note: Instead of a function name, an array containing an object reference and a method name can also be supplied.
*/
static sxi32 VmXMLStartElementHandler(SyXMLRawStr *pStart, SyXMLRawStr *pNS, sxu32 nAttr, SyXMLRawStr *aAttr, void *pUserData) {
ph7_xml_engine *pEngine = (ph7_xml_engine *)pUserData;
ph7_value *pCallback, *pTag, *pAttr;
/* Point to the target user defined callback */
pCallback = &pEngine->aCB[PH7_XML_START_TAG];
/* Make sure the given callback is callable */
if(!PH7_VmIsCallable(pEngine->pVm, pCallback, 0)) {
/* Not callable,return immediately*/
return SXRET_OK;
}
/* Create a ph7_value holding the tag name */
pTag = VmXMLValue(pEngine, pStart, pNS);
/* Create a ph7_value holding the tag attributes */
pAttr = VmXMLAttrValue(pEngine, aAttr, nAttr);
if(pTag == 0 || pAttr == 0) {
SXUNUSED(pNS); /* cc warning */
/* Out of mem,return immediately */
return SXRET_OK;
}
/* Invoke the user callback */
PH7_VmCallUserFunctionAp(pEngine->pVm, pCallback, 0, &pEngine->sParserValue, pTag, pAttr, 0);
/* Clean-up the mess left behind */
ph7_context_release_value(pEngine->pCtx, pTag);
ph7_context_release_value(pEngine->pCtx, pAttr);
return SXRET_OK;
}
/*
* End element handler.
* The user defined callback must accept two parameters:
* end_element_handler(resource $parser,string $name)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $name
* The second parameter, name, contains the name of the element for which this handler is called.
* If case-folding is in effect for this parser, the element name will be in uppercase letters.
* Note: Instead of a function name, an array containing an object reference and a method name
* can also be supplied.
*/
static sxi32 VmXMLEndElementHandler(SyXMLRawStr *pEnd, SyXMLRawStr *pNS, void *pUserData) {
ph7_xml_engine *pEngine = (ph7_xml_engine *)pUserData;
ph7_value *pCallback, *pTag;
/* Point to the target user defined callback */
pCallback = &pEngine->aCB[PH7_XML_END_TAG];
/* Make sure the given callback is callable */
if(!PH7_VmIsCallable(pEngine->pVm, pCallback, 0)) {
/* Not callable,return immediately*/
return SXRET_OK;
}
/* Create a ph7_value holding the tag name */
pTag = VmXMLValue(pEngine, pEnd, pNS);
if(pTag == 0) {
SXUNUSED(pNS); /* cc warning */
/* Out of mem,return immediately */
return SXRET_OK;
}
/* Invoke the user callback */
PH7_VmCallUserFunctionAp(pEngine->pVm, pCallback, 0, &pEngine->sParserValue, pTag, 0);
/* Clean-up the mess left behind */
ph7_context_release_value(pEngine->pCtx, pTag);
return SXRET_OK;
}
/*
* Character data handler.
* The user defined callback must accept two parameters:
* handler(resource $parser,string $data)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $data
* The second parameter, data, contains the character data as a string.
* Character data handler is called for every piece of a text in the XML document.
* It can be called multiple times inside each fragment (e.g. for non-ASCII strings).
* If a handler function is set to an empty string, or FALSE, the handler in question is disabled.
* Note: Instead of a function name, an array containing an object reference and a method name can also be supplied.
*/
static sxi32 VmXMLTextHandler(SyXMLRawStr *pText, void *pUserData) {
ph7_xml_engine *pEngine = (ph7_xml_engine *)pUserData;
ph7_value *pCallback, *pData;
/* Point to the target user defined callback */
pCallback = &pEngine->aCB[PH7_XML_CDATA];
/* Make sure the given callback is callable */
if(!PH7_VmIsCallable(pEngine->pVm, pCallback, 0)) {
/* Not callable,return immediately*/
return SXRET_OK;
}
/* Create a ph7_value holding the data */
pData = VmXMLValue(pEngine, &(*pText), 0);
if(pData == 0) {
/* Out of mem,return immediately */
return SXRET_OK;
}
/* Invoke the user callback */
PH7_VmCallUserFunctionAp(pEngine->pVm, pCallback, 0, &pEngine->sParserValue, pData, 0);
/* Clean-up the mess left behind */
ph7_context_release_value(pEngine->pCtx, pData);
return SXRET_OK;
}
/*
* Processing instruction (PI) handler.
* The user defined callback must accept two parameters:
* handler(resource $parser,string $target,string $data)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $target
* The second parameter, target, contains the PI target.
* $data
* The third parameter, data, contains the PI data.
* Note: Instead of a function name, an array containing an object reference
* and a method name can also be supplied.
*/
static sxi32 VmXMLPIHandler(SyXMLRawStr *pTargetStr, SyXMLRawStr *pDataStr, void *pUserData) {
ph7_xml_engine *pEngine = (ph7_xml_engine *)pUserData;
ph7_value *pCallback, *pTarget, *pData;
/* Point to the target user defined callback */
pCallback = &pEngine->aCB[PH7_XML_PI];
/* Make sure the given callback is callable */
if(!PH7_VmIsCallable(pEngine->pVm, pCallback, 0)) {
/* Not callable,return immediately*/
return SXRET_OK;
}
/* Get a ph7_value holding the data */
pTarget = VmXMLValue(pEngine, &(*pTargetStr), 0);
pData = VmXMLValue(pEngine, &(*pDataStr), 0);
if(pTarget == 0 || pData == 0) {
/* Out of mem,return immediately */
return SXRET_OK;
}
/* Invoke the user callback */
PH7_VmCallUserFunctionAp(pEngine->pVm, pCallback, 0, &pEngine->sParserValue, pTarget, pData, 0);
/* Clean-up the mess left behind */
ph7_context_release_value(pEngine->pCtx, pTarget);
ph7_context_release_value(pEngine->pCtx, pData);
return SXRET_OK;
}
/*
* Namespace declaration handler.
* The user defined callback must accept two parameters:
* handler(resource $parser,string $prefix,string $uri)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $prefix
* The prefix is a string used to reference the namespace within an XML object.
* $uri
* Uniform Resource Identifier (URI) of namespace.
* Note: Instead of a function name, an array containing an object reference
* and a method name can also be supplied.
*/
static sxi32 VmXMLNSStartHandler(SyXMLRawStr *pUriStr, SyXMLRawStr *pPrefixStr, void *pUserData) {
ph7_xml_engine *pEngine = (ph7_xml_engine *)pUserData;
ph7_value *pCallback, *pUri, *pPrefix;
/* Point to the target user defined callback */
pCallback = &pEngine->aCB[PH7_XML_NS_START];
/* Make sure the given callback is callable */
if(!PH7_VmIsCallable(pEngine->pVm, pCallback, 0)) {
/* Not callable,return immediately*/
return SXRET_OK;
}
/* Get a ph7_value holding the PREFIX/URI */
pUri = VmXMLValue(pEngine, pUriStr, 0);
pPrefix = VmXMLValue(pEngine, pPrefixStr, 0);
if(pUri == 0 || pPrefix == 0) {
/* Out of mem,return immediately */
return SXRET_OK;
}
/* Invoke the user callback */
PH7_VmCallUserFunctionAp(pEngine->pVm, pCallback, 0, &pEngine->sParserValue, pUri, pPrefix, 0);
/* Clean-up the mess left behind */
ph7_context_release_value(pEngine->pCtx, pUri);
ph7_context_release_value(pEngine->pCtx, pPrefix);
return SXRET_OK;
}
/*
* Namespace end declaration handler.
* The user defined callback must accept two parameters:
* handler(resource $parser,string $prefix)
* $parser
* The first parameter, parser, is a reference to the XML parser calling the handler.
* $prefix
* The prefix is a string used to reference the namespace within an XML object.
* Note: Instead of a function name, an array containing an object reference
* and a method name can also be supplied.
*/
static sxi32 VmXMLNSEndHandler(SyXMLRawStr *pPrefixStr, void *pUserData) {
ph7_xml_engine *pEngine = (ph7_xml_engine *)pUserData;
ph7_value *pCallback, *pPrefix;
/* Point to the target user defined callback */
pCallback = &pEngine->aCB[PH7_XML_NS_END];
/* Make sure the given callback is callable */
if(!PH7_VmIsCallable(pEngine->pVm, pCallback, 0)) {
/* Not callable,return immediately*/
return SXRET_OK;
}
/* Get a ph7_value holding the prefix */
pPrefix = VmXMLValue(pEngine, pPrefixStr, 0);
if(pPrefix == 0) {
/* Out of mem,return immediately */
return SXRET_OK;
}
/* Invoke the user callback */
PH7_VmCallUserFunctionAp(pEngine->pVm, pCallback, 0, &pEngine->sParserValue, pPrefix, 0);
/* Clean-up the mess left behind */
ph7_context_release_value(pEngine->pCtx, pPrefix);
return SXRET_OK;
}
/*
* Error Message consumer handler.
* Each time the XML parser encounter a syntax error or any other error
* related to XML processing,the following callback is invoked by the
* underlying XML parser.
*/
static sxi32 VmXMLErrorHandler(const char *zMessage, sxi32 iErrCode, SyToken *pToken, void *pUserData) {
ph7_xml_engine *pEngine = (ph7_xml_engine *)pUserData;
/* Save the error code */
pEngine->iErrCode = iErrCode;
SXUNUSED(zMessage); /* cc warning */
if(pToken) {
pEngine->nLine = pToken->nLine;
}
/* Abort XML processing immediately */
return SXERR_ABORT;
}
/*
* int xml_parse(resource $parser,string $data[,bool $is_final = false ])
* Parses an XML document. The handlers for the configured events are called
* as many times as necessary.
* Parameters
* $parser
* A reference to the XML parser.
* $data
* Chunk of data to parse. A document may be parsed piece-wise by calling
* xml_parse() several times with new data, as long as the is_final parameter
* is set and TRUE when the last data is parsed.
* $is_final
* NOT USED. This implementation require that all the processed input be
* entirely loaded in memory.
* Return
* Returns 1 on success or 0 on failure.
*/
static int vm_builtin_xml_parse(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
SyXMLParser *pParser;
const char *zData;
int nByte;
if(nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_string(apArg[1])) {
/* Missing/Ivalid arguments,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
if(pEngine->iNest > 0) {
/* This can happen when the user callback call xml_parse() again
* in it's body which is forbidden.
*/
ph7_context_throw_error_format(pCtx, PH7_CTX_ERR,
"Recursive call to %s,PH7 is returning false",
ph7_function_name(pCtx)
);
/* Return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
pEngine->pCtx = pCtx;
/* Point to the underlying XML parser */
pParser = &pEngine->sParser;
/* Register elements handler */
SyXMLParserSetEventHandler(pParser, pEngine,
VmXMLStartElementHandler,
VmXMLTextHandler,
VmXMLErrorHandler,
0,
VmXMLEndElementHandler,
VmXMLPIHandler,
0,
0,
VmXMLNSStartHandler,
VmXMLNSEndHandler
);
pEngine->iErrCode = SXML_ERROR_NONE;
/* Extract the raw XML input */
zData = ph7_value_to_string(apArg[1], &nByte);
/* Start the parse process */
pEngine->iNest++;
SyXMLProcess(pParser, zData, (sxu32)nByte);
pEngine->iNest--;
/* Return the parse result */
ph7_result_int(pCtx, pEngine->iErrCode == SXML_ERROR_NONE ? 1 : 0);
return PH7_OK;
}
/*
* bool xml_parser_set_option(resource $parser,int $option,mixed $value)
* Sets an option in an XML parser.
* Parameters
* $parser
* A reference to the XML parser to set an option in.
* $option
* Which option to set. See below.
* The following options are available:
* XML_OPTION_CASE_FOLDING integer Controls whether case-folding is enabled for this XML parser.
* XML_OPTION_SKIP_TAGSTART integer Specify how many characters should be skipped in the beginning of a tag name.
* XML_OPTION_SKIP_WHITE integer Whether to skip values consisting of whitespace characters.
* XML_OPTION_TARGET_ENCODING string Sets which target encoding to use in this XML parser.
* $value
* The option's new value.
* Return
* Returns 1 on success or 0 on failure.
* Note:
* Well,none of these options have meaning under the built-in XML parser so a call to this
* function is a no-op.
*/
static int vm_builtin_xml_parser_set_option(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
if(nArg < 2 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Always return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/*
* mixed xml_parser_get_option(resource $parser,int $option)
* Get options from an XML parser.
* Parameters
* $parser
* A reference to the XML parser to set an option in.
* $option
* Which option to fetch.
* Return
* This function returns FALSE if parser does not refer to a valid parser
* or if option isn't valid.Else the option's value is returned.
*/
static int vm_builtin_xml_parser_get_option(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_xml_engine *pEngine;
int nOp;
if(nArg < 2 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Ivalid argument,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the XML engine */
pEngine = (ph7_xml_engine *)ph7_value_to_resource(apArg[0]);
if(IS_INVALID_XML_ENGINE(pEngine)) {
/* Corrupt engine,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Extract the option */
nOp = ph7_value_to_int(apArg[1]);
switch(nOp) {
case SXML_OPTION_SKIP_TAGSTART:
case SXML_OPTION_SKIP_WHITE:
case SXML_OPTION_CASE_FOLDING:
ph7_result_int(pCtx, 0);
break;
case SXML_OPTION_TARGET_ENCODING:
ph7_result_string(pCtx, "UTF-8", (int)sizeof("UTF-8") - 1);
break;
default:
/* Unknown option,return FALSE*/
ph7_result_bool(pCtx, 0);
break;
}
return PH7_OK;
}
/*
* string xml_error_string(int $code)
* Gets the XML parser error string associated with the given code.
* Parameters
* $code
* An error code from xml_get_error_code().
* Return
* Returns a string with a textual description of the error
* code, or FALSE if no description was found.
*/
static int vm_builtin_xml_error_string(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int nErr = -1;
if(nArg > 0) {
nErr = ph7_value_to_int(apArg[0]);
}
switch(nErr) {
case SXML_ERROR_DUPLICATE_ATTRIBUTE:
ph7_result_string(pCtx, "Duplicate attribute", -1/*Compute length automatically*/);
break;
case SXML_ERROR_INCORRECT_ENCODING:
ph7_result_string(pCtx, "Incorrect encoding", -1);
break;
case SXML_ERROR_INVALID_TOKEN:
ph7_result_string(pCtx, "Unexpected token", -1);
break;
case SXML_ERROR_MISPLACED_XML_PI:
ph7_result_string(pCtx, "Misplaced processing instruction", -1);
break;
case SXML_ERROR_NO_MEMORY:
ph7_result_string(pCtx, "Out of memory", -1);
break;
case SXML_ERROR_NONE:
ph7_result_string(pCtx, "Not an error", -1);
break;
case SXML_ERROR_TAG_MISMATCH:
ph7_result_string(pCtx, "Tag mismatch", -1);
break;
case -1:
ph7_result_string(pCtx, "Unknown error code", -1);
break;
default:
ph7_result_string(pCtx, "Syntax error", -1);
break;
}
return PH7_OK;
}
PH7_PRIVATE sxi32 initializeModule(ph7_vm *pVm, ph7_real *ver, SyString *desc) {
sxi32 rc;
sxu32 n;
desc->zString = MODULE_DESC;
*ver = MODULE_VER;
for(n = 0; n < SX_ARRAYSIZE(xmlConstList); ++n) {
rc = ph7_create_constant(&(*pVm), xmlConstList[n].zName, xmlConstList[n].xExpand, &(*pVm));
if(rc != SXRET_OK) {
return rc;
}
}
for(n = 0; n < SX_ARRAYSIZE(xmlFuncList); ++n) {
rc = ph7_create_function(&(*pVm), xmlFuncList[n].zName, xmlFuncList[n].xFunc, &(*pVm));
if(rc != SXRET_OK) {
return rc;
}
}
return SXRET_OK;
}