提交scripts
This commit is contained in:
1 parent
82caf72036
commit
07dabbd186
224 files changed
+130146
No files matched your search
@@ -0,0 +1,419 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// SML.cpp
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "Common.h"
|
||||
#include "SML.h"
|
||||
|
||||
using namespace SEACAVE;
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
#define SML_AUTOVALUES_OFF 0
|
||||
#define SML_AUTOVALUES_ON 1
|
||||
#ifndef SML_AUTOVALUES
|
||||
#define SML_AUTOVALUES SML_AUTOVALUES_ON
|
||||
#endif
|
||||
|
||||
#define SML_SECTIONOPENBRACKET _T("{")
|
||||
#define SML_SECTIONCLOSEBRACKET _T("}")
|
||||
#define SML_NAMEOPENBRACKET _T("[")
|
||||
#define SML_NAMECLOSEBRACKET _T("]")
|
||||
#define SML_NAMETOKEN _T("=")
|
||||
#define SML_VALUETOKEN _T("\n")
|
||||
#define SML_INDENT _T("\t")
|
||||
|
||||
#define SML_TOKEN_SECTIONOPENBRACKET SML_SECTIONOPENBRACKET[0]
|
||||
#define SML_TOKEN_SECTIONCLOSEBRACKET SML_SECTIONCLOSEBRACKET[0]
|
||||
#define SML_TOKEN_NAMEOPENBRACKET SML_NAMEOPENBRACKET[0]
|
||||
#define SML_TOKEN_NAMECLOSEBRACKET SML_NAMECLOSEBRACKET[0]
|
||||
#define SML_TOKEN_NAMETOKEN SML_NAMETOKEN[0]
|
||||
#define SML_TOKEN_VALUETOKEN SML_VALUETOKEN[0]
|
||||
#define SML_TOKEN_INDENT SML_INDENT[0]
|
||||
#define SML_TOKEN_IGNORECHARS _T("\n\r\t ")
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
/*-----------------------------------------------------------*
|
||||
* SML class implementation *
|
||||
*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
SML::SML(const String& name)
|
||||
:
|
||||
m_strName(name),
|
||||
m_fncInitItem(NULL),
|
||||
m_fncSaveItem(NULL),
|
||||
m_fncReleaseItem(NULL),
|
||||
m_fncItemData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
SML::~SML()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Released all used memory for this nod and its children
|
||||
*/
|
||||
void SML::Release()
|
||||
{
|
||||
m_arrChildren.ReleaseDelete();
|
||||
if (m_fncReleaseItem != NULL) {
|
||||
for (SMLITEMMAP::iterator it=GetBegin(); it!=GetEnd(); ++it)
|
||||
m_fncReleaseItem(it->second, m_fncItemData);
|
||||
}
|
||||
SMLITEMMAP::Release();
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Load the values from a file;
|
||||
* all children are generated if they do not exist
|
||||
*/
|
||||
bool SML::Load(const String& fileName)
|
||||
{
|
||||
File oStream(fileName, File::READ, File::OPEN);
|
||||
if (!oStream.isOpen())
|
||||
return false;
|
||||
return Load(oStream);
|
||||
}
|
||||
bool SML::Load(ISTREAM& oStream)
|
||||
{
|
||||
// create the section token filter and mem-file
|
||||
MemFile memFile;
|
||||
TokenIStream filter(&oStream);
|
||||
filter.setTrimTokens(SML_TOKEN_IGNORECHARS);
|
||||
// and parse section
|
||||
return ParseSection(filter, memFile);
|
||||
}
|
||||
bool SML::ParseSection(TokenIStream& filter, MemFile& memFile)
|
||||
{
|
||||
while (true) {
|
||||
// find first section start (NameOpenBracket)
|
||||
filter.setToken(SML_TOKEN_NAMEOPENBRACKET);
|
||||
filter.readLine(memFile);
|
||||
|
||||
// parse values before the new section or end of section
|
||||
const size_f_t posMemFile = memFile.getPos();
|
||||
MemFile valuesMemFile;
|
||||
TokenIStream sectionFilter(&memFile, SML_TOKEN_SECTIONCLOSEBRACKET);
|
||||
const size_f_t lenValues = sectionFilter.readLine(valuesMemFile);
|
||||
if (ParseValues(valuesMemFile) == false)
|
||||
return false; // Parse Error: invalid values
|
||||
ASSERT(valuesMemFile.getSize() == 0);
|
||||
|
||||
// if end of section found, return
|
||||
if (!sectionFilter.isEOS()) {
|
||||
// if a name open bracket was found before the EOS,
|
||||
// then restore it for the parent next ParseSection()
|
||||
memFile.setPos(posMemFile+(lenValues+1)*sizeof(TCHAR));
|
||||
if (!filter.isEOS())
|
||||
filter.restoreToken();
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ASSERT(memFile.getSize()-posMemFile == lenValues*(size_f_t)sizeof(TCHAR));
|
||||
ASSERT(posMemFile == 0 || memFile.getSize()-posMemFile == memFile.getSizeLeft() || memFile.getSizeLeft() == 0);
|
||||
memFile.setSize(0);
|
||||
}
|
||||
|
||||
// if no more data, return
|
||||
if (filter.isEOS())
|
||||
break;
|
||||
|
||||
// parse child section name
|
||||
filter.setToken(SML_TOKEN_NAMECLOSEBRACKET);
|
||||
const size_t lenName = filter.readLine(memFile);
|
||||
ASSERT(!filter.isEOS());
|
||||
if (lenName == 0)
|
||||
return false; // Parse Error: invalid section name
|
||||
const String strChildName((LPCTSTR)memFile.getData(), lenName);
|
||||
memFile.growSize(-((size_f_t)(lenName*sizeof(TCHAR))));
|
||||
ASSERT(memFile.getSize() == 0);
|
||||
// create the child with the given name
|
||||
const IDX idxChild = CreateChildUnique(strChildName);
|
||||
LPSML const pChild = m_arrChildren[idxChild];
|
||||
pChild->SetFncItem(m_fncInitItem, m_fncSaveItem, m_fncReleaseItem, m_fncItemData);
|
||||
|
||||
// parse child section
|
||||
filter.setToken(SML_TOKEN_SECTIONOPENBRACKET);
|
||||
filter.readLine(memFile);
|
||||
filter.trimBackLine(memFile);
|
||||
ASSERT(memFile.getSize() == 0);
|
||||
if (pChild->ParseSection(filter, memFile) == false)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool SML::ParseValues(MemFile& valuesMemFile)
|
||||
{
|
||||
if (valuesMemFile.getSize() == 0)
|
||||
return true;
|
||||
// loop through all name/value pairs
|
||||
MemFile memLine;
|
||||
TokenIStream filterLine(&valuesMemFile);
|
||||
filterLine.setTrimTokens(SML_TOKEN_IGNORECHARS);
|
||||
filterLine.setToken(SML_TOKEN_VALUETOKEN);
|
||||
MemFile memValue;
|
||||
TokenIStream filterValue(&memLine);
|
||||
filterValue.setTrimTokens(SML_TOKEN_IGNORECHARS);
|
||||
filterValue.setToken(SML_TOKEN_NAMETOKEN);
|
||||
do {
|
||||
// parse value name and value
|
||||
filterLine.readLine(memLine);
|
||||
filterLine.trimBackLine(memLine);
|
||||
filterLine.trimFrontLine(memLine);
|
||||
if (memLine.isEOF())
|
||||
continue; // empty line, return
|
||||
// parse value name
|
||||
const size_t lenNameValueReal = (size_t)memLine.getSizeLeft();
|
||||
const size_t lenName = filterValue.readLine(memValue);
|
||||
#if SML_AUTOVALUES == SML_AUTOVALUES_ON
|
||||
String szName;
|
||||
if (filterValue.trimBackLine(memValue) == lenName || lenNameValueReal == lenName) {
|
||||
// no name found, auto generate the name
|
||||
szName = _T("Item") + String::ToString(size());
|
||||
} else {
|
||||
// read the name
|
||||
szName = (LPCTSTR)memValue.getData();
|
||||
memValue.setSize(0);
|
||||
}
|
||||
#else
|
||||
filterValue.trimBackLine(memValue);
|
||||
String szName = (LPCTSTR)memValue.getData();
|
||||
ASSERT(!filterValue.isEOS() && !szName.IsEmpty());
|
||||
if (filterValue.isEOS() || szName.IsEmpty()) {
|
||||
memValue.setSize(0);
|
||||
memLine.setSize(0);
|
||||
filterValue.setPos(0);
|
||||
continue; // Parse Error: invalid syntax ('=' not found)
|
||||
}
|
||||
ASSERT(szName.size() == memValue.getSizeLeft());
|
||||
memValue.setSize(0);
|
||||
#endif
|
||||
SMLVALUE& val = operator[](szName);
|
||||
// parse value
|
||||
filterValue.read(memValue);
|
||||
LPCTSTR szValue = filterValue.trimFrontLine(memValue);
|
||||
val.val = szValue;
|
||||
ASSERT((size_f_t)_tcslen(szValue) == memValue.getSizeLeft());
|
||||
memValue.setSize(0);
|
||||
memLine.setSize(0);
|
||||
filterValue.setPos(0);
|
||||
} while (!filterLine.isEOS());
|
||||
// all file processed, safe to reset it to 0
|
||||
valuesMemFile.setSize(0);
|
||||
return true;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Write to a file the values of this node and its children.
|
||||
* Set to false the second parameter in order not to save the empty children.
|
||||
*/
|
||||
bool SML::Save(const String& fileName, SAVEFLAG flags) const
|
||||
{
|
||||
File oStream(fileName, File::WRITE, File::CREATE | File::TRUNCATE);
|
||||
if (!oStream.isOpen())
|
||||
return false;
|
||||
return Save(oStream, flags);
|
||||
}
|
||||
bool SML::Save(OSTREAM& oStream, SAVEFLAG flags) const
|
||||
{
|
||||
// save all values and all children
|
||||
return SaveIntern(oStream, _T(""), flags);
|
||||
}
|
||||
bool SML::SaveBracketize(OSTREAM& oStream, const String& strIndent, SAVEFLAG flags) const
|
||||
{
|
||||
// save its name
|
||||
oStream.print(_T("%s" SML_NAMEOPENBRACKET "%s" SML_NAMECLOSEBRACKET "\n"), strIndent.c_str(), m_strName.c_str());
|
||||
oStream.print(_T("%s" SML_SECTIONOPENBRACKET "\n"), strIndent.c_str());
|
||||
// save all values and all children
|
||||
SaveIntern(oStream, strIndent+SML_TOKEN_INDENT, flags);
|
||||
// close bracket
|
||||
oStream.print(_T("%s" SML_SECTIONCLOSEBRACKET "\n"), strIndent.c_str());
|
||||
return true;
|
||||
}
|
||||
bool SML::SaveIntern(OSTREAM& oStream, const String& strIndent, SAVEFLAG flags) const
|
||||
{
|
||||
const Flags& flgs = (const Flags&)flags;
|
||||
if (flgs.isAnySet(SORT | SORTINV)) {
|
||||
// sort values alphabetically and save them
|
||||
StringArr lines(0, GetSize());
|
||||
for (SMLITEMMAP::const_iterator item=GetBegin(); item!=GetEnd(); ++item)
|
||||
if (!m_fncSaveItem || m_fncSaveItem((*item).second, m_fncItemData))
|
||||
lines.InsertSort(String::FormatString(_T("%s%s " SML_NAMETOKEN " %s" SML_VALUETOKEN), strIndent.c_str(), (*item).first.c_str(), (*item).second.val.c_str()),
|
||||
(flgs.isAnySet(SORT) ? String::CompareAlphabetically : String::CompareAlphabeticallyInv));
|
||||
FOREACH(l, lines)
|
||||
oStream.print(lines[l]);
|
||||
} else {
|
||||
// save all values directly
|
||||
for (SMLITEMMAP::const_iterator item=GetBegin(); item!=GetEnd(); ++item)
|
||||
if (!m_fncSaveItem || m_fncSaveItem((*item).second, m_fncItemData))
|
||||
oStream.print(_T("%s%s " SML_NAMETOKEN " %s" SML_VALUETOKEN), strIndent.c_str(), (*item).first.c_str(), (*item).second.val.c_str());
|
||||
}
|
||||
// save now all children
|
||||
bool bFirst = IsEmpty();
|
||||
FOREACH(i, m_arrChildren) {
|
||||
const SML* pSML = m_arrChildren[i];
|
||||
// skip empty children
|
||||
if (!flgs.isSet(SAVEEMPTY) && pSML->IsEmpty() && pSML->m_arrChildren.IsEmpty())
|
||||
continue;
|
||||
// insert a new line to separate from the above section (only for visual aspect)
|
||||
if (bFirst)
|
||||
bFirst = false;
|
||||
else
|
||||
oStream.print(_T("\n"));
|
||||
// save child
|
||||
pSML->SaveBracketize(oStream, strIndent, flags);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Create and insert a new child
|
||||
*/
|
||||
IDX SML::CreateChild(const String& strChildName)
|
||||
{
|
||||
return InsertChild(new SML(strChildName));
|
||||
}
|
||||
IDX SML::CreateChildUnique(const String& strChildName)
|
||||
{
|
||||
return InsertChildUnique(new SML(strChildName));
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Insert a new child
|
||||
*/
|
||||
IDX SML::InsertChild(const LPSML pSML)
|
||||
{
|
||||
return m_arrChildren.InsertSort(pSML, SML::Compare);
|
||||
}
|
||||
IDX SML::InsertChildUnique(const LPSML pSML)
|
||||
{
|
||||
const std::pair<IDX,bool> res(m_arrChildren.InsertSortUnique(pSML, SML::Compare));
|
||||
if (res.second)
|
||||
delete pSML;
|
||||
return res.first;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Remove an existing child
|
||||
*/
|
||||
void SML::RemoveChild(IDX idx)
|
||||
{
|
||||
m_arrChildren.RemoveAtMove(idx);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Remove and destroy an existing child
|
||||
*/
|
||||
void SML::DestroyChild(IDX idx)
|
||||
{
|
||||
delete m_arrChildren[idx];
|
||||
RemoveChild(idx);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve an child by its name; NO_INDEX if unexistent
|
||||
*/
|
||||
IDX SML::GetChild(const String& name) const
|
||||
{
|
||||
return m_arrChildren.FindFirst(&name, SML::CompareName);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve an item; NULL if unexistent
|
||||
*/
|
||||
const SMLVALUE* SML::GetValue(const String& key) const
|
||||
{
|
||||
const_iterator it = Find(key);
|
||||
if (it == GetEnd())
|
||||
return NULL;
|
||||
return &(it->second);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Insert or retrieve an item; initialize it if necessary
|
||||
*/
|
||||
SMLVALUE& SML::GetValue(const String& key)
|
||||
{
|
||||
bool bExisted;
|
||||
SMLVALUE& val = (*Insert(key, bExisted)).second;
|
||||
if (!bExisted && m_fncInitItem != NULL)
|
||||
m_fncInitItem(key, val, m_fncItemData);
|
||||
return val;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve an unnamed item by index
|
||||
*/
|
||||
const SMLVALUE& SML::GetValue(IDX idx) const
|
||||
{
|
||||
ASSERT(idx < this->size());
|
||||
const String szName(_T("Item") + String::ToString(idx));
|
||||
return this->at(szName);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Reset items' init and release functions
|
||||
*/
|
||||
void SML::SetFncItem(TFncInitItem fncInit, TFncSaveItem fncSave, TFncReleaseItem fncRelease, void* data)
|
||||
{
|
||||
m_fncInitItem = fncInit;
|
||||
m_fncSaveItem = fncSave;
|
||||
m_fncReleaseItem = fncRelease;
|
||||
m_fncItemData = data;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/**
|
||||
* Compare two SML nodes by name
|
||||
*/
|
||||
int STCALL SML::Compare(const void* l, const void* r)
|
||||
{
|
||||
return _tcscmp((*((const SML**)l))->GetName(), (*((const SML**)r))->GetName());
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Compare a name and a SML node name
|
||||
*/
|
||||
int STCALL SML::CompareName(const void* l, const void* r)
|
||||
{
|
||||
return _tcscmp((*((const SML**)l))->GetName(), ((const String*)r)->c_str());
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
Reference in new issue
Block a user