1 /*!********************************************************************
2  Audacity: A Digital Audio Editor
3 
4  @file UpdateDataParser.cpp
5  @brief Declare a class that parses update server data format.
6 
7  Anton Gerasimov
8  **********************************************************************/
9 
10 #include "UpdateDataParser.h"
11 
12 #include "XMLFileReader.h"
13 #include "MemoryX.h"
14 #include <wx/platinfo.h>
15 
UpdateDataParser()16 UpdateDataParser::UpdateDataParser()
17 {}
18 
~UpdateDataParser()19 UpdateDataParser::~UpdateDataParser()
20 {}
21 
Parse(const VersionPatch::UpdateDataFormat & updateData,VersionPatch * versionPatch)22 bool UpdateDataParser::Parse(const VersionPatch::UpdateDataFormat& updateData, VersionPatch* versionPatch)
23 {
24     XMLFileReader xmlReader;
25 
26     ValueRestorer<VersionPatch*> setter{ mVersionPatch, versionPatch };
27 
28     return xmlReader.ParseString(this, updateData);
29 }
30 
SplitChangelogSentences(const wxString & changelogContent)31 wxArrayString UpdateDataParser::SplitChangelogSentences(const wxString& changelogContent)
32 {
33     wxArrayString changelogSentenceList;
34 
35     size_t pos = 0;
36     std::string s(changelogContent.ToStdString());
37     std::string token;
38     const std::string delimiter(". ");
39 
40     while ((pos = s.find(delimiter)) != std::string::npos)
41     {
42         token = s.substr(0, pos + 1);
43         changelogSentenceList.Add(wxString(token).Trim());
44 
45         s.erase(0, pos + delimiter.length());
46     }
47     changelogSentenceList.Add(wxString(s).Trim());
48 
49     return changelogSentenceList;
50 }
51 
HandleXMLTag(const std::string_view & tag,const AttributesList & attrs)52 bool UpdateDataParser::HandleXMLTag(const std::string_view& tag, const AttributesList& attrs)
53 {
54     if (tag == mXmlTagNames[XmlParsedTags::kDescriptionTag])
55     {
56         mXmlParsingState = XmlParsedTags::kDescriptionTag;
57         return true;
58     }
59 
60     const wxPlatformInfo& info = wxPlatformInfo::Get();
61 
62     constexpr bool is32Bit = sizeof(void*) == 4;
63     constexpr bool is64Bit = sizeof(void*) == 8;
64 
65     if (is32Bit)
66     {
67        if (tag == mXmlTagNames[XmlParsedTags::kWin32Tag])
68        {
69           if (info.GetOperatingSystemId() & wxOS_WINDOWS)
70              mXmlParsingState = XmlParsedTags::kOsTag;
71           return true;
72        }
73     }
74 
75     if (is64Bit)
76     {
77        if (tag == mXmlTagNames[XmlParsedTags::kWin64Tag])
78        {
79           if (info.GetOperatingSystemId() & wxOS_WINDOWS)
80              mXmlParsingState = XmlParsedTags::kOsTag;
81           return true;
82        }
83     }
84 
85     if (tag == mXmlTagNames[XmlParsedTags::kMacosTag])
86     {
87         if (info.GetOperatingSystemId() & wxOS_MAC)
88             mXmlParsingState = XmlParsedTags::kOsTag;
89         return true;
90     }
91 
92     if (tag == mXmlTagNames[XmlParsedTags::kLinuxTag])
93     {
94         if (info.GetOperatingSystemId() & wxOS_UNIX_LINUX)
95             mXmlParsingState = XmlParsedTags::kOsTag;
96         return true;
97     }
98 
99     if (tag == mXmlTagNames[XmlParsedTags::kVersionTag])
100     {
101         if (mXmlParsingState == XmlParsedTags::kOsTag)
102             mXmlParsingState = XmlParsedTags::kVersionTag;
103         return true;
104     }
105 
106     if (tag == mXmlTagNames[XmlParsedTags::kLinkTag])
107     {
108         if (mXmlParsingState == XmlParsedTags::kOsTag)
109             mXmlParsingState = XmlParsedTags::kLinkTag;
110         return true;
111     }
112 
113     for (auto& xmlTag : mXmlTagNames)
114     {
115         if (tag == xmlTag.second)
116             return true;
117     }
118 
119     return false;
120 }
121 
HandleXMLEndTag(const std::string_view & tag)122 void UpdateDataParser::HandleXMLEndTag(const std::string_view& tag)
123 {
124     if (mXmlParsingState == XmlParsedTags::kDescriptionTag ||
125         mXmlParsingState == XmlParsedTags::kLinkTag)
126         mXmlParsingState = XmlParsedTags::kNotUsedTag;
127 
128     // If it is our working OS, using "kOsTag" for keeping ready for parse state for both tags:
129     // <Version> and <Link>, that ordered one after another.
130     if (mXmlParsingState == XmlParsedTags::kVersionTag)
131         mXmlParsingState = XmlParsedTags::kOsTag;
132 }
133 
HandleXMLContent(const std::string_view & content)134 void UpdateDataParser::HandleXMLContent(const std::string_view& content)
135 {
136     if (mVersionPatch == nullptr)
137         return;
138 
139     wxString trimmedContent = std::string(content);
140 
141     switch (mXmlParsingState)
142     {
143     case XmlParsedTags::kDescriptionTag:
144         trimmedContent.Trim(true).Trim(false);
145         mVersionPatch->changelog = SplitChangelogSentences(trimmedContent);
146         break;
147 
148     case XmlParsedTags::kVersionTag:
149         trimmedContent.Trim(true).Trim(false);
150         mVersionPatch->version = VersionId::ParseFromString(trimmedContent);
151         break;
152 
153     case XmlParsedTags::kLinkTag:
154         trimmedContent.Trim(true).Trim(false);
155         mVersionPatch->download = trimmedContent;
156         break;
157 
158     default:
159         break;
160     }
161 }
162 
HandleXMLChild(const std::string_view & tag)163 XMLTagHandler* UpdateDataParser::HandleXMLChild(const std::string_view& tag)
164 {
165     for (auto& xmlTag : mXmlTagNames)
166     {
167         if (tag == xmlTag.second)
168             return this;
169     }
170 
171     return NULL;
172 }
173