diff options
Diffstat (limited to 'miranda-wine/protocols/JabberG/jabber_xml.cpp')
-rw-r--r-- | miranda-wine/protocols/JabberG/jabber_xml.cpp | 786 |
1 files changed, 786 insertions, 0 deletions
diff --git a/miranda-wine/protocols/JabberG/jabber_xml.cpp b/miranda-wine/protocols/JabberG/jabber_xml.cpp new file mode 100644 index 0000000..d3bd155 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_xml.cpp @@ -0,0 +1,786 @@ +/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 George Hazan
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or ( at your option ) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+File name : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_xml.cpp,v $
+Revision : $Revision: 3703 $
+Last change on : $Date: 2006-09-05 17:54:42 +0400 (Втр, 05 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+static BOOL JabberXmlProcessElem( XmlState *xmlState, XmlElemType elemType, char* elemText, char* elemAttr );
+static void JabberXmlRemoveChild( XmlNode *node, XmlNode *child );
+
+void JabberXmlInitState( XmlState *xmlState )
+{
+ if ( xmlState == NULL ) return;
+ xmlState->root.name = NULL;
+ xmlState->root.depth = 0;
+ xmlState->root.numAttr = 0;
+ xmlState->root.maxNumAttr = 0;
+ xmlState->root.attr = NULL;
+ xmlState->root.numChild = 0;
+ xmlState->root.maxNumChild = 0;
+ xmlState->root.child = NULL;
+ xmlState->root.text = NULL;
+ xmlState->root.state = NODE_OPEN;
+ xmlState->callback1_open = NULL;
+ xmlState->callback1_close = NULL;
+ xmlState->callback2_open = NULL;
+ xmlState->callback2_close = NULL;
+ xmlState->userdata1_open = NULL;
+ xmlState->userdata1_close = NULL;
+ xmlState->userdata2_open = NULL;
+ xmlState->userdata2_close = NULL;
+}
+
+void JabberXmlDestroyState( XmlState *xmlState )
+{
+ int i;
+ XmlNode *node;
+
+ if ( xmlState == NULL ) return;
+ // Note: cannot use JabberXmlFreeNode() to mir_free xmlState->root
+ // because it will do mir_free( xmlState->root ) which is not freeable.
+ node = &( xmlState->root );
+
+ // Free all children first
+ for ( i=0; i<node->numChild; i++ )
+ delete node->child[i];
+ if ( node->child ) mir_free( node->child );
+
+ // Free all attributes
+ for ( i=0; i<node->numAttr; i++ )
+ delete node->attr[i];
+ if ( node->attr ) mir_free( node->attr );
+
+ // Free string field
+ if ( node->text ) mir_free( node->text );
+ if ( node->name ) mir_free( node->name );
+
+ memset( xmlState, 0, sizeof( XmlState ));
+}
+
+BOOL JabberXmlSetCallback( XmlState *xmlState, int depth, XmlElemType type, JABBER_XML_CALLBACK callback, void *userdata )
+{
+ if ( depth==1 && type==ELEM_OPEN ) {
+ xmlState->callback1_open = callback;
+ xmlState->userdata1_open = userdata;
+ }
+ else if ( depth==1 && type==ELEM_CLOSE ) {
+ xmlState->callback1_close = callback;
+ xmlState->userdata1_close = userdata;
+ }
+ else if ( depth==2 && type==ELEM_OPEN ) {
+ xmlState->callback2_open = callback;
+ xmlState->userdata2_open = userdata;
+ }
+ else if ( depth==2 && type==ELEM_CLOSE ) {
+ xmlState->callback2_close = callback;
+ xmlState->userdata2_close = userdata;
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+#define TAG_MAX_LEN 50
+#define ATTR_MAX_LEN 1024
+
+static char* skipSpaces( char* p, int* num = NULL )
+{
+ int i;
+
+ for ( i=0; *p != 0 && isspace( BYTE( *p )); i++ )
+ p++;
+
+ if ( num != NULL )
+ num += i;
+ return p;
+}
+
+static char* findClose( char* p )
+{
+ while ( *p != 0 ) {
+ switch( *p ) {
+ case '>': return p;
+
+ case '\'':
+ case '\"':
+ p = strchr( p+1, *p );
+ if ( p == NULL )
+ return NULL;
+ }
+
+ p++;
+ }
+
+ return NULL;
+}
+
+int JabberXmlParse( XmlState *xmlState, char* buffer )
+{
+ char* r;
+ int num = 0;
+ char tag[TAG_MAX_LEN];
+ char attr[ATTR_MAX_LEN];
+ XmlElemType elemType;
+
+ char* p = skipSpaces( buffer, &num );
+
+ while ( *p != 0 ) {
+ // found starting bracket
+ if ( *p == '<' ) {
+ if ( memcmp( p, "<!--", 4 ) == 0 ) {
+ char* q = strstr( p+4, "-->" );
+ if ( q == NULL )
+ break;
+
+ p = q+3;
+ continue;
+ }
+
+ char* q = findClose( p+1 );
+ if ( q == NULL )
+ break;
+
+ // found closing bracket
+ for ( r=p+1; *r!='>' && *r!=' ' && *r!='\t'; r++ );
+ if ( r-( p+1 ) > TAG_MAX_LEN ) {
+ JabberLog( "TAG_MAX_LEN too small, ignore current tag" );
+ }
+ else {
+ if ( *( p+1 ) == '/' ) { // closing tag
+ strncpy( tag, p+2, r-( p+2 ));
+ tag[r-( p+2 )] = '\0';
+ elemType = ELEM_CLOSE;
+ }
+ else {
+ if ( *( r-1 ) == '/' ) { // single open/close tag
+ strncpy( tag, p+1, r-( p+1 )-1 );
+ tag[r-( p+1 )-1] = '\0';
+ elemType = ELEM_OPENCLOSE;
+ }
+ else {
+ strncpy( tag, p+1, r-( p+1 ));
+ tag[r-( p+1 )] = '\0';
+ elemType = ELEM_OPEN;
+ }
+ }
+ for ( ;r<q && ( *r==' ' || *r=='\t' ); r++ );
+ if ( q-r > ATTR_MAX_LEN ) {
+ JabberLog( "ATTR_MAX_LEN too small, ignore current tag" );
+ }
+ else {
+ strncpy( attr, r, q-r );
+ if (( q-r )>0 && attr[q-r-1]=='/' ) {
+ attr[q-r-1] = '\0';
+ elemType = ELEM_OPENCLOSE;
+ }
+ else
+ attr[q-r] = '\0';
+ JabberXmlProcessElem( xmlState, elemType, tag, attr );
+ }
+ }
+ num += ( q-p+1 );
+ p = q + 1;
+ if ( elemType==ELEM_CLOSE || elemType==ELEM_OPENCLOSE )
+ p = skipSpaces( p, &num ); // Skip whitespaces after end tags
+ }
+ else { // found inner text
+ char* q = strchr( p+1, '<' );
+ if ( q == NULL )
+ break;
+
+ // found starting bracket of the next element
+ char* str = ( char* )mir_alloc( q-p+1 );
+ strncpy( str, p, q-p );
+ str[q-p] = '\0';
+ JabberXmlProcessElem( xmlState, ELEM_TEXT, str, NULL );
+ mir_free( str );
+ num += ( q-p );
+ p = q;
+ } }
+
+ return num;
+}
+
+static void JabberXmlParseAttr( XmlNode *node, char* text )
+{
+ char* kstart, *vstart;
+ int klen, vlen;
+ char* p;
+ XmlAttr *a;
+
+ if ( node==NULL || text==NULL || strlen( text )<=0 )
+ return;
+
+ for ( p=text;; ) {
+
+ // Skip leading whitespaces
+ p = skipSpaces( p );
+ if ( *p == '\0' )
+ break;
+
+ // Fetch key
+ kstart = p;
+ for ( ;*p!='\0' && *p!='=' && *p!=' ' && *p!='\t'; p++ );
+ klen = p-kstart;
+
+ if ( node->numAttr >= node->maxNumAttr ) {
+ node->maxNumAttr = node->numAttr + 20;
+ node->attr = ( XmlAttr ** ) mir_realloc( node->attr, node->maxNumAttr*sizeof( XmlAttr * ));
+ }
+ a = node->attr[node->numAttr] = new XmlAttr();
+ node->numAttr++;
+
+ // Skip possible whitespaces between key and '='
+ p = skipSpaces( p );
+
+ if ( *p == '\0' ) {
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+ a->value = mir_tstrdup( _T(""));
+ break;
+ }
+
+ if ( *p != '=' ) {
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+ a->value = mir_tstrdup( _T(""));
+ continue;
+ }
+
+ // Found '='
+ p++;
+
+ // Skip possible whitespaces between '=' and value
+ p = skipSpaces( p );
+
+ if ( *p == '\0' ) {
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+ a->value = mir_tstrdup( _T(""));
+ break;
+ }
+
+ // Fetch value
+ if ( *p=='\'' || *p=='"' ) {
+ p++;
+ vstart = p;
+ for ( ;*p!='\0' && *p!=*( vstart-1 ); p++ );
+ vlen = p-vstart;
+ if ( *p != '\0' ) p++;
+ }
+ else {
+ vstart = p;
+ for ( ;*p!='\0' && *p!=' ' && *p!='\t'; p++ );
+ vlen = p-vstart;
+ }
+
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+
+ JabberUtfToTchar( vstart, vlen, a->value );
+ }
+}
+
+static BOOL JabberXmlProcessElem( XmlState *xmlState, XmlElemType elemType, char* elemText, char* elemAttr )
+{
+ XmlNode *node, *parentNode, *n;
+ BOOL activateCallback = FALSE;
+ char* text, *attr;
+
+ if ( elemText == NULL ) return FALSE;
+
+ if ( elemType==ELEM_OPEN && !strcmp( elemText, "?xml" )) {
+ JabberLog( "XML: skip <?xml> tag" );
+ return TRUE;
+ }
+
+ // Find active node
+ node = &( xmlState->root );
+ parentNode = NULL;
+ while ( node->numChild>0 && node->child[node->numChild-1]->state==NODE_OPEN ) {
+ parentNode = node;
+ node = node->child[node->numChild-1];
+ }
+
+ if ( node->state != NODE_OPEN ) return FALSE;
+
+ text = NEWSTR_ALLOCA( elemText );
+
+ if ( elemAttr )
+ attr = NEWSTR_ALLOCA( elemAttr );
+ else
+ attr = NULL;
+
+ switch ( elemType ) {
+ case ELEM_OPEN:
+ if ( node->numChild >= node->maxNumChild ) {
+ node->maxNumChild = node->numChild + 20;
+ node->child = ( XmlNode ** ) mir_realloc( node->child, node->maxNumChild*sizeof( XmlNode * ));
+ }
+ n = node->child[node->numChild] = new XmlNode(text);
+ node->numChild++;
+ n->depth = node->depth + 1;
+ n->state = NODE_OPEN;
+ n->numChild = n->maxNumChild = 0;
+ n->child = NULL;
+ n->numAttr = n->maxNumAttr = 0;
+ n->attr = NULL;
+ JabberXmlParseAttr( n, attr );
+ n->text = NULL;
+ if ( n->depth==1 && xmlState->callback1_open!=NULL )
+ ( *( xmlState->callback1_open ))( n, xmlState->userdata1_open );
+ if ( n->depth==2 && xmlState->callback2_open!=NULL )
+ ( *xmlState->callback2_open )( n, xmlState->userdata2_open );
+ break;
+ case ELEM_OPENCLOSE:
+ if ( node->numChild >= node->maxNumChild ) {
+ node->maxNumChild = node->numChild + 20;
+ node->child = ( XmlNode ** ) mir_realloc( node->child, node->maxNumChild*sizeof( XmlNode * ));
+ }
+ n = node->child[node->numChild] = new XmlNode( text );
+ node->numChild++;
+ n->depth = node->depth + 1;
+ n->state = NODE_CLOSE;
+ n->numChild = n->maxNumAttr = 0;
+ n->child = NULL;
+ n->numAttr = n->maxNumAttr = 0;
+ n->attr = NULL;
+ JabberXmlParseAttr( n, attr );
+ n->text = NULL;
+ if ( n->depth==1 && xmlState->callback1_close!=NULL ) {
+ ( *( xmlState->callback1_close ))( n, xmlState->userdata1_close );
+ JabberXmlRemoveChild( node, n );
+ }
+ if ( n->depth==2 && xmlState->callback2_close!=NULL ) {
+ ( *xmlState->callback2_close )( n, xmlState->userdata2_close );
+ JabberXmlRemoveChild( node, n );
+ }
+ break;
+ case ELEM_CLOSE:
+ if ( node->name!=NULL && !strcmp( node->name, text )) {
+ node->state = NODE_CLOSE;
+ if ( node->depth==1 && xmlState->callback1_close!=NULL ) {
+ ( *( xmlState->callback1_close ))( node, xmlState->userdata1_close );
+ JabberXmlRemoveChild( parentNode, node );
+ }
+ else if ( node->depth==2 && xmlState->callback2_close!=NULL ) {
+ ( *xmlState->callback2_close )( node, xmlState->userdata2_close );
+ JabberXmlRemoveChild( parentNode, node );
+ } }
+ else {
+ JabberLog( "XML: Closing </%s> without opening tag", text );
+ return FALSE;
+ }
+ break;
+ case ELEM_TEXT:
+ JabberUtfToTchar( text, strlen( text ), node->text );
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+TCHAR* JabberXmlGetAttrValue( XmlNode *node, char* key )
+{
+ if ( node==NULL || node->numAttr<=0 || key==NULL || strlen( key )<=0 )
+ return NULL;
+
+ for ( int i=0; i<node->numAttr; i++ )
+ if ( !lstrcmpA( key, node->attr[i]->name ))
+ return node->attr[i]->value;
+
+ return NULL;
+}
+
+XmlNode *JabberXmlGetChild( XmlNode *node, char* tag )
+{
+ return JabberXmlGetNthChild( node, tag, 1 );
+}
+
+XmlNode *JabberXmlGetNthChild( XmlNode *node, char* tag, int nth )
+{
+ int i, num;
+
+ if ( node==NULL || node->numChild<=0 || tag==NULL || strlen( tag )<=0 || nth<1 )
+ return NULL;
+ num = 1;
+ for ( i=0; i<node->numChild; i++ ) {
+ if ( node->child[i]->name && !strcmp( tag, node->child[i]->name )) {
+ if ( num == nth ) {
+ return node->child[i];
+ }
+ num++;
+ }
+ }
+ return NULL;
+}
+
+XmlNode *JabberXmlGetChildWithGivenAttrValue( XmlNode *node, char* tag, char* attrKey, TCHAR* attrValue )
+{
+ if ( node==NULL || node->numChild<=0 || tag==NULL || strlen( tag )<=0 || attrKey==NULL || strlen( attrKey )<=0 || attrValue==NULL || lstrlen( attrValue )<=0 )
+ return NULL;
+
+ TCHAR* str;
+ for ( int i=0; i<node->numChild; i++ )
+ if ( node->child[i]->name && !strcmp( tag, node->child[i]->name ))
+ if (( str=JabberXmlGetAttrValue( node->child[i], attrKey )) != NULL )
+ if ( !lstrcmp( str, attrValue ))
+ return node->child[i];
+
+ return NULL;
+}
+
+static void JabberXmlRemoveChild( XmlNode *node, XmlNode *child )
+{
+ int i;
+
+ if ( node==NULL || child==NULL || node->numChild<=0 ) return;
+ for ( i=0; i<node->numChild; i++ ) {
+ if ( node->child[i] == child )
+ break;
+ }
+ if ( i < node->numChild ) {
+ for ( ++i; i<node->numChild; i++ )
+ node->child[i-1] = node->child[i];
+ node->numChild--;
+ delete child;
+ }
+}
+
+XmlNode *JabberXmlCopyNode( XmlNode *node )
+{
+ if ( node == NULL )
+ return NULL;
+
+ XmlNode *n = new XmlNode( node->name );
+ // Copy attributes
+ if ( node->numAttr > 0 ) {
+ n->attr = ( XmlAttr ** ) mir_alloc( node->numAttr*sizeof( XmlAttr * ));
+ for ( int i=0; i < node->numAttr; i++ ) {
+ n->attr[i] = new XmlAttr;
+ if ( node->attr[i]->name )
+ n->attr[i]->name = mir_strdup( node->attr[i]->name );
+ if ( node->attr[i]->value )
+ n->attr[i]->value = mir_tstrdup( node->attr[i]->value );
+ }
+ }
+ else
+ n->attr = NULL;
+ // Recursively copy children
+ if ( node->numChild > 0 ) {
+ n->child = ( XmlNode ** ) mir_alloc( node->numChild*sizeof( XmlNode * ));
+ for ( int i=0; i<node->numChild; i++ )
+ n->child[i] = JabberXmlCopyNode( node->child[i] );
+ }
+ else
+ n->child = NULL;
+ // Copy other fields
+ n->numAttr = node->numAttr;
+ n->maxNumAttr = node->numAttr;
+ n->numChild = node->numChild;
+ n->maxNumChild = node->numChild;
+ n->depth = node->depth;
+ n->state = node->state;
+ n->text = ( node->text )?mir_tstrdup( node->text ):NULL;
+ return n;
+}
+
+XmlNode *JabberXmlAddChild( XmlNode *n, char* name )
+{
+ if ( n==NULL || name==NULL )
+ return NULL;
+
+ XmlNode* result = new XmlNode( name );
+ if ( result == NULL )
+ return NULL;
+
+ return n->addChild( result );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// XmlNodeIq class members
+
+XmlNodeIq::XmlNodeIq( const char* type, int id, const TCHAR* to ) :
+ XmlNode( "iq" )
+{
+ if ( type != NULL ) addAttr( "type", type );
+ if ( to != NULL ) addAttr( "to", to );
+ if ( id != NOID ) addAttrID( id );
+}
+
+XmlNodeIq::XmlNodeIq( const char* type, const TCHAR* idStr, const TCHAR* to ) :
+ XmlNode( "iq" )
+{
+ if ( type != NULL ) addAttr( "type", type );
+ if ( to != NULL ) addAttr( "to", to );
+ if ( idStr != NULL ) addAttr( "id", idStr );
+}
+
+#if defined( _UNICODE )
+XmlNodeIq::XmlNodeIq( const char* type, int id, const char* to ) :
+ XmlNode( "iq" )
+{
+ if ( type != NULL ) addAttr( "type", type );
+ if ( to != NULL ) addAttr( "to", to );
+ if ( id != NOID ) addAttrID( id );
+}
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// XmlNode class members
+
+XmlNode::XmlNode( const char* pszName )
+{
+ memset( this, 0, sizeof( XmlNode ));
+ name = mir_strdup( pszName );
+}
+
+XmlNode::XmlNode( const char* pszName, const TCHAR* ptszText )
+{
+ memset( this, 0, sizeof( XmlNode ));
+ name = mir_strdup( pszName );
+ #if defined( _UNICODE )
+ sendText = JabberTextEncodeW( ptszText );
+ #else
+ sendText = JabberTextEncode( ptszText );
+ #endif
+}
+
+#if defined( _UNICODE )
+XmlNode::XmlNode( const char* pszName, const char* ptszText )
+{
+ memset( this, 0, sizeof( XmlNode ));
+ name = mir_strdup( pszName );
+ sendText = JabberTextEncode( ptszText );
+}
+#endif
+
+XmlNode::~XmlNode()
+{
+ if ( this == NULL ) return;
+
+ // Free all children first
+ int i;
+ for ( i=0; i < numChild; i++ )
+ delete child[i];
+ if ( child ) mir_free( child );
+
+ // Free all attributes
+ for ( i=0; i < numAttr; i++ )
+ delete attr[i];
+ if ( attr ) mir_free( attr );
+
+ // Free string field
+ if ( text ) mir_free( text );
+ if ( name ) mir_free( name );
+}
+
+XmlAttr* XmlNode::addAttr( XmlAttr* a )
+{
+ if ( this == NULL || a == NULL )
+ return NULL;
+
+ int i = numAttr++;
+ attr = ( XmlAttr ** ) mir_realloc( attr, sizeof( XmlAttr * ) * numAttr );
+ attr[i] = a;
+ return a;
+}
+
+XmlAttr* XmlNode::addAttr( const char* pszName, const TCHAR* ptszValue )
+{
+ return addAttr( new XmlAttr( pszName, ptszValue ));
+}
+
+#if defined( _UNICODE )
+XmlAttr* XmlNode::addAttr( const char* pszName, const char* pszValue )
+{
+ return addAttr( new XmlAttr( pszName, pszValue ));
+}
+#endif
+
+XmlAttr* XmlNode::addAttr( const char* pszName, int value )
+{
+ if ( this == NULL )
+ return NULL;
+
+ TCHAR buf[ 40 ];
+ _itot( value, buf, 10 );
+ return addAttr( new XmlAttr( pszName, buf ));
+}
+
+XmlAttr* XmlNode::addAttrID( int id )
+{
+ if ( this == NULL )
+ return NULL;
+
+ TCHAR text[ 100 ];
+ mir_sntprintf( text, SIZEOF(text), _T("mir_%d"), id );
+ return addAttr( new XmlAttr( "id", text ));
+}
+
+XmlNode* XmlNode::addChild( XmlNode* pNode )
+{
+ if ( this == NULL || pNode == NULL )
+ return NULL;
+
+ int i = numChild++;
+ child = ( XmlNode ** ) mir_realloc( child, sizeof( XmlNode * ) * numChild );
+ child[i] = pNode;
+ pNode->depth = depth+1;
+ return pNode;
+}
+
+XmlNode* XmlNode::addChild( const char* pszName )
+{
+ return addChild( new XmlNode( pszName ));
+}
+
+XmlNode* XmlNode::addChild( const char* pszName, const TCHAR* ptszValue )
+{
+ return addChild( new XmlNode( pszName, ptszValue ));
+}
+
+#if defined( _UNICODE )
+XmlNode* XmlNode::addChild( const char* pszName, const char* pszValue )
+{
+ return addChild( new XmlNode( pszName, pszValue ));
+}
+#endif
+
+XmlNode* XmlNode::addQuery( const char* szNameSpace )
+{
+ XmlNode* n = addChild( "query" );
+ if ( n )
+ n->addAttr( "xmlns", szNameSpace );
+ return n;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// text extraction routines
+
+static char* sttCopyNode( const XmlNode* n, char* dest )
+{
+ if ( n->props ) {
+ lstrcpyA( dest, n->props ); dest += lstrlenA( n->props );
+ }
+
+ *dest++ = '<';
+ lstrcpyA( dest, n->name ); dest += lstrlenA( n->name );
+
+ for ( int i=0; i < n->numAttr; i++ ) {
+ *dest++ = ' ';
+ lstrcpyA( dest, n->attr[i]->name ); dest += lstrlenA( n->attr[i]->name );
+ *dest++ = '=';
+ *dest++ = '\'';
+ lstrcpyA( dest, n->attr[i]->sendValue ); dest += lstrlenA( n->attr[i]->sendValue );
+ *dest++ = '\'';
+ }
+
+ if ( n->numChild != 0 || n->sendText != NULL )
+ *dest++ = '>';
+
+ if ( n->sendText != NULL ) {
+ lstrcpyA( dest, n->sendText ); dest += lstrlenA( n->sendText );
+ }
+
+ if ( n->numChild != 0 )
+ for ( int i=0; i < n->numChild; i++ )
+ dest = sttCopyNode( n->child[i], dest );
+
+ if ( n->numChild != 0 || n->sendText != NULL ) {
+ *dest++ = '<';
+ *dest++ = '/';
+ lstrcpyA( dest, n->name ); dest += lstrlenA( n->name );
+ }
+ else if ( !n->dirtyHack ) *dest++ = '/';
+
+ *dest++ = '>';
+ *dest = 0;
+ return dest;
+}
+
+char* XmlNode::getText() const
+{
+ int cbLen = getTextLen();
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ sttCopyNode( this, result );
+ return result;
+}
+
+int XmlNode::getTextLen() const
+{
+ int result = 10 + lstrlenA( props ) + lstrlenA( name )*2 + lstrlenA( sendText );
+
+ for ( int i=0; i < numAttr; i++ )
+ result += lstrlenA( attr[i]->name ) + lstrlenA( attr[i]->sendValue ) + 4;
+
+ for ( int j=0; j < numChild; j++ )
+ result += child[j]->getTextLen();
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// XmlAttr class members
+
+XmlAttr::XmlAttr() :
+ name( NULL ), value( NULL )
+{
+}
+
+XmlAttr::XmlAttr( const char* pszName, const TCHAR* ptszValue )
+{
+ name = mir_strdup( pszName );
+ #if defined( _UNICODE )
+ sendValue = JabberTextEncodeW( ptszValue );
+ #else
+ sendValue = JabberTextEncode( ptszValue );
+ #endif
+}
+
+#if defined( _UNICODE )
+XmlAttr::XmlAttr( const char* pszName, const char* ptszValue )
+{
+ name = mir_strdup( pszName );
+ sendValue = JabberTextEncode( ptszValue );
+}
+#endif
+
+XmlAttr::~XmlAttr()
+{
+ if ( name != NULL ) mir_free( name );
+ if ( value != NULL ) mir_free( value );
+}
|