1 /*
2  * Copyright (c) 2015, Intel Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software without
17  * specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "ParameterFramework.h"
32 #include <ParameterMgrPlatformConnector.h>
33 
34 #include <iostream>
35 #include <limits>
36 #include <string>
37 #include <map>
38 
39 #include <cassert>
40 #include <cstring>
41 #include <cstdlib>
42 
43 using std::string;
44 
45 /** Rename long pfw types to short ones in pfw namespace. */
46 namespace pfw
47 {
48     typedef ISelectionCriterionInterface Criterion;
49     typedef std::map<string, Criterion *> Criteria;
50     typedef CParameterMgrPlatformConnector Pfw;
51 }
52 
53 /** Class to abstract the boolean+string status api. */
54 class Status
55 {
56 public:
57     /** Fail without an instance of status. */
failure()58     static bool failure() { return false; }
59     /** Fail with the given error msg. */
failure(const string & msg)60     bool failure(const string &msg) { mMsg = msg; return false; }
61     /** Success (no error message). */
success()62     bool success() { mMsg.clear(); return true; }
63 
64     /** Forward a status operation.
65       * @param success[in] the operaton status to forward
66       *                    or forward a previous failure if omitted
67       */
forward(bool success=false)68     bool forward(bool success = false) {
69         if (success) { mMsg.clear(); }
70         return success;
71     }
72     /** Error message accessors.
73       *
74       * Pfw api requires to provide a reference to a string in order
75       * for it to log. This function provide a reference to a string that
76       * will be added to the error message on failure.
77       */
msg()78     string &msg() { return mMsg; }
79 private:
80     string mMsg;
81 };
82 
83 ///////////////////////////////
84 ///////////// Log /////////////
85 ///////////////////////////////
86 
87 /** Default log callback. Log to cout or cerr depending on level. */
defaultLogCb(void *,PfwLogLevel level,const char * logLine)88 static void defaultLogCb(void *, PfwLogLevel level, const char *logLine) {
89     switch (level) {
90     case pfwLogInfo:
91         std::cout << logLine << std::endl;
92         break;
93     case pfwLogWarning:
94         std::cerr << logLine << std::endl;
95         break;
96     };
97 }
98 
99 static PfwLogger defaultLogger = { NULL, &defaultLogCb };
100 
101 class LogWrapper : public CParameterMgrPlatformConnector::ILogger
102 {
103 public:
LogWrapper(const PfwLogger & logger)104     LogWrapper(const PfwLogger &logger) : mLogger(logger) {}
LogWrapper()105     LogWrapper() : mLogger() {}
~LogWrapper()106     virtual ~LogWrapper() {}
107 private:
log(bool bIsWarning,const string & strLog)108     virtual void log(bool bIsWarning, const string &strLog)
109     {
110         // A LogWrapper should NOT be register to the pfw (thus log called)
111         // if logCb is NULL.
112         assert(mLogger.logCb != NULL);
113         mLogger.logCb(mLogger.userCtx,
114                       bIsWarning ? pfwLogWarning : pfwLogInfo,
115                       strLog.c_str());
116     }
117     PfwLogger mLogger;
118 };
119 
120 ///////////////////////////////
121 ///////////// Core ////////////
122 ///////////////////////////////
123 
124 struct PfwHandler_
125 {
126     void setLogger(const PfwLogger *logger);
127     bool createCriteria(const PfwCriterion criteria[], size_t criterionNb);
128 
129     pfw::Criteria criteria;
130     pfw::Pfw *pfw;
131     /** Status of the last called function.
132       * Is mutable because even a const function can fail.
133       */
134     mutable Status lastStatus;
135 private:
136     LogWrapper mLogger;
137 };
138 
139 
pfwCreate()140 PfwHandler *pfwCreate()
141 {
142     return new PfwHandler();
143 }
144 
pfwDestroy(PfwHandler * handle)145 void pfwDestroy(PfwHandler *handle)
146 {
147     if(handle != NULL and handle->pfw != NULL) {
148         delete handle->pfw;
149     }
150     delete handle;
151 }
152 
setLogger(const PfwLogger * logger)153 void PfwHandler::setLogger(const PfwLogger *logger)
154 {
155     if (logger != NULL and logger->logCb == NULL) {
156         return; // There is no callback, do not log => do not add a logger
157     }
158     mLogger = logger != NULL ? *logger : defaultLogger;
159     pfw->setLogger(&mLogger);
160 }
161 
162 
createCriteria(const PfwCriterion criteriaArray[],size_t criterionNb)163 bool PfwHandler::createCriteria(const PfwCriterion criteriaArray[], size_t criterionNb)
164 {
165     Status &status = lastStatus;
166     // Add criteria
167     for (size_t criterionIndex = 0; criterionIndex < criterionNb; ++criterionIndex) {
168         const PfwCriterion &criterion = criteriaArray[criterionIndex];
169         if (criterion.name == NULL) {
170             return status.failure("Criterion name is NULL");
171         }
172         if (criterion.values == NULL) {
173             return status.failure("Criterion values is NULL");
174         }
175         // Check that the criterion does not exist
176         if (criteria.find(criterion.name) != criteria.end()) {
177             return status.failure("Criterion \"" + string(criterion.name) +
178                                   "\" already exist");
179         }
180 
181         // Create criterion type
182         ISelectionCriterionTypeInterface *type =
183             pfw->createSelectionCriterionType(criterion.inclusive);
184         assert(type != NULL);
185         // Add criterion values
186         for (size_t valueIndex = 0; criterion.values[valueIndex] != NULL; ++valueIndex) {
187             int value;
188             if (criterion.inclusive) {
189                 // Check that (int)1 << valueIndex would not overflow (UB)
190                 if(std::numeric_limits<int>::max() >> valueIndex == 0) {
191                     return status.failure("Too many values for criterion " +
192                                           string(criterion.name));
193                 }
194                 value = 1 << valueIndex;
195             } else {
196                 value = valueIndex;
197             }
198             const char * valueName = criterion.values[valueIndex];
199             if(not type->addValuePair(value, valueName)) {
200                 return status.failure("Could not add value " + string(valueName) +
201                                       " to criterion " + criterion.name);
202             }
203         }
204         // Create criterion and add it to the pfw
205         criteria[criterion.name] = pfw->createSelectionCriterion(criterion.name, type);
206     }
207     return status.success();
208 }
209 
210 
pfwStart(PfwHandler * handle,const char * configPath,const PfwCriterion criteria[],size_t criterionNb,const PfwLogger * logger)211 bool pfwStart(PfwHandler *handle, const char *configPath,
212               const PfwCriterion criteria[], size_t criterionNb,
213               const PfwLogger *logger)
214 {
215     // Check that the api is correctly used
216     if (handle == NULL) { return Status::failure(); }
217     Status &status = handle->lastStatus;
218 
219     if (handle->pfw != NULL) {
220         return status.failure("Can not start an already started parameter framework");
221     }
222     if (configPath == NULL) {
223         return status.failure("char *configPath is NULL, "
224                               "while starting the parameter framework");
225     }
226     if (criteria == NULL) {
227         return status.failure("char *criteria is NULL, "
228                               "while starting the parameter framework "
229                               "(config path is " + string(configPath) + ")");
230     }
231     // Create a pfw
232     handle->pfw = new CParameterMgrPlatformConnector(configPath);
233 
234     handle->setLogger(logger);
235 
236     if (not handle->createCriteria(criteria, criterionNb)) {
237         return status.failure();
238     }
239 
240     return status.forward(handle->pfw->start(status.msg()));
241 }
242 
pfwGetLastError(const PfwHandler * handle)243 const char *pfwGetLastError(const PfwHandler *handle)
244 {
245     return handle == NULL ? NULL : handle->lastStatus.msg().c_str();
246 }
247 
getCriterion(const pfw::Criteria & criteria,const string & name)248 static pfw::Criterion *getCriterion(const pfw::Criteria &criteria,
249                                     const string &name)
250 {
251     pfw::Criteria::const_iterator it = criteria.find(name);
252     return it == criteria.end() ? NULL : it->second;
253 }
254 
pfwSetCriterion(PfwHandler * handle,const char name[],int value)255 bool pfwSetCriterion(PfwHandler *handle, const char name[], int value)
256 {
257     if (handle == NULL) { return Status::failure(); }
258     Status &status = handle->lastStatus;
259     if (name == NULL) {
260         return status.failure("char *name of the criterion is NULL, "
261                               "while setting a criterion.");
262     }
263     if (handle->pfw == NULL) {
264         return status.failure("Can not set criterion \"" + string(name) +
265                               "\" as the parameter framework is not started.");
266     }
267     pfw::Criterion *criterion = getCriterion(handle->criteria, name);
268     if (criterion == NULL) {
269         return status.failure("Can not set criterion " + string(name) + " as does not exist");
270     }
271     criterion->setCriterionState(value);
272     return status.success();
273 }
pfwGetCriterion(const PfwHandler * handle,const char name[],int * value)274 bool pfwGetCriterion(const PfwHandler *handle, const char name[], int *value)
275 {
276     if (handle == NULL) { return Status::failure(); }
277     Status &status = handle->lastStatus;
278     if (name == NULL) {
279         return status.failure("char *name of the criterion is NULL, "
280                               "while getting a criterion.");
281     }
282     if (handle->pfw == NULL) {
283         return status.failure("Can not get criterion \"" + string(name) +
284                               "\" as the parameter framework is not started.");
285     }
286     if (value == NULL) {
287         return status.failure("Can not get criterion \"" + string(name) +
288                               "\" as the out value is NULL.");
289     }
290     pfw::Criterion *criterion = getCriterion(handle->criteria, name);
291     if (criterion == NULL) {
292         return status.failure("Can not get criterion " + string(name) + " as it does not exist");
293     }
294     *value = criterion->getCriterionState();
295     return status.success();
296 }
297 
pfwApplyConfigurations(const PfwHandler * handle)298 bool pfwApplyConfigurations(const PfwHandler *handle)
299 {
300     if (handle == NULL) { return Status::failure(); }
301     Status &status = handle->lastStatus;
302     if (handle->pfw == NULL) {
303         return status.failure("Can not commit criteria "
304                               "as the parameter framework is not started.");
305     }
306     handle->pfw->applyConfigurations();
307     return status.success();
308 }
309 
310 ///////////////////////////////
311 /////// Parameter access //////
312 ///////////////////////////////
313 
314 struct PfwParameterHandler_
315 {
316     PfwHandler &pfw;
317     CParameterHandle &parameter;
318 };
319 
pfwBindParameter(PfwHandler * handle,const char path[])320 PfwParameterHandler *pfwBindParameter(PfwHandler *handle, const char path[])
321 {
322     if (handle == NULL) { return NULL; }
323     Status &status = handle->lastStatus;
324     if (path == NULL) {
325         status.failure("Can not bind a parameter without its path");
326         return NULL;
327     }
328     if (handle->pfw == NULL) {
329         status.failure("The parameter framework is not started, "
330                        "while trying to bind parameter \"" + string(path) + "\")");
331         return NULL;
332     }
333 
334     CParameterHandle *paramHandle;
335     paramHandle = handle->pfw->createParameterHandle(path, status.msg());
336     if (paramHandle == NULL) {
337         return NULL;
338     }
339 
340     status.success();
341     PfwParameterHandler publicHandle = {*handle, *paramHandle};
342     return new PfwParameterHandler(publicHandle);
343 }
344 
pfwUnbindParameter(PfwParameterHandler * handle)345 void pfwUnbindParameter(PfwParameterHandler *handle)
346 {
347     if (handle == NULL) { return; }
348     delete &handle->parameter;
349     delete handle;
350 }
351 
352 
pfwGetIntParameter(const PfwParameterHandler * handle,int32_t * value)353 bool pfwGetIntParameter(const PfwParameterHandler *handle, int32_t *value)
354 {
355     if (handle == NULL) { return Status::failure(); }
356     Status &status = handle->pfw.lastStatus;
357     if (value == NULL) {
358         return status.failure("int32_t *value is NULL, "
359                     "while trying to get parameter \"" +
360                     handle->parameter.getPath() + "\" value as int)");
361     }
362     return status.forward(handle->parameter.getAsSignedInteger(*value, status.msg()));
363 }
pfwSetIntParameter(PfwParameterHandler * handle,int32_t value)364 bool pfwSetIntParameter(PfwParameterHandler *handle, int32_t value)
365 {
366     if (handle == NULL) { return Status::failure(); }
367     Status &status = handle->pfw.lastStatus;
368     return status.forward(handle->parameter.setAsSignedInteger(value, status.msg()));
369 }
370 
pfwGetStringParameter(const PfwParameterHandler * handle,const char * value[])371 bool pfwGetStringParameter(const PfwParameterHandler *handle, const char *value[])
372 {
373     if (handle == NULL) { return Status::failure(); }
374     Status &status = handle->pfw.lastStatus;
375     if (value == NULL) {
376         return status.failure("char **value is NULL, "
377                     "while trying to get parameter \"" +
378                     handle->parameter.getPath() + "\" value as string)");
379     }
380     *value = NULL;
381     string retValue;
382     bool success = handle->parameter.getAsString(retValue, status.msg());
383     if (not success) { return status.forward(); }
384 
385     *value = strdup(retValue.c_str());
386     return status.success();
387 }
388 
pfwSetStringParameter(PfwParameterHandler * handle,const char value[])389 bool pfwSetStringParameter(PfwParameterHandler *handle, const char value[])
390 {
391     if (handle == NULL) { return Status::failure(); }
392     Status &status = handle->pfw.lastStatus;
393     return status.forward(handle->parameter.setAsString(value, status.msg()));
394 }
395 
pfwFree(void * ptr)396 void pfwFree(void *ptr) { std::free(ptr); }
397 
398