tizen beta release
[framework/web/wrt-installer.git] / src / configuration_parser / powder_parser.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file        powder_parser.cpp
18  * @author      Piotr Marcinkiewicz (p.marcinkiew@samsung.com)
19  * @version     0.1
20  * @brief       Parser for WAC defined POWDER
21  */
22
23 #include <algorithm>
24 #include <cstdio>
25 #include <cerrno>
26 #include <ewk_main.h>
27 #include <dpl/log/log.h>
28 #include <dpl/sstream.h>
29 #include <dpl/foreach.h>
30 #include "powder_parser.h"
31 #include "ignoring_parser.h"
32 #include "deny_all_parser.h"
33
34 namespace {
35 void MergeDescriptions(WrtDB::Powder::Description* dest,
36         const WrtDB::Powder::Description& src)
37 {
38     Assert(dest);
39 //    LogInfo("MergeDescriptions dest: " << *dest <<
40 //            " src: " << src);
41     if (!dest->ageRating) {
42         dest->ageRating = src.ageRating;
43     } else {
44         if (!!src.ageRating) {
45             if (*dest->ageRating > *src.ageRating) {
46                 dest->ageRating = src.ageRating;
47             }
48         }
49     }
50     FOREACH(catIter, src.categories)
51     {
52         FOREACH(levelIter, catIter->second.levels)
53         {
54             dest->categories[catIter->first].levels.push_back(*levelIter);
55         }
56     }
57 //    LogInfo("MergeDescriptions result:" << *dest);
58 }
59
60 //TODO::Check if list of delimiters is valid
61 const DPL::String constPowderDelimiters = DPL::FromUTF32String(L" ,;\n\r\t");
62 } //anonymous namespace
63
64 std::ostream & operator<<(std::ostream& aStream,
65         const StringSet& aContainer)
66 {
67     if (!aContainer.empty()) {
68         StringSet::const_iterator iter = aContainer.begin();
69         aStream << "{[" << *iter;
70         ++iter;
71         for (/*empty*/; iter != aContainer.end(); ++iter) {
72             aStream << "] [" << *iter;
73         }
74         aStream << "]}";
75     }
76     return aStream;
77 }
78
79 #define DEFINE_ELEMENT_FUNC(element, myClass)              \
80     m_map[DPL::FromUTF32String(L"" # element)] =            \
81         DPL::MakeDelegate(this, &myClass::OnElement_ ## element);
82
83 class DenyUnknownTagsParser : public ElementParser
84 {
85   public:
86     DenyUnknownTagsParser() : ElementParser()
87     {
88     }
89
90     void Accept(const XmlAttribute& /*attribute*/)
91     {
92     }
93
94     void Accept(const Element& /*element*/)
95     {
96     }
97
98     void Accept(const Text& /*text*/)
99     {
100     }
101
102     ElementParserPtr OnDenyElement()
103     {
104         return ElementParserPtr(new DenyAllParser());
105     }
106
107     ActionFunc GetElementParser(const DPL::String& /*ns*/,
108             const DPL::String& /*name*/)
109     {
110         return DPL::MakeDelegate(this, &DenyUnknownTagsParser::OnDenyElement);
111     }
112
113   protected:
114     FuncMap m_map;
115 };
116
117 StringSet TokenizeTag(const DPL::String& buffer)
118 {
119     StringSet data;
120     DPL::Tokenize(buffer, constPowderDelimiters,
121                   std::insert_iterator<StringSet>(data, data.begin()), true);
122     return data;
123 }
124
125 class SetOfTextValuesParser : public DenyUnknownTagsParser
126 {
127   public:
128     explicit SetOfTextValuesParser(std::set<DPL::String>* data) :
129         DenyUnknownTagsParser(),
130         m_data(data)
131     {
132         Assert(m_data);
133     }
134
135     virtual void Accept(const Text& text)
136     {
137         LogDebug("text");
138         m_buffer += text.value;
139     }
140     void Verify()
141     {
142         *m_data = TokenizeTag(m_buffer);
143     }
144
145   private:
146     DPL::String m_buffer;
147     StringSet* m_data;
148 };
149
150 // It is data structure used by iriset parser to match IRI's
151 // and preserve processing result
152 struct IrisetParserData
153 {
154     const DPL::String* m_host;
155     const DPL::String* m_path;
156     bool m_matched;
157     IrisetParserData(const DPL::String& host,
158             const DPL::String& path) :
159         m_host(&host),
160         m_path(&path),
161         m_matched(false)
162     {
163     }
164 };
165
166 class IrisetParser : public DenyUnknownTagsParser
167 {
168   public:
169     explicit IrisetParser(IrisetParserData* data) :
170         DenyUnknownTagsParser(),
171         m_data(data),
172         m_hostsDetected(0),
173         m_pathsDetected(0)
174     {
175         Assert(m_data);
176         DEFINE_ELEMENT_FUNC(includehosts, IrisetParser);
177         DEFINE_ELEMENT_FUNC(includeexactpaths, IrisetParser);
178     }
179
180     ElementParserPtr OnElement_includehosts()
181     {
182         m_hostsDetected++;
183         return ElementParserPtr(new SetOfTextValuesParser(&m_hosts));
184     }
185
186     ElementParserPtr OnElement_includeexactpaths()
187     {
188         m_pathsDetected++;
189         return ElementParserPtr(new SetOfTextValuesParser(&m_paths));
190     }
191
192     void Verify()
193     {
194         if (m_hostsDetected <= 1 && m_pathsDetected <= 1) {
195             LogInfo("Matching iriset for host [" <<
196                     *m_data->m_host << "] path [" <<
197                     *m_data->m_path << "]");
198             LogInfo("hosts: " << m_hosts <<
199                     " paths: " << m_paths);
200             m_data->m_matched =
201                 m_hosts.find(*m_data->m_host) != m_hosts.end() &&
202                 m_paths.find(*m_data->m_path) != m_paths.end();
203         } else {
204             ThrowMsg(PowderParserException::ParserFailed,
205                      "Invalid iriset contents");
206         }
207     }
208
209   private:
210     IrisetParserData* m_data;
211     typedef StringSet Container;
212     Container m_hosts;
213     Container m_paths;
214     size_t m_hostsDetected;
215     size_t m_pathsDetected;
216 };
217
218 class WacCategoryParser : public DenyUnknownTagsParser
219 {
220   public:
221     WacCategoryParser(WrtDB::Powder::Description::LevelEntry* data) :
222         DenyUnknownTagsParser(),
223         m_data(data)
224     {
225         Assert(m_data);
226     }
227
228     virtual void Accept(const Text& text)
229     {
230         LogDebug("text");
231         m_buffer += text.value;
232     }
233
234     static StringSet GetAllowedAttributes()
235     {
236         StringSet allowed;
237         allowed.insert(DPL::FromUTF32String(L"xa"));
238         allowed.insert(DPL::FromUTF32String(L"xb"));
239         allowed.insert(DPL::FromUTF32String(L"xc"));
240         allowed.insert(DPL::FromUTF32String(L"xd"));
241         allowed.insert(DPL::FromUTF32String(L"xe"));
242         return allowed;
243     }
244
245     virtual void Accept(const XmlAttribute& attribute)
246     {
247         static StringSet allowed = GetAllowedAttributes();
248         if (allowed.find(attribute.name) != allowed.end()) {
249             if (DPL::FromUTF32String(L"1") == attribute.value) {
250                 m_data->context.insert(attribute.name);
251             } else if (DPL::FromUTF32String(L"0") != attribute.value) {
252                 ThrowMsg(PowderParserException::ParserFailed,
253                          "Invalid attribute for WAC category tag");
254             }
255         } else {
256             ThrowMsg(PowderParserException::ParserFailed,
257                      "Invalid tag in descriptionset");
258         }
259     }
260
261     virtual void Verify()
262     {
263         StringSet values = TokenizeTag(m_buffer);
264         bool numberFound = false;
265
266         FOREACH(wordIter, values) {
267             DPL::IStringStream str(*wordIter);
268             int rating;
269             str >> rating;
270             if (str.fail()) {
271                 ThrowMsg(PowderParserException::ParserFailed,
272                          "WAC category level is not number");
273             } else {
274                 if (numberFound) {
275                     ThrowMsg(PowderParserException::ParserFailed,
276                              "Too many WAC category levels");
277                 } else {
278                     if (rating >= MIN_AGE_RATING && rating <= MAX_AGE_RATING) {
279                         m_data->level =
280                             static_cast<WrtDB::Powder::Description::LevelEnum>(
281                                     rating);
282                         numberFound = true;
283                     } else {
284                         ThrowMsg(PowderParserException::ParserFailed,
285                                  "WAC category level is out of range ");
286                     }
287                 }
288             }
289         }
290         if (!numberFound) {
291             ThrowMsg(PowderParserException::ParserFailed,
292                      "WAC category level is not present in tag");
293         }
294     }
295
296   private:
297     WrtDB::Powder::Description::LevelEntry* m_data;
298     DPL::String m_buffer;
299     static const int MIN_AGE_RATING = 0;
300     static const int MAX_AGE_RATING = 5;
301 };
302
303 class DescriptorSetParser : public DenyUnknownTagsParser
304 {
305   public:
306     typedef WrtDB::Powder::Description::CategoryEntries::iterator CatIter;
307     explicit DescriptorSetParser(WrtDB::Powder::Description* data) :
308         DenyUnknownTagsParser(),
309         m_data(data)
310     {
311         Assert(m_data);
312 #define ELEM(tag) DEFINE_ELEMENT_FUNC(tag, DescriptorSetParser)
313         ELEM(aa);
314         ELEM(nu);
315         ELEM(se);
316         ELEM(vi);
317         ELEM(la);
318         ELEM(dr);
319         ELEM(ga);
320         ELEM(ha);
321         ELEM(ug);
322 #undef ELEM
323         m_map[DPL::FromUTF32String(L"displayicon")] =
324             DPL::MakeDelegate(this, &DescriptorSetParser::OnIgnoredElement);
325     }
326
327     ElementParserPtr OnElement_aa()
328     {
329         m_ages.push_back(StringSet());
330         return ElementParserPtr(new SetOfTextValuesParser(&m_ages.back()));
331     }
332
333 #define GENERATE_ELEMENT_FUNC(element)                                         \
334     ElementParserPtr OnElement_ ## element()                                   \
335     {                                                                          \
336         LogInfo("WAC category tag detected: " << # element);                   \
337         CatIter category =                                                     \
338             m_data->categories.find(DPL::FromUTF32String(L"" # element));      \
339         if (m_data->categories.end() == category)                              \
340         {                                                                      \
341             std::pair<CatIter, bool> result =                                  \
342                 m_data->categories.insert(std::make_pair(                      \
343                                               DPL::FromUTF32String(L"" #       \
344                                                                    element),   \
345                                               WrtDB::Powder::Description::     \
346                                                   CategoryEntry()));           \
347             category = result.first;                                           \
348         }                                                                      \
349         category->second.levels.push_back(                                     \
350             WrtDB::Powder::Description::LevelEntry());                         \
351         return ElementParserPtr(new                                            \
352                                 WacCategoryParser(                             \
353                                         &category->second.levels.back()));     \
354     }                                                                          \
355
356     GENERATE_ELEMENT_FUNC(nu)
357     GENERATE_ELEMENT_FUNC(se)
358     GENERATE_ELEMENT_FUNC(vi)
359     GENERATE_ELEMENT_FUNC(la)
360     GENERATE_ELEMENT_FUNC(dr)
361     GENERATE_ELEMENT_FUNC(ga)
362     GENERATE_ELEMENT_FUNC(ha)
363     GENERATE_ELEMENT_FUNC(ug)
364
365 #undef GENERATE_ELEMENT_FUNC
366
367     ElementParserPtr OnIgnoredElement()
368     {
369         return ElementParserPtr(new IgnoringParser());
370     }
371
372     void Verify()
373     {
374         if (m_ages.size() > 1) {
375             ThrowMsg(PowderParserException::ParserFailed,
376                      "More than one aa tags: not implemented");
377         } else if (m_ages.size() == 1) {
378             if (!m_ages.at(0).empty() && m_ages.at(0).size() <= 1) {
379                 DPL::IStringStream str(*m_ages.at(0).begin());
380                 int rating = 12;
381                 str >> rating;
382                 if (str.fail()) {
383                     ThrowMsg(PowderParserException::ParserFailed,
384                              "Invalid number in age rating");
385                 } else {
386                     m_data->ageRating = rating;
387                 }
388             } else {
389                 ThrowMsg(PowderParserException::ParserFailed,
390                          "Not valid age value in aa tag ");
391             }
392         }
393 //        LogInfo("Descriptionset verified: " << *m_data);
394     }
395
396   private:
397     typedef std::vector<StringSet> AgesTags;
398     AgesTags m_ages;
399     WrtDB::Powder::Description* m_data;
400 };
401
402 class DrParser : public DenyUnknownTagsParser
403 {
404   public:
405     DrParser(WrtDB::Powder::Description* data,
406             const DPL::String& host,
407             const DPL::String& path) :
408         DenyUnknownTagsParser(),
409         m_data(data),
410         m_host(host),
411         m_path(path)
412     {
413         Assert(m_data);
414         DEFINE_ELEMENT_FUNC(iriset, DrParser);
415         DEFINE_ELEMENT_FUNC(descriptorset, DrParser);
416     }
417
418     ElementParserPtr OnElement_iriset()
419     {
420         m_iriSetOutcomes.push_back(IrisetParserData(m_host, m_path));
421         return ElementParserPtr(new IrisetParser(&m_iriSetOutcomes.back()));
422     }
423
424     ElementParserPtr OnElement_descriptorset()
425     {
426         m_descriptions.push_back(WrtDB::Powder::Description());
427         return ElementParserPtr(new
428                                 DescriptorSetParser(&m_descriptions.back()));
429     }
430
431     void Verify()
432     {
433         if (m_iriSetOutcomes.empty() || m_descriptions.empty()) {
434             ThrowMsg(
435                 PowderParserException::ParserFailed,
436                 "dr tag don't contain at lease one iriset and descriptionset ");
437         } else {
438             IriSetOutcomes::const_iterator outIter;
439             for (outIter = m_iriSetOutcomes.begin();
440                  outIter != m_iriSetOutcomes.end() && !outIter->m_matched;
441                  ++outIter) {
442             }
443             if (outIter != m_iriSetOutcomes.end()) {
444                 LogInfo("Matching iriset found");
445                 typedef PowderDescriptions::const_iterator DescIter;
446                 for (DescIter descIter = m_descriptions.begin();
447                      descIter != m_descriptions.end(); ++descIter) {
448                     MergeDescriptions(m_data, *descIter);
449                 }
450             } else {
451                 LogWarning("No matching iriset found");
452             }
453         }
454 //        LogInfo("dr tag verified" << *m_data);
455     }
456   private:
457     typedef std::vector<WrtDB::Powder::Description> PowderDescriptions;
458     PowderDescriptions m_descriptions;
459     typedef std::vector<IrisetParserData> IriSetOutcomes;
460     IriSetOutcomes m_iriSetOutcomes;
461     WrtDB::Powder::Description* m_data;
462     const DPL::String& m_host;
463     const DPL::String& m_path;
464 };
465
466 PowderParser::PowderParser(PowderParserData* data) :
467     ElementParser(),
468     m_data(data->description),
469     m_host(data->host),
470     m_path(data->path)
471 {
472     Assert(m_data);
473     m_map[DPL::FromUTF32String(L"attribution")] =
474         DPL::MakeDelegate(this, &PowderParser::OnIgnoredElement);
475     DEFINE_ELEMENT_FUNC(dr, PowderParser);
476 }
477
478 ElementParserPtr PowderParser::OnIgnoredElement()
479 {
480     return ElementParserPtr(new IgnoringParser());
481 }
482
483 ElementParserPtr PowderParser::OnElement_dr()
484 {
485     return ElementParserPtr(new DrParser(m_data, m_host, m_path));
486 }
487
488 void PowderParser::Accept(const Element& /*element*/)
489 {
490 }
491
492 void PowderParser::Accept(const XmlAttribute& /*attribute*/)
493 {
494 }
495
496 void PowderParser::Accept(const Text& /*text*/)
497 {
498 }
499
500 void PowderParser::Verify()
501 {
502 //    LogInfo("powder tag verified " << *m_data);
503 }
504
505 ElementParserPtr PowderParser::OnDenyElement()
506 {
507     return ElementParserPtr(new DenyAllParser());
508 }
509
510 ElementParser::ActionFunc PowderParser::GetElementParser(const DPL::String& /*ns*/,
511         const DPL::String& name)
512 {
513     FuncMap::const_iterator it = m_map.find(name);
514     if (it != m_map.end()) {
515         return it->second;
516     } else {
517         return DPL::MakeDelegate(this, &PowderParser::OnDenyElement);
518     }
519 }
520
521 #undef DEFINE_ELEMENT_FUNC