mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 13:14:59 -06:00
210 lines
4.0 KiB
C++
Executable File
210 lines
4.0 KiB
C++
Executable File
// 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, pos) while (IsSpaceChar(s[pos])) pos++;
|
|
|
|
static bool ReadProperty(const AString &s, int &pos, CXmlProp &prop)
|
|
{
|
|
prop.Name.Empty();
|
|
prop.Value.Empty();
|
|
for (; pos < s.Length(); pos++)
|
|
{
|
|
char c = s[pos];
|
|
if (!IsValidChar(c))
|
|
break;
|
|
prop.Name += c;
|
|
}
|
|
|
|
if (prop.Name.IsEmpty())
|
|
return false;
|
|
|
|
SKIP_SPACES(s, pos);
|
|
if (s[pos++] != '=')
|
|
return false;
|
|
|
|
SKIP_SPACES(s, pos);
|
|
if (s[pos++] != '\"')
|
|
return false;
|
|
|
|
while (pos < s.Length())
|
|
{
|
|
char c = s[pos++];
|
|
if (c == '\"')
|
|
return true;
|
|
prop.Value += c;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int CXmlItem::FindProperty(const AString &propName) const
|
|
{
|
|
for (int i = 0; i < Props.Size(); i++)
|
|
if (Props[i].Name == propName)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
AString CXmlItem::GetPropertyValue(const AString &propName) const
|
|
{
|
|
int index = FindProperty(propName);
|
|
if (index >= 0)
|
|
return Props[index].Value;
|
|
return AString();
|
|
}
|
|
|
|
bool CXmlItem::IsTagged(const AString &tag) const
|
|
{
|
|
return (IsTag && Name == tag);
|
|
}
|
|
|
|
int CXmlItem::FindSubTag(const AString &tag) const
|
|
{
|
|
for (int i = 0; i < SubItems.Size(); i++)
|
|
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();
|
|
}
|
|
|
|
AString CXmlItem::GetSubStringForTag(const AString &tag) const
|
|
{
|
|
int index = FindSubTag(tag);
|
|
if (index >= 0)
|
|
return SubItems[index].GetSubString();
|
|
return AString();
|
|
}
|
|
|
|
bool CXmlItem::ParseItems(const AString &s, int &pos, int numAllowedLevels)
|
|
{
|
|
if (numAllowedLevels == 0)
|
|
return false;
|
|
SubItems.Clear();
|
|
AString finishString = "</";
|
|
for (;;)
|
|
{
|
|
SKIP_SPACES(s, pos);
|
|
|
|
if (s.Mid(pos, finishString.Length()) == finishString)
|
|
return true;
|
|
|
|
CXmlItem item;
|
|
if (!item.ParseItem(s, pos, numAllowedLevels - 1))
|
|
return false;
|
|
SubItems.Add(item);
|
|
}
|
|
}
|
|
|
|
bool CXmlItem::ParseItem(const AString &s, int &pos, int numAllowedLevels)
|
|
{
|
|
SKIP_SPACES(s, pos);
|
|
|
|
int pos2 = s.Find('<', pos);
|
|
if (pos2 < 0)
|
|
return false;
|
|
if (pos2 != pos)
|
|
{
|
|
IsTag = false;
|
|
Name += s.Mid(pos, pos2 - pos);
|
|
pos = pos2;
|
|
return true;
|
|
}
|
|
IsTag = true;
|
|
|
|
pos++;
|
|
SKIP_SPACES(s, pos);
|
|
|
|
for (; pos < s.Length(); pos++)
|
|
{
|
|
char c = s[pos];
|
|
if (!IsValidChar(c))
|
|
break;
|
|
Name += c;
|
|
}
|
|
if (Name.IsEmpty() || pos == s.Length())
|
|
return false;
|
|
|
|
int posTemp = pos;
|
|
for (;;)
|
|
{
|
|
SKIP_SPACES(s, pos);
|
|
if (s[pos] == '/')
|
|
{
|
|
pos++;
|
|
// SKIP_SPACES(s, pos);
|
|
return (s[pos++] == '>');
|
|
}
|
|
if (s[pos] == '>')
|
|
{
|
|
if (!ParseItems(s, ++pos, numAllowedLevels))
|
|
return false;
|
|
AString finishString = AString("</") + Name + AString(">");
|
|
if (s.Mid(pos, finishString.Length()) != finishString)
|
|
return false;
|
|
pos += finishString.Length();
|
|
return true;
|
|
}
|
|
if (posTemp == pos)
|
|
return false;
|
|
|
|
CXmlProp prop;
|
|
if (!ReadProperty(s, pos, prop))
|
|
return false;
|
|
Props.Add(prop);
|
|
posTemp = pos;
|
|
}
|
|
}
|
|
|
|
static bool SkipHeader(const AString &s, int &pos, const AString &startString, const AString &endString)
|
|
{
|
|
SKIP_SPACES(s, pos);
|
|
if (s.Mid(pos, startString.Length()) == startString)
|
|
{
|
|
pos = s.Find(endString, pos);
|
|
if (pos < 0)
|
|
return false;
|
|
pos += endString.Length();
|
|
SKIP_SPACES(s, pos);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CXml::Parse(const AString &s)
|
|
{
|
|
int pos = 0;
|
|
if (!SkipHeader(s, pos, "<?xml", "?>"))
|
|
return false;
|
|
if (!SkipHeader(s, pos, "<!DOCTYPE", ">"))
|
|
return false;
|
|
if (!Root.ParseItem(s, pos, 1000))
|
|
return false;
|
|
SKIP_SPACES(s, pos);
|
|
return (pos == s.Length() && Root.IsTag);
|
|
}
|