#include #include "wx/mstream.h" #include #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 = 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) { 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 { 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; 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); 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; } void TXmlItem::RemoveLastChild() { if (m_Children != NULL) { wxNode* n = m_Children->GetLast(); if (n != NULL) m_Children->DeleteNode(n); } } bool TXmlItem::Read(wxInputStream& inf) { const int 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, long 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, long 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, (long)&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 << ""; } else outf << " />"; } else outf << GetText(); } wxString TXmlItem::AsString() const { wxString str; for (size_t nSize = 8192; ; nSize *= 2) { char* 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, long jolly) { const wxChar* strTag = (const wxChar*)jolly; return item.GetTag() == strTag; } TXmlItem* TXmlItem::FindFirst(const wxChar* strTag) const { return ((TXmlItem*)this)->ForEach(FindFirstCallback, (long)strTag); } TXmlItem::TXmlItem() : m_Attributes(NULL), m_Children(NULL) { } TXmlItem::~TXmlItem() { if (m_Attributes) delete m_Attributes; if (m_Children) delete m_Children; }