Add initial values support - values to feed the shared database on first startup.
[platform/core/security/key-manager.git] / src / manager / initial-values / parser.cpp
1 /*
2  *  Copyright (c) 2000 - 2015 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        parser.cpp
18  * @author      Maciej Karpiuk (m.karpiuk2@samsung.com)
19  * @version     1.0
20  * @brief       XML parser class implementation.
21  */
22
23 #include <string>
24 #include <string.h>
25 #include <algorithm>
26 #include <exception>
27 #include <libxml/parser.h>
28 #include <libxml/valid.h>
29 #include <libxml/xmlschemas.h>
30 #include <parser.h>
31 #include <xml-utils.h>
32 #include <dpl/log/log.h>
33
34 namespace CKM {
35 namespace XML {
36
37 Parser::Parser(const std::string &XML_filename)
38     : m_errorCb(0)
39 {
40     m_XMLfile = XML_filename;
41     memset(&m_saxHandler, 0, sizeof(m_saxHandler));
42     m_saxHandler.startElement = &Parser::StartElement;
43     m_saxHandler.endElement = &Parser::EndElement;
44     m_saxHandler.characters = &Parser::Characters;
45     m_saxHandler.error = &Parser::Error;
46     m_saxHandler.warning = &Parser::Warning;
47 }
48 Parser::~Parser()
49 {
50     xmlCleanupParser();
51 }
52
53 int Parser::Validate(const std::string &XSD_schema)
54 {
55     if(XSD_schema.empty()) {
56         LogError("no XSD file path given");
57         return ERROR_INVALID_ARGUMENT;
58     }
59
60     int retCode;
61     std::unique_ptr<xmlSchemaParserCtxt, void(*)(xmlSchemaParserCtxtPtr)>
62             parserCtxt(xmlSchemaNewParserCtxt(XSD_schema.c_str()),
63                        [](xmlSchemaParserCtxtPtr ctx){ xmlSchemaFreeParserCtxt(ctx); });
64     if(!parserCtxt) {
65         LogError("XSD file path is invalid");
66         return ERROR_INVALID_ARGUMENT;
67     }
68
69     std::unique_ptr<xmlSchema, void(*)(xmlSchemaPtr)>
70         schema(xmlSchemaParse(parserCtxt.get()),
71                        [](xmlSchemaPtr schemaPtr){ xmlSchemaFree(schemaPtr); });
72     if(!schema) {
73         LogError("Parsing XSD file failed");
74         return ERROR_XSD_PARSE_FAILED;
75     }
76
77
78     std::unique_ptr<xmlSchemaValidCtxt, void(*)(xmlSchemaValidCtxtPtr)>
79         validCtxt(xmlSchemaNewValidCtxt(schema.get()),
80                        [](xmlSchemaValidCtxtPtr validCtxPtr){ xmlSchemaFreeValidCtxt(validCtxPtr); });
81     if(!validCtxt) {
82         LogError("Internal parser error");
83         return ERROR_INTERNAL;
84     }
85
86     xmlSetStructuredErrorFunc(NULL, NULL);
87     xmlSetGenericErrorFunc(this, &Parser::ErrorValidate);
88     xmlThrDefSetStructuredErrorFunc(NULL, NULL);
89     xmlThrDefSetGenericErrorFunc(this, &Parser::ErrorValidate);
90
91     retCode = xmlSchemaValidateFile(validCtxt.get(), m_XMLfile.c_str(), 0);
92     if(0 != retCode) {
93         LogWarning("Validating XML file failed, ec: " << retCode);
94         retCode = ERROR_XML_VALIDATION_FAILED;
95     }
96     else
97         retCode = PARSE_SUCCESS;
98
99     return retCode;
100 }
101
102 int Parser::Parse()
103 {
104     if(m_elementListenerMap.empty()) {
105         LogError("Can not parse XML file: no registered element callbacks.");
106         return ERROR_INVALID_ARGUMENT;
107     }
108     int retCode = xmlSAXUserParseFile(&m_saxHandler, this, m_XMLfile.c_str());
109     if(0 != retCode) {
110         LogWarning("Parsing XML file failed, ec: " << retCode);
111         return ERROR_XML_PARSE_FAILED;
112     }
113     // if error detected while parsing
114     if(m_elementListenerMap.empty()) {
115         LogError("Critical error detected while parsing.");
116         return ERROR_INTERNAL;
117     }
118     return PARSE_SUCCESS;
119 }
120
121 int Parser::RegisterErrorCb(const ErrorCb newCb)
122 {
123     if(m_errorCb) {
124         LogError("Callback already registered!");
125         return ERROR_CALLBACK_PRESENT;
126     }
127     m_errorCb = newCb;
128     return PARSE_SUCCESS;
129 }
130
131 int Parser::RegisterElementCb(const char * elementName,
132                               const StartCb startCb,
133                               const EndCb endCb)
134 {
135     if(!elementName)
136         return ERROR_INVALID_ARGUMENT;
137
138     std::string key(elementName);
139
140     if(m_elementListenerMap.find(elementName) != m_elementListenerMap.end()) {
141         LogError("Callback for element " << elementName << " already registered!");
142         return ERROR_CALLBACK_PRESENT;
143     }
144
145     m_elementListenerMap[key] = {startCb, endCb};
146     return PARSE_SUCCESS;
147 }
148
149 void Parser::StartElement(const xmlChar *name,
150                           const xmlChar **attrs)
151 {
152     std::string key(reinterpret_cast<const char*>(name));
153     if(m_elementListenerMap.find(key) == m_elementListenerMap.end())
154         return;
155
156     ElementHandlerPtr newHandler;
157     const ElementListener & current = m_elementListenerMap[key];
158     if(current.startCb)
159     {
160         Attributes attribs;
161         {
162             size_t numAttrs = 0;
163             std::string key;
164             while(attrs && attrs[numAttrs])
165             {
166                 const char *attrChr = reinterpret_cast<const char*>(attrs[numAttrs]);
167                 if((numAttrs%2)==0)
168                     key = std::string(attrChr);
169                 else
170                     attribs[key] = std::string(attrChr);
171                 numAttrs ++;
172             }
173         }
174
175         newHandler = current.startCb();
176         if(newHandler)
177             newHandler->Start(attribs);
178     }
179     // always put a handler, even if it's empty. This will not break
180     // the sequence of queued elements when popping from the queue.
181     m_elementHandlerStack.push(newHandler);
182 }
183
184 void Parser::EndElement(const xmlChar *name)
185 {
186     std::string key(reinterpret_cast<const char*>(name));
187     if(m_elementListenerMap.find(key) == m_elementListenerMap.end())
188         return;
189
190     // this should never ever happen
191     if( m_elementHandlerStack.empty() )
192         throw std::runtime_error("internal error: element queue desynchronized!");
193
194     ElementHandlerPtr &currentHandler = m_elementHandlerStack.top();
195     if(currentHandler)
196         currentHandler->End();
197
198     const ElementListener & current = m_elementListenerMap[key];
199     if(current.endCb)
200         current.endCb(currentHandler);
201
202     m_elementHandlerStack.pop();
203 }
204
205 void Parser::Characters(const xmlChar *ch, size_t chLen)
206 {
207     std::string chars = trim(std::string(reinterpret_cast<const char*>(ch), chLen));
208     if(chars.empty())
209         return;
210
211     if( !m_elementHandlerStack.empty() )
212     {
213         ElementHandlerPtr &currentHandler = m_elementHandlerStack.top();
214         if(currentHandler)
215             currentHandler->Characters(chars);
216     }
217 }
218
219 void Parser::Error(const ErrorType errorType, const char *msg, va_list &args)
220 {
221     if(!m_errorCb)
222         return;
223
224     va_list args2;
225     try
226     {
227         va_copy(args2, args);
228         std::vector<char> buf(1 + std::vsnprintf(NULL, 0, msg, args));
229         std::vsnprintf(buf.data(), buf.size(), msg, args2);
230         m_errorCb(errorType, trim(std::string(buf.begin(), buf.end())));
231     }
232     catch(...) {
233         LogError("Error callback throwed an exception.");
234         // if an error handler throwed exception,
235         // do not call further callbacks
236         m_elementListenerMap.clear();
237     }
238     va_end(args2);
239 }
240
241 //
242 // -------------------------- start of static wrappers --------------------------
243 //
244 void Parser::CallbackHelper(std::function<void (void)> func)
245 {
246     try
247     {
248         func();
249         return;
250     }
251     catch(const std::exception &e) {
252         LogError("parser error: " << e.what());
253         if(m_errorCb)
254             m_errorCb(PARSE_ERROR, e.what());
255     }
256     catch(...) {
257         LogError("unknown parser error");
258         if(m_errorCb)
259             m_errorCb(PARSE_ERROR, "unknown parser error");
260     }
261     // raise error flag - unregister listeners
262     m_elementListenerMap.clear();
263 }
264 void Parser::StartElement(void *userData,
265                           const xmlChar *name,
266                           const xmlChar **attrs)
267 {
268     Parser *parser = static_cast<Parser *>(userData);
269     parser->CallbackHelper([&parser, &name, &attrs] { parser->StartElement(name, attrs); });
270 }
271 void Parser::EndElement(void *userData,
272                         const xmlChar *name)
273 {
274     Parser *parser = static_cast<Parser *>(userData);
275     parser->CallbackHelper([&parser, &name] { parser->EndElement(name); });
276 }
277 void Parser::Characters(void *userData,
278                         const xmlChar *ch,
279                         int len)
280 {
281     Parser *parser = static_cast<Parser *>(userData);
282     parser->CallbackHelper([&parser, &ch, &len] { parser->Characters(ch, static_cast<size_t>(len)); });
283 }
284
285 void Parser::ErrorValidate(void *userData,
286                            const char *msg,
287                            ...)
288 {
289     va_list args;
290     va_start(args, msg);
291     Parser *parser = static_cast<Parser *>(userData);
292     parser->Error(VALIDATION_ERROR, msg, args);
293     va_end(args);
294 }
295
296 void Parser::Error(void *userData,
297                    const char *msg,
298                    ...)
299 {
300     va_list args;
301     va_start(args, msg);
302     Parser *parser = static_cast<Parser *>(userData);
303     parser->Error(PARSE_ERROR, msg, args);
304     va_end(args);
305 }
306
307 void Parser::Warning(void *userData,
308                      const char *msg,
309                      ...)
310 {
311     va_list args;
312     va_start(args, msg);
313     Parser &parser = *(static_cast<Parser *>(userData));
314     parser.Error(PARSE_WARNING, msg, args);
315     va_end(args);
316 }
317 //
318 // -------------------------- end of static wrappers --------------------------
319 //
320 }
321 }