Files
itgmania212121/stepmania/src/XmlFile.cpp
T

1116 lines
28 KiB
C++
Raw Normal View History

2004-02-09 08:10:01 +00:00
#include "global.h"
#include "XmlFile.h"
#include <iostream>
#include <sstream>
#include <string>
2004-02-10 09:42:01 +00:00
#include "RageFile.h"
2004-04-02 05:06:32 +00:00
#include "RageLog.h"
2004-07-18 21:55:49 +00:00
#include "RageUtil.h"
#include "DateTime.h"
2005-01-07 09:09:23 +00:00
#include "Foreach.h"
#include "arch/Dialog/Dialog.h"
2004-02-09 08:10:01 +00:00
2004-08-18 22:09:23 +00:00
static const char chXMLTagOpen = '<';
2005-02-18 13:05:17 +00:00
static const char chXMLTagClose = '>';
2005-02-18 14:03:50 +00:00
static const char chXMLQuestion = '?'; // used in checking for meta tags: "<?TAG ... ?/>"
2005-02-18 13:05:17 +00:00
static const char chXMLTagPre = '/';
static const char chXMLEscape = '\\'; // for value field escape
2005-02-18 14:03:50 +00:00
static const char chXMLExclamation = '!';
static const char chXMLDash = '-';
2004-02-09 08:10:01 +00:00
static const XENTITY x_EntityTable[] = {
{ '&', ("&amp;"), 5 } ,
{ '\"', ("&quot;"), 6 } ,
{ '\'', ("&apos;"), 6 } ,
{ '<', ("&lt;"), 4 } ,
{ '>', ("&gt;"), 4 }
};
2004-07-23 02:27:37 +00:00
XENTITYS entityDefault((XENTITY*)x_EntityTable, sizeof(x_EntityTable)/sizeof(x_EntityTable[0]) );
2004-02-09 08:10:01 +00:00
2004-05-23 02:28:36 +00:00
// skip spaces
2004-07-22 20:14:26 +00:00
char* tcsskip( const char* psz )
2004-02-09 08:10:01 +00:00
{
2005-01-07 21:52:59 +00:00
while( psz && isspace(*psz) ) psz++;
2004-02-09 08:10:01 +00:00
2004-02-25 01:09:17 +00:00
return (char*)psz;
2004-02-09 08:10:01 +00:00
}
2004-07-22 20:14:26 +00:00
// Name : tcsechr
2004-02-25 01:09:17 +00:00
// Desc : similar with strchr with escape process
2004-02-09 08:10:01 +00:00
// Param : escape - will be escape character
2004-07-22 20:14:26 +00:00
char* tcsechr( const char* psz, int ch, int escape )
2004-02-09 08:10:01 +00:00
{
2004-02-25 01:09:17 +00:00
char* pch = (char*)psz;
char* prev_escape = NULL;
2004-02-09 08:10:01 +00:00
while( pch && *pch )
{
if( *pch == escape && prev_escape == NULL )
prev_escape = pch;
else
{
prev_escape = NULL;
2004-02-25 01:09:17 +00:00
if( *pch == ch ) return (char*)pch;
2004-02-09 08:10:01 +00:00
}
pch++;
}
return pch;
}
2004-02-25 01:09:17 +00:00
// Desc : similar with strlen with escape process
2004-02-09 08:10:01 +00:00
// Param : escape - will be escape character
2004-07-22 20:14:26 +00:00
int tcselen( int escape, const char *start, const char *end )
2004-02-09 08:10:01 +00:00
{
int len = 0;
2004-07-22 19:25:17 +00:00
if( end == NULL )
end = (char*) sizeof(long);
const char *prev_escape = NULL;
2004-07-22 19:25:17 +00:00
while( start && *start && start<end )
2004-02-09 08:10:01 +00:00
{
2004-07-22 19:25:17 +00:00
if( *start == escape && prev_escape == NULL )
prev_escape = start;
2004-02-09 08:10:01 +00:00
else
{
prev_escape = NULL;
len++;
}
2004-07-22 19:25:17 +00:00
++start;
2004-02-09 08:10:01 +00:00
}
return len;
}
// Desc : similar with _tcscpy with escape process
// Param : escape - will be escape character
2004-07-22 19:25:17 +00:00
void unescape( char *psz, int escape, char* srt, char* end = NULL )
2004-02-09 08:10:01 +00:00
{
2004-07-22 19:25:17 +00:00
const char* pch = srt;
2004-02-25 01:09:17 +00:00
if( end==NULL ) end = (char*)sizeof(long);
2004-07-22 19:25:17 +00:00
const char* prev_escape = NULL;
2004-02-09 08:10:01 +00:00
while( pch && *pch && pch<end )
{
if( *pch == escape && prev_escape == NULL )
prev_escape = pch;
else
{
prev_escape = NULL;
*psz++ = *pch;
}
pch++;
}
*psz = '\0';
}
2004-02-25 01:09:17 +00:00
// Desc : similar with strpbrk with escape process
2004-02-09 08:10:01 +00:00
// Param : escape - will be escape character
2004-07-22 20:14:26 +00:00
char* tcsepbrk( const char* psz, const char* chset, int escape )
2004-02-09 08:10:01 +00:00
{
2004-02-25 01:09:17 +00:00
char* pch = (char*)psz;
char* prev_escape = NULL;
2004-02-09 08:10:01 +00:00
while( pch && *pch )
{
if( *pch == escape && prev_escape == NULL )
prev_escape = pch;
else
{
prev_escape = NULL;
2004-02-25 01:09:17 +00:00
if( strchr( chset, *pch ) )
return (char*)pch;
2004-02-09 08:10:01 +00:00
}
pch++;
}
return pch;
}
// Desc : put string of (psz~end) on ps string
2004-07-22 20:14:26 +00:00
void SetString( char* psz, char* end, CString* ps, bool trim = false, int escape = 0 )
2004-02-09 08:10:01 +00:00
{
if( trim )
{
2004-02-25 01:09:17 +00:00
while( psz && psz < end && isspace(*psz) ) psz++;
while( (end-1) && psz < (end-1) && isspace(*(end-1)) ) end--;
2004-02-09 08:10:01 +00:00
}
int len = end - psz;
if( len <= 0 ) return;
if( escape )
{
2004-07-22 20:14:26 +00:00
len = tcselen( escape, psz, end );
2004-07-22 18:25:58 +00:00
char* szTemp = new char[len];
2004-07-22 19:25:17 +00:00
unescape( szTemp, escape, psz, end );
2004-02-09 08:10:01 +00:00
*ps = szTemp;
2004-07-22 18:25:58 +00:00
delete [] szTemp;
2004-02-09 08:10:01 +00:00
}
else
{
2004-07-22 19:31:54 +00:00
ps->assign( psz, len );
2004-02-09 08:10:01 +00:00
}
}
XNode::~XNode()
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
Clear();
2004-02-09 08:10:01 +00:00
}
2005-01-07 14:28:00 +00:00
void XNode::Clear()
2004-02-09 08:10:01 +00:00
{
2005-01-07 09:09:23 +00:00
FOREACH_Child( this, p )
SAFE_DELETE( p );
2005-01-07 14:28:00 +00:00
m_childs.clear();
2004-02-09 08:10:01 +00:00
2005-01-07 09:09:23 +00:00
FOREACH_Attr( this, p2 )
SAFE_DELETE( p2 );
2005-01-07 14:28:00 +00:00
m_attrs.clear();
2004-02-09 08:10:01 +00:00
}
// attr1="value1" attr2='value2' attr3=value3 />
// ^- return pointer
//========================================================
// Name : LoadAttributes
// Desc : loading attribute plain xml text
// Param : pszAttrs - xml of attributes
// pi = parser information
// Return : advanced string pointer. (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2005-01-07 09:09:23 +00:00
char* XNode::LoadAttributes( const char* pszAttrs, PARSEINFO *pi /*= &piDefault*/)
2004-02-09 08:10:01 +00:00
{
2004-02-25 01:09:17 +00:00
char* xml = (char*)pszAttrs;
2004-02-09 08:10:01 +00:00
while( xml && *xml )
{
2004-07-22 20:14:26 +00:00
xml = tcsskip( xml );
2004-02-09 19:33:56 +00:00
if( !xml )
continue;
// close tag
2005-02-18 14:03:50 +00:00
if( *xml == chXMLTagClose || *xml == chXMLTagPre || *xml == chXMLQuestion || *xml == chXMLDash )
2004-02-09 19:33:56 +00:00
// wel-formed tag
return xml;
// XML Attr Name
2004-08-18 22:09:23 +00:00
char* pEnd = strpbrk( xml, " =" );
2004-02-09 19:33:56 +00:00
if( pEnd == NULL )
2004-02-09 08:10:01 +00:00
{
2004-02-09 19:33:56 +00:00
// error
2005-02-18 11:55:34 +00:00
if( !pi->error_occur )
2004-02-09 19:33:56 +00:00
{
2005-02-18 11:55:34 +00:00
pi->error_occur = true;
2004-02-09 19:33:56 +00:00
pi->error_pointer = xml;
pi->error_code = PIE_ATTR_NO_VALUE;
2005-01-07 14:28:00 +00:00
pi->error_string = ssprintf( ("<%s> attribute has error "), m_sName.c_str() );
2004-02-09 19:33:56 +00:00
}
return NULL;
}
2004-07-23 02:27:37 +00:00
XAttr *attr = new XAttr;
2004-02-09 08:10:01 +00:00
2004-02-09 19:33:56 +00:00
// XML Attr Name
2005-01-07 14:28:00 +00:00
SetString( xml, pEnd, &attr->m_sName );
2004-02-09 19:33:56 +00:00
// add new attribute
2005-01-07 14:28:00 +00:00
DEBUG_ASSERT( attr->m_sName.size() );
m_attrs.insert( pair<CString,XAttr*>(attr->m_sName, attr) );
2004-02-09 19:33:56 +00:00
xml = pEnd;
// XML Attr Value
2004-07-22 20:14:26 +00:00
xml = tcsskip( xml );
2004-02-09 19:33:56 +00:00
if( !xml )
continue;
2004-02-25 01:09:17 +00:00
//if( xml = strchr( xml, '=' ) )
2004-02-09 19:33:56 +00:00
if( *xml == '=' )
{
2004-07-22 20:14:26 +00:00
xml = tcsskip( ++xml );
2004-02-09 19:33:56 +00:00
if( !xml )
continue;
// if " or '
// or none quote
int quote = *xml;
if( quote == '"' || quote == '\'' )
2005-01-07 14:28:00 +00:00
{
2004-07-22 20:14:26 +00:00
pEnd = tcsechr( ++xml, quote, chXMLEscape );
2005-01-07 14:28:00 +00:00
}
2004-02-09 19:33:56 +00:00
else
2004-02-09 08:10:01 +00:00
{
2004-02-09 19:33:56 +00:00
//attr= value>
// none quote mode
2004-07-22 20:14:26 +00:00
//pEnd = tcsechr( xml, ' ', '\\' );
pEnd = tcsepbrk( xml, (" >"), chXMLEscape );
2004-02-09 08:10:01 +00:00
}
2004-02-09 19:33:56 +00:00
bool trim = pi->trim_value;
2004-08-18 22:09:23 +00:00
char escape = pi->escape_value;
2005-01-07 14:28:00 +00:00
//SetString( xml, pEnd, &attr->m_sValue, trim, chXMLEscape );
SetString( xml, pEnd, &attr->m_sValue, trim, escape );
2004-02-09 08:10:01 +00:00
xml = pEnd;
2004-02-09 19:33:56 +00:00
// ATTRVALUE
if( pi->entity_value && pi->entitys )
2005-01-07 14:28:00 +00:00
attr->m_sValue = pi->entitys->Ref2Entity(attr->m_sValue);
2004-02-09 08:10:01 +00:00
2004-02-09 19:33:56 +00:00
if( quote == '"' || quote == '\'' )
xml++;
2004-02-09 08:10:01 +00:00
}
}
2005-02-18 14:03:50 +00:00
// not well-formed tag
2004-02-09 08:10:01 +00:00
return NULL;
}
// <TAG attr1="value1" attr2='value2' attr3=value3 >
// </TAG>
// or
// <TAG />
// ^- return pointer
//========================================================
// Name : Load
// Desc : load xml plain text
// Param : pszXml - plain xml text
// pi = parser information
// Return : advanced string pointer (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2004-07-23 02:27:37 +00:00
char* XNode::Load( const char* pszXml, PARSEINFO *pi /*= &piDefault*/ )
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
Clear();
2004-02-09 08:10:01 +00:00
2004-02-25 01:09:17 +00:00
char* xml = (char*)pszXml;
2004-02-09 08:10:01 +00:00
// <
2004-02-25 01:09:17 +00:00
xml = strchr( xml, chXMLTagOpen );
2004-02-09 08:10:01 +00:00
if( xml == NULL )
return NULL;
// </
if( xml[1] == chXMLTagPre )
2004-02-09 08:10:01 +00:00
return xml;
/* <!-- */
if( !strncmp(xml+1, "!--", 3) )
{
xml += 4;
/* Find the close tag. */
char *pEnd = strstr( xml, "-->" );
if( pEnd == NULL )
{
if( !pi->error_occur )
{
pi->error_occur = true;
pi->error_pointer = xml;
pi->error_code = PIE_ALONE_NOT_CLOSED;
pi->error_string = "Unterminated comment";
}
return NULL;
}
// Skip -->.
xml = pEnd + 3;
return Load( xml, pi );
}
2004-02-09 08:10:01 +00:00
// XML Node Tag Name Open
xml++;
2005-01-07 21:52:59 +00:00
char* pTagEnd = strpbrk( xml, " \t\r\n/>" );
2005-01-07 14:28:00 +00:00
SetString( xml, pTagEnd, &m_sName );
2005-02-18 14:03:50 +00:00
2004-02-09 08:10:01 +00:00
xml = pTagEnd;
// Generate XML Attributte List
2004-02-09 19:33:56 +00:00
xml = LoadAttributes( xml, pi );
if( xml == NULL )
return NULL;
2005-02-18 14:03:50 +00:00
// alone tag <TAG ... /> or <?TAG ... ?> or <!-- ... -->
// current pointer: ^ ^ ^
if( *xml == chXMLTagPre || *xml == chXMLQuestion || *xml == chXMLDash )
2004-02-09 08:10:01 +00:00
{
2004-02-09 19:33:56 +00:00
xml++;
2005-02-18 14:03:50 +00:00
// skip over 2nd dash
if( *xml == chXMLDash )
xml++;
2004-02-09 19:33:56 +00:00
if( *xml == chXMLTagClose )
2004-07-11 04:06:59 +00:00
{
2005-02-18 13:05:17 +00:00
// well-formed tag
2004-07-11 04:06:59 +00:00
++xml;
// UGLY: We want to ignore all XML meta tags. So, since the Node we
// just loaded is a meta tag, then Load ourself again using the rest
// of the file until we reach a non-meta tag.
2005-02-18 14:03:50 +00:00
if( !m_sName.empty() && (m_sName[0] == chXMLQuestion || m_sName[0] == chXMLExclamation) )
2004-07-11 04:06:59 +00:00
xml = Load( xml, pi );
return xml;
}
2004-02-09 19:33:56 +00:00
else
2004-02-09 08:10:01 +00:00
{
2004-02-09 19:33:56 +00:00
// error: <TAG ... / >
2005-02-18 11:55:34 +00:00
if( !pi->error_occur )
2004-02-09 19:33:56 +00:00
{
2005-02-18 11:55:34 +00:00
pi->error_occur = true;
2004-02-09 19:33:56 +00:00
pi->error_pointer = xml;
pi->error_code = PIE_ALONE_NOT_CLOSED;
pi->error_string = ("Element must be closed.");
}
// not wel-formed tag
return NULL;
}
}
else
// open/close tag <TAG ..> ... </TAG>
// ^- current pointer
{
// text value°¡ ¾øÀ¸¸E³Öµµ·ÏÇÑ´Ù.
2005-01-07 14:28:00 +00:00
//if( this->m_sValue.empty() || this->m_sValue == ("") )
if( XIsEmptyString( m_sValue ) )
2004-02-09 19:33:56 +00:00
{
// Text Value
2004-08-18 22:09:23 +00:00
char* pEnd = tcsechr( ++xml, chXMLTagOpen, chXMLEscape );
2004-02-09 19:33:56 +00:00
if( pEnd == NULL )
2004-02-09 08:10:01 +00:00
{
2005-02-18 11:55:34 +00:00
if( !pi->error_occur )
2004-02-09 08:10:01 +00:00
{
2005-02-18 11:55:34 +00:00
pi->error_occur = true;
2004-02-09 08:10:01 +00:00
pi->error_pointer = xml;
2004-02-09 19:33:56 +00:00
pi->error_code = PIE_NOT_CLOSED;
2005-01-07 14:28:00 +00:00
pi->error_string = ssprintf( "%s must be closed with </%s>", m_sName.c_str(), m_sName.c_str() );
2004-02-09 08:10:01 +00:00
}
2004-02-09 19:33:56 +00:00
// error cos not exist CloseTag </TAG>
2004-02-09 08:10:01 +00:00
return NULL;
}
2004-02-09 19:33:56 +00:00
bool trim = pi->trim_value;
2004-08-18 22:09:23 +00:00
char escape = pi->escape_value;
2005-01-07 14:28:00 +00:00
//SetString( xml, pEnd, &m_sValue, trim, chXMLEscape );
SetString( xml, pEnd, &m_sValue, trim, escape );
2004-02-09 19:33:56 +00:00
xml = pEnd;
// TEXTVALUE reference
if( pi->entity_value && pi->entitys )
2005-01-07 14:28:00 +00:00
m_sValue = pi->entitys->Ref2Entity(m_sValue);
2004-02-09 08:10:01 +00:00
}
2004-02-09 19:33:56 +00:00
// generate child nodes
while( xml && *xml )
2004-02-09 08:10:01 +00:00
{
2004-07-23 02:27:37 +00:00
XNode *node = new XNode;
2004-02-09 19:33:56 +00:00
xml = node->Load( xml,pi );
2005-01-07 14:28:00 +00:00
if( !node->m_sName.empty() )
2004-02-09 19:33:56 +00:00
{
2005-01-07 14:28:00 +00:00
DEBUG_ASSERT( node->m_sName.size() );
m_childs.insert( pair<CString,XNode*>(node->m_sName, node) );
2004-02-09 19:33:56 +00:00
}
else
{
delete node;
}
// open/close tag <TAG ..> ... </TAG>
// ^- current pointer
// CloseTag case
if( xml && *xml && *(xml+1) && *xml == chXMLTagOpen && *(xml+1) == chXMLTagPre )
2004-02-09 08:10:01 +00:00
{
2004-02-09 19:33:56 +00:00
// </Close>
xml+=2; // C
2004-07-22 20:14:26 +00:00
xml = tcsskip( xml );
2004-02-09 19:33:56 +00:00
if( xml == NULL )
return NULL;
CString closename;
2004-08-18 22:09:23 +00:00
char* pEnd = strpbrk( xml, " >" );
2004-02-09 08:10:01 +00:00
if( pEnd == NULL )
{
2005-02-18 11:55:34 +00:00
if( !pi->error_occur )
2004-02-09 08:10:01 +00:00
{
2005-02-18 11:55:34 +00:00
pi->error_occur = true;
2004-02-09 08:10:01 +00:00
pi->error_pointer = xml;
pi->error_code = PIE_NOT_CLOSED;
2005-01-07 14:28:00 +00:00
pi->error_string = ssprintf( "it must be closed with </%s>", m_sName.c_str() );
2004-02-09 08:10:01 +00:00
}
2004-02-09 19:33:56 +00:00
// error
2004-02-09 08:10:01 +00:00
return NULL;
}
2004-07-22 20:14:26 +00:00
SetString( xml, pEnd, &closename );
2005-01-07 14:28:00 +00:00
if( closename == this->m_sName )
2004-02-09 08:10:01 +00:00
{
2004-02-09 19:33:56 +00:00
// wel-formed open/close
xml = pEnd+1;
// return '>' or ' ' after pointer
return xml;
2004-02-09 08:10:01 +00:00
}
else
{
2004-02-09 19:33:56 +00:00
xml = pEnd+1;
// not welformed open/close
2005-02-18 11:55:34 +00:00
if( !pi->error_occur )
2004-02-09 08:10:01 +00:00
{
2005-02-18 11:55:34 +00:00
pi->error_occur = true;
2004-02-09 19:33:56 +00:00
pi->error_pointer = xml;
pi->error_code = PIE_NOT_NESTED;
2005-01-07 14:28:00 +00:00
pi->error_string = ssprintf( "'<%s> ... </%s>' is not well-formed.", m_sName.c_str(), closename.c_str() );
2004-02-09 19:33:56 +00:00
2004-02-09 08:10:01 +00:00
}
2004-02-09 19:33:56 +00:00
return NULL;
2004-02-09 08:10:01 +00:00
}
2004-02-09 19:33:56 +00:00
}
else // Alone child Tag Loaded
// else ÇØ¾ßÇÏ´ÂÁE¸»¾Æ¾ßÇÏ´ÂÁEÀǽɰ£´Ù.
{
2005-01-07 14:28:00 +00:00
//if( xml && this->m_sValue.empty() && *xml !=chXMLTagOpen )
if( xml && XIsEmptyString( m_sValue ) && *xml !=chXMLTagOpen )
2004-02-09 08:10:01 +00:00
{
2004-02-09 19:33:56 +00:00
// Text Value
2004-08-18 22:09:23 +00:00
char* pEnd = tcsechr( xml, chXMLTagOpen, chXMLEscape );
2004-02-09 19:33:56 +00:00
if( pEnd == NULL )
2004-02-09 08:10:01 +00:00
{
2004-02-09 19:33:56 +00:00
// error cos not exist CloseTag </TAG>
2005-02-18 11:55:34 +00:00
if( !pi->error_occur )
2004-02-09 08:10:01 +00:00
{
2005-02-18 11:55:34 +00:00
pi->error_occur = true;
2004-02-09 19:33:56 +00:00
pi->error_pointer = xml;
pi->error_code = PIE_NOT_CLOSED;
2005-01-07 14:28:00 +00:00
pi->error_string = ssprintf( "it must be closed with </%s>", m_sName.c_str() );
2004-02-09 08:10:01 +00:00
}
2004-02-09 19:33:56 +00:00
return NULL;
2004-02-09 08:10:01 +00:00
}
2004-02-09 19:33:56 +00:00
bool trim = pi->trim_value;
2004-08-18 22:09:23 +00:00
char escape = pi->escape_value;
2005-01-07 14:28:00 +00:00
//SetString( xml, pEnd, &m_sValue, trim, chXMLEscape );
SetString( xml, pEnd, &m_sValue, trim, escape );
2004-02-09 19:33:56 +00:00
xml = pEnd;
//TEXTVALUE
if( pi->entity_value && pi->entitys )
2005-01-07 14:28:00 +00:00
m_sValue = pi->entitys->Ref2Entity(m_sValue);
2004-02-09 08:10:01 +00:00
}
}
}
}
return xml;
}
//========================================================
// Name : GetXML
// Desc : convert plain xml text from parsed xml attirbute
// Param :
// Return : converted plain string
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2005-02-18 13:05:17 +00:00
bool XAttr::GetXML( RageFileBasic &f, DISP_OPT *opt ) const
2004-02-09 08:10:01 +00:00
{
return f.Write(m_sName + "='" + (opt && opt->reference_value && opt->entitys ? opt->entitys->Entity2Ref(m_sValue) : m_sValue) + "' ") != -1;
2004-02-09 08:10:01 +00:00
}
//========================================================
// Name : GetXML
// Desc : convert plain xml text from parsed xml node
// Param :
// Return : converted plain string
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2005-02-18 13:05:17 +00:00
bool XNode::GetXML( RageFileBasic &f, DISP_OPT *opt ) const
2004-02-09 08:10:01 +00:00
{
// tab
if( opt && opt->newline )
{
if( opt && opt->newline )
2004-06-06 20:47:48 +00:00
if( f.Write("\r\n") == -1 )
return false;
if( opt->write_tabs )
for( int i = 0 ; i < opt->tab_base ; i++)
if( f.Write("\t") == -1 )
return false;
2004-02-09 08:10:01 +00:00
}
// <TAG
2005-01-07 14:28:00 +00:00
if( f.Write("<" + m_sName) == -1 )
2004-06-06 20:47:48 +00:00
return false;
2004-02-09 08:10:01 +00:00
// <TAG Attr1="Val1"
2005-01-07 14:28:00 +00:00
if( !m_attrs.empty() )
2004-06-06 20:47:48 +00:00
if( f.Write(" ") == -1 )
return false;
2005-02-18 03:07:22 +00:00
FOREACH_CONST_Attr( this, p )
2005-01-07 09:09:23 +00:00
if( !p->GetXML(f, opt) )
2004-06-06 20:47:48 +00:00
return false;
2004-02-09 08:10:01 +00:00
2005-01-07 14:28:00 +00:00
if( m_childs.empty() && m_sValue.empty() )
2004-02-09 08:10:01 +00:00
{
// <TAG Attr1="Val1"/> alone tag
2004-06-06 20:47:48 +00:00
if( f.Write("/>") == -1 )
return false;
2004-02-09 08:10:01 +00:00
}
else
{
// <TAG Attr1="Val1"> and get child
2004-06-06 20:47:48 +00:00
if( f.Write(">") == -1 )
return false;
2005-01-07 14:28:00 +00:00
if( opt && opt->newline && !m_childs.empty() )
2004-02-09 08:10:01 +00:00
{
opt->tab_base++;
}
2005-02-18 03:07:22 +00:00
FOREACH_CONST_Child( this, p )
2005-01-07 09:09:23 +00:00
if( !p->GetXML( f, opt ) )
2004-06-06 20:47:48 +00:00
return false;
2004-02-09 08:10:01 +00:00
// Text Value
2005-01-07 14:28:00 +00:00
if( m_sValue != ("") )
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
if( opt && opt->newline && !m_childs.empty() )
2004-02-09 08:10:01 +00:00
{
if( opt && opt->newline )
2004-06-06 20:47:48 +00:00
if( f.Write("\r\n") == -1 )
return false;
if( opt->write_tabs )
for( int i = 0 ; i < opt->tab_base ; i++)
if( f.Write("\t") == -1 )
return false;
2004-02-09 08:10:01 +00:00
}
2005-06-16 02:49:39 +00:00
if( f.Write((opt && opt->reference_value && opt->entitys ? opt->entitys->Entity2Ref(m_sValue) : m_sValue)) == -1 )
2004-06-06 20:47:48 +00:00
return false;
2004-02-09 08:10:01 +00:00
}
// </TAG> CloseTag
2005-01-07 14:28:00 +00:00
if( opt && opt->newline && !m_childs.empty() )
2004-02-09 08:10:01 +00:00
{
2004-06-06 20:47:48 +00:00
if( f.Write("\r\n") == -1 )
return false;
if( opt->write_tabs )
for( int i = 0 ; i < opt->tab_base-1 ; i++)
if( f.Write("\t") == -1 )
return false;
2004-02-09 08:10:01 +00:00
}
2005-01-07 14:28:00 +00:00
if( f.Write("</" + m_sName + ">") == -1 )
2004-06-06 20:47:48 +00:00
return false;
2004-02-09 08:10:01 +00:00
if( opt && opt->newline )
{
2005-01-07 14:28:00 +00:00
if( !m_childs.empty() )
2004-02-09 08:10:01 +00:00
opt->tab_base--;
}
}
2004-06-06 20:47:48 +00:00
return true;
2004-02-09 08:10:01 +00:00
}
2004-07-17 21:49:32 +00:00
//========================================================
// Name : GetValue
// Desc :
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
//========================================================
2005-01-07 14:28:00 +00:00
void XNode::GetValue(CString &out) const { out = m_sValue; }
void XNode::GetValue(int &out) const { out = atoi(m_sValue); }
void XNode::GetValue(float &out) const { out = strtof(m_sValue, NULL); }
void XNode::GetValue(bool &out) const { out = atoi(m_sValue) != 0; }
void XNode::GetValue(unsigned &out) const { out = (unsigned)atoi(m_sValue); }
2005-01-07 14:28:00 +00:00
void XNode::GetValue(DateTime &out) const { out.FromString( m_sValue ); }
2004-07-18 21:55:49 +00:00
2005-01-07 14:28:00 +00:00
void XAttr::GetValue(CString &out) const { out = m_sValue; }
void XAttr::GetValue(int &out) const { out = atoi(m_sValue); }
void XAttr::GetValue(float &out) const { out = strtof(m_sValue, NULL); }
void XAttr::GetValue(bool &out) const { out = atoi(m_sValue) != 0; }
void XAttr::GetValue(unsigned &out) const { out = (unsigned)atoi(m_sValue); }
2005-01-07 14:28:00 +00:00
void XAttr::GetValue(DateTime &out) const { out.FromString( m_sValue ); }
2004-07-18 21:55:49 +00:00
//========================================================
// Name : SetValue
// Desc :
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
//========================================================
2005-01-07 14:28:00 +00:00
void XNode::SetValue(int v) { m_sValue = ssprintf("%d",v); }
void XNode::SetValue(float v) { m_sValue = ssprintf("%f",v); }
void XNode::SetValue(bool v) { m_sValue = ssprintf("%d",v); }
void XNode::SetValue(unsigned v) { m_sValue = ssprintf("%u",v); }
void XNode::SetValue(const DateTime &v) { m_sValue = v.GetString(); }
2004-07-17 21:49:32 +00:00
2004-02-09 08:10:01 +00:00
//========================================================
// Name : GetAttr
// Desc : get attribute with attribute name
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2004-07-23 02:27:37 +00:00
const XAttr *XNode::GetAttr( const char* attrname ) const
2004-02-22 05:12:23 +00:00
{
2005-01-07 14:28:00 +00:00
multimap<CString, XAttr*>::const_iterator it = m_attrs.find( attrname );
if( it != m_attrs.end() )
{
DEBUG_ASSERT( attrname == it->second->m_sName );
2005-01-07 09:09:23 +00:00
return it->second;
2005-01-07 14:28:00 +00:00
}
2004-02-22 05:12:23 +00:00
return NULL;
}
2004-07-23 02:27:37 +00:00
XAttr *XNode::GetAttr( const char* attrname )
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
multimap<CString, XAttr*>::iterator it = m_attrs.find( attrname );
if( it != m_attrs.end() )
{
DEBUG_ASSERT( attrname == it->second->m_sName );
2005-01-07 09:09:23 +00:00
return it->second;
2005-01-07 14:28:00 +00:00
}
2004-02-09 08:10:01 +00:00
return NULL;
}
//========================================================
// Name : GetAttrValue
// Desc : get attribute with attribute name, return its value
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
const char* XNode::GetAttrValue( const char* attrname )
2004-02-09 08:10:01 +00:00
{
2004-07-23 02:27:37 +00:00
XAttr *attr = GetAttr( attrname );
2005-01-07 14:28:00 +00:00
return attr ? (const char*)attr->m_sValue : NULL;
2004-02-09 08:10:01 +00:00
}
//========================================================
// Name : GetChildCount
// Desc : get child node count
// Param :
// Return : 0 return if no child
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-12-26
//========================================================
int XNode::GetChildCount()
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
return m_childs.size();
2004-02-09 08:10:01 +00:00
}
//========================================================
// Name : GetChild
// Desc : Find child with name and return child
// Param :
// Return : NULL return if no child.
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2004-07-23 02:27:37 +00:00
XNode *XNode::GetChild( const char* name )
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
multimap<CString, XNode*>::iterator it = m_childs.find( name );
if( it != m_childs.end() )
{
DEBUG_ASSERT( name == it->second->m_sName );
2005-01-07 09:09:23 +00:00
return it->second;
2005-01-07 14:28:00 +00:00
}
2004-02-09 08:10:01 +00:00
return NULL;
}
2004-07-23 02:27:37 +00:00
const XNode *XNode::GetChild( const char* name ) const
2004-02-19 03:19:41 +00:00
{
2005-01-07 14:28:00 +00:00
multimap<CString, XNode*>::const_iterator it = m_childs.find( name );
if( it != m_childs.end() )
{
DEBUG_ASSERT( name == it->second->m_sName );
2005-01-07 09:09:23 +00:00
return it->second;
2005-01-07 14:28:00 +00:00
}
2004-02-19 03:19:41 +00:00
return NULL;
}
2004-02-09 08:10:01 +00:00
//========================================================
// Name : GetChildValue
// Desc : Find child with name and return child's value
// Param :
// Return : NULL return if no child.
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
const char* XNode::GetChildValue( const char* name )
2004-02-09 08:10:01 +00:00
{
2004-07-23 02:27:37 +00:00
XNode *node = GetChild( name );
2005-01-07 14:28:00 +00:00
return (node != NULL)? (const char*)node->m_sValue : NULL;
2004-02-09 08:10:01 +00:00
}
2004-07-23 02:27:37 +00:00
XAttr *XNode::GetChildAttr( const char* name, const char* attrname )
2004-02-09 08:10:01 +00:00
{
2004-07-23 02:27:37 +00:00
XNode *node = GetChild(name);
2004-02-09 08:10:01 +00:00
return node ? node->GetAttr(attrname) : NULL;
}
const char* XNode::GetChildAttrValue( const char* name, const char* attrname )
2004-02-09 08:10:01 +00:00
{
2004-07-23 02:27:37 +00:00
XAttr *attr = GetChildAttr( name, attrname );
2005-01-07 14:28:00 +00:00
return attr ? (const char*)attr->m_sValue : NULL;
2004-02-09 08:10:01 +00:00
}
//========================================================
// Name : AppendChild
// Desc : add node
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2005-01-07 14:28:00 +00:00
XNode *XNode::AppendChild( const char* name, const char* value ) { XNode *p = new XNode; p->m_sName = name; p->m_sValue = value; return AppendChild( p ); }
XNode *XNode::AppendChild( const char* name, float value ) { XNode *p = new XNode; p->m_sName = name; p->SetValue( value ); return AppendChild( p ); }
XNode *XNode::AppendChild( const char* name, int value ) { XNode *p = new XNode; p->m_sName = name; p->SetValue( value ); return AppendChild( p ); }
XNode *XNode::AppendChild( const char* name, unsigned value ) { XNode *p = new XNode; p->m_sName = name; p->SetValue( value ); return AppendChild( p ); }
XNode *XNode::AppendChild( const char* name, const DateTime &value ) { XNode *p = new XNode; p->m_sName = name; p->SetValue( value ); return AppendChild( p ); }
2004-02-09 08:10:01 +00:00
//========================================================
// Name : AppendChild
// Desc : add node
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2004-07-23 02:27:37 +00:00
XNode *XNode::AppendChild( XNode *node )
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
DEBUG_ASSERT( node->m_sName.size() );
m_childs.insert( pair<CString,XNode*>(node->m_sName,node) );
2004-02-09 08:10:01 +00:00
return node;
}
//========================================================
// Name : RemoveChild
// Desc : detach node and delete object
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2004-07-23 02:27:37 +00:00
bool XNode::RemoveChild( XNode *node )
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
FOREACHMM( CString, XNode*, m_childs, p )
2004-02-09 08:10:01 +00:00
{
2005-01-07 09:09:23 +00:00
if( p->second == node )
{
SAFE_DELETE( p->second );
2005-01-07 14:28:00 +00:00
m_childs.erase( p );
2005-01-07 09:09:23 +00:00
return true;
}
2004-02-09 08:10:01 +00:00
}
return false;
}
//========================================================
// Name : AppendAttr
// Desc : add attribute
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2004-07-23 02:27:37 +00:00
XAttr *XNode::AppendAttr( XAttr *attr )
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
DEBUG_ASSERT( attr->m_sName.size() );
m_attrs.insert( pair<CString,XAttr*>(attr->m_sName,attr) );
2004-02-09 08:10:01 +00:00
return attr;
}
//========================================================
// Name : RemoveAttr
// Desc : detach attribute and delete object
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2004-07-23 02:27:37 +00:00
bool XNode::RemoveAttr( XAttr *attr )
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
FOREACHMM( CString, XAttr*, m_attrs, p )
2004-02-09 08:10:01 +00:00
{
2005-01-07 09:09:23 +00:00
if( p->second == attr )
{
SAFE_DELETE( p->second );
2005-01-07 14:28:00 +00:00
m_attrs.erase( p );
2005-01-07 09:09:23 +00:00
return true;
}
2004-02-09 08:10:01 +00:00
}
return false;
}
//========================================================
2005-01-07 14:28:00 +00:00
// Name : AppendAttr
// Desc : add attribute
2004-02-09 08:10:01 +00:00
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2005-01-07 14:28:00 +00:00
XAttr *XNode::AppendAttr( const char* name /*= NULL*/, const char* value /*= NULL*/ )
2004-02-09 08:10:01 +00:00
{
2004-07-23 02:27:37 +00:00
XAttr *attr = new XAttr;
2005-01-07 14:28:00 +00:00
attr->m_sName = name;
attr->m_sValue = value;
return AppendAttr( attr );
2004-02-09 08:10:01 +00:00
}
2005-01-07 14:28:00 +00:00
XAttr *XNode::AppendAttr( const char* name, float value ){ return AppendAttr(name,ssprintf("%f",value)); }
XAttr *XNode::AppendAttr( const char* name, int value ) { return AppendAttr(name,ssprintf("%d",value)); }
XAttr *XNode::AppendAttr( const char* name, unsigned value ) { return AppendAttr(name,ssprintf("%u",value)); }
2004-02-09 08:10:01 +00:00
//========================================================
2005-01-07 14:28:00 +00:00
// Name : SetAttrValue
2004-02-09 08:10:01 +00:00
// Desc : add attribute
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
2005-01-07 14:28:00 +00:00
void XNode::SetAttrValue( const char* name, const char* value )
2004-02-09 08:10:01 +00:00
{
2005-01-07 14:28:00 +00:00
XAttr* pAttr = GetAttr( name );
if( pAttr )
pAttr->m_sValue = value;
else
AppendAttr( name, value );
2004-02-09 08:10:01 +00:00
}
2004-07-23 02:27:37 +00:00
XENTITYS::XENTITYS( XENTITY *entities, int count )
2004-02-09 08:10:01 +00:00
{
for( int i = 0; i < count; i++)
push_back( entities[i] );
}
2004-07-23 02:27:37 +00:00
XENTITY *XENTITYS::GetEntity( int entity )
2004-02-09 08:10:01 +00:00
{
for( unsigned i = 0 ; i < size(); i ++ )
{
if( at(i).entity == entity )
2004-07-23 02:27:37 +00:00
return (XENTITY *) (&at(i));
2004-02-09 08:10:01 +00:00
}
return NULL;
}
2004-07-23 02:27:37 +00:00
XENTITY *XENTITYS::GetEntity( char* entity )
2004-02-09 08:10:01 +00:00
{
for( unsigned i = 0 ; i < size(); i ++ )
{
2004-02-25 01:09:17 +00:00
char* ref = (char*)at(i).ref;
char* ps = entity;
2004-02-09 08:10:01 +00:00
while( ref && *ref )
if( *ref++ != *ps++ )
break;
if( ref && !*ref ) // found!
2004-07-23 02:27:37 +00:00
return (XENTITY *) (&at(i));
2004-02-09 08:10:01 +00:00
}
return NULL;
}
int XENTITYS::GetEntityCount( const char* str )
2004-02-09 08:10:01 +00:00
{
int nCount = 0;
2004-02-25 01:09:17 +00:00
char* ps = (char*)str;
2004-02-09 08:10:01 +00:00
while( ps && *ps )
if( GetEntity( *ps++ ) ) nCount ++;
return nCount;
}
int XENTITYS::Ref2Entity( const char* estr, char* str, int strlen )
2004-02-09 08:10:01 +00:00
{
2004-02-25 01:09:17 +00:00
char* pes = (char*)estr;
char* ps = str;
char* ps_end = ps+strlen;
2004-02-09 08:10:01 +00:00
while( pes && *pes && ps < ps_end )
{
2004-07-23 02:27:37 +00:00
XENTITY *ent = GetEntity( pes );
2004-02-09 08:10:01 +00:00
if( ent )
{
// copy entity meanning char
*ps = ent->entity;
pes += ent->ref_len;
}
else
*ps = *pes++; // default character copy
ps++;
}
*ps = '\0';
// total copied characters
return ps-str;
}
int XENTITYS::Entity2Ref( const char* str, char* estr, int estrlen )
2004-02-09 08:10:01 +00:00
{
2004-02-25 01:09:17 +00:00
char* ps = (char*)str;
char* pes = (char*)estr;
char* pes_end = pes+estrlen;
2004-02-09 08:10:01 +00:00
while( ps && *ps && pes < pes_end )
{
2004-07-23 02:27:37 +00:00
XENTITY *ent = GetEntity( *ps );
2004-02-09 08:10:01 +00:00
if( ent )
{
// copy entity string
2004-02-25 01:09:17 +00:00
char* ref = (char*)ent->ref;
2004-02-09 08:10:01 +00:00
while( ref && *ref )
*pes++ = *ref++;
}
else
*pes++ = *ps; // default character copy
ps++;
}
*pes = '\0';
// total copied characters
return pes-estr;
}
CString XENTITYS::Ref2Entity( const char* estr )
2004-02-09 08:10:01 +00:00
{
CString es;
if( estr )
{
2004-02-25 01:09:17 +00:00
int len = strlen(estr);
// char* esbuf = es.GetBufferSetLength( len+1 );
2004-07-22 18:25:58 +00:00
char* szTemp = new char[len+1];
2004-02-09 08:10:01 +00:00
if( szTemp )
Ref2Entity( estr, szTemp, len );
es = szTemp;
2004-07-22 18:25:58 +00:00
delete [] szTemp;
2004-02-09 08:10:01 +00:00
}
return es;
}
CString XENTITYS::Entity2Ref( const char* str )
2004-02-09 08:10:01 +00:00
{
CString s;
if( str )
{
int nEntityCount = GetEntityCount(str);
if( nEntityCount == 0 )
return CString(str);
2004-02-25 01:09:17 +00:00
int len = strlen(str) + nEntityCount*10 ;
//char* sbuf = s.GetBufferSetLength( len+1 );
2004-07-22 18:25:58 +00:00
char* szTemp = new char[len+1];
2004-02-09 08:10:01 +00:00
if( szTemp )
Entity2Ref( str, szTemp, len );
s = szTemp;
2004-07-22 18:25:58 +00:00
delete [] szTemp;
2004-02-09 08:10:01 +00:00
}
return s;
}
2004-02-25 01:09:17 +00:00
CString XRef2Entity( const char* estr )
2004-02-09 08:10:01 +00:00
{
return entityDefault.Ref2Entity( estr );
}
2004-02-25 01:09:17 +00:00
CString XEntity2Ref( const char* str )
2004-02-09 08:10:01 +00:00
{
return entityDefault.Entity2Ref( str );
}
2004-02-10 09:42:01 +00:00
bool XNode::LoadFromFile( const CString &sFile )
2004-02-10 09:42:01 +00:00
{
RageFile f;
if( !f.Open(sFile, RageFile::READ) )
2004-04-02 05:06:32 +00:00
{
LOG->Warn("Couldn't open %s for reading: %s", sFile.c_str(), f.GetError().c_str() );
2004-02-10 09:42:01 +00:00
return false;
2004-04-02 05:06:32 +00:00
}
2005-01-08 19:12:44 +00:00
bool bSuccess = LoadFromFile( f );
if( !bSuccess )
{
CString sWarning = ssprintf( "XML: LoadFromFile failed for file: %s", sFile.c_str() );
LOG->Warn( sWarning );
Dialog::OK( sWarning, "XML_PARSE_ERROR" );
}
return bSuccess;
2005-01-08 19:12:44 +00:00
}
bool XNode::LoadFromFile( RageFileBasic &f )
2005-01-08 19:12:44 +00:00
{
PARSEINFO pi;
2004-02-10 09:42:01 +00:00
CString s;
2004-06-06 20:47:48 +00:00
if( f.Read( s ) == -1 )
{
pi.error_occur = true;
pi.error_pointer = NULL;
pi.error_code = PIE_READ_ERROR;
pi.error_string = f.GetError();
2004-06-06 20:47:48 +00:00
goto error;
2004-06-06 20:47:48 +00:00
}
this->Load( s, &pi );
if( pi.error_occur )
goto error;
return true;
error:
CString sWarning = ssprintf( "XML: LoadFromFile failed: %s", pi.error_string.c_str() );
LOG->Warn( sWarning );
Dialog::OK( sWarning, "XML_PARSE_ERROR" );
return false;
2004-02-10 09:42:01 +00:00
}
2005-02-18 03:07:22 +00:00
bool XNode::SaveToFile( RageFileBasic &f, DISP_OPT *opt ) const
2004-02-10 09:42:01 +00:00
{
2004-07-11 01:58:55 +00:00
f.PutLine( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" );
if( !opt->stylesheet.empty() )
f.PutLine( "<?xml-stylesheet type=\"text/xsl\" href=\"" + opt->stylesheet + "\"?>" );
2004-06-06 20:47:48 +00:00
if( !this->GetXML(f, opt) )
return false;
if( f.Flush() == -1 )
return false;
2004-02-10 09:42:01 +00:00
return true;
}
2004-07-18 21:55:49 +00:00
2005-02-18 03:07:22 +00:00
bool XNode::SaveToFile( const CString &sFile, DISP_OPT *opt ) const
2004-12-18 05:37:53 +00:00
{
RageFile f;
if( !f.Open(sFile, RageFile::WRITE) )
{
LOG->Warn("Couldn't open %s for writing: %s", sFile.c_str(), f.GetError().c_str() );
return false;
}
return SaveToFile( f, opt );
}
2004-07-18 21:55:49 +00:00
bool XIsEmptyString( const char* str )
{
CString s(str);
TrimLeft( s );
TrimRight( s );
return ( s.empty() || s == "" );
}