d7b93c2169
git-svn-id: svn://10.65.10.50/branches/R_10_00@23015 c028cbd2-c16b-5b4b-a496-9718f37d4682
618 lines
12 KiB
C++
Executable File
618 lines
12 KiB
C++
Executable File
#include <colors.h>
|
|
#include <dongle.h>
|
|
#include <real.h>
|
|
#include <xml.h>
|
|
|
|
#include <incstr.h>
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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 </SOAP-ENV>
|
|
{
|
|
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 <?xml version="1.0" encoding="UTF-8" ?>
|
|
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 << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
|
|
|
|
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 << "<head>" << endl;
|
|
out << " <title>" << title << "</title>" << endl;
|
|
out << " <meta name=Author content=\"" << user() << "\" />" << endl;
|
|
out << " <meta name=Generator content=\"" << dongle().product() << "\"/>" << endl;
|
|
out << " <meta name=Vendor content=\"" << dongle().reseller() << "\"/>" << endl;
|
|
out << " <style type=\"text/css\">" << endl;
|
|
out << " th = { background-color:"; WriteXmlColor(out, BTN_BACK_COLOR); out << " }" << endl;
|
|
out << " </style>" << endl;
|
|
out << "</head>" << endl;
|
|
}
|