#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_VmMemoryError(pCtx->pVm);
		/* 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_VmMemoryError(pCtx->pVm);
		/* 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_VmThrowError(pCtx->pVm, PH7_CTX_DEPRECATED, "This function is deprecated 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_VmMemoryError(pEngine->pCtx->pVm);
		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_VmMemoryError(pEngine->pCtx->pVm);
		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_VmMemoryError(pEngine->pCtx->pVm);
			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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
									   "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;
}