📄 xml.cpp
字号:
//
// XML.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza 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.
//
// Shareaza 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 Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "StdAfx.h"
#include "Shareaza.h"
#include "XML.h"
#ifdef DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// CXMLNode construction
CXMLNode::CXMLNode(CXMLElement* pParent, LPCTSTR pszName)
{
m_nNode = xmlNode;
m_pParent = pParent;
if ( pszName ) m_sName = pszName;
}
CXMLNode::~CXMLNode()
{
}
//////////////////////////////////////////////////////////////////////
// CXMLNode parsing
BOOL CXMLNode::ParseMatch(LPCTSTR& pszBase, LPCTSTR pszToken)
{
LPCTSTR pszXML = pszBase;
int nParse = 0;
for ( ; *pszXML == ' ' || *pszXML == '\t' || *pszXML == '\r' || *pszXML == '\n' ; pszXML++, nParse++ );
if ( ! *pszXML ) return FALSE;
for ( ; *pszXML && *pszToken ; pszXML++, pszToken++, nParse++ )
{
if ( *pszXML != *pszToken ) return FALSE;
}
pszBase += nParse;
return TRUE;
}
BOOL CXMLNode::ParseIdentifier(LPCTSTR& pszBase, CString& strIdentifier)
{
LPCTSTR pszXML = pszBase;
int nParse = 0;
for ( ; *pszXML == ' ' || *pszXML == '\t' || *pszXML == '\r' || *pszXML == '\n' ; pszXML++, nParse++ );
if ( ! *pszXML ) return FALSE;
int nIdentifier = 0;
for ( ; *pszXML && ( _istalnum( *pszXML ) || *pszXML == ':' || *pszXML == '_' ) ; pszXML++, nIdentifier++ );
if ( ! nIdentifier ) return FALSE;
pszBase += nParse;
_tcsncpy( strIdentifier.GetBuffer( nIdentifier ), pszBase, nIdentifier );
strIdentifier.ReleaseBuffer( nIdentifier );
pszBase += nIdentifier;
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CXMLNode string to value
CString CXMLNode::StringToValue(LPCTSTR& pszXML, int nLength)
{
CString strValue;
if ( ! nLength || ! *pszXML ) return strValue;
LPTSTR pszValue = strValue.GetBuffer( nLength + 4 );
LPTSTR pszOut = pszValue;
LPTSTR pszNull = (LPTSTR)pszXML + nLength;
TCHAR cNull = *pszNull;
*pszNull = 0;
while ( *pszXML && pszXML < pszNull )
{
if ( _istspace( *pszXML ) )
{
if ( pszValue != pszOut ) *pszOut++ = ' ';
pszXML++;
while ( *pszXML && _istspace( *pszXML ) ) pszXML++;
if ( ! *pszXML || pszXML >= pszNull ) break;
}
if ( *pszXML == '&' )
{
pszXML++;
if ( ! *pszXML || pszXML >= pszNull ) break;
if ( _tcsnicmp( pszXML, _T("amp;"), 4 ) == 0 )
{
*pszOut++ = '&';
pszXML += 4;
}
else if ( _tcsnicmp( pszXML, _T("lt;"), 3 ) == 0 )
{
*pszOut++ = '<';
pszXML += 3;
}
else if ( _tcsnicmp( pszXML, _T("gt;"), 3 ) == 0 )
{
*pszOut++ = '>';
pszXML += 3;
}
else if ( _tcsnicmp( pszXML, _T("quot;"), 5 ) == 0 )
{
*pszOut++ = '\"';
pszXML += 5;
}
else if ( _tcsnicmp( pszXML, _T("apos;"), 5 ) == 0 )
{
*pszOut++ = '\'';
pszXML += 5;
}
else if ( _tcsnicmp( pszXML, _T("nbsp;"), 5 ) == 0 )
{
*pszOut++ = ' ';
pszXML += 5;
}
else if ( *pszXML == '#' )
{
int nChar;
pszXML++;
if ( ! *pszXML || pszXML >= pszNull || ! _istdigit( *pszXML ) ) break;
if ( _stscanf( pszXML, _T("%lu;"), &nChar ) == 1 )
{
*pszOut++ = (TCHAR)nChar;
while ( *pszXML && *pszXML != ';' ) pszXML++;
if ( ! *pszXML || pszXML >= pszNull ) break;
pszXML++;
}
}
else
{
*pszOut++ = '&';
}
}
else
{
*pszOut++ = *pszXML++;
}
}
ASSERT( pszNull == pszXML );
*pszNull = cNull;
ASSERT( pszOut - pszValue <= nLength );
strValue.ReleaseBuffer( (int)( pszOut - pszValue ) );
return strValue;
}
//////////////////////////////////////////////////////////////////////
// CXMLNode value to string
#define V2S_APPEND(x,y) \
if ( (x) > nOut ) \
{ \
strXML.ReleaseBuffer( nLen + nOut ); \
nOut += (x) + 16; \
pszOut = strXML.GetBuffer( nLen + nOut ) + nLen; \
} \
{ for ( LPCTSTR pszIn = (y) ; *pszIn ; nOut--, nLen++ ) *pszOut++ = *pszIn++; }
void CXMLNode::ValueToString(LPCTSTR pszValue, CString& strXML)
{
int nLen = strXML.GetLength();
int nOut = (int)_tcslen( pszValue );
LPTSTR pszOut = strXML.GetBuffer( nLen + nOut ) + nLen;
for ( ; *pszValue ; pszValue++ )
{
#ifdef UNICODE
int nChar = (int)(unsigned short)*pszValue;
#else
int nChar = (int)(unsigned char)*pszValue;
#endif
switch ( nChar )
{
case '&':
V2S_APPEND( 5, _T("&") );
break;
case '<':
V2S_APPEND( 4, _T("<") );
break;
case '>':
V2S_APPEND( 4, _T(">") );
break;
case '\"':
V2S_APPEND( 6, _T(""") );
break;
case '\'':
V2S_APPEND( 6, _T("'") );
break;
default:
if ( nChar > 127 )
{
CString strItem;
strItem.Format( _T("&#%lu;"), nChar );
V2S_APPEND( strItem.GetLength(), strItem );
}
else if ( nOut > 0 )
{
*pszOut++ = nChar;
nOut--;
nLen++;
}
else
{
strXML.ReleaseBuffer( nLen + nOut );
nOut += 16;
pszOut = strXML.GetBuffer( nLen + nOut ) + nLen;
*pszOut++ = nChar;
nOut--;
nLen++;
}
break;
}
}
strXML.ReleaseBuffer( nLen );
}
//////////////////////////////////////////////////////////////////////
// CXMLNode serialize
#ifdef _AFX
void CXMLNode::Serialize(CArchive& ar)
{
if ( ar.IsStoring() )
{
ar << m_sName;
ar << m_sValue;
}
else
{
ar >> m_sName;
ar >> m_sValue;
}
}
#endif
//////////////////////////////////////////////////////////////////////
// CXMLNode string helper
void CXMLNode::UniformString(CString& str)
{
static LPCTSTR pszOK = _T("'-&");
str.TrimLeft();
str.TrimRight();
BOOL bSpace = TRUE;
for ( int nPos = 0 ; nPos < str.GetLength() ; nPos++ )
{
#ifdef UNICODE
int nChar = (int)(unsigned short)str.GetAt( nPos );
#else
int nChar = (int)(unsigned char)str.GetAt( nPos );
#endif
if ( nChar <= 32 )
{
if ( bSpace )
{
str = str.Left( nPos ) + str.Mid( nPos + 1 );
nPos--;
}
else
{
if ( nChar != 32 ) str.SetAt( nPos, 32 );
bSpace = TRUE;
}
}
else if ( ! _istalnum( nChar ) && nChar < 0xC0 && _tcschr( pszOK, nChar ) == NULL )
{
str = str.Left( nPos ) + str.Mid( nPos + 1 );
nPos--;
}
else
{
bSpace = FALSE;
}
}
}
//////////////////////////////////////////////////////////////////////
// CXMLElement construction
CXMLElement::CXMLElement(CXMLElement* pParent, LPCTSTR pszName) : CXMLNode( pParent, pszName )
{
m_nNode = xmlElement;
}
CXMLElement::~CXMLElement()
{
DeleteAllElements();
DeleteAllAttributes();
}
//////////////////////////////////////////////////////////////////////
// CXMLElement clone
CXMLElement* CXMLElement::Clone(CXMLElement* pParent)
{
CXMLElement* pClone = new CXMLElement( pParent, m_sName );
for ( POSITION pos = GetAttributeIterator() ; pos ; )
{
CXMLAttribute* pAttribute = GetNextAttribute( pos )->Clone( pClone );
CString strName( pAttribute->m_sName );
strName.MakeLower();
pClone->m_pAttributes.SetAt( strName, pAttribute );
}
for ( pos = GetElementIterator() ; pos ; )
{
CXMLElement* pElement = GetNextElement( pos );
pClone->m_pElements.AddTail( pElement->Clone( pClone ) );
}
pClone->m_sValue = m_sValue;
return pClone;
}
//////////////////////////////////////////////////////////////////////
// CXMLElement delete
void CXMLElement::DeleteAllElements()
{
for ( POSITION pos = m_pElements.GetHeadPosition() ; pos ; )
{
delete (CXMLElement*)m_pElements.GetNext( pos );
}
m_pElements.RemoveAll();
}
void CXMLElement::DeleteAllAttributes()
{
for ( POSITION pos = m_pAttributes.GetStartPosition() ; pos ; )
{
CXMLAttribute* pAttribute = NULL;
CString strName;
m_pAttributes.GetNextAssoc( pos, strName, XMLVOID(pAttribute) );
delete pAttribute;
}
m_pAttributes.RemoveAll();
}
//////////////////////////////////////////////////////////////////////
// CXMLElement to string
CString CXMLElement::ToString(BOOL bHeader, BOOL bNewline)
{
CString strXML;
if ( bHeader ) strXML = _T("<?xml version=\"1.0\"?>");
if ( bNewline ) strXML += _T("\r\n");
ToString( strXML, bNewline );
ASSERT( strXML.GetLength() == _tcslen(strXML) );
return strXML;
}
void CXMLElement::ToString(CString& strXML, BOOL bNewline)
{
strXML += '<' + m_sName;
for ( POSITION pos = GetAttributeIterator() ; pos ; )
{
strXML += ' ';
CXMLAttribute* pAttribute = GetNextAttribute( pos );
pAttribute->ToString( strXML );
}
pos = GetElementIterator();
if ( pos == NULL && m_sValue.IsEmpty() )
{
strXML += _T("/>");
if ( bNewline ) strXML += _T("\r\n");
return;
}
strXML += '>';
if ( bNewline && pos ) strXML += _T("\r\n");
while ( pos )
{
CXMLElement* pElement = GetNextElement( pos );
pElement->ToString( strXML, bNewline );
}
ValueToString( m_sValue, strXML );
strXML += _T("</") + m_sName + '>';
if ( bNewline ) strXML += _T("\r\n");
}
//////////////////////////////////////////////////////////////////////
// CXMLElement from string
CXMLElement* CXMLElement::FromString(LPCTSTR pszXML, BOOL bHeader)
{
CXMLElement* pElement = NULL;
LPCTSTR pszElement = NULL;
#ifdef _AFX
try
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -