1 /*
2 Copyright (c) 2018, MIPI Alliance, Inc.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 * Neither the name of the copyright holder nor the names of its
18 contributors may be used to endorse or promote products derived
19 from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Contributors:
36 * Norbert Schulz (Intel Corporation) - Initial API and implementation
37 */
38
39 #include <iomanip>
40 #include <sstream>
41 #include <iostream>
42 #include <type_traits>
43
44 #include "mipi_syst_collateral.h"
45 #include "mipi_syst_guid.h"
46
47 MIPI_SYST_NAMESPACE_BEGIN
48
49 const char tagCollateral[] = "syst:Collateral";
50 const char tagClient[] = "syst:Client";
51 const char tagGuids[] = "syst:Guids";
52 const char tagGuid[] = "syst:Guid";
53 const char tagBuilds[] = "syst:Builds";
54 const char tagBuild[] = "syst:Build";
55 const char tagCatalog32[] = "syst:Catalog32";
56 const char tagCatalog64[] = "syst:Catalog64";
57 const char tagSourceFiles[] = "syst:SourceFiles";
58 const char tagFile[] = "syst:File";
59 const char tagShort32[] = "syst:Short32";
60 const char tagShort64[] = "syst:Short64";
61 const char tagWrite[] = "syst:Write";
62 const char tagProtocol[] = "syst:Protocol";
63 const char tagModules[] = "syst:Modules";
64 const char tagModule[] = "syst:Module";
65 const char tagID[] = "ID";
66 const char tagMask[] = "Mask";
67 const char tagFileAttr[] = "File";
68 const char tagLine[] = "Line";
69 const char tagFormat[] = "syst:Format";
70
71
parseXml(const std::string & filename)72 std::vector<collateral*> collateral::parseXml(const std::string& filename)
73 {
74 pugi::xml_document doc;
75 pugi::xml_parse_result scan_result(doc.load_file(filename.c_str()));
76 std::stringstream sstr;
77
78 if (!scan_result) {
79 sstr
80 << "XML parser error on file "
81 << filename
82 << " : "
83 << scan_result.description();
84
85 throw std::invalid_argument(sstr.str());
86 }
87
88 std::vector<collateral*> result;
89
90 for(auto client(doc.child(tagCollateral).child(tagClient));
91 client;
92 client = client.next_sibling(tagClient))
93 {
94 result.push_back(new collateral(client, filename));
95 }
96 return result;
97 }
98
99
collateral(pugi::xml_node & node,const std::string & file)100 collateral::collateral(pugi::xml_node& node, const std::string& file) :
101 m_file(file),
102 m_name(node.attribute("Name").as_string())
103 {
104 // Scan id <-> item mappings
105 //
106 parseMaskedItems(node.child(tagGuids), tagGuid, m_guids);
107 parseMaskedItems(node.child(tagBuilds), tagBuild, m_builds);
108 parseMaskedItems(node.child(tagSourceFiles), tagFile, m_files);
109 parseMaskedItems(node.child(tagModules), tagModule, m_modules);
110 parseMaskedItems(node.child(tagCatalog32), tagFormat, m_msgs32);
111 parseMaskedItems(node.child(tagCatalog64), tagFormat, m_msgs64);
112 parseMaskedItems(node.child(tagShort32), tagFormat, m_shorts32);
113 parseMaskedItems(node.child(tagShort64), tagFormat, m_shorts64);
114 parseMaskedItems(node.child(tagWrite), tagProtocol, m_writeTypes);
115 }
116
match(const guid & g,uint64_t build) const117 bool collateral::match(const guid& g, uint64_t build) const
118 {
119 for (auto& it : m_guids) {
120 if ((g & it.mask()) == (it.key() & it.mask()))
121 {
122 if (build != 0x0) {
123 // find collateral with matching build number
124 //
125 if (m_builds.find(build) != m_builds.end())
126 {
127 return true;
128 }
129 } else {
130 return true;
131 }
132 }
133 }
134
135 return false;
136 }
137
getCatalogEntry(uint32_t id) const138 template<> const collateral::catalogentry<uint32_t> * collateral::getCatalogEntry<>(uint32_t id) const
139 {
140 auto hit = m_msgs32.find(id);
141 return (hit != m_msgs32.end()) ? &hit->value() : nullptr;
142 }
143
getCatalogEntry(uint64_t id) const144 template<> const collateral::catalogentry<uint64_t> * collateral::getCatalogEntry<>(uint64_t id) const
145 {
146 auto hit = m_msgs64.find(id);
147 return (hit != m_msgs64.end()) ? &hit->value() : nullptr;
148 }
getSourceFile(uint32_t id) const149 const std::string * collateral::getSourceFile(uint32_t id) const
150 {
151 auto hit = m_files.find(id);
152 return (hit != m_files.end()) ? &hit->value() : nullptr;
153 }
154
getWriteType(uint8_t id) const155 const std::string * collateral::getWriteType(uint8_t id) const
156 {
157 auto hit(m_writeTypes.find(id));
158 return (hit != m_writeTypes.end()) ? &hit->value() : nullptr;
159 }
160
getShortEntry(uint32_t id) const161 template<> const collateral::catalogentry<uint32_t> * collateral::getShortEntry<>(uint32_t id) const
162 {
163 auto hit(m_shorts32.find(id));
164 return (hit != m_shorts32.end()) ? &hit->value() : nullptr;
165 }
getShortEntry(uint64_t id) const166 template<> const collateral::catalogentry<uint64_t> * collateral::getShortEntry<>(uint64_t id) const
167 {
168 auto hit(m_shorts64.find(id));
169 return (hit != m_shorts64.end()) ? &hit->value() : nullptr;
170 }
171
parse(K & dest,const std::string & s)172 template<typename K> bool parse(K& dest, const std::string& s)
173 {
174 return stringToNum<K>(s, dest);
175 }
176
parse(guid & g,const std::string & s)177 template<> bool parse<guid>(guid& g, const std::string& s)
178 {
179 return g.parse(s);
180 }
181
nomask()182 template<typename K> K nomask() { return (K)-1; }
nomask()183 template<> guid nomask<guid>() { return guid("{ffffffff-ffff-ffff-ffff-ffffffffffff}"); }
184
operator <<(std::ostream & os,const collateral::catalogentry<T> & p)185 template<typename T> std::ostream & operator<<(std::ostream &os, const collateral::catalogentry<T>& p)
186 {
187 return os << p.msg;
188 }
189
190 template<typename K, typename V>
parseMaskedItems(pugi::xml_node root,const char * tag,masked_vector<K,V> & dest)191 void collateral::parseMaskedItems(
192 pugi::xml_node root, const char * tag, masked_vector<K, V>& dest)
193 {
194 for (pugi::xml_node item(root.child(tag));
195 item;
196 item = item.next_sibling(tag))
197 {
198 masked_item<K, V> data;
199
200 std::string keyStr(item.attribute(tagID).as_string());
201 std::string val(item.child_value());
202
203 if (!parse<K>(data.key(), keyStr)) {
204 std::stringstream what;
205 what <<
206 "Malformed " << tag << "entry ID=\"" << keyStr <<
207 "\" value =\"" << val << "\"" <<
208 " for catalog " << m_name;
209 throw std::invalid_argument(what.str());
210 }
211
212 std::string maskStr(item.attribute(tagMask).as_string());
213 if (!maskStr.empty()) {
214 if (!parse<K>(data.mask(), maskStr)) {
215 std::stringstream what;
216 what <<
217 "Malformed " << tag << "entry Mask=\"" << maskStr <<
218 "\" value =\"" << val << "\"" <<
219 " for catalog " << m_name;
220 throw std::invalid_argument(what.str());
221 }
222 } else {
223 data.mask() = nomask<K>();
224 }
225
226 data.value() = val;
227
228 // scan option file/line data if value supports source positions
229 //
230 if (std::is_base_of<catalogentry<K>, V>::value) {
231 catalogentry<K> * entry((catalogentry<K>*)&data.value());
232 entry->mask = data.mask();
233
234 std::string file(item.attribute(tagFileAttr).as_string());
235 std::string line(item.attribute(tagLine).as_string());
236
237 if (!file.empty()) {
238 if (!parse(entry->m_file, file)) {
239 std::stringstream what;
240 what <<
241 "Malformed File attribute " << file <<
242 "in section " << tag <<
243 " for catalog " << m_name;
244 throw std::invalid_argument(what.str());
245 }
246 }
247
248 if (!line.empty()) {
249 if (!parse(entry->m_line, line)) {
250 std::stringstream what;
251 what <<
252 "Malformed Line attribute " << line <<
253 "in section " << tag <<
254 " for catalog " << m_name;
255 throw std::invalid_argument(what.str());
256 }
257 }
258 }
259
260 auto it = dest.find(data.key());
261 if (it != dest.end() && it->value() != val) {
262 std::cerr <<
263 "Overwriting ID" << data.key() << " -> " << val <<
264 " old value: " << it->value() << std::endl;
265 *it = data;
266 }
267 else {
268 dest.push_back(data);
269 }
270 }
271 }
272
273 /** Helper to parse a GUID "{...}" string into the binary representation.
274 * @param str GUID ascii string "{xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
275 * @param guid resulting guid
276 * @return true if guid could be parserd
277 */
parse(const std::string & str)278 bool guid::parse(const std::string& str)
279 {
280 if (
281 (str.length() != sizeof("{00000000-0000-0000-0000-000000000000}")-1) ||
282 str[0]!= '{' ||str[37] != '}' ||
283 str[9] != '-' || str[14] != '-' || str[19] != '-' || str[24] != '-'
284 )
285 {
286 return false;
287 }
288
289 // parse the byte values;
290 //
291 const char * p(str.c_str()+1);
292
293 for (int i(0); i < 16; ++i, p += 2) {
294 if (i == 4 || i == 6|| i == 8 || i == 10) {
295 p++; // skip "-"
296 }
297 std::stringstream sstr(std::string(p, 2));
298 uint16_t temp;
299
300 if (! (sstr >> std::hex >>temp)) {
301 return false;
302 }
303 u.b[i] = (uint8_t)(temp);
304 }
305
306 return true;
307 }
308
operator <<(std::ostream & os,const guid & g)309 std::ostream& operator<<(std::ostream& os, const guid& g)
310 {
311 auto flags(os.flags());
312
313
314 os << '{';
315
316 for (int i(0); i < 16; ++i) {
317 os << std::setfill('0') << std::noshowbase << std::hex << std::setw(2)
318 << (uint16_t)g.u.b[i];
319
320 if (i == 3 || i == 5|| i == 7 || i == 9) {
321 os << '-';
322 }
323 }
324
325 os << '}';
326
327 os.flags(flags);
328 return os;
329 }
330
331 MIPI_SYST_NAMESPACE_END