#include <stdarg.h>
#include <stdlib.h>
#include "perl-libxml-mm.h"
#include "XSUB.h"
#include "ppport.h"
#include <libxml/tree.h>
#ifdef XML_LIBXML_GDOME_SUPPORT
#include <libgdome/gdome.h>
#include <libgdome/gdome-libxml-util.h>
#endif
#include "perl-libxml-sax.h"
const
char
*
PmmNodeTypeName( xmlNodePtr elem ){
const
char
*name =
"XML::LibXML::Node"
;
if
( elem != NULL ) {
switch
( elem->type ) {
case
XML_ELEMENT_NODE:
name =
"XML::LibXML::Element"
;
break
;
case
XML_TEXT_NODE:
name =
"XML::LibXML::Text"
;
break
;
case
XML_COMMENT_NODE:
name =
"XML::LibXML::Comment"
;
break
;
case
XML_CDATA_SECTION_NODE:
name =
"XML::LibXML::CDATASection"
;
break
;
case
XML_ATTRIBUTE_NODE:
name =
"XML::LibXML::Attr"
;
break
;
case
XML_DOCUMENT_NODE:
case
XML_HTML_DOCUMENT_NODE:
name =
"XML::LibXML::Document"
;
break
;
case
XML_DOCUMENT_FRAG_NODE:
name =
"XML::LibXML::DocumentFragment"
;
break
;
case
XML_NAMESPACE_DECL:
name =
"XML::LibXML::Namespace"
;
break
;
case
XML_DTD_NODE:
name =
"XML::LibXML::Dtd"
;
break
;
case
XML_PI_NODE:
name =
"XML::LibXML::PI"
;
break
;
default
:
name =
"XML::LibXML::Node"
;
break
;
};
return
name;
}
return
""
;
}
void
PmmFreeHashTable(xmlHashTablePtr table)
{
if
( xmlHashSize(table) > 0 ) {
warn(
"PmmFreeHashTable: not empty\n"
);
}
xmlHashFree(table, NULL);
}
#ifdef XML_LIBXML_THREADS
extern
SV* PROXY_NODE_REGISTRY_MUTEX;
void
PmmRegistryDumpHashScanner(
void
* payload,
void
* data, xmlChar * name)
{
LocalProxyNodePtr lp = (LocalProxyNodePtr) payload;
ProxyNodePtr node = (ProxyNodePtr) lp->proxy;
const
char
* CLASS = PmmNodeTypeName( PmmNODE(node) );
warn(
"%s=%p with %d references (%d perl)\n"
,CLASS,node,PmmREFCNT(node),lp->count);
}
void
PmmDumpRegistry(xmlHashTablePtr r)
{
if
( r )
{
SvLOCK(PROXY_NODE_REGISTRY_MUTEX);
warn(
"%d total nodes\n"
, xmlHashSize(r));
xmlHashScan(r, PmmRegistryDumpHashScanner, NULL);
SvUNLOCK(PROXY_NODE_REGISTRY_MUTEX);
}
}
xmlHashTablePtr*
PmmProxyNodeRegistryPtr(ProxyNodePtr proxy)
{
croak(
"PmmProxyNodeRegistryPtr: TODO!\n"
);
return
NULL;
}
#define _PMM_HASH_NAME_SIZE(n) n+(n>>3)+(n%8>0 ? 1 : 0)
xmlChar *
PmmRegistryName(
void
* ptr)
{
unsigned
long
int
v = (unsigned
long
int
) ptr;
int
HASH_NAME_SIZE = _PMM_HASH_NAME_SIZE(
sizeof
(
void
*));
xmlChar * name;
int
i;
name = (xmlChar *) safemalloc(HASH_NAME_SIZE+1);
for
(i = 0; i < HASH_NAME_SIZE; ++i)
{
name[i] = (xmlChar) (128 | v);
v >>= 7;
}
name[HASH_NAME_SIZE] =
'\0'
;
return
name;
}
LocalProxyNodePtr
PmmNewLocalProxyNode(ProxyNodePtr proxy)
{
LocalProxyNodePtr lp;
Newc(0, lp, 1, LocalProxyNode, LocalProxyNode);
lp->proxy = proxy;
lp->count = 0;
return
lp;
}
LocalProxyNodePtr
PmmRegisterProxyNode(ProxyNodePtr proxy)
{
xmlChar * name = PmmRegistryName( proxy );
LocalProxyNodePtr lp = PmmNewLocalProxyNode( proxy );
SvLOCK(PROXY_NODE_REGISTRY_MUTEX);
if
( xmlHashAddEntry(PmmREGISTRY, name, lp) )
croak(
"PmmRegisterProxyNode: error adding node to hash, hash size is %d\n"
,xmlHashSize(PmmREGISTRY));
SvUNLOCK(PROXY_NODE_REGISTRY_MUTEX);
Safefree(name);
return
lp;
}
static
void
PmmRegistryHashDeallocator(
void
*payload, xmlChar *name)
{
Safefree((LocalProxyNodePtr) payload);
}
void
PmmUnregisterProxyNode(ProxyNodePtr proxy)
{
xmlChar * name = PmmRegistryName( proxy );
SvLOCK(PROXY_NODE_REGISTRY_MUTEX);
if
( xmlHashRemoveEntry(PmmREGISTRY, name, PmmRegistryHashDeallocator) )
croak(
"PmmUnregisterProxyNode: error removing node from hash\n"
);
Safefree(name);
SvUNLOCK(PROXY_NODE_REGISTRY_MUTEX);
}
LocalProxyNodePtr
PmmRegistryLookup(ProxyNodePtr proxy)
{
xmlChar * name = PmmRegistryName( proxy );
LocalProxyNodePtr lp = xmlHashLookup(PmmREGISTRY, name);
Safefree(name);
return
lp;
}
void
PmmRegistryREFCNT_inc(ProxyNodePtr proxy)
{
LocalProxyNodePtr lp = PmmRegistryLookup( proxy );
if
( lp )
lp->count++;
else
PmmRegisterProxyNode( proxy )->count++;
}
void
PmmRegistryREFCNT_dec(ProxyNodePtr proxy)
{
LocalProxyNodePtr lp = PmmRegistryLookup(proxy);
if
( lp && --(lp->count) == 0 )
PmmUnregisterProxyNode(proxy);
}
void
*
PmmRegistryHashCopier(
void
*payload, xmlChar *name)
{
ProxyNodePtr proxy = ((LocalProxyNodePtr) payload)->proxy;
LocalProxyNodePtr lp;
Newc(0, lp, 1, LocalProxyNode, LocalProxyNode);
memcpy
(lp, payload,
sizeof
(LocalProxyNode));
PmmREFCNT_inc(proxy);
return
lp;
}
void
PmmCloneProxyNodes()
{
SV *sv_reg = get_sv(
"XML::LibXML::__PROXY_NODE_REGISTRY"
,0);
xmlHashTablePtr reg_copy;
SvLOCK(PROXY_NODE_REGISTRY_MUTEX);
reg_copy = xmlHashCopy(PmmREGISTRY, PmmRegistryHashCopier);
SvIV_set(SvRV(sv_reg), PTR2IV(reg_copy));
SvUNLOCK(PROXY_NODE_REGISTRY_MUTEX);
}
int
PmmProxyNodeRegistrySize()
{
return
xmlHashSize(PmmREGISTRY);
}
#endif /* end of XML_LIBXML_THREADS */
ProxyNodePtr
PmmNewNode(xmlNodePtr node)
{
ProxyNodePtr proxy = NULL;
if
( node == NULL ) {
xs_warn(
"PmmNewNode: no node found\n"
);
return
NULL;
}
if
( node->_private == NULL ) {
switch
( node->type ) {
case
XML_DOCUMENT_NODE:
case
XML_HTML_DOCUMENT_NODE:
case
XML_DOCB_DOCUMENT_NODE:
proxy = (ProxyNodePtr)xmlMalloc(
sizeof
(
struct
_DocProxyNode));
if
(proxy != NULL) {
((DocProxyNodePtr)proxy)->psvi_status = Pmm_NO_PSVI;
SetPmmENCODING(proxy, XML_CHAR_ENCODING_NONE);
}
break
;
default
:
proxy = (ProxyNodePtr)xmlMalloc(
sizeof
(
struct
_ProxyNode));
break
;
}
if
(proxy != NULL) {
proxy->node = node;
proxy->owner = NULL;
proxy->count = 0;
node->_private = (
void
*) proxy;
}
}
else
{
proxy = (ProxyNodePtr)node->_private;
}
return
proxy;
}
ProxyNodePtr
PmmNewFragment(xmlDocPtr doc)
{
ProxyNodePtr retval = NULL;
xmlNodePtr frag = NULL;
xs_warn(
"PmmNewFragment: new frag\n"
);
frag = xmlNewDocFragment( doc );
retval = PmmNewNode(frag);
if
( doc != NULL ) {
xs_warn(
"PmmNewFragment: inc document\n"
);
if
( doc->_private != NULL ) {
xs_warn(
"PmmNewFragment: doc->_private being incremented!\n"
);
PmmREFCNT_inc(((ProxyNodePtr)doc->_private));
}
retval->owner = (xmlNodePtr)doc;
}
return
retval;
}
void
PmmFreeNode( xmlNodePtr node )
{
switch
( node->type ) {
case
XML_DOCUMENT_NODE:
case
XML_HTML_DOCUMENT_NODE:
xs_warn(
"PmmFreeNode: XML_DOCUMENT_NODE\n"
);
xmlFreeDoc( (xmlDocPtr) node );
break
;
case
XML_ATTRIBUTE_NODE:
xs_warn(
"PmmFreeNode: XML_ATTRIBUTE_NODE\n"
);
if
( node->parent == NULL ) {
xs_warn(
"PmmFreeNode: free node!\n"
);
node->ns = NULL;
xmlFreeProp( (xmlAttrPtr) node );
}
break
;
case
XML_DTD_NODE:
if
( node->doc != NULL ) {
if
( node->doc->extSubset != (xmlDtdPtr)node
&& node->doc->intSubset != (xmlDtdPtr)node ) {
xs_warn(
"PmmFreeNode: XML_DTD_NODE\n"
);
node->doc = NULL;
xmlFreeDtd( (xmlDtdPtr)node );
}
}
else
{
xs_warn(
"PmmFreeNode: XML_DTD_NODE (no doc)\n"
);
xmlFreeDtd( (xmlDtdPtr)node );
}
break
;
case
XML_DOCUMENT_FRAG_NODE:
xs_warn(
"PmmFreeNode: XML_DOCUMENT_FRAG_NODE\n"
);
default
:
xs_warn(
"PmmFreeNode: normal node\n"
);
xmlFreeNode( node);
break
;
}
}
int
PmmREFCNT_dec( ProxyNodePtr node )
{
xmlNodePtr libnode = NULL;
ProxyNodePtr owner = NULL;
int
retval = 0;
if
( node != NULL ) {
retval = PmmREFCNT(node)--;
if
( PmmREFCNT(node) < 0 )
warn(
"PmmREFCNT_dec: REFCNT decremented below 0 for %p!"
, node );
if
( PmmREFCNT(node) <= 0 ) {
xs_warn(
"PmmREFCNT_dec: NODE DELETION\n"
);
libnode = PmmNODE( node );
if
( libnode != NULL ) {
if
( libnode->_private != node ) {
xs_warn(
"PmmREFCNT_dec: lost node\n"
);
libnode = NULL;
}
else
{
libnode->_private = NULL;
}
}
PmmNODE( node ) = NULL;
if
( PmmOWNER(node) && PmmOWNERPO(node) ) {
xs_warn(
"PmmREFCNT_dec: DOC NODE!\n"
);
owner = PmmOWNERPO(node);
PmmOWNER( node ) = NULL;
if
( libnode != NULL && libnode->parent == NULL ) {
xs_warn(
"PmmREFCNT_dec: REAL DELETE\n"
);
PmmFreeNode( libnode );
}
xs_warn(
"PmmREFCNT_dec: decrease owner\n"
);
PmmREFCNT_dec( owner );
}
else
if
( libnode != NULL ) {
xs_warn(
"PmmREFCNT_dec: STANDALONE REAL DELETE\n"
);
PmmFreeNode( libnode );
}
else
{
xs_warn(
"PmmREFCNT_dec: NO OWNER\n"
);
}
xmlFree( node );
}
}
else
{
xs_warn(
"PmmREFCNT_dec: lost node\n"
);
}
return
retval;
}
SV*
PmmNodeToSv( xmlNodePtr node, ProxyNodePtr owner )
{
ProxyNodePtr dfProxy= NULL;
SV * retval = &PL_sv_undef;
const
char
* CLASS =
"XML::LibXML::Node"
;
if
( node != NULL ) {
#ifdef XML_LIBXML_THREADS
if
( PmmUSEREGISTRY )
SvLOCK(PROXY_NODE_REGISTRY_MUTEX);
#endif
CLASS = PmmNodeTypeName( node );
xs_warn(
"PmmNodeToSv: return new perl node of class:\n"
);
xs_warn( CLASS );
if
( node->_private != NULL ) {
dfProxy = PmmNewNode(node);
}
else
{
dfProxy = PmmNewNode(node);
if
( dfProxy != NULL ) {
if
( owner != NULL ) {
dfProxy->owner = PmmNODE( owner );
PmmREFCNT_inc( owner );
}
else
{
xs_warn(
"PmmNodeToSv: node contains itself (owner==NULL)\n"
);
}
}
else
{
croak(
"XML::LibXML: failed to create a proxy node (out of memory?)\n"
);
}
}
retval = NEWSV(0,0);
sv_setref_pv( retval, CLASS, (
void
*)dfProxy );
#ifdef XML_LIBXML_THREADS
if
( PmmUSEREGISTRY )
PmmRegistryREFCNT_inc(dfProxy);
#endif
PmmREFCNT_inc(dfProxy);
switch
( node->type ) {
case
XML_DOCUMENT_NODE:
case
XML_HTML_DOCUMENT_NODE:
case
XML_DOCB_DOCUMENT_NODE:
if
( ((xmlDocPtr)node)->encoding != NULL ) {
SetPmmENCODING(dfProxy, (
int
)xmlParseCharEncoding( (
const
char
*)((xmlDocPtr)node)->encoding ));
}
break
;
default
:
break
;
}
#ifdef XML_LIBXML_THREADS
if
( PmmUSEREGISTRY )
SvUNLOCK(PROXY_NODE_REGISTRY_MUTEX);
#endif
}
else
{
xs_warn(
"PmmNodeToSv: no node found!\n"
);
}
return
retval;
}
xmlNodePtr
PmmCloneNode( xmlNodePtr node,
int
recursive )
{
xmlNodePtr retval = NULL;
if
( node != NULL ) {
switch
( node->type ) {
case
XML_ELEMENT_NODE:
case
XML_TEXT_NODE:
case
XML_CDATA_SECTION_NODE:
case
XML_ENTITY_REF_NODE:
case
XML_PI_NODE:
case
XML_COMMENT_NODE:
case
XML_DOCUMENT_FRAG_NODE:
case
XML_ENTITY_DECL:
retval = xmlCopyNode( node, recursive ? 1 : 2 );
break
;
case
XML_ATTRIBUTE_NODE:
retval = (xmlNodePtr) xmlCopyProp( NULL, (xmlAttrPtr) node );
break
;
case
XML_DOCUMENT_NODE:
case
XML_HTML_DOCUMENT_NODE:
retval = (xmlNodePtr) xmlCopyDoc( (xmlDocPtr)node, recursive );
break
;
case
XML_DOCUMENT_TYPE_NODE:
case
XML_DTD_NODE:
retval = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr)node );
break
;
case
XML_NAMESPACE_DECL:
retval = ( xmlNodePtr ) xmlCopyNamespace( (xmlNsPtr) node );
break
;
default
:
break
;
}
}
return
retval;
}
xmlNodePtr
PmmSvNodeExt( SV* perlnode,
int
copy )
{
xmlNodePtr retval = NULL;
ProxyNodePtr proxy = NULL;
if
( perlnode != NULL && perlnode != &PL_sv_undef ) {
xs_warn(
"PmmSvNodeExt: perlnode found\n"
);
if
( sv_derived_from(perlnode,
"XML::LibXML::Node"
) ) {
proxy = SvPROXYNODE(perlnode);
if
( proxy != NULL ) {
xs_warn(
"PmmSvNodeExt: is a xmlNodePtr structure\n"
);
retval = PmmNODE( proxy ) ;
}
if
( retval != NULL
&& ((ProxyNodePtr)retval->_private) != proxy ) {
xs_warn(
"PmmSvNodeExt: no node in proxy node\n"
);
PmmNODE( proxy ) = NULL;
retval = NULL;
}
}
#ifdef XML_LIBXML_GDOME_SUPPORT
else
if
( sv_derived_from( perlnode,
"XML::GDOME::Node"
) ) {
GdomeNode* gnode = (GdomeNode*)SvIV((SV*)SvRV( perlnode ));
if
( gnode == NULL ) {
warn(
"no XML::GDOME data found (datastructure empty)"
);
}
else
{
retval = gdome_xml_n_get_xmlNode( gnode );
if
( retval == NULL ) {
xs_warn(
"PmmSvNodeExt: no XML::LibXML node found in GDOME object\n"
);
}
else
if
( copy == 1 ) {
retval = PmmCloneNode( retval, 1 );
}
}
}
#endif
}
return
retval;
}
xmlNodePtr
PmmSvOwner( SV* perlnode )
{
xmlNodePtr retval = NULL;
if
( perlnode != NULL
&& perlnode != &PL_sv_undef
&& SvPROXYNODE(perlnode) != NULL ) {
retval = PmmOWNER( SvPROXYNODE(perlnode) );
}
return
retval;
}
SV*
PmmSetSvOwner( SV* perlnode, SV* extra )
{
if
( perlnode != NULL && perlnode != &PL_sv_undef ) {
PmmOWNER( SvPROXYNODE(perlnode)) = PmmNODE( SvPROXYNODE(extra) );
PmmREFCNT_inc( SvPROXYNODE(extra) );
}
return
perlnode;
}
void
PmmFixOwnerList( xmlNodePtr list, ProxyNodePtr parent );
int
PmmFixOwner( ProxyNodePtr nodetofix, ProxyNodePtr parent )
{
ProxyNodePtr oldParent = NULL;
if
( nodetofix != NULL ) {
switch
( PmmNODE(nodetofix)->type ) {
case
XML_ENTITY_DECL:
case
XML_ATTRIBUTE_DECL:
case
XML_NAMESPACE_DECL:
case
XML_ELEMENT_DECL:
case
XML_DOCUMENT_NODE:
xs_warn(
"PmmFixOwner: don't need to fix this type of node\n"
);
return
(0);
default
:
break
;
}
if
( PmmOWNER(nodetofix) != NULL ) {
oldParent = PmmOWNERPO(nodetofix);
}
if
( oldParent != parent ) {
xs_warn(
"PmmFixOwner: re-parenting node\n"
);
if
( parent && parent != nodetofix ){
PmmOWNER(nodetofix) = PmmNODE(parent);
PmmREFCNT_inc( parent );
}
else
{
PmmOWNER(nodetofix) = NULL;
}
if
( oldParent != NULL && oldParent != nodetofix )
PmmREFCNT_dec(oldParent);
if
( PmmNODE(nodetofix)->type != XML_ATTRIBUTE_NODE
&& PmmNODE(nodetofix)->type != XML_DTD_NODE
&& PmmNODE(nodetofix)->properties != NULL ) {
PmmFixOwnerList( (xmlNodePtr)PmmNODE(nodetofix)->properties,
parent );
}
if
( parent == NULL || PmmNODE(nodetofix)->parent == NULL ) {
parent = nodetofix;
}
PmmFixOwnerList(PmmNODE(nodetofix)->children, parent);
}
else
{
xs_warn(
"PmmFixOwner: node doesn't need to get fixed\n"
);
}
return
(1);
}
return
(0);
}
void
PmmFixOwnerList( xmlNodePtr list, ProxyNodePtr parent )
{
if
( list != NULL ) {
xmlNodePtr iterator = list;
while
( iterator != NULL ) {
switch
( iterator->type ) {
case
XML_ENTITY_DECL:
case
XML_ATTRIBUTE_DECL:
case
XML_NAMESPACE_DECL:
case
XML_ELEMENT_DECL:
xs_warn(
"PmmFixOwnerList: don't need to fix this type of node\n"
);
iterator = iterator->next;
continue
;
break
;
default
:
break
;
}
if
( iterator->_private != NULL ) {
PmmFixOwner( (ProxyNodePtr)iterator->_private, parent );
}
else
{
if
( iterator->type != XML_ATTRIBUTE_NODE
&& iterator->properties != NULL ){
PmmFixOwnerList( (xmlNodePtr)iterator->properties, parent );
}
PmmFixOwnerList(iterator->children, parent);
}
iterator = iterator->next;
}
}
}
void
PmmFixOwnerNode( xmlNodePtr node, ProxyNodePtr parent )
{
if
( node != NULL && parent != NULL ) {
if
( node->_private != NULL ) {
xs_warn(
"PmmFixOwnerNode: calling PmmFixOwner\n"
);
PmmFixOwner( (ProxyNodePtr)(node->_private), parent );
}
else
{
xs_warn(
"PmmFixOwnerNode: calling PmmFixOwnerList\n"
);
PmmFixOwnerList(node->children, parent );
}
}
}
ProxyNodePtr
PmmNewContext(xmlParserCtxtPtr node)
{
ProxyNodePtr proxy = NULL;
proxy = (ProxyNodePtr)xmlMalloc(
sizeof
(ProxyNode));
if
(proxy != NULL) {
proxy->node = (xmlNodePtr)node;
proxy->owner = NULL;
proxy->count = 0;
}
else
{
warn(
"empty context"
);
}
return
proxy;
}
int
PmmContextREFCNT_dec( ProxyNodePtr node )
{
xmlParserCtxtPtr libnode = NULL;
int
retval = 0;
if
( node != NULL ) {
retval = PmmREFCNT(node)--;
if
( PmmREFCNT(node) <= 0 ) {
xs_warn(
"PmmContextREFCNT_dec: NODE DELETION\n"
);
libnode = (xmlParserCtxtPtr)PmmNODE( node );
if
( libnode != NULL ) {
if
(libnode->_private != NULL ) {
if
( libnode->_private != (
void
*)node ) {
PmmSAXCloseContext( libnode );
}
else
{
xmlFree( libnode->_private );
}
libnode->_private = NULL;
}
PmmNODE( node ) = NULL;
xmlFreeParserCtxt(libnode);
}
}
xmlFree( node );
}
return
retval;
}
SV*
PmmContextSv( xmlParserCtxtPtr ctxt )
{
ProxyNodePtr dfProxy= NULL;
SV * retval = &PL_sv_undef;
const
char
* CLASS =
"XML::LibXML::ParserContext"
;
if
( ctxt != NULL ) {
dfProxy = PmmNewContext(ctxt);
retval = NEWSV(0,0);
sv_setref_pv( retval, CLASS, (
void
*)dfProxy );
PmmREFCNT_inc(dfProxy);
}
else
{
xs_warn(
"PmmContextSv: no node found!\n"
);
}
return
retval;
}
xmlParserCtxtPtr
PmmSvContext( SV * scalar )
{
xmlParserCtxtPtr retval = NULL;
if
( scalar != NULL
&& scalar != &PL_sv_undef
&& sv_isa( scalar,
"XML::LibXML::ParserContext"
)
&& SvPROXYNODE(scalar) != NULL ) {
retval = (xmlParserCtxtPtr)PmmNODE( SvPROXYNODE(scalar) );
}
else
{
if
( scalar == NULL
&& scalar == &PL_sv_undef ) {
xs_warn(
"PmmSvContext: no scalar!\n"
);
}
else
if
( ! sv_isa( scalar,
"XML::LibXML::ParserContext"
) ) {
xs_warn(
"PmmSvContext: bad object\n"
);
}
else
if
(SvPROXYNODE(scalar) == NULL) {
xs_warn(
"PmmSvContext: empty object\n"
);
}
else
{
xs_warn(
"PmmSvContext: nothing was wrong!\n"
);
}
}
return
retval;
}
xmlChar*
PmmFastEncodeString(
int
charset,
const
xmlChar *string,
const
xmlChar *encoding,
STRLEN len )
{
xmlCharEncodingHandlerPtr coder = NULL;
xmlChar *retval = NULL;
xmlBufferPtr in = NULL, out = NULL;
int
i;
if
(len == 0)
len=xmlStrlen(string);
for
(i=0; i<len; i++) {
if
(!string[i] || string[i] & 0x80) {
break
;
}
}
if
(i>=len)
return
xmlStrdup( string );
xs_warn(
"PmmFastEncodeString: string is non-ascii\n"
);
if
( charset == XML_CHAR_ENCODING_ERROR){
if
(xmlStrcmp(encoding,(
const
xmlChar*)
"UTF-16LE"
)==0) {
charset = XML_CHAR_ENCODING_UTF16LE;
}
else
if
(xmlStrcmp(encoding,(
const
xmlChar*)
"UTF-16BE"
)==0) {
charset = XML_CHAR_ENCODING_UTF16BE;
}
}
if
( charset == XML_CHAR_ENCODING_UTF8 ) {
return
xmlStrdup( string );
}
else
if
( charset == XML_CHAR_ENCODING_UTF16LE || charset == XML_CHAR_ENCODING_UTF16BE ){
if
(len>=2 && (
char
)string[0]==
'\xFE'
&& (
char
)string[1]==
'\xFF'
) {
xs_warn(
"detected BE BOM\n"
);
string += 2;
len -= 2;
coder = xmlGetCharEncodingHandler( XML_CHAR_ENCODING_UTF16BE );
}
else
if
(len>=2 && (
char
)string[0]==
'\xFF'
&& (
char
)string[1]==
'\xFE'
) {
xs_warn(
"detected LE BOM\n"
);
string += 2;
len -= 2;
coder = xmlGetCharEncodingHandler( XML_CHAR_ENCODING_UTF16LE );
}
else
{
coder= xmlGetCharEncodingHandler( (xmlCharEncoding)charset );
}
}
else
if
( charset == XML_CHAR_ENCODING_ERROR ){
coder =xmlFindCharEncodingHandler( (
const
char
*)encoding );
}
else
if
( charset == XML_CHAR_ENCODING_NONE ){
xs_warn(
"PmmFastEncodeString: no encoding found\n"
);
}
else
{
coder= xmlGetCharEncodingHandler( (xmlCharEncoding)charset );
}
if
( coder != NULL ) {
xs_warn(
"PmmFastEncodeString: coding machine found \n"
);
in = xmlBufferCreateStatic((
void
*)string, len);
out = xmlBufferCreate();
if
( xmlCharEncInFunc( coder, out, in ) >= 0 ) {
retval = xmlStrdup( out->content );
}
else
{
}
xmlBufferFree( in );
xmlBufferFree( out );
xmlCharEncCloseFunc( coder );
}
return
retval;
}
xmlChar*
PmmFastDecodeString(
int
charset,
const
xmlChar *string,
const
xmlChar *encoding,
STRLEN* len )
{
xmlCharEncodingHandlerPtr coder = NULL;
xmlChar *retval = NULL;
xmlBufferPtr in = NULL, out = NULL;
if
(len==NULL)
return
NULL;
*len = 0;
if
( charset == XML_CHAR_ENCODING_ERROR){
if
(xmlStrcmp(encoding,(
const
xmlChar*)
"UTF-16LE"
)==0) {
charset = XML_CHAR_ENCODING_UTF16LE;
}
else
if
(xmlStrcmp(encoding,(
const
xmlChar*)
"UTF-16BE"
)==0) {
charset = XML_CHAR_ENCODING_UTF16BE;
}
}
if
( charset == XML_CHAR_ENCODING_UTF8 ) {
retval = xmlStrdup( string );
*len = xmlStrlen(retval);
}
else
if
( charset == XML_CHAR_ENCODING_ERROR ){
coder = xmlFindCharEncodingHandler( (
const
char
*) encoding );
}
else
if
( charset == XML_CHAR_ENCODING_NONE ){
warn(
"PmmFastDecodeString: no encoding found\n"
);
}
else
{
coder= xmlGetCharEncodingHandler( (xmlCharEncoding)charset );
}
if
( coder != NULL ) {
in = xmlBufferCreateStatic((
void
*)string,xmlStrlen(string));
out = xmlBufferCreate();
if
( xmlCharEncOutFunc( coder, out, in ) >= 0 ) {
*len = xmlBufferLength(out);
retval = xmlStrndup(xmlBufferContent(out), *len);
}
else
{
}
xmlBufferFree( in );
xmlBufferFree( out );
xmlCharEncCloseFunc( coder );
}
return
retval;
}
xmlChar*
PmmEncodeString(
const
char
*encoding,
const
xmlChar *string, STRLEN len ){
xmlCharEncoding enc;
xmlChar *ret = NULL;
if
( string != NULL ) {
if
( encoding != NULL ) {
xs_warn(
"PmmEncodeString: encoding to UTF-8 from:\n"
);
xs_warn( encoding );
enc = xmlParseCharEncoding( encoding );
ret = PmmFastEncodeString( enc, string, (
const
xmlChar *)encoding,len);
}
else
{
ret = xmlStrdup( string );
}
}
return
ret;
}
SV*
C2Sv(
const
xmlChar *string,
const
xmlChar *encoding )
{
SV *retval = &PL_sv_undef;
xmlCharEncoding enc;
if
( string != NULL ) {
if
( encoding != NULL ) {
enc = xmlParseCharEncoding( (
const
char
*)encoding );
}
else
{
enc = (xmlCharEncoding)0;
}
if
( enc == 0 ) {
enc = XML_CHAR_ENCODING_UTF8;
}
retval = newSVpvn( (
const
char
*)string, (STRLEN) xmlStrlen(string) );
if
( enc == XML_CHAR_ENCODING_UTF8 ) {
#ifdef HAVE_UTF8
xs_warn(
"C2Sv: set UTF8-SV-flag\n"
);
SvUTF8_on(retval);
#endif
}
}
return
retval;
}
xmlChar *
Sv2C( SV* scalar,
const
xmlChar *encoding )
{
xmlChar *retval = NULL;
xs_warn(
"SV2C: start!\n"
);
if
( scalar != NULL && scalar != &PL_sv_undef ) {
STRLEN len = 0;
char
* t_pv =SvPV(scalar, len);
xmlChar* ts = NULL;
xmlChar* string = xmlStrdup((xmlChar*)t_pv);
if
( xmlStrlen(string) > 0 ) {
xs_warn(
"SV2C: no undefs\n"
);
#ifdef HAVE_UTF8
xs_warn(
"SV2C: use UTF8\n"
);
if
( !DO_UTF8(scalar) && encoding != NULL ) {
#else
if
( encoding != NULL ) {
#endif
xs_warn(
"SV2C: domEncodeString!\n"
);
ts= PmmEncodeString( (
const
char
*)encoding, string, len );
xs_warn(
"SV2C: done encoding!\n"
);
if
( string != NULL ) {
xmlFree(string);
}
string=ts;
}
}
retval = xmlStrdup(string);
if
(string != NULL ) {
xmlFree(string);
}
}
xs_warn(
"SV2C: end!\n"
);
return
retval;
}
SV*
nodeC2Sv(
const
xmlChar * string, xmlNodePtr refnode )
{
SV* retval = &PL_sv_undef;
STRLEN len = 0;
xmlChar * decoded = NULL;
if
( refnode != NULL ) {
xmlDocPtr real_doc = refnode->doc;
if
( real_doc != NULL && real_doc->encoding != NULL ) {
xs_warn(
" encode node !!"
);
if
( PmmNodeEncoding(real_doc) == XML_CHAR_ENCODING_NONE ) {
SetPmmNodeEncoding(real_doc, XML_CHAR_ENCODING_UTF8);
}
decoded = PmmFastDecodeString( PmmNodeEncoding(real_doc),
(
const
xmlChar *)string,
(
const
xmlChar *)real_doc->encoding,
&len );
xs_warn(
"push decoded string into SV"
);
retval = newSVpvn( (
const
char
*)decoded, len );
xmlFree( decoded );
if
( PmmNodeEncoding( real_doc ) == XML_CHAR_ENCODING_UTF8 ) {
#ifdef HAVE_UTF8
xs_warn(
"nodeC2Sv: set UTF8-SV-flag\n"
);
SvUTF8_on(retval);
#endif
}
return
retval;
}
}
return
C2Sv(string, NULL );
}
xmlChar *
nodeSv2C( SV * scalar, xmlNodePtr refnode )
{
if
( refnode != NULL ) {
xmlDocPtr real_dom = refnode->doc;
xs_warn(
"nodeSv2C: have node!\n"
);
if
(real_dom != NULL && real_dom->encoding != NULL ) {
xs_warn(
"nodeSv2C: encode string!\n"
);
if
( scalar != NULL && scalar != &PL_sv_undef ) {
STRLEN len = 0;
char
* t_pv =SvPV(scalar, len);
xmlChar* string = NULL;
if
( t_pv && len > 0 ) {
xs_warn(
"nodeSv2C: no undefs\n"
);
#ifdef HAVE_UTF8
xs_warn(
"nodeSv2C: use UTF8\n"
);
if
( !DO_UTF8(scalar) ) {
#endif
xs_warn(
"nodeSv2C: domEncodeString!\n"
);
if
( PmmNodeEncoding(real_dom) == XML_CHAR_ENCODING_NONE ) {
SetPmmNodeEncoding(real_dom, XML_CHAR_ENCODING_UTF8);
}
string= PmmFastEncodeString( PmmNodeEncoding(real_dom),
(xmlChar*) t_pv,
(
const
xmlChar*)real_dom->encoding,
len);
xs_warn(
"nodeSv2C: done!\n"
);
#ifdef HAVE_UTF8
}
else
{
xs_warn(
"nodeSv2C: no encoding set, use UTF8!\n"
);
}
#endif
}
if
(string==NULL) {
return
xmlStrndup((xmlChar*)t_pv,len);
}
else
{
return
string;
}
}
else
{
xs_warn(
"nodeSv2C: return NULL\n"
);
return
NULL;
}
}
else
{
xs_warn(
"nodeSv2C: document has no encoding defined! use simple SV extraction\n"
);
}
}
xs_warn(
"nodeSv2C: no encoding !!\n"
);
return
Sv2C( scalar, NULL );
}
SV *
PmmNodeToGdomeSv( xmlNodePtr node )
{
SV * retval = &PL_sv_undef;
#ifdef XML_LIBXML_GDOME_SUPPORT
GdomeNode * gnode = NULL;
GdomeException exc;
const
char
* CLASS =
""
;
if
( node != NULL ) {
gnode = gdome_xml_n_mkref( node );
if
( gnode != NULL ) {
switch
(gdome_n_nodeType(gnode, &exc)) {
case
GDOME_ELEMENT_NODE:
CLASS =
"XML::GDOME::Element"
;
break
;
case
GDOME_ATTRIBUTE_NODE:
CLASS =
"XML::GDOME::Attr"
;
break
;
case
GDOME_TEXT_NODE:
CLASS =
"XML::GDOME::Text"
;
break
;
case
GDOME_CDATA_SECTION_NODE:
CLASS =
"XML::GDOME::CDATASection"
;
break
;
case
GDOME_ENTITY_REFERENCE_NODE:
CLASS =
"XML::GDOME::EntityReference"
;
break
;
case
GDOME_ENTITY_NODE:
CLASS =
"XML::GDOME::Entity"
;
break
;
case
GDOME_PROCESSING_INSTRUCTION_NODE:
CLASS =
"XML::GDOME::ProcessingInstruction"
;
break
;
case
GDOME_COMMENT_NODE:
CLASS =
"XML::GDOME::Comment"
;
break
;
case
GDOME_DOCUMENT_TYPE_NODE:
CLASS =
"XML::GDOME::DocumentType"
;
break
;
case
GDOME_DOCUMENT_FRAGMENT_NODE:
CLASS =
"XML::GDOME::DocumentFragment"
;
break
;
case
GDOME_NOTATION_NODE:
CLASS =
"XML::GDOME::Notation"
;
break
;
case
GDOME_DOCUMENT_NODE:
CLASS =
"XML::GDOME::Document"
;
break
;
default
:
break
;
}
retval = NEWSV(0,0);
sv_setref_pv( retval, CLASS, gnode);
}
}
#endif
return
retval;
}