p7zip/CPP/Common/MyXml.cpp
2017-10-11 12:35:36 +02:00

261 lines
4.5 KiB
C++

// MyXml.cpp
#include "StdAfx.h"
#include "MyXml.h"
static bool IsValidChar(char c)
{
return
c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9' ||
c == '-';
}
static bool IsSpaceChar(char c)
{
return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A);
}
#define SKIP_SPACES(s) while (IsSpaceChar(*s)) s++;
int CXmlItem::FindProp(const AString &propName) const throw()
{
FOR_VECTOR (i, Props)
if (Props[i].Name == propName)
return i;
return -1;
}
AString CXmlItem::GetPropVal(const AString &propName) const
{
int index = FindProp(propName);
if (index >= 0)
return Props[index].Value;
return AString();
}
bool CXmlItem::IsTagged(const AString &tag) const throw()
{
return (IsTag && Name == tag);
}
int CXmlItem::FindSubTag(const AString &tag) const throw()
{
FOR_VECTOR (i, SubItems)
if (SubItems[i].IsTagged(tag))
return i;
return -1;
}
AString CXmlItem::GetSubString() const
{
if (SubItems.Size() == 1)
{
const CXmlItem &item = SubItems[0];
if (!item.IsTag)
return item.Name;
}
return AString();
}
const AString * CXmlItem::GetSubStringPtr() const throw()
{
if (SubItems.Size() == 1)
{
const CXmlItem &item = SubItems[0];
if (!item.IsTag)
return &item.Name;
}
return NULL;
}
AString CXmlItem::GetSubStringForTag(const AString &tag) const
{
int index = FindSubTag(tag);
if (index >= 0)
return SubItems[index].GetSubString();
return AString();
}
const char * CXmlItem::ParseItem(const char *s, int numAllowedLevels)
{
SKIP_SPACES(s);
const char *beg = s;
for (;;)
{
char c;
c = *s; if (c == 0 || c == '<') break; s++;
c = *s; if (c == 0 || c == '<') break; s++;
}
if (*s == 0)
return NULL;
if (s != beg)
{
IsTag = false;
Name.SetFrom(beg, (unsigned)(s - beg));
return s;
}
IsTag = true;
s++;
SKIP_SPACES(s);
beg = s;
for (;; s++)
if (!IsValidChar(*s))
break;
if (s == beg || *s == 0)
return NULL;
Name.SetFrom(beg, (unsigned)(s - beg));
for (;;)
{
beg = s;
SKIP_SPACES(s);
if (*s == '/')
{
s++;
// SKIP_SPACES(s);
if (*s != '>')
return NULL;
return s + 1;
}
if (*s == '>')
{
s++;
if (numAllowedLevels == 0)
return NULL;
SubItems.Clear();
for (;;)
{
SKIP_SPACES(s);
if (s[0] == '<' && s[1] == '/')
break;
CXmlItem &item = SubItems.AddNew();
s = item.ParseItem(s, numAllowedLevels - 1);
if (!s)
return NULL;
}
s += 2;
unsigned len = Name.Len();
for (unsigned i = 0; i < len; i++)
if (s[i] != Name[i])
return NULL;
s += len;
if (s[0] != '>')
return NULL;
return s + 1;
}
if (beg == s)
return NULL;
// ReadProperty
CXmlProp &prop = Props.AddNew();
beg = s;
for (;; s++)
{
char c = *s;
if (!IsValidChar(c))
break;
}
if (s == beg)
return NULL;
prop.Name.SetFrom(beg, (unsigned)(s - beg));
SKIP_SPACES(s);
if (*s != '=')
return NULL;
s++;
SKIP_SPACES(s);
if (*s != '\"')
return NULL;
s++;
beg = s;
for (;;)
{
char c = *s;
if (c == 0)
return NULL;
if (c == '\"')
break;
s++;
}
prop.Value.SetFrom(beg, (unsigned)(s - beg));
s++;
}
}
static const char * SkipHeader(const char *s, const char *startString, const char *endString)
{
SKIP_SPACES(s);
if (IsString1PrefixedByString2(s, startString))
{
s = strstr(s, endString);
if (!s)
return NULL;
s += strlen(endString);
}
return s;
}
void CXmlItem::AppendTo(AString &s) const
{
if (IsTag)
s += '<';
s += Name;
if (IsTag)
{
FOR_VECTOR (i, Props)
{
const CXmlProp &prop = Props[i];
s += ' ';
s += prop.Name;
s += '=';
s += '\"';
s += prop.Value;
s += '\"';
}
s += '>';
}
FOR_VECTOR (i, SubItems)
{
const CXmlItem &item = SubItems[i];
if (i != 0 && !SubItems[i - 1].IsTag)
s += ' ';
item.AppendTo(s);
}
if (IsTag)
{
s += '<';
s += '/';
s += Name;
s += '>';
}
}
bool CXml::Parse(const char *s)
{
s = SkipHeader(s, "<?xml", "?>"); if (!s) return false;
s = SkipHeader(s, "<!DOCTYPE", ">"); if (!s) return false;
s = Root.ParseItem(s, 1000);
if (!s || !Root.IsTag)
return false;
SKIP_SPACES(s);
return *s == 0;
}
/*
void CXml::AppendTo(AString &s) const
{
Root.AppendTo(s);
}
*/