1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmCPackIFWRepository.h"
4 
5 #include <cstddef>
6 
7 #include "cmCPackIFWGenerator.h"
8 #include "cmGeneratedFileStream.h"
9 #include "cmSystemTools.h"
10 #include "cmValue.h"
11 #include "cmXMLParser.h"
12 #include "cmXMLWriter.h"
13 
cmCPackIFWRepository()14 cmCPackIFWRepository::cmCPackIFWRepository()
15   : Update(cmCPackIFWRepository::None)
16 {
17 }
18 
IsValid() const19 bool cmCPackIFWRepository::IsValid() const
20 {
21   bool valid = true;
22 
23   switch (this->Update) {
24     case cmCPackIFWRepository::None:
25     case cmCPackIFWRepository::Add:
26     case cmCPackIFWRepository::Remove:
27       valid = !this->Url.empty();
28       break;
29     case cmCPackIFWRepository::Replace:
30       valid = !this->OldUrl.empty() && !this->NewUrl.empty();
31       break;
32   }
33 
34   return valid;
35 }
36 
ConfigureFromOptions()37 bool cmCPackIFWRepository::ConfigureFromOptions()
38 {
39   // Name;
40   if (this->Name.empty()) {
41     return false;
42   }
43 
44   std::string prefix =
45     "CPACK_IFW_REPOSITORY_" + cmsys::SystemTools::UpperCase(this->Name) + "_";
46 
47   // Update
48   if (this->IsOn(prefix + "ADD")) {
49     this->Update = cmCPackIFWRepository::Add;
50   } else if (this->IsOn(prefix + "REMOVE")) {
51     this->Update = cmCPackIFWRepository::Remove;
52   } else if (this->IsOn(prefix + "REPLACE")) {
53     this->Update = cmCPackIFWRepository::Replace;
54   } else {
55     this->Update = cmCPackIFWRepository::None;
56   }
57 
58   // Url
59   if (cmValue url = this->GetOption(prefix + "URL")) {
60     this->Url = *url;
61   } else {
62     this->Url.clear();
63   }
64 
65   // Old url
66   if (cmValue oldUrl = this->GetOption(prefix + "OLD_URL")) {
67     this->OldUrl = *oldUrl;
68   } else {
69     this->OldUrl.clear();
70   }
71 
72   // New url
73   if (cmValue newUrl = this->GetOption(prefix + "NEW_URL")) {
74     this->NewUrl = *newUrl;
75   } else {
76     this->NewUrl.clear();
77   }
78 
79   // Enabled
80   if (this->IsOn(prefix + "DISABLED")) {
81     this->Enabled = "0";
82   } else {
83     this->Enabled.clear();
84   }
85 
86   // Username
87   if (cmValue username = this->GetOption(prefix + "USERNAME")) {
88     this->Username = *username;
89   } else {
90     this->Username.clear();
91   }
92 
93   // Password
94   if (cmValue password = this->GetOption(prefix + "PASSWORD")) {
95     this->Password = *password;
96   } else {
97     this->Password.clear();
98   }
99 
100   // DisplayName
101   if (cmValue displayName = this->GetOption(prefix + "DISPLAY_NAME")) {
102     this->DisplayName = *displayName;
103   } else {
104     this->DisplayName.clear();
105   }
106 
107   return this->IsValid();
108 }
109 
110 /** \class cmCPackeIFWUpdatesPatcher
111  * \brief Helper class that parses and patch Updates.xml file (QtIFW)
112  */
113 class cmCPackeIFWUpdatesPatcher : public cmXMLParser
114 {
115 public:
cmCPackeIFWUpdatesPatcher(cmCPackIFWRepository * r,cmXMLWriter & x)116   cmCPackeIFWUpdatesPatcher(cmCPackIFWRepository* r, cmXMLWriter& x)
117     : repository(r)
118     , xout(x)
119     , patched(false)
120   {
121   }
122 
123   cmCPackIFWRepository* repository;
124   cmXMLWriter& xout;
125   bool patched;
126 
127 protected:
StartElement(const std::string & name,const char ** atts)128   void StartElement(const std::string& name, const char** atts) override
129   {
130     this->xout.StartElement(name);
131     this->StartFragment(atts);
132   }
133 
StartFragment(const char ** atts)134   void StartFragment(const char** atts)
135   {
136     for (size_t i = 0; atts[i]; i += 2) {
137       const char* key = atts[i];
138       const char* value = atts[i + 1];
139       this->xout.Attribute(key, value);
140     }
141   }
142 
EndElement(const std::string & name)143   void EndElement(const std::string& name) override
144   {
145     if (name == "Updates" && !this->patched) {
146       this->repository->WriteRepositoryUpdates(this->xout);
147       this->patched = true;
148     }
149     this->xout.EndElement();
150     if (this->patched) {
151       return;
152     }
153     if (name == "Checksum") {
154       this->repository->WriteRepositoryUpdates(this->xout);
155       this->patched = true;
156     }
157   }
158 
CharacterDataHandler(const char * data,int length)159   void CharacterDataHandler(const char* data, int length) override
160   {
161     std::string content(data, data + length);
162     if (content.empty() || content == " " || content == "  " ||
163         content == "\n") {
164       return;
165     }
166     this->xout.Content(content);
167   }
168 };
169 
PatchUpdatesXml()170 bool cmCPackIFWRepository::PatchUpdatesXml()
171 {
172   // Lazy directory initialization
173   if (this->Directory.empty() && this->Generator) {
174     this->Directory = this->Generator->toplevel;
175   }
176 
177   // Filenames
178   std::string updatesXml = this->Directory + "/repository/Updates.xml";
179   std::string updatesPatchXml =
180     this->Directory + "/repository/UpdatesPatch.xml";
181 
182   // Output stream
183   cmGeneratedFileStream fout(updatesPatchXml);
184   cmXMLWriter xout(fout);
185 
186   xout.StartDocument();
187 
188   this->WriteGeneratedByToStrim(xout);
189 
190   // Patch
191   {
192     cmCPackeIFWUpdatesPatcher patcher(this, xout);
193     patcher.ParseFile(updatesXml.data());
194   }
195 
196   xout.EndDocument();
197 
198   fout.Close();
199 
200   return cmSystemTools::RenameFile(updatesPatchXml, updatesXml);
201 }
202 
WriteRepositoryConfig(cmXMLWriter & xout) const203 void cmCPackIFWRepository::WriteRepositoryConfig(cmXMLWriter& xout) const
204 {
205   xout.StartElement("Repository");
206 
207   // Url
208   xout.Element("Url", this->Url);
209   // Enabled
210   if (!this->Enabled.empty()) {
211     xout.Element("Enabled", this->Enabled);
212   }
213   // Username
214   if (!this->Username.empty()) {
215     xout.Element("Username", this->Username);
216   }
217   // Password
218   if (!this->Password.empty()) {
219     xout.Element("Password", this->Password);
220   }
221   // DisplayName
222   if (!this->DisplayName.empty()) {
223     xout.Element("DisplayName", this->DisplayName);
224   }
225 
226   xout.EndElement();
227 }
228 
WriteRepositoryUpdate(cmXMLWriter & xout) const229 void cmCPackIFWRepository::WriteRepositoryUpdate(cmXMLWriter& xout) const
230 {
231   xout.StartElement("Repository");
232 
233   switch (this->Update) {
234     case cmCPackIFWRepository::None:
235       break;
236     case cmCPackIFWRepository::Add:
237       xout.Attribute("action", "add");
238       break;
239     case cmCPackIFWRepository::Remove:
240       xout.Attribute("action", "remove");
241       break;
242     case cmCPackIFWRepository::Replace:
243       xout.Attribute("action", "replace");
244       break;
245   }
246 
247   // Url
248   if (this->Update == cmCPackIFWRepository::Add ||
249       this->Update == cmCPackIFWRepository::Remove) {
250     xout.Attribute("url", this->Url);
251   } else if (this->Update == cmCPackIFWRepository::Replace) {
252     xout.Attribute("oldUrl", this->OldUrl);
253     xout.Attribute("newUrl", this->NewUrl);
254   }
255   // Enabled
256   if (!this->Enabled.empty()) {
257     xout.Attribute("enabled", this->Enabled);
258   }
259   // Username
260   if (!this->Username.empty()) {
261     xout.Attribute("username", this->Username);
262   }
263   // Password
264   if (!this->Password.empty()) {
265     xout.Attribute("password", this->Password);
266   }
267   // DisplayName
268   if (!this->DisplayName.empty()) {
269     xout.Attribute("displayname", this->DisplayName);
270   }
271 
272   xout.EndElement();
273 }
274 
WriteRepositoryUpdates(cmXMLWriter & xout)275 void cmCPackIFWRepository::WriteRepositoryUpdates(cmXMLWriter& xout)
276 {
277   if (!this->RepositoryUpdate.empty()) {
278     xout.StartElement("RepositoryUpdate");
279     for (cmCPackIFWRepository* r : this->RepositoryUpdate) {
280       r->WriteRepositoryUpdate(xout);
281     }
282     xout.EndElement();
283   }
284 }
285