#include #include #include #include #include /////////////////////////////////////////////////////////// // Utilities /////////////////////////////////////////////////////////// void Spaces(ostream& outf, int nSpaces) { outf << '\n'; if (nSpaces > 0) { TString str(nSpaces, ' '); str.print_on(outf); } } int hex2int(const char* 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; } const TString& EscapeSequence(char cStart, istream& inf) { TString& str = get_tmp_string(); if (cStart == '&') { char c; for (c = inf.get(); c != ';' && c > ' '; c = inf.get()) str << c; if (c == ';') // Ho trovato il carattere di fine sequenza { if (str[0] == '#') { str[0] = hex2int((const char*)str+1); str[1] = '\0'; } else if (str[0] >= '0' && str[0] <= '9') { str[0] = atoi(str); str[1] = '\0'; } else { if (str == "lt") return str ="<"; if (str == "gt") return str =">"; if (str == "nbsp") return str =" "; if (str == "Agrave") return str ="À"; if (str == "Egrave") return str ="È"; if (str == "Eacuto") return str ="É"; if (str == "Igrave") return str ="Ì"; if (str == "Ograve") return str ="Ò"; if (str == "Ugrave") return str ="Ù"; if (str == "agrave") return str ="à"; if (str == "egrave") return str ="è"; if (str == "eacuto") return str ="é"; if (str == "igrave") return str ="ì"; if (str == "ograve") return str ="ò"; if (str == "ugrave") return str ="ù"; const char tmp[2] = { cStart, '\0' }; str.insert(tmp); } } else { str.insert("&"); // Non era un escape! } } return str; } void WriteXmlString(ostream& outf, const char* str) { for (int i = 0; str[i]; i++) { const char c = str[i]; if ((c < ' ' && c != '\n' && c != '\r') || strchr("<>/&", c) != NULL) { const unsigned int n = (unsigned char)c; TString8 tmp; tmp.format("&#%02X;", n); tmp.print_on(outf); } else outf << c; } } void WriteXmlColor(ostream& out, COLOR rgb) { TString8 str; str.format("#%02X%02X%02X", XVT_COLOR_GET_RED(rgb), XVT_COLOR_GET_GREEN(rgb), XVT_COLOR_GET_BLUE(rgb)); out << str; } /////////////////////////////////////////////////////////// // TXmlAttr /////////////////////////////////////////////////////////// class TXmlAttr : public TString { public: void Write(ostream& outf) const; TXmlAttr(const char* str) : TString(str) { } }; void TXmlAttr::Write(ostream& outf) const { outf << '"'; WriteXmlString(outf, *this); outf << '"'; } /////////////////////////////////////////////////////////// // TXmlItem /////////////////////////////////////////////////////////// TXmlItem& TXmlItem::SetAttr(const char* strAttr, const char* strVal) { if (m_Attributes == NULL) m_Attributes = new TAssoc_array; m_Attributes->remove(strAttr); if (strVal && *strVal) m_Attributes->add(strAttr, new TXmlAttr(strVal)); return *this; } const TString& TXmlItem::GetAttr(const char* strAttr) const { if (m_Attributes != NULL) { const TXmlAttr* str = (const TXmlAttr*)m_Attributes->objptr(strAttr); if (str != NULL) return *str; } return EMPTY_STRING; } TXmlItem& TXmlItem::SetAttr(const char* strAttr, int n) { TString16 str; if (n != 0) str << n; return SetAttr(strAttr, str); } TXmlItem& TXmlItem::SetColorAttr(const char* strAttr, COLOR rgb) { TString8 str; str.format("#%02X%02X%02X", XVT_COLOR_GET_RED(rgb), XVT_COLOR_GET_GREEN(rgb), XVT_COLOR_GET_BLUE(rgb)); return SetAttr(strAttr, str); } int TXmlItem::GetIntAttr(const char* strAttr, int def) const { const TString& str = GetAttr(strAttr); if (str.not_empty()) def = atoi(str); return def; } TXmlItem& TXmlItem::SetAttr(const char* strAttr, bool b) { return SetAttr(strAttr, b ? "1" : ""); } bool TXmlItem::GetBoolAttr(const char* strAttr) const { return GetIntAttr(strAttr, 0) != 0; } int TXmlItem::GetChildren() const { int n = 0; if (m_Children != NULL) n = m_Children->items(); return n; } TXmlItem* TXmlItem::GetChild(size_t n) const { TXmlItem* i = NULL; if (m_Children != NULL) i = (TXmlItem*)m_Children->objptr(n); return i; } bool TXmlItem::GetWord(istream& inf, TString& str) const { str.cut(0); int cFirstChar = EOF; while (!inf.eof()) { cFirstChar = inf.get(); if (cFirstChar <= 0 || cFirstChar > ' ') break; } if (cFirstChar == EOF) return false; str << char(cFirstChar); const bool bIsString = cFirstChar == '"' || cFirstChar == '\''; if (!bIsString) { if (strchr("<=/>", cFirstChar) != NULL) return true; // Simboli terminali if (cFirstChar == '&') str = EscapeSequence(cFirstChar, inf); } while (!inf.eof()) { int c = inf.get(); if (bIsString) { if (c == '&') str << EscapeSequence(c, inf); else { if (c >= '\0' && c <= ' ') c = ' '; str << char(c); } if (c == cFirstChar) break; } else { if (c >= '\0' && c <= ' ') break; if (strchr("<=/>", c)) { inf.putback(char(c)); break; } if (c == '&') str << EscapeSequence(c, inf); else str << char(c); } } return str.not_empty(); } int TXmlItem::ReadTag(istream& inf) { TString str; if (!GetWord(inf, str)) return -1; if (str[0] != '<') // No tag = sequence of words { bool bFirstChar = true; while (!inf.eof()) { char c = inf.get(); if (c == '<') { inf.putback(c); break; } if (bFirstChar) { if (c != ' ' && c != '=') str << ' '; bFirstChar = false; } if (c == '&') str << EscapeSequence(c, inf); else str << c; } SetTag(""); SetText(str); return 0; } TString name, tmp; bool bChildrenFollow = true; GetWord(inf, m_strTag); if (m_strTag == "/") // Sto leggendo un tag di chiusura del tipo { bChildrenFollow = false; GetWord(inf, tmp); m_strTag << tmp; } while (GetWord(inf, name)) { if (name[0] == '>') return bChildrenFollow ? +1 : 0; if (name[0] == '/' || name[0] == '?') // Gestisce i casi "/>" e "?>") { bChildrenFollow = false; continue; } // Ho letto un nome di attributo GetWord(inf, tmp); if (tmp.empty() || tmp[0] != '=') break; // Leggo il valore dell'attributo GetWord(inf, tmp); const int len = tmp.len(); if (len >= 2 && (tmp[0] == '"' || tmp[0] == '\'') && tmp[len-1] == tmp[0]) { tmp.rtrim(1); tmp.ltrim(1); } SetAttr(name, tmp); } return -1; } TXmlItem& TXmlItem::AddChild(TXmlItem* pItem) { if (m_Children == NULL) m_Children = new TArray; if (pItem == NULL) pItem = new TXmlItem; m_Children->add(pItem); return *pItem; } TXmlItem& TXmlItem::AddChild(const char* strTagName) { TXmlItem& i = AddChild((TXmlItem*)NULL); i.SetTag(strTagName); return i; } TXmlItem& TXmlItem::AddSoapString(const char* name, const char* value, bool typized) { TXmlItem& xmlVar = AddChild(name); if (typized) xmlVar.SetAttr("xsi:type", "xsd:string"); if (value && *value) xmlVar.AddChild("").SetText(value); return xmlVar; } TXmlItem& TXmlItem::AddSoapInt(const char* name, int value, bool typized) { TXmlItem& xmlVar = AddChild(name); if (typized) xmlVar.SetAttr("xsi:type", "xsd:int"); TString16 str; str << value; xmlVar.AddChild("").SetText(str); return xmlVar; } void TXmlItem::RemoveLastChild() { if (m_Children != NULL) m_Children->destroy(m_Children->last()); } bool TXmlItem::Read(istream& inf) { Destroy(); int res = ReadTag(inf); // Ignora la eventuale riga if (res == 0 && GetTag()[0] == '?') { Destroy(); 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[0] == '/') 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) { TString* strText = (TString*)jolly; const TString& str = item.GetText(); if (!str.empty()) { if (!strText->empty()) *strText << " "; *strText << str; } return false; } bool TXmlItem::GetEnclosedText(TString& text) const { text.cut(0); ((TXmlItem*)this)->ForEach(GetEnclosedTextCallback, (long)&text); return text.not_empty(); } TXmlItem& TXmlItem::AddEnclosedText(const char* str) { TXmlItem* item = FindFirst(""); if (item == NULL) item = &AddChild(""); if (item->m_strText == NULL) item->SetText(str); else *item->m_strText << str; return *item; } TXmlItem& operator<<(TXmlItem& item, const char* str) { item.AddEnclosedText(str); return item; } void TXmlItem::Write(ostream& outf, int tab) const { if (tab == 0) outf << ""; if (!GetTag().empty()) { Spaces(outf, tab); outf << '<'; GetTag().print_on(outf); if (m_Attributes != NULL) { TAssoc_array& ass = *m_Attributes; FOR_EACH_ASSOC_OBJECT(ass, h, k, a) { outf << ' ' << k << '='; const TXmlAttr* attr = (const TXmlAttr*)a; attr->Write(outf); } } if (GetChildren() > 0) { int n; outf << '>'; for (n = 0; ; n++) { TXmlItem* c = GetChild(n); if (c == NULL) break; c->Write(outf, tab+1); } if (GetChild(n-1)->GetText().empty()) Spaces(outf, tab); outf << '<' << '/'; GetTag().print_on(outf); outf << '>'; } else outf << ' ' << '/' << '>'; } else { WriteXmlString(outf, GetText()); } } void TXmlItem::AsString(TString& str) const { for (size_t nSize = 8192; ; nSize *= 2) { char* buf = str.get_buffer(nSize); memset(buf, 0, nSize); ostrstream outf(buf, nSize); Write(outf, 0); if (buf[nSize-1] == '\0') break; } } void TXmlItem::Save(const char* strFilename) const { ofstream outf(strFilename); Write(outf, 0); } bool TXmlItem::Load(const char* strFilename) { bool ok = false; if (strFilename && *strFilename) { if (strncmp(strFilename, "http://", 7) == 0 || strncmp(strFilename, "ftp://", 6) == 0) { TFilename tmp; tmp.temp(NULL, "xml"); xvt_fsys_fcopy(strFilename, tmp); ifstream qry(tmp); ok = Read(qry); qry.close(); xvt_fsys_remove_file(tmp); } else { ifstream qry(strFilename); ok = Read(qry); } } return ok; } static bool FindFirstCallback(TXmlItem& item, long jolly) { const char* strTag = (const char*)jolly; return item.GetTag() == strTag; } void TXmlItem::Destroy() { m_strTag.cut(0); if (m_strText) m_strText->cut(0); if (m_Attributes) m_Attributes->destroy(); if (m_Children) m_Children->destroy(); } TXmlItem* TXmlItem::FindFirst(const char* strTag) const { return ((TXmlItem*)this)->ForEach(FindFirstCallback, (long)strTag); } TXmlItem* TXmlItem::FindFirstChild(const char* strTag) const { const int n = GetChildren(); for (int i = 0; i < n; i++) { TXmlItem* c = GetChild(i); if (c->GetTag() == strTag) return c; } return NULL; } TXmlItem::TXmlItem() : m_strTag(15), m_strText(NULL), m_Attributes(NULL), m_Children(NULL) { } TXmlItem::~TXmlItem() { if (m_strText) delete m_strText; if (m_Attributes) delete m_Attributes; if (m_Children) delete m_Children; } void save_html_head(ostream& out, const char* title) { out << "" << endl; out << " " << title << "" << endl; out << " " << endl; out << " " << endl; out << " " << endl; out << " " << endl; out << "" << endl; }