46d30d0ca2
Files correlati : lurch.exe Ricompilazione Demo : [ ] Commento : Questo maggiordomo non solo e' in grado di ammazzare la servitu' oziosa... ma anche di risuscitarla quanto questa si suicida! git-svn-id: svn://10.65.10.50/trunk@19979 c028cbd2-c16b-5b4b-a496-9718f37d4682
555 lines
10 KiB
C++
Executable File
555 lines
10 KiB
C++
Executable File
#include <wx/wx.h>
|
|
|
|
#include "wx/mstream.h"
|
|
#include <wx/wfstream.h>
|
|
|
|
#include "xml.h"
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Utilities
|
|
///////////////////////////////////////////////////////////
|
|
|
|
wxOutputStream& operator<<(wxOutputStream& outf, const wxChar* str)
|
|
{
|
|
if (str && *str)
|
|
outf.Write(str, wxStrlen(str));
|
|
return outf;
|
|
}
|
|
|
|
wxOutputStream& operator<<(wxOutputStream& outf, wxString str)
|
|
{
|
|
if (!str.IsEmpty())
|
|
outf.Write(str, str.Length());
|
|
return outf;
|
|
}
|
|
|
|
wxInputStream& operator>>(wxInputStream& inf, wxString& str)
|
|
{
|
|
const off_t nStart = inf.TellI();
|
|
wxChar* buf = str.GetWriteBuf(1024); *buf = '\0';
|
|
inf.Read(buf, 1024);
|
|
str.UngetWriteBuf();
|
|
const int nEol = str.Find('\n');
|
|
if (nEol >= 0)
|
|
{
|
|
if (str[(size_t)(nEol+1)] > '\0')
|
|
inf.SeekI(nStart+nEol+1, (wxSeekMode) 0);
|
|
str.Truncate(nEol);
|
|
str.Trim();
|
|
}
|
|
else
|
|
{
|
|
if (!str.IsEmpty())
|
|
inf.SeekI(nStart+str.Length(), (wxSeekMode) 0);
|
|
}
|
|
|
|
return inf;
|
|
}
|
|
|
|
void Spaces(wxOutputStream& outf, int nSpaces)
|
|
{
|
|
outf << "\n";
|
|
if (nSpaces > 0)
|
|
{
|
|
wxString str;
|
|
str.Append(' ', nSpaces);
|
|
outf << str;
|
|
}
|
|
}
|
|
|
|
int hex2int(const wxChar* str)
|
|
{
|
|
int n = 0;
|
|
for (int i = 0; str[i]; i++)
|
|
{
|
|
if (str[i] >= '0' && str[i] <= '9')
|
|
{
|
|
n *= 16;
|
|
n += str[i]-'0';
|
|
} else
|
|
if (str[i] >= 'A' && str[i] <= 'F')
|
|
{
|
|
n *= 16;
|
|
n += str[i]-'A'+10;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
wxString EscapeSequence(char cStart, wxInputStream& inf)
|
|
{
|
|
wxString str;
|
|
|
|
if (cStart == '&')
|
|
{
|
|
for (wxChar c = inf.GetC(); c != ';'; c = inf.GetC())
|
|
str += c;
|
|
unsigned n = 0;
|
|
sscanf(str, "#%X", &n);
|
|
str = char(n);
|
|
}
|
|
else
|
|
str = cStart;
|
|
|
|
return str;
|
|
}
|
|
|
|
void WriteXmlString(wxOutputStream& outf, const wxChar* str)
|
|
{
|
|
for (int i = 0; str[i]; i++)
|
|
{
|
|
wxChar c = str[i];
|
|
if (c < 0 || c > 'z' || strchr("<>/&", c) != NULL)
|
|
{
|
|
unsigned int n = (unsigned char)c;
|
|
char str[8]; sprintf(str, "&#%02X;", n);
|
|
outf << str;
|
|
}
|
|
else
|
|
outf << c;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TXmlAttr
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TXmlAttr : public wxObject
|
|
{
|
|
public:
|
|
wxString m_str;
|
|
|
|
void Write(wxOutputStream& outf) const;
|
|
|
|
TXmlAttr(const wxChar* str) : m_str(str) { }
|
|
};
|
|
|
|
void TXmlAttr::Write(wxOutputStream& outf) const
|
|
{
|
|
if (m_str.IsEmpty())
|
|
{
|
|
outf << "\"\"";
|
|
}
|
|
else
|
|
{
|
|
if (m_str.IsNumber())
|
|
outf << m_str;
|
|
else
|
|
outf << "\"" << m_str << "\"";
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TXmlItem
|
|
///////////////////////////////////////////////////////////
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(TXmlItem, wxObject)
|
|
|
|
TXmlItem& TXmlItem::SetAttr(const wxChar* strAttr, const wxChar* strVal)
|
|
{
|
|
if (m_Attributes == NULL)
|
|
{
|
|
m_Attributes = new wxHashTable(wxKEY_STRING, 17);
|
|
m_Attributes->DeleteContents(true);
|
|
}
|
|
else
|
|
m_Attributes->Delete(strAttr);
|
|
m_Attributes->Put(strAttr, new TXmlAttr(strVal));
|
|
return *this;
|
|
}
|
|
|
|
wxString TXmlItem::GetAttr(const wxChar* strAttr) const
|
|
{
|
|
wxString strResult;
|
|
if (m_Attributes != NULL)
|
|
{
|
|
const TXmlAttr* str = (const TXmlAttr*)m_Attributes->Get(strAttr);
|
|
if (str != NULL)
|
|
strResult = str->m_str;
|
|
}
|
|
return strResult;
|
|
}
|
|
|
|
TXmlItem& TXmlItem::SetAttr(const wxChar* strAttr, long nVal)
|
|
{
|
|
return SetAttr(strAttr, wxString::Format("%ld", nVal));
|
|
}
|
|
|
|
int TXmlItem::GetChildren() const
|
|
{
|
|
int n = 0;
|
|
if (m_Children != NULL)
|
|
n = (int)m_Children->GetCount();
|
|
return n;
|
|
}
|
|
|
|
TXmlItem* TXmlItem::GetChild(size_t n) const
|
|
{
|
|
TXmlItem* i = NULL;
|
|
if (m_Children != NULL && n < m_Children->GetCount())
|
|
{
|
|
wxNode* pNode = m_Children->Item(n);
|
|
if (pNode != NULL)
|
|
i = (TXmlItem*)pNode->GetData();
|
|
}
|
|
return i;
|
|
}
|
|
|
|
|
|
wxString TXmlItem::GetWord(wxInputStream& inf) const
|
|
{
|
|
wxString str;
|
|
|
|
int cFirstChar = EOF;
|
|
while (!inf.Eof())
|
|
{
|
|
cFirstChar = inf.GetC();
|
|
if (cFirstChar <= 0 || cFirstChar > ' ')
|
|
break;
|
|
}
|
|
if (cFirstChar == EOF)
|
|
return str;
|
|
|
|
const bool bIsString = cFirstChar == '"' || cFirstChar == '\'';
|
|
if (bIsString)
|
|
str = "";
|
|
else
|
|
{
|
|
str = char(cFirstChar);
|
|
if (strchr("<=/>", cFirstChar))
|
|
return str; // Simboli terminali
|
|
}
|
|
|
|
while (!inf.Eof())
|
|
{
|
|
int c = inf.GetC();
|
|
if (bIsString)
|
|
{
|
|
if (c == cFirstChar)
|
|
break;
|
|
if (c >= '\0' && c <= ' ')
|
|
c = ' ';
|
|
str += wxChar(c);
|
|
}
|
|
else
|
|
{
|
|
if (c >= '\0' && c <= ' ')
|
|
break;
|
|
if (strchr("<=/>", c))
|
|
{
|
|
inf.Ungetch(char(c));
|
|
break;
|
|
}
|
|
if (c == '&')
|
|
str += EscapeSequence(c, inf);
|
|
else
|
|
str += wxChar(c);
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
int TXmlItem::ReadTag(wxInputStream& inf)
|
|
{
|
|
wxString str = GetWord(inf);
|
|
if (str.IsEmpty())
|
|
return -1;
|
|
|
|
if (str[0u] != '<') // No tag = sequence of words
|
|
{
|
|
bool bFirstChar = true;
|
|
while (!inf.Eof())
|
|
{
|
|
wxChar c = inf.GetC();
|
|
if (c == '<')
|
|
{
|
|
inf.Ungetch(c);
|
|
break;
|
|
}
|
|
if (bFirstChar)
|
|
{
|
|
if (c != ' ' && c != '=')
|
|
str << ' ';
|
|
bFirstChar = false;
|
|
}
|
|
if (c == '&')
|
|
str += EscapeSequence(c, inf);
|
|
else
|
|
str << c;
|
|
}
|
|
SetTag("");
|
|
SetText(str);
|
|
return 0;
|
|
}
|
|
|
|
bool bChildrenFollow = true;
|
|
|
|
m_strTag = GetWord(inf);
|
|
if (m_strTag == "/") // Sto leggendo un tag di chiusura del tipo </SOAP-ENV>
|
|
{
|
|
bChildrenFollow = false;
|
|
m_strTag += GetWord(inf);
|
|
}
|
|
|
|
wxString name = GetWord(inf);
|
|
while (!name.IsEmpty())
|
|
{
|
|
if (name[ 0u] == '>')
|
|
return bChildrenFollow ? +1 : 0;
|
|
|
|
if (name[0u] == '/')
|
|
{
|
|
bChildrenFollow = false;
|
|
name = GetWord(inf);
|
|
continue;
|
|
}
|
|
|
|
// Ho letto un nome di attributo
|
|
wxString str = GetWord(inf);
|
|
if (str.IsEmpty() || str[0u] != '=')
|
|
break;
|
|
// Leggo il valore dell'attributo
|
|
str = GetWord(inf);
|
|
const size_t len = str.Len();
|
|
if (len >= 2 && (str[0] == '"' || str[0] == '\'') && str[len-1] == str[0])
|
|
{
|
|
str = str.Mid(1, len - 2);
|
|
}
|
|
SetAttr(name, str);
|
|
|
|
name = GetWord(inf);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
TXmlItem& TXmlItem::AddChild(TXmlItem* pItem)
|
|
{
|
|
if (m_Children == NULL)
|
|
{
|
|
m_Children = new wxList;
|
|
m_Children->DeleteContents(true);
|
|
}
|
|
if (pItem == NULL)
|
|
pItem = new TXmlItem;
|
|
m_Children->Append(pItem);
|
|
return *pItem;
|
|
}
|
|
|
|
TXmlItem& TXmlItem::AddChild(const wxChar* strTagName)
|
|
{
|
|
TXmlItem& i = AddChild((TXmlItem*)NULL);
|
|
i.SetTag(strTagName);
|
|
return i;
|
|
}
|
|
|
|
TXmlItem& TXmlItem::AddSoapString(const wxChar* name, const wxChar* value, bool typized)
|
|
{
|
|
TXmlItem& xmlVar = AddChild(name);
|
|
if (typized)
|
|
xmlVar.SetAttr("xsi:type", "xsd:string");
|
|
xmlVar.AddChild("").SetText(value);
|
|
return xmlVar;
|
|
}
|
|
|
|
TXmlItem& TXmlItem::AddSoapInt(const wxChar* name, int value, bool typized)
|
|
{
|
|
TXmlItem& xmlVar = AddChild(name);
|
|
if (typized)
|
|
xmlVar.SetAttr("xsi:type", "xsd:int");
|
|
wxString str; str += value;
|
|
xmlVar.AddChild("").SetText(str);
|
|
return xmlVar;
|
|
}
|
|
|
|
wxString TXmlItem::GetSoapString(const wxChar* tag, const wxChar* def) const
|
|
{
|
|
const TXmlItem* i = FindFirst(tag);
|
|
return i != NULL ? i->GetEnclosedText().Trim() : def;
|
|
}
|
|
|
|
long TXmlItem::GetSoapInt(const wxChar* tag, long def) const
|
|
{
|
|
const wxString str = GetSoapString(tag);
|
|
long n;
|
|
if (str.ToLong(&n))
|
|
def = n;
|
|
return def;
|
|
}
|
|
|
|
void TXmlItem::RemoveLastChild()
|
|
{
|
|
if (m_Children != NULL)
|
|
{
|
|
wxNode* n = m_Children->GetLast();
|
|
if (n != NULL)
|
|
m_Children->DeleteNode(n);
|
|
}
|
|
}
|
|
|
|
bool TXmlItem::Read(wxInputStream& inf)
|
|
{
|
|
int res = ReadTag(inf);
|
|
|
|
// Ignora la eventuale riga <?xml version="1.0" encoding="UTF-8" ?>
|
|
if (res == 0 && GetTag()[0] == '?')
|
|
res = ReadTag(inf);
|
|
|
|
if (res > 0) // There are children ahead
|
|
{
|
|
while (!inf.Eof())
|
|
{
|
|
TXmlItem& item = AddChild("/"); // Add dummy child
|
|
if (item.Read(inf))
|
|
{
|
|
if (item.m_strTag[0u] == '/')
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
RemoveLastChild(); // Remove dummy child
|
|
}
|
|
return res >= 0;
|
|
}
|
|
|
|
TXmlItem* TXmlItem::ForEach(XmlItemCallback cb, void* jolly)
|
|
{
|
|
if (cb(*this, jolly))
|
|
return this;
|
|
|
|
for (int n = 0; ; n++)
|
|
{
|
|
TXmlItem* c = GetChild(n);
|
|
if (c == NULL)
|
|
break;
|
|
c = c->ForEach(cb, jolly);
|
|
if (c)
|
|
return c;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static bool GetEnclosedTextCallback(TXmlItem& item, void* jolly)
|
|
{
|
|
wxString* strText = (wxString*)jolly;
|
|
const wxString& str = item.GetText();
|
|
if (!str.IsEmpty())
|
|
{
|
|
if (!strText->IsEmpty())
|
|
*strText << " ";
|
|
*strText << str;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
wxString TXmlItem::GetEnclosedText() const
|
|
{
|
|
wxString text;
|
|
((TXmlItem*)this)->ForEach(GetEnclosedTextCallback, &text);
|
|
return text;
|
|
}
|
|
|
|
TXmlItem& TXmlItem::AddEnclosedText(const wxChar* str)
|
|
{
|
|
TXmlItem* item = FindFirst("");
|
|
if (item == NULL)
|
|
item = &AddChild("");
|
|
item->m_strText += str;
|
|
return *item;
|
|
}
|
|
|
|
TXmlItem& operator<<(TXmlItem& item, const wxChar* str)
|
|
{
|
|
item.AddEnclosedText(str);
|
|
return item;
|
|
}
|
|
|
|
void TXmlItem::Write(wxOutputStream& outf, int tab) const
|
|
{
|
|
if (!GetTag().IsEmpty())
|
|
{
|
|
Spaces(outf, tab);
|
|
outf << "<" << GetTag();
|
|
if (m_Attributes != NULL)
|
|
{
|
|
m_Attributes->BeginFind();
|
|
for (wxHashTable::Node* pNode = m_Attributes->Next(); pNode; pNode = m_Attributes->Next())
|
|
{
|
|
outf << " " << pNode->GetKeyString() << "=";
|
|
const TXmlAttr* attr = (const TXmlAttr*)pNode->GetData();
|
|
attr->Write(outf);
|
|
}
|
|
}
|
|
if (GetChildren() > 0)
|
|
{
|
|
outf << ">";
|
|
int n;
|
|
|
|
for (n = 0; ; n++)
|
|
{
|
|
TXmlItem* c = GetChild(n);
|
|
if (c == NULL)
|
|
break;
|
|
c->Write(outf, tab+1);
|
|
}
|
|
if (GetChild(n-1)->GetText().IsEmpty())
|
|
Spaces(outf, tab);
|
|
outf << "</" << GetTag() << ">";
|
|
}
|
|
else
|
|
outf << " />";
|
|
}
|
|
else
|
|
outf << GetText();
|
|
}
|
|
|
|
wxString TXmlItem::AsString() const
|
|
{
|
|
wxString str;
|
|
for (size_t nSize = 8192; ; nSize *= 2)
|
|
{
|
|
wxChar* buf = str.GetWriteBuf(nSize);
|
|
memset(buf, 0, nSize);
|
|
wxMemoryOutputStream outf(buf, nSize);
|
|
Write(outf, 0);
|
|
str.UngetWriteBuf();
|
|
if (buf[nSize-1] == '\0')
|
|
break;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
void TXmlItem::Save(const wxChar* strFilename) const
|
|
{
|
|
wxFileOutputStream outf(strFilename);
|
|
Write(outf, 0);
|
|
}
|
|
|
|
static bool FindFirstCallback(TXmlItem& item, void* jolly)
|
|
{
|
|
const wxChar* strTag = (const wxChar*)jolly;
|
|
return item.GetTag() == strTag;
|
|
}
|
|
|
|
TXmlItem* TXmlItem::FindFirst(const wxChar* strTag) const
|
|
{
|
|
return ((TXmlItem*)this)->ForEach(FindFirstCallback, (void*)strTag);
|
|
}
|
|
|
|
TXmlItem::TXmlItem()
|
|
: m_Attributes(NULL), m_Children(NULL)
|
|
{ }
|
|
|
|
TXmlItem::~TXmlItem()
|
|
{
|
|
if (m_Attributes)
|
|
delete m_Attributes;
|
|
if (m_Children)
|
|
delete m_Children;
|
|
}
|
|
|