diff --git a/stepmania/src/Makefile.am b/stepmania/src/Makefile.am index 9498449424..f058a58b09 100644 --- a/stepmania/src/Makefile.am +++ b/stepmania/src/Makefile.am @@ -67,7 +67,7 @@ ScoreKeeper.h ScoreKeeperMAX2.cpp ScoreKeeperMAX2.h ScoreKeeperRave.cpp ScoreKee Song.cpp song.h SongCacheIndex.cpp SongCacheIndex.h SongOptions.cpp SongOptions.h StageStats.cpp StageStats.h Steps.cpp Steps.h \ Style.h StyleDef.cpp StyleDef.h StyleInput.h TimingData.cpp TimingData.h TitleSubstitution.cpp TitleSubstitution.h -FileTypes = IniFile.cpp IniFile.h MsdFile.cpp MsdFile.h +FileTypes = IniFile.cpp IniFile.h MsdFile.cpp MsdFile.h XmlFile.cpp XmlFile.h StepMania = StdString.h StepMania.cpp StepMania.h global.cpp global.h diff --git a/stepmania/src/ProfileManager.cpp b/stepmania/src/ProfileManager.cpp index 612d8e6eb6..9eb7e622e2 100644 --- a/stepmania/src/ProfileManager.cpp +++ b/stepmania/src/ProfileManager.cpp @@ -31,6 +31,7 @@ #include "Bookkeeper.h" #include #include "MemoryCardManager.h" +#include "XmlFile.h" ProfileManager* PROFILEMAN = NULL; // global and accessable from anywhere in our program @@ -220,6 +221,7 @@ bool ProfileManager::SaveProfile( PlayerNumber pn ) SaveCategoryScoresToDir( m_sProfileDir[pn], (ProfileSlot)pn ); SaveSongScoresToDir( m_sProfileDir[pn], (ProfileSlot)pn ); + SaveSongScoresToDirXml( m_sProfileDir[pn], (ProfileSlot)pn ); SaveCourseScoresToDir( m_sProfileDir[pn], (ProfileSlot)pn ); SaveStatsWebPageToDir( m_sProfileDir[pn], (ProfileSlot)pn ); @@ -389,6 +391,7 @@ void ProfileManager::SaveMachineScoresToDisk() SaveCategoryScoresToDir( MACHINE_PROFILE_DIR, PROFILE_SLOT_MACHINE ); SaveSongScoresToDir( MACHINE_PROFILE_DIR, PROFILE_SLOT_MACHINE ); + SaveSongScoresToDirXml( MACHINE_PROFILE_DIR, PROFILE_SLOT_MACHINE ); SaveCourseScoresToDir( MACHINE_PROFILE_DIR, PROFILE_SLOT_MACHINE ); SaveStatsWebPageToDir( MACHINE_PROFILE_DIR, PROFILE_SLOT_MACHINE ); } @@ -929,6 +932,86 @@ void ProfileManager::SaveSongScoresToDir( CString sDir, ProfileSlot slot ) } } +void ProfileManager::SaveSongScoresToDirXml( CString sDir, ProfileSlot slot ) +{ + Profile* pProfile = GetProfile( slot ); + ASSERT( pProfile ); + + CString fn = sDir + SONG_SCORES_FILE+".xml"; + + LOG->Trace("SongManager::SaveSongScoresToFile %s", fn.c_str()); + + RageFile f; + if( !f.Open(fn, RageFile::WRITE) ) + { + LOG->Warn( "Couldn't open file \"%s\" for writing: %s", fn.c_str(), f.GetError().c_str() ); + return; + } + + XNode xml; + xml.name = "SongScores"; + + const vector &vpSongs = SONGMAN->GetAllSongs(); + + for( unsigned s=0; s vNotesToWrite; + for( unsigned i=0; im_apNotes.size(); ++i ) + { + Steps* pNotes = pSong->m_apNotes[i]; + HighScoreList &hsl = pProfile->GetStepsHighScoreList( pNotes ); + if( hsl.iNumTimesPlayed == 0 && hsl.vHighScores.empty() ) + continue; + vNotesToWrite.push_back( pNotes ); + } + + if( vNotesToWrite.empty() ) + continue; + + LPXNode pSongNode = xml.AppendChild( "Song" ); + pSongNode->AppendChild( "Dir", pSong->GetSongDir() ); + + for( unsigned n=0; nAppendChild( "Steps" ); + + Steps* pNotes = vNotesToWrite[n]; + ASSERT(pNotes); + + HighScoreList &hsl = pProfile->GetStepsHighScoreList( pNotes ); + + pStepsNode->AppendChild( "StepsType", pNotes->m_StepsType ); + pStepsNode->AppendChild( "Difficulty", pNotes->GetDifficulty() ); + pStepsNode->AppendChild( "Description", pNotes->GetDescription() ); + pStepsNode->AppendChild( "NumTimesPlayed", hsl.iNumTimesPlayed ); + + for( int l=0; l<(int)hsl.vHighScores.size(); l++ ) + { + HighScore &hs = hsl.vHighScores[l]; + + LPXNode pHighScoreNode = pSongNode->AppendChild( "HighScore" ); + + // tricky: wipe out "name to fill in" markers + if( IsRankingToFillIn(hs.sName) ) + hs.sName = ""; + + pHighScoreNode->AppendChild( "Name", hs.sName ); + pHighScoreNode->AppendChild( "Grade", hs.grade ); + pHighScoreNode->AppendChild( "Score", hs.iScore ); + pHighScoreNode->AppendChild( "Percent", hs.fPercentDP ); + } + } + } + + FileWrite( f, xml.GetXML() ); +} + /* static CString HTMLQuoteDoubleQuotes( CString str ) { str.Replace( "\"", """ ); diff --git a/stepmania/src/ProfileManager.h b/stepmania/src/ProfileManager.h index f00c8051ce..64000e3cf8 100644 --- a/stepmania/src/ProfileManager.h +++ b/stepmania/src/ProfileManager.h @@ -98,6 +98,7 @@ public: void ReadCourseScoresFromDir( CString sDir, ProfileSlot slot ); void ReadCategoryScoresFromDir( CString sDir, ProfileSlot slot ); + void SaveSongScoresToDirXml( CString sDir, ProfileSlot slot ); void SaveSongScoresToDir( CString sDir, ProfileSlot slot ); void SaveCourseScoresToDir( CString sDir, ProfileSlot slot ); void SaveCategoryScoresToDir( CString sDir, ProfileSlot slot ); diff --git a/stepmania/src/StepMania.dsp b/stepmania/src/StepMania.dsp index c031ae658c..647f3600fb 100644 --- a/stepmania/src/StepMania.dsp +++ b/stepmania/src/StepMania.dsp @@ -65,7 +65,7 @@ IntDir=.\../Debug6 TargetDir=\stepmania\stepmania\Program TargetName=StepMania-debug SOURCE="$(InputPath)" -PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi # End Special Build Tool @@ -103,8 +103,8 @@ IntDir=.\../Debug_Xbox TargetDir=\stepmania\stepmania TargetName=default SOURCE="$(InputPath)" -PreLink_Cmds=disasm\verinc cl /Zl /nologo /c \ - verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=disasm\verinc cl /Zl /nologo /c \ + verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi ia32.vdi # End Special Build Tool @@ -144,7 +144,7 @@ IntDir=.\../Release6 TargetDir=\stepmania\stepmania\Program TargetName=StepMania SOURCE="$(InputPath)" -PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi # End Special Build Tool @@ -184,8 +184,8 @@ IntDir=.\../Release_Xbox TargetDir=\stepmania\stepmania TargetName=default SOURCE="$(InputPath)" -PreLink_Cmds=disasm\verinc cl /Zl /nologo /c \ - verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=disasm\verinc cl /Zl /nologo /c \ + verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi ia32.vdi # End Special Build Tool @@ -1909,6 +1909,25 @@ SOURCE=.\MsdFile.cpp SOURCE=.\MsdFile.h # End Source File +# Begin Source File + +SOURCE=.\XmlFile.cpp + +!IF "$(CFG)" == "StepMania - Win32 Debug" + +!ELSEIF "$(CFG)" == "StepMania - Xbox Debug" + +!ELSEIF "$(CFG)" == "StepMania - Win32 Release" + +!ELSEIF "$(CFG)" == "StepMania - Xbox Release" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\XmlFile.h +# End Source File # End Group # Begin Group "StepMania" diff --git a/stepmania/src/StepMania.vcproj b/stepmania/src/StepMania.vcproj index 26b9e2408b..24c707fc59 100644 --- a/stepmania/src/StepMania.vcproj +++ b/stepmania/src/StepMania.vcproj @@ -810,6 +810,12 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ + + + + +#include +#include + + +static const TCHAR chXMLTagOpen = '<'; +static const TCHAR chXMLTagClose = '>'; +static const TCHAR chXMLTagPre = '/'; +static const TCHAR chXMLEscape = '\\'; // for value field escape + + +static const XENTITY x_EntityTable[] = { + { '&', ("&"), 5 } , + { '\"', ("""), 6 } , + { '\'', ("'"), 6 } , + { '<', ("<"), 4 } , + { '>', (">"), 4 } + }; + +PARSEINFO piDefault; +DISP_OPT optDefault; +XENTITYS entityDefault((LPXENTITY)x_EntityTable, sizeof(x_EntityTable)/sizeof(x_EntityTable[0]) ); +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + + +//======================================================== +// Name : _tcschrs +// Desc : same with _tcspbrk +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPTSTR _tcschrs( LPCTSTR psz, LPCTSTR pszchs ) +{ + while( psz && *psz ) + { + if( strchr( pszchs, *psz ) ) + return (LPTSTR)psz; + psz++; + } + return NULL; +} + +//======================================================== +// Name : _tcsskip +// Desc : skip space +// Param : +// Return : skiped string +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPTSTR _tcsskip( LPCTSTR psz ) +{ + while( psz && *psz == ' ' ) psz++; + + return (LPTSTR)psz; +} + +//======================================================== +// Name : _tcsechr +// Desc : similar with _tcschr with escape process +// Param : escape - will be escape character +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPTSTR _tcsechr( LPCTSTR psz, int ch, int escape ) +{ + LPTSTR pch = (LPTSTR)psz; + LPTSTR prev_escape = NULL; + while( pch && *pch ) + { + if( *pch == escape && prev_escape == NULL ) + prev_escape = pch; + else + { + prev_escape = NULL; + if( *pch == ch ) return (LPTSTR)pch; + } + pch++; + } + return pch; +} + +//======================================================== +// Name : _tcselen +// Desc : similar with _tcslen with escape process +// Param : escape - will be escape character +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +int _tcselen( int escape, LPTSTR srt, LPTSTR end = NULL ) +{ + int len = 0; + LPTSTR pch = srt; + if( end==NULL ) end = (LPTSTR)sizeof(long); + LPTSTR prev_escape = NULL; + while( pch && *pch && pchGetBufferSetLength( len ); + char* szTemp = new char[len]; + _tcsecpy( szTemp, escape, psz, end ); + *ps = szTemp; + } + else + { +// LPTSTR pss = ps->GetBufferSetLength(len + 1 ); + char* szTemp = new char[len+1]; + memcpy( szTemp, psz, len ); + szTemp[len] = '\0'; + *ps = szTemp; + } +} + +_tagXMLNode::~_tagXMLNode() +{ + Close(); +} + +void _tagXMLNode::Close() +{ + unsigned i; + + for( i = 0 ; i < childs.size(); i ++) + { + LPXNode p = childs[i]; + if( p ) + { + delete p; childs[i] = NULL; + } + } + childs.clear(); + + for( i = 0 ; i < attrs.size(); i ++) + { + LPXAttr p = attrs[i]; + if( p ) + { + delete p; attrs[i] = NULL; + } + } + attrs.clear(); +} + +// 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 +//======================================================== +LPTSTR _tagXMLNode::LoadAttributes( LPCTSTR pszAttrs , LPPARSEINFO pi /*= &piDefault*/) +{ + LPTSTR xml = (LPTSTR)pszAttrs; + + while( xml && *xml ) + { + if( xml = _tcsskip( xml ) ) + { + // close tag + if( *xml == chXMLTagClose || *xml == chXMLTagPre ) + // wel-formed tag + return xml; + + // XML Attr Name + TCHAR* pEnd = _tcspbrk( xml, " =" ); + if( pEnd == NULL ) + { + // error + if( pi->erorr_occur == false ) + { + pi->erorr_occur = true; + pi->error_pointer = xml; + pi->error_code = PIE_ATTR_NO_VALUE; + pi->error_string.Format( ("<%s> attribute has error "), name ); + } + return NULL; + } + + LPXAttr attr = new XAttr; + attr->parent = this; + + // XML Attr Name + _SetString( xml, pEnd, &attr->name ); + + // add new attribute + attrs.push_back( attr ); + xml = pEnd; + + // XML Attr Value + if( xml = _tcsskip( xml ) ) + { + //if( xml = _tcschr( xml, '=' ) ) + if( *xml == '=' ) + { + if( xml = _tcsskip( ++xml ) ) + { + // if " or ' + // or none quote + int quote = *xml; + if( quote == '"' || quote == '\'' ) + pEnd = _tcsechr( ++xml, quote, chXMLEscape ); + else + { + //attr= value> + // none quote mode + //pEnd = _tcsechr( xml, ' ', '\\' ); + pEnd = _tcsepbrk( xml, (" >"), chXMLEscape ); + } + + bool trim = pi->trim_value; + TCHAR escape = pi->escape_value; + //_SetString( xml, pEnd, &attr->value, trim, chXMLEscape ); + _SetString( xml, pEnd, &attr->value, trim, escape ); + xml = pEnd; + // ATTRVALUE + if( pi->entity_value && pi->entitys ) + attr->value = pi->entitys->Ref2Entity(attr->value); + + if( quote == '"' || quote == '\'' ) + xml++; + } + } + } + } + } + + // not wel-formed tag + return NULL; +} + +// +// +// or +// +// ^- 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 +//======================================================== +LPTSTR _tagXMLNode::Load( LPCTSTR pszXml, LPPARSEINFO pi /*= &piDefault*/ ) +{ + // Close it + Close(); + + LPTSTR xml = (LPTSTR)pszXml; + + xml = _tcschr( xml, chXMLTagOpen ); + if( xml == NULL ) + return NULL; + + // Close Tag + if( *(xml+1) == chXMLTagPre ) // " ); + _SetString( xml, pTagEnd, &name ); + xml = pTagEnd; + // Generate XML Attributte List + if( xml = LoadAttributes( xml, pi ) ) + { + // alone tag + if( *xml == chXMLTagPre ) + { + xml++; + if( *xml == chXMLTagClose ) + // wel-formed tag + return ++xml; + else + { + // error: + if( pi->erorr_occur == false ) + { + pi->erorr_occur = true; + 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 ... + // ^- current pointer + { + // text value°¡ ¾øÀ¸¸é ³Öµµ·ÏÇÑ´Ù. + //if( this->value.IsEmpty() || this->value == ("") ) + if( XIsEmptyString( value ) ) + { + // Text Value + TCHAR* pEnd = _tcsechr( ++xml, chXMLTagOpen, chXMLEscape ); + if( pEnd == NULL ) + { + if( pi->erorr_occur == false ) + { + pi->erorr_occur = true; + pi->error_pointer = xml; + pi->error_code = PIE_NOT_CLOSED; + pi->error_string.Format(("%s must be closed with "), name ); + } + // error cos not exist CloseTag + return NULL; + } + + bool trim = pi->trim_value; + TCHAR escape = pi->escape_value; + //_SetString( xml, pEnd, &value, trim, chXMLEscape ); + _SetString( xml, pEnd, &value, trim, escape ); + + xml = pEnd; + // TEXTVALUE reference + if( pi->entity_value && pi->entitys ) + value = pi->entitys->Ref2Entity(value); + } + + // generate child nodes + while( xml && *xml ) + { + LPXNode node = new XNode; + node->parent = this; + + xml = node->Load( xml,pi ); + if( node->name.IsEmpty() == FALSE ) + { + childs.push_back( node ); + } + else + { + delete node; + } + + // open/close tag ... + // ^- current pointer + // CloseTag case + if( xml && *xml && *(xml+1) && *xml == chXMLTagOpen && *(xml+1) == chXMLTagPre ) + { + // + xml+=2; // C + + if( xml = _tcsskip( xml ) ) + { + CString closename; + TCHAR* pEnd = _tcspbrk( xml, " >" ); + if( pEnd == NULL ) + { + if( pi->erorr_occur == false ) + { + pi->erorr_occur = true; + pi->error_pointer = xml; + pi->error_code = PIE_NOT_CLOSED; + pi->error_string.Format(("it must be closed with "), name ); + } + // error + return NULL; + } + _SetString( xml, pEnd, &closename ); + if( closename == this->name ) + { + // wel-formed open/close + xml = pEnd+1; + // return '>' or ' ' after pointer + return xml; + } + else + { + xml = pEnd+1; + // not welformed open/close + if( pi->erorr_occur == false ) + { + pi->erorr_occur = true; + pi->error_pointer = xml; + pi->error_code = PIE_NOT_NESTED; + pi->error_string.Format(("'<%s> ... ' is not wel-formed."), name, closename ); + + } + return NULL; + } + } + } + else // Alone child Tag Loaded + // else ÇØ¾ßÇÏ´ÂÁö ¸»¾Æ¾ßÇÏ´ÂÁö Àǽɰ£´Ù. + { + + //if( xml && this->value.IsEmpty() && *xml !=chXMLTagOpen ) + if( xml && XIsEmptyString( value ) && *xml !=chXMLTagOpen ) + { + // Text Value + TCHAR* pEnd = _tcsechr( xml, chXMLTagOpen, chXMLEscape ); + if( pEnd == NULL ) + { + // error cos not exist CloseTag + if( pi->erorr_occur == false ) + { + pi->erorr_occur = true; + pi->error_pointer = xml; + pi->error_code = PIE_NOT_CLOSED; + pi->error_string.Format(("it must be closed with "), name ); + } + return NULL; + } + + bool trim = pi->trim_value; + TCHAR escape = pi->escape_value; + //_SetString( xml, pEnd, &value, trim, chXMLEscape ); + _SetString( xml, pEnd, &value, trim, escape ); + + xml = pEnd; + //TEXTVALUE + if( pi->entity_value && pi->entitys ) + value = pi->entitys->Ref2Entity(value); + } + } + } + } + } + + 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 +//======================================================== +CString _tagXMLAttr::GetXML( LPDISP_OPT opt /*= &optDefault*/ ) +{ + std::ostringstream os; + //os << (LPCTSTR)name << "='" << (LPCTSTR)value << "' "; + os << (LPCTSTR)name << "='" + << (LPCTSTR)(opt->reference_value&&opt->entitys?opt->entitys->Entity2Ref(value):value) << "' "; + return os.str().c_str(); +} + +//======================================================== +// Name : GetXML +// Desc : convert plain xml text from parsed xml node +// Param : +// Return : converted plain string +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +CString _tagXMLNode::GetXML( LPDISP_OPT opt /*= &optDefault*/ ) +{ + std::ostringstream os; + + // tab + if( opt && opt->newline ) + { + if( opt && opt->newline ) + os << "\r\n"; + for( int i = 0 ; i < opt->tab_base ; i++) + os << '\t'; + } + + // GetXML(opt); + } + + if( childs.empty() && value.IsEmpty() ) + { + // alone tag + os << "/>"; + } + else + { + // and get child + os << '>'; + if( opt && opt->newline && !childs.empty() ) + { + opt->tab_base++; + } + + for( unsigned i = 0 ; i < childs.size(); i++ ) + os << (LPCTSTR)childs[i]->GetXML( opt ); + + // Text Value + if( value != ("") ) + { + if( opt && opt->newline && !childs.empty() ) + { + if( opt && opt->newline ) + os << "\r\n"; + for( int i = 0 ; i < opt->tab_base ; i++) + os << '\t'; + } + os << (LPCTSTR)(opt->reference_value&&opt->entitys?opt->entitys->Entity2Ref(value):value); + } + + // CloseTag + if( opt && opt->newline && !childs.empty() ) + { + os << "\r\n"; + for( int i = 0 ; i < opt->tab_base-1 ; i++) + os << '\t'; + } + os << "'; + + if( opt && opt->newline ) + { + if( !childs.empty() ) + opt->tab_base--; + } + } + + return os.str().c_str(); +} + +//======================================================== +// Name : GetAttr +// Desc : get attribute with attribute name +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXAttr _tagXMLNode::GetAttr( LPCTSTR attrname ) +{ + for( unsigned i = 0 ; i < attrs.size(); i++ ) + { + LPXAttr attr = attrs[i]; + if( attr ) + { + if( attr->name == attrname ) + return attr; + } + } + return NULL; +} + +//======================================================== +// Name : GetAttrs +// Desc : find attributes with attribute name, return its list +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +XAttrs _tagXMLNode::GetAttrs( LPCTSTR name ) +{ + XAttrs attrs; + for( unsigned i = 0 ; i < attrs.size(); i++ ) + { + LPXAttr attr = attrs[i]; + if( attr ) + { + if( attr->name == name ) + attrs.push_back( attr ); + } + } + return attrs; +} + +//======================================================== +// Name : GetAttrValue +// Desc : get attribute with attribute name, return its value +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPCTSTR _tagXMLNode::GetAttrValue( LPCTSTR attrname ) +{ + LPXAttr attr = GetAttr( attrname ); + return attr ? (LPCTSTR)attr->value : NULL; +} + +XNodes _tagXMLNode::GetChilds() +{ + return childs; +} + +//======================================================== +// Name : GetChilds +// Desc : Find childs with name and return childs list +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +XNodes _tagXMLNode::GetChilds( LPCTSTR name ) +{ + XNodes nodes; + for( unsigned i = 0 ; i < childs.size(); i++ ) + { + LPXNode node = childs[i]; + if( node ) + { + if( node->name == name ) + nodes.push_back( node ); + } + } + return nodes; +} + +//======================================================== +// Name : GetChild +// Desc : get child node with index +// Param : +// Return : NULL return if no child. +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXNode _tagXMLNode::GetChild( int i ) +{ + if( i >= 0 && i < (int)childs.size() ) + return childs[i]; + return NULL; +} + +//======================================================== +// Name : GetChildCount +// Desc : get child node count +// Param : +// Return : 0 return if no child +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-12-26 +//======================================================== +int _tagXMLNode::GetChildCount() +{ + return childs.size(); +} + +//======================================================== +// Name : GetChild +// Desc : Find child with name and return child +// Param : +// Return : NULL return if no child. +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXNode _tagXMLNode::GetChild( LPCTSTR name ) +{ + for( unsigned i = 0 ; i < childs.size(); i++ ) + { + LPXNode node = childs[i]; + if( node ) + { + if( node->name == name ) + return node; + } + } + return NULL; +} + +//======================================================== +// 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 +//======================================================== +LPCTSTR _tagXMLNode::GetChildValue( LPCTSTR name ) +{ + LPXNode node = GetChild( name ); + return (node != NULL)? (LPCTSTR)node->value : NULL; +} + +LPXAttr _tagXMLNode::GetChildAttr( LPCTSTR name, LPCTSTR attrname ) +{ + LPXNode node = GetChild(name); + return node ? node->GetAttr(attrname) : NULL; +} + +LPCTSTR _tagXMLNode::GetChildAttrValue( LPCTSTR name, LPCTSTR attrname ) +{ + LPXAttr attr = GetChildAttr( name, attrname ); + return attr ? (LPCTSTR)attr->value : NULL; +} + + +//======================================================== +// Name : GetChildIterator +// Desc : get child nodes iterator +// Param : +// Return : NULL return if no childs. +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +XNodes::iterator _tagXMLNode::GetChildIterator( LPXNode node ) +{ + XNodes::iterator it = childs.begin(); + for( ; it != childs.end() ; ++(it) ) + { + if( *it == node ) + return it; + } + return NULL; +} + +//======================================================== +// Name : AppendChild +// Desc : add node +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXNode _tagXMLNode::AppendChild( LPCTSTR name /*= NULL*/, LPCTSTR value /*= NULL*/ ) +{ + return AppendChild( CreateNode( name, value ) ); +} + +LPXNode _tagXMLNode::AppendChild( LPCTSTR name /*= NULL*/, float value /*= NULL*/ ) +{ + return AppendChild( name, ssprintf("%f",value) ); +} + +LPXNode _tagXMLNode::AppendChild( LPCTSTR name /*= NULL*/, int value /*= NULL*/ ) +{ + return AppendChild( name, ssprintf("%d",value) ); +} + +//======================================================== +// Name : AppendChild +// Desc : add node +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXNode _tagXMLNode::AppendChild( LPXNode node ) +{ + node->parent = this; + childs.push_back( node ); + return node; +} + +//======================================================== +// Name : RemoveChild +// Desc : detach node and delete object +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +bool _tagXMLNode::RemoveChild( LPXNode node ) +{ + XNodes::iterator it = GetChildIterator( node ); + if( it != NULL ) + { + delete *it; + childs.erase( it ); + return true; + } + return false; +} + +//======================================================== +// Name : GetAttr +// Desc : get attribute with index in attribute list +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXAttr _tagXMLNode::GetAttr( int i ) +{ + if( i >= 0 && i < (int)attrs.size() ) + return attrs[i]; + return NULL; +} + +//======================================================== +// Name : GetAttrIterator +// Desc : get attribute iterator +// Param : +// Return : std::vector::iterator +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +XAttrs::iterator _tagXMLNode::GetAttrIterator( LPXAttr attr ) +{ + XAttrs::iterator it = attrs.begin(); + for( ; it != attrs.end() ; ++(it) ) + { + if( *it == attr ) + return it; + } + return NULL; +} + +//======================================================== +// Name : AppendAttr +// Desc : add attribute +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXAttr _tagXMLNode::AppendAttr( LPXAttr attr ) +{ + attr->parent = this; + attrs.push_back( attr ); + return attr; +} + +//======================================================== +// Name : RemoveAttr +// Desc : detach attribute and delete object +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +bool _tagXMLNode::RemoveAttr( LPXAttr attr ) +{ + XAttrs::iterator it = GetAttrIterator( attr ); + if( it != NULL ) + { + delete *it; + attrs.erase( it ); + return true; + } + return false; +} + +//======================================================== +// Name : CreateNode +// Desc : Create node object and return it +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXNode _tagXMLNode::CreateNode( LPCTSTR name /*= NULL*/, LPCTSTR value /*= NULL*/ ) +{ + LPXNode node = new XNode; + node->name = name; + node->value = value; + return node; +} + +//======================================================== +// Name : CreateAttr +// Desc : create Attribute object and return it +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXAttr _tagXMLNode::CreateAttr( LPCTSTR name /*= NULL*/, LPCTSTR value /*= NULL*/ ) +{ + LPXAttr attr = new XAttr; + attr->name = name; + attr->value = value; + return attr; +} + +//======================================================== +// Name : AppendAttr +// Desc : add attribute +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXAttr _tagXMLNode::AppendAttr( LPCTSTR name /*= NULL*/, LPCTSTR value /*= NULL*/ ) +{ + return AppendAttr( CreateAttr( name, value ) ); +} + +//======================================================== +// Name : DetachChild +// Desc : no delete object, just detach in list +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXNode _tagXMLNode::DetachChild( LPXNode node ) +{ + XNodes::iterator it = GetChildIterator( node ); + if( it != NULL ) + { + childs.erase( it ); + return node; + } + return NULL; +} + +//======================================================== +// Name : DetachAttr +// Desc : no delete object, just detach in list +// Param : +// Return : +//-------------------------------------------------------- +// Coder Date Desc +// bro 2002-10-29 +//======================================================== +LPXAttr _tagXMLNode::DetachAttr( LPXAttr attr ) +{ + XAttrs::iterator it = GetAttrIterator( attr ); + if( it != NULL ) + { + attrs.erase( it ); + return attr; + } + return NULL; +} + +_tagXMLEntitys::_tagXMLEntitys( LPXENTITY entities, int count ) +{ + for( int i = 0; i < count; i++) + push_back( entities[i] ); +} + +LPXENTITY _tagXMLEntitys::GetEntity( int entity ) +{ + for( unsigned i = 0 ; i < size(); i ++ ) + { + if( at(i).entity == entity ) + return LPXENTITY(&at(i)); + } + return NULL; +} + +LPXENTITY _tagXMLEntitys::GetEntity( LPTSTR entity ) +{ + for( unsigned i = 0 ; i < size(); i ++ ) + { + LPTSTR ref = (LPTSTR)at(i).ref; + LPTSTR ps = entity; + while( ref && *ref ) + if( *ref++ != *ps++ ) + break; + if( ref && !*ref ) // found! + return LPXENTITY(&at(i)); + } + return NULL; +} + +int _tagXMLEntitys::GetEntityCount( LPCTSTR str ) +{ + int nCount = 0; + LPTSTR ps = (LPTSTR)str; + while( ps && *ps ) + if( GetEntity( *ps++ ) ) nCount ++; + return nCount; +} + +int _tagXMLEntitys::Ref2Entity( LPCTSTR estr, LPTSTR str, int strlen ) +{ + LPTSTR pes = (LPTSTR)estr; + LPTSTR ps = str; + LPTSTR ps_end = ps+strlen; + while( pes && *pes && ps < ps_end ) + { + LPXENTITY ent = GetEntity( pes ); + 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 _tagXMLEntitys::Entity2Ref( LPCTSTR str, LPTSTR estr, int estrlen ) +{ + LPTSTR ps = (LPTSTR)str; + LPTSTR pes = (LPTSTR)estr; + LPTSTR pes_end = pes+estrlen; + while( ps && *ps && pes < pes_end ) + { + LPXENTITY ent = GetEntity( *ps ); + if( ent ) + { + // copy entity string + LPTSTR ref = (LPTSTR)ent->ref; + while( ref && *ref ) + *pes++ = *ref++; + } + else + *pes++ = *ps; // default character copy + ps++; + } + *pes = '\0'; + + // total copied characters + return pes-estr; +} + +CString _tagXMLEntitys::Ref2Entity( LPCTSTR estr ) +{ + CString es; + if( estr ) + { + int len = _tcslen(estr); +// LPTSTR esbuf = es.GetBufferSetLength( len+1 ); + char* szTemp = new char[len+1]; + if( szTemp ) + Ref2Entity( estr, szTemp, len ); + es = szTemp; + } + return es; +} + +CString _tagXMLEntitys::Entity2Ref( LPCTSTR str ) +{ + CString s; + if( str ) + { + int nEntityCount = GetEntityCount(str); + if( nEntityCount == 0 ) + return CString(str); + int len = _tcslen(str) + nEntityCount*10 ; + //LPTSTR sbuf = s.GetBufferSetLength( len+1 ); + char* szTemp = new char[len+1]; + if( szTemp ) + Entity2Ref( str, szTemp, len ); + s = szTemp; + } + return s; +} + +CString XRef2Entity( LPCTSTR estr ) +{ + return entityDefault.Ref2Entity( estr ); +} + +CString XEntity2Ref( LPCTSTR str ) +{ + return entityDefault.Entity2Ref( str ); +} diff --git a/stepmania/src/XmlFile.h b/stepmania/src/XmlFile.h new file mode 100644 index 0000000000..9eff62f56d --- /dev/null +++ b/stepmania/src/XmlFile.h @@ -0,0 +1,191 @@ +// XmlFile.h: interface for the XmlFile class. +// +// Adapted from http://www.codeproject.com/cpp/xmlite.asp +// by Chris. The CodeProject FAQ says "all developers may freely +// use the code in their own applications". +// +// XmlFile : XML Lite Parser Library +// by bro ( Cho,Kyung Min: bro@shinbiro.com ) 2002-10-30 +// History. +// 2002-10-29 : First Coded. Parsing XMLElelement and Attributes. +// get xml parsed string ( looks good ) +// 2002-10-30 : Get Node Functions, error handling ( not completed ) +// 2002-12-06 : Helper Funtion string to long +// 2002-12-12 : Entity Helper Support +// 2003-04-08 : Close, +// 2003-07=23 : add property escape_value. (now no escape on default) +// fix escape functions +////////////////////////////////////////////////////////////////////// + +#include +#include + +// TCHAR defines +#define LPTSTR char* +#define LPCTSTR const char* +#define _tcschr strchr +//#define FALSE false +#define _istspace isspace +#define _tcspbrk strpbrk +#define IsEmpty empty +#define _tcslen strlen +#define _tcsecpy strlen + +struct _tagXMLAttr; +typedef _tagXMLAttr XAttr, *LPXAttr; +typedef std::vector XAttrs; +struct _tagXMLNode; +typedef _tagXMLNode XNode, *LPXNode; +typedef std::vector XNodes, *LPXNodes; + +// Entity Encode/Decode Support +typedef struct _tagXmlEntity +{ + TCHAR entity; // entity ( & " ' < > ) + TCHAR ref[10]; // entity reference ( & " etc ) + int ref_len; // entity reference length +}XENTITY,*LPXENTITY; + +typedef struct _tagXMLEntitys : public std::vector +{ + LPXENTITY GetEntity( int entity ); + LPXENTITY GetEntity( LPTSTR entity ); + int GetEntityCount( LPCTSTR str ); + int Ref2Entity( LPCTSTR estr, LPTSTR str, int strlen ); + int Entity2Ref( LPCTSTR str, LPTSTR estr, int estrlen ); + CString Ref2Entity( LPCTSTR estr ); + CString Entity2Ref( LPCTSTR str ); + + _tagXMLEntitys(){}; + _tagXMLEntitys( LPXENTITY entities, int count ); +}XENTITYS,*LPXENTITYS; +extern XENTITYS entityDefault; +CString XRef2Entity( LPCTSTR estr ); +CString XEntity2Ref( LPCTSTR str ); + +typedef enum +{ + PIE_PARSE_WELFORMED = 0, + PIE_ALONE_NOT_CLOSED, + PIE_NOT_CLOSED, + PIE_NOT_NESTED, + PIE_ATTR_NO_VALUE +}PCODE; + +// Parse info. +typedef struct _tagParseInfo +{ + bool trim_value; // [set] do trim when parse? + bool entity_value; // [set] do convert from reference to entity? ( < -> < ) + LPXENTITYS entitys; // [set] entity table for entity decode + TCHAR escape_value; // [set] escape value (default '\\') + + LPTSTR xml; // [get] xml source + bool erorr_occur; // [get] is occurance of error? + LPTSTR error_pointer; // [get] error position of xml source + PCODE error_code; // [get] error code + CString error_string; // [get] error string + + _tagParseInfo() { trim_value = true; entity_value = true; entitys = &entityDefault; xml = NULL; erorr_occur = false; error_pointer = NULL; error_code = PIE_PARSE_WELFORMED; escape_value = 0; } +}PARSEINFO,*LPPARSEINFO; +extern PARSEINFO piDefault; + +// display optional environment +typedef struct _tagDispOption +{ + bool newline; // newline when new tag + bool reference_value; // do convert from entity to reference ( < -> < ) + LPXENTITYS entitys; // entity table for entity encode + + int tab_base; // internal usage + _tagDispOption() { newline = true; reference_value = true; entitys = &entityDefault; tab_base = 0; } +}DISP_OPT, *LPDISP_OPT; +extern DISP_OPT optDefault; + +// XAttr : Attribute Implementation +typedef struct _tagXMLAttr +{ + CString name; + CString value; + + _tagXMLNode* parent; + + CString GetXML( LPDISP_OPT opt = &optDefault ); +}XAttr, *LPXAttr; + +// XMLNode structure +typedef struct _tagXMLNode +{ + // name and value + CString name; + CString value; + + // internal variables + LPXNode parent; // parent node + XNodes childs; // child node + XAttrs attrs; // attributes + + // Load/Save XML + LPTSTR Load( LPCTSTR pszXml, LPPARSEINFO pi = &piDefault ); + LPTSTR LoadAttributes( LPCTSTR pszAttrs, LPPARSEINFO pi = &piDefault ); + CString GetXML( LPDISP_OPT opt = &optDefault ); + + // in own attribute list + LPXAttr GetAttr( LPCTSTR attrname ); + LPCTSTR GetAttrValue( LPCTSTR attrname ); + XAttrs GetAttrs( LPCTSTR name ); + + // in one level child nodes + LPXNode GetChild( LPCTSTR name ); + LPCTSTR GetChildValue( LPCTSTR name ); + XNodes GetChilds( LPCTSTR name ); + XNodes GetChilds(); + + LPXAttr GetChildAttr( LPCTSTR name, LPCTSTR attrname ); + LPCTSTR GetChildAttrValue( LPCTSTR name, LPCTSTR attrname ); + + // modify DOM + int GetChildCount(); + LPXNode GetChild( int i ); + XNodes::iterator GetChildIterator( LPXNode node ); + LPXNode CreateNode( LPCTSTR name = NULL, LPCTSTR value = NULL ); + LPXNode AppendChild( LPCTSTR name = NULL, LPCTSTR value = NULL ); + LPXNode AppendChild( LPCTSTR name, float value ); + LPXNode AppendChild( LPCTSTR name, int value ); + LPXNode AppendChild( LPXNode node ); + bool RemoveChild( LPXNode node ); + LPXNode DetachChild( LPXNode node ); + + + LPXAttr GetAttr( int i ); + XAttrs::iterator GetAttrIterator( LPXAttr node ); + LPXAttr CreateAttr( LPCTSTR anem = NULL, LPCTSTR value = NULL ); + LPXAttr AppendAttr( LPCTSTR name = NULL, LPCTSTR value = NULL ); + LPXAttr AppendAttr( LPXAttr attr ); + bool RemoveAttr( LPXAttr attr ); + LPXAttr DetachAttr( LPXAttr attr ); + + // operator overloads + LPXNode operator [] ( int i ) { return GetChild(i); } + + _tagXMLNode() { parent = NULL; } + ~_tagXMLNode(); + + void Close(); +}XNode, *LPXNode; + +// Helper Funtion +inline long XStr2Int( LPCTSTR str, long default_value = 0 ) +{ + return str ? atol(str) : default_value; +} + +inline bool XIsEmptyString( LPCTSTR str ) +{ + CString s(str); + TrimLeft( s ); + TrimRight( s ); + + return ( s.empty() || s == "" ); +} +