blob: 96c452d7529d6fb5ccbe0076b62eb1588c1423c4 [file] [log] [blame]
STMicroelectronics99e8a3f2017-10-12 14:32:47 -07001/******************************************************************************
2 *
3 * Copyright (C) 2011-2012 Broadcom Corporation
4 * Copyright (C) 2013 ST Microelectronics S.A.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Modified by ST Microelectronics S.A. (- changed configuration filename)
19 * (- changed getValue and GetStrValue)
20 *
21 *
22 ******************************************************************************/
23#include <stdio.h>
24#include <list>
25#include <string>
26#include <vector>
Arach MOHAMMED BRAHIM703cc542018-03-28 18:00:05 +020027#include <log/log.h>
STMicroelectronics99e8a3f2017-10-12 14:32:47 -070028#include "android_logmsg.h"
Arach MOHAMMED BRAHIMa52e4592018-01-29 11:44:06 +010029#include <sys/stat.h>
STMicroelectronics99e8a3f2017-10-12 14:32:47 -070030const char alternative_config_path[] = "";
Arach MOHAMMED BRAHIMa52e4592018-01-29 11:44:06 +010031const char* transport_config_paths[] = {"/odm/etc/", "/vendor/etc/", "/etc/"};
STMicroelectronics99e8a3f2017-10-12 14:32:47 -070032
Arach MOHAMMED BRAHIMa52e4592018-01-29 11:44:06 +010033const int transport_config_path_size =
34 (sizeof(transport_config_paths) / sizeof(transport_config_paths[0]));
STMicroelectronics99e8a3f2017-10-12 14:32:47 -070035#define config_name "libnfc-st.conf"
36#define extra_config_base "libnfc-st-"
37#define extra_config_ext ".conf"
38#define IsStringValue 0x80000000
39
40using namespace ::std;
41
42class CNfcParam : public string {
43 public:
44 CNfcParam();
45 CNfcParam(const char* name, const string& value);
46 CNfcParam(const char* name, unsigned long value);
47 virtual ~CNfcParam();
48 unsigned long numValue() const { return m_numValue; }
49 const char* str_value() const { return m_str_value.c_str(); }
50 size_t str_len() const { return m_str_value.length(); }
51
52 private:
53 string m_str_value;
54 unsigned long m_numValue;
55};
56
57class CNfcConfig : public vector<const CNfcParam*> {
58 public:
59 virtual ~CNfcConfig();
60 static CNfcConfig& GetInstance();
61 friend void readOptionalConfig(const char* optional);
62
63 bool getValue(const char* name, char* pValue, size_t& len) const;
64 bool getValue(const char* name, unsigned long& rValue) const;
65 bool getValue(const char* name, unsigned short& rValue) const;
66 const CNfcParam* find(const char* p_name) const;
67 void clean();
68
69 private:
70 CNfcConfig();
71 bool readConfig(const char* name, bool bResetContent);
72 void moveFromList();
73 void moveToList();
74 void add(const CNfcParam* pParam);
75 list<const CNfcParam*> m_list;
76 bool mValidFile;
77
78 unsigned long state;
79
80 inline bool Is(unsigned long f) { return (state & f) == f; }
81 inline void Set(unsigned long f) { state |= f; }
82 inline void Reset(unsigned long f) { state &= ~f; }
83};
84
85/*******************************************************************************
86**
87** Function: isPrintable()
88**
Arach MOHAMMED BRAHIM89233c72018-02-08 16:29:42 +010089** Description: determine if 'c' is printable
STMicroelectronics99e8a3f2017-10-12 14:32:47 -070090**
Arach MOHAMMED BRAHIM89233c72018-02-08 16:29:42 +010091** Returns: 1, if printable, otherwise 0
STMicroelectronics99e8a3f2017-10-12 14:32:47 -070092**
93*******************************************************************************/
94inline bool isPrintable(char c) {
95 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
96 (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-' || c == '.';
97}
98
99/*******************************************************************************
100**
101** Function: isDigit()
102**
Arach MOHAMMED BRAHIM89233c72018-02-08 16:29:42 +0100103** Description: determine if 'c' is numeral digit
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700104**
Arach MOHAMMED BRAHIM89233c72018-02-08 16:29:42 +0100105** Returns: true, if numerical digit
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700106**
107*******************************************************************************/
108inline bool isDigit(char c, int base) {
109 if ('0' <= c && c <= '9') return true;
110 if (base == 16) {
111 if (('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) return true;
112 }
113 return false;
114}
115
116/*******************************************************************************
117**
118** Function: getDigitValue()
119**
Arach MOHAMMED BRAHIM89233c72018-02-08 16:29:42 +0100120** Description: return numerical value of a decimal or hex char
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700121**
Arach MOHAMMED BRAHIM89233c72018-02-08 16:29:42 +0100122** Returns: numerical value if decimal or hex char, otherwise 0
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700123**
124*******************************************************************************/
125inline int getDigitValue(char c, int base) {
126 if ('0' <= c && c <= '9') return c - '0';
127 if (base == 16) {
128 if ('A' <= c && c <= 'F')
129 return c - 'A' + 10;
130 else if ('a' <= c && c <= 'f')
131 return c - 'a' + 10;
132 }
133 return 0;
134}
135
136/*******************************************************************************
137**
Arach MOHAMMED BRAHIMa52e4592018-01-29 11:44:06 +0100138** Function: findConfigFile()
139**
140** Description: find config file among transport_config_paths**
141**
142** Returns: none
143**
144*******************************************************************************/
145void findConfigFile(const string& configName,
146 string& filePath) {
147 for (int i = 0; i < transport_config_path_size - 1; i++) {
148 filePath.assign(transport_config_paths[i]);
149 filePath += configName;
150 struct stat file_stat;
151 if (stat(filePath.c_str(), &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
152 return;
153 }
154 }
155 filePath.assign(transport_config_paths[transport_config_path_size - 1]);
156 filePath += configName;
157}
158
159/*******************************************************************************
160**
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700161** Function: CNfcConfig::readConfig()
162**
163** Description: read Config settings and parse them into a linked list
164** move the element from linked list to a array at the end
165**
Arach MOHAMMED BRAHIM89233c72018-02-08 16:29:42 +0100166** Returns: 1, if there are any config data, 0 otherwise
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700167**
168*******************************************************************************/
169bool CNfcConfig::readConfig(const char* name, bool bResetContent) {
170 enum {
171 BEGIN_LINE = 1,
172 TOKEN,
173 STR_VALUE,
174 NUM_VALUE,
175 BEGIN_HEX,
176 BEGIN_QUOTE,
177 END_LINE
178 };
179
180 FILE* fd = NULL;
181 string token;
182 string strValue;
183 unsigned long numValue = 0;
184 CNfcParam* pParam = NULL;
185 int i = 0;
186 int base = 0;
187 char c = 0;
188
189 state = BEGIN_LINE;
190 /* open config file, read it into a buffer */
191 if ((fd = fopen(name, "rb")) == NULL) {
192 STLOG_HAL_W("%s Cannot open config file %s\n", __func__, name);
193 if (bResetContent) {
194 STLOG_HAL_W("%s Using default value for all settings\n", __func__);
195 mValidFile = false;
196 }
197 return false;
198 }
199 STLOG_HAL_D("%s Opened %s config %s\n", __func__,
200 (bResetContent ? "base" : "optional"), name);
201
202 mValidFile = true;
203 if (size() > 0) {
204 if (bResetContent)
205 clean();
206 else
207 moveToList();
208 }
209
210 while (!feof(fd) && fread(&c, 1, 1, fd) == 1) {
211 switch (state & 0xff) {
212 case BEGIN_LINE:
213 if (c == '#')
214 state = END_LINE;
215 else if (isPrintable(c)) {
216 i = 0;
217 token.erase();
218 strValue.erase();
219 state = TOKEN;
220 token.push_back(c);
221 }
222 break;
223 case TOKEN:
224 if (c == '=') {
225 token.push_back('\0');
226 state = BEGIN_QUOTE;
227 } else if (isPrintable(c))
228 token.push_back(c);
229 else
230 state = END_LINE;
231 break;
232 case BEGIN_QUOTE:
233 if (c == '"') {
234 state = STR_VALUE;
235 base = 0;
236 } else if (c == '0')
237 state = BEGIN_HEX;
238 else if (isDigit(c, 10)) {
239 state = NUM_VALUE;
240 base = 10;
241 numValue = getDigitValue(c, base);
242 i = 0;
243 } else if (c == '{') {
244 state = NUM_VALUE;
245 base = 16;
246 i = 0;
247 Set(IsStringValue);
248 } else
249 state = END_LINE;
250 break;
251 case BEGIN_HEX:
252 if (c == 'x' || c == 'X') {
253 state = NUM_VALUE;
254 base = 16;
255 numValue = 0;
256 i = 0;
257 break;
258 } else if (isDigit(c, 10)) {
259 state = NUM_VALUE;
260 base = 10;
261 numValue = getDigitValue(c, base);
Arach MOHAMMED BRAHIMabf4b1c2018-01-29 11:24:53 +0100262 i=0;
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700263 break;
264 } else if (c != '\n' && c != '\r') {
265 state = END_LINE;
266 break;
267 }
Chih-Hung Hsieh27dd1ec2018-10-19 14:27:53 -0700268 [[fallthrough]]; // fall through to numValue to handle numValue
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700269
270 case NUM_VALUE:
271 if (isDigit(c, base)) {
272 numValue *= base;
273 numValue += getDigitValue(c, base);
274 ++i;
275 } else if (base == 16 &&
276 (c == ':' || c == '-' || c == ' ' || c == '}')) {
277 if (i > 0) {
278 int n = (i + 1) / 2;
279 while (n-- > 0) {
280 unsigned char c = (numValue >> (n * 8)) & 0xFF;
281 strValue.push_back(c);
282 }
283 }
284 Set(IsStringValue);
285 numValue = 0;
286 i = 0;
287 } else {
288 if (c == '\n' || c == '\r')
289 state = BEGIN_LINE;
290 else
291 state = END_LINE;
292 if (Is(IsStringValue) && base == 16 && i > 0) {
293 int n = (i + 1) / 2;
294 while (n-- > 0) strValue.push_back(((numValue >> (n * 8)) & 0xFF));
295 }
296 if (strValue.length() > 0)
297 pParam = new CNfcParam(token.c_str(), strValue);
298 else
299 pParam = new CNfcParam(token.c_str(), numValue);
300 add(pParam);
301 strValue.erase();
302 numValue = 0;
303 }
304 break;
305 case STR_VALUE:
306 if (c == '"') {
307 strValue.push_back('\0');
308 state = END_LINE;
309 pParam = new CNfcParam(token.c_str(), strValue);
310 add(pParam);
311 } else if (isPrintable(c))
312 strValue.push_back(c);
313 break;
314 case END_LINE:
315 if (c == '\n' || c == '\r') state = BEGIN_LINE;
316 break;
317 default:
318 break;
319 }
320 }
321
322 fclose(fd);
323
324 moveFromList();
325 return size() > 0;
326}
327
328/*******************************************************************************
329**
330** Function: CNfcConfig::CNfcConfig()
331**
332** Description: class constructor
333**
334** Returns: none
335**
336*******************************************************************************/
337CNfcConfig::CNfcConfig() : mValidFile(true) {}
338
339/*******************************************************************************
340**
341** Function: CNfcConfig::~CNfcConfig()
342**
343** Description: class destructor
344**
345** Returns: none
346**
347*******************************************************************************/
348CNfcConfig::~CNfcConfig() {}
349
350/*******************************************************************************
351**
352** Function: CNfcConfig::GetInstance()
353**
354** Description: get class singleton object
355**
356** Returns: none
357**
358*******************************************************************************/
359CNfcConfig& CNfcConfig::GetInstance() {
360 static CNfcConfig theInstance;
361
362 if (theInstance.size() == 0 && theInstance.mValidFile) {
363 string strPath;
364 if (alternative_config_path[0] != '\0') {
365 strPath.assign(alternative_config_path);
366 strPath += config_name;
367 theInstance.readConfig(strPath.c_str(), true);
368 if (!theInstance.empty()) {
369 return theInstance;
370 }
371 }
Arach MOHAMMED BRAHIMa52e4592018-01-29 11:44:06 +0100372 findConfigFile(config_name, strPath);
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700373 theInstance.readConfig(strPath.c_str(), true);
374 }
375
376 return theInstance;
377}
378
379/*******************************************************************************
380**
381** Function: CNfcConfig::getValue()
382**
383** Description: get a string value of a setting
384**
385** Returns: true if setting exists
386** false if setting does not exist
387**
388*******************************************************************************/
389bool CNfcConfig::getValue(const char* name, char* pValue, size_t& len) const {
390 const CNfcParam* pParam = find(name);
Arach MOHAMMED BRAHIMa52e4592018-01-29 11:44:06 +0100391 if (pParam == NULL || pValue== NULL) return false;
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700392
393 if (pParam->str_len() > 0) {
394 memset(pValue, 0, len);
395 if (len > pParam->str_len()) len = pParam->str_len();
396 memcpy(pValue, pParam->str_value(), len);
397 return true;
398 }
399 return false;
400}
401
402/*******************************************************************************
403**
404** Function: CNfcConfig::getValue()
405**
406** Description: get a long numerical value of a setting
407**
408** Returns: true if setting exists
409** false if setting does not exist
410**
411*******************************************************************************/
412bool CNfcConfig::getValue(const char* name, unsigned long& rValue) const {
413 const CNfcParam* pParam = find(name);
414 if (pParam == NULL) return false;
415
416 if (pParam->str_len() == 0) {
417 rValue = static_cast<unsigned long>(pParam->numValue());
418 return true;
419 }
420 return false;
421}
422
423/*******************************************************************************
424**
425** Function: CNfcConfig::getValue()
426**
427** Description: get a short numerical value of a setting
428**
429** Returns: true if setting exists
430** false if setting does not exist
431**
432*******************************************************************************/
433bool CNfcConfig::getValue(const char* name, unsigned short& rValue) const {
434 const CNfcParam* pParam = find(name);
435 if (pParam == NULL) return false;
436
437 if (pParam->str_len() == 0) {
438 rValue = static_cast<unsigned short>(pParam->numValue());
439 return true;
440 }
441 return false;
442}
443
444/*******************************************************************************
445**
446** Function: CNfcConfig::find()
447**
448** Description: search if a setting exist in the setting array
449**
450** Returns: pointer to the setting object
451**
452*******************************************************************************/
453const CNfcParam* CNfcConfig::find(const char* p_name) const {
454 if (size() == 0) return NULL;
455
456 for (const_iterator it = begin(), itEnd = end(); it != itEnd; ++it) {
457 if (**it < p_name)
458 continue;
459 else if (**it == p_name) {
460 if ((*it)->str_len() > 0) {
461 STLOG_HAL_D("%s found %s=%s\n", __func__, p_name, (*it)->str_value());
462 } else {
463 STLOG_HAL_D("%s found %s=(0x%lX)\n", __func__, p_name, (*it)->numValue());
464 }
465 return *it;
466 } else
467 break;
468 }
469 return NULL;
470}
471
472/*******************************************************************************
473**
474** Function: CNfcConfig::clean()
475**
476** Description: reset the setting array
477**
478** Returns: none
479**
480*******************************************************************************/
481void CNfcConfig::clean() {
482 if (size() == 0) return;
483
484 for (iterator it = begin(), itEnd = end(); it != itEnd; ++it) delete *it;
485 clear();
486}
487
488/*******************************************************************************
489**
490** Function: CNfcConfig::Add()
491**
492** Description: add a setting object to the list
493**
494** Returns: none
495**
496*******************************************************************************/
497void CNfcConfig::add(const CNfcParam* pParam) {
498 if (m_list.size() == 0) {
499 m_list.push_back(pParam);
500 return;
501 }
502 for (list<const CNfcParam *>::iterator it = m_list.begin(),
503 itEnd = m_list.end();
504 it != itEnd; ++it) {
505 if (**it < pParam->c_str()) continue;
506 m_list.insert(it, pParam);
507 return;
508 }
509 m_list.push_back(pParam);
510}
511
512/*******************************************************************************
513**
514** Function: CNfcConfig::moveFromList()
515**
516** Description: move the setting object from list to array
517**
518** Returns: none
519**
520*******************************************************************************/
521void CNfcConfig::moveFromList() {
522 if (m_list.size() == 0) return;
523
524 for (list<const CNfcParam *>::iterator it = m_list.begin(),
525 itEnd = m_list.end();
526 it != itEnd; ++it)
527 push_back(*it);
528 m_list.clear();
529}
530
531/*******************************************************************************
532**
533** Function: CNfcConfig::moveToList()
534**
535** Description: move the setting object from array to list
536**
537** Returns: none
538**
539*******************************************************************************/
540void CNfcConfig::moveToList() {
541 if (m_list.size() != 0) m_list.clear();
542
543 for (iterator it = begin(), itEnd = end(); it != itEnd; ++it)
544 m_list.push_back(*it);
545 clear();
546}
547
548/*******************************************************************************
549**
550** Function: CNfcParam::CNfcParam()
551**
552** Description: class constructor
553**
554** Returns: none
555**
556*******************************************************************************/
557CNfcParam::CNfcParam() : m_numValue(0) {}
558
559/*******************************************************************************
560**
561** Function: CNfcParam::~CNfcParam()
562**
563** Description: class destructor
564**
565** Returns: none
566**
567*******************************************************************************/
568CNfcParam::~CNfcParam() {}
569
570/*******************************************************************************
571**
572** Function: CNfcParam::CNfcParam()
573**
574** Description: class copy constructor
575**
576** Returns: none
577**
578*******************************************************************************/
579CNfcParam::CNfcParam(const char* name, const string& value)
580 : string(name), m_str_value(value), m_numValue(0) {}
581
582/*******************************************************************************
583**
584** Function: CNfcParam::CNfcParam()
585**
586** Description: class copy constructor
587**
588** Returns: none
589**
590*******************************************************************************/
591CNfcParam::CNfcParam(const char* name, unsigned long value)
592 : string(name), m_numValue(value) {}
593
594/*******************************************************************************
595**
596** Function: GetStrValue
597**
598** Description: API function for getting a string value of a setting
599**
Arach MOHAMMED BRAHIM89233c72018-02-08 16:29:42 +0100600** Returns: True if found, otherwise False.
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700601**
602*******************************************************************************/
603extern "C" int GetStrValue(const char* name, char* pValue, unsigned long l) {
604 size_t len = l;
605 CNfcConfig& rConfig = CNfcConfig::GetInstance();
606
Arach MOHAMMED BRAHIMabf4b1c2018-01-29 11:24:53 +0100607 return rConfig.getValue(name, pValue, len);
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700608}
609
610/*******************************************************************************
611**
612** Function: GetNumValue
613**
614** Description: API function for getting a numerical value of a setting
615**
Arach MOHAMMED BRAHIM89233c72018-02-08 16:29:42 +0100616** Returns: True if found, otherwise False.
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700617**
618*******************************************************************************/
619extern "C" int GetNumValue(const char* name, void* pValue, unsigned long len) {
620 if (!pValue) return false;
621
622 CNfcConfig& rConfig = CNfcConfig::GetInstance();
623 const CNfcParam* pParam = rConfig.find(name);
624
625 if (pParam == NULL) return false;
626 unsigned long v = pParam->numValue();
627 if (v == 0 && pParam->str_len() > 0 && pParam->str_len() < 4) {
628 const unsigned char* p = (const unsigned char*)pParam->str_value();
629 for (size_t i = 0; i < pParam->str_len(); ++i) {
630 v *= 256;
631 v += *p++;
632 }
633 }
634 switch (len) {
635 case sizeof(unsigned long):
636 *(static_cast<unsigned long*>(pValue)) = (unsigned long)v;
637 break;
638 case sizeof(unsigned short):
639 *(static_cast<unsigned short*>(pValue)) = (unsigned short)v;
640 break;
641 case sizeof(unsigned char):
642 *(static_cast<unsigned char*>(pValue)) = (unsigned char)v;
643 break;
644 default:
645 return false;
646 }
647 return true;
648}
649
650/*******************************************************************************
651**
652** Function: resetConfig
653**
654** Description: reset settings array
655**
656** Returns: none
657**
658*******************************************************************************/
659extern void resetConfig() {
660 CNfcConfig& rConfig = CNfcConfig::GetInstance();
661
662 rConfig.clean();
663}
664
665/*******************************************************************************
666**
667** Function: readOptionalConfig()
668**
669** Description: read Config settings from an optional conf file
670**
671** Returns: none
672**
673*******************************************************************************/
674void readOptionalConfig(const char* extra) {
675 string strPath;
Arach MOHAMMED BRAHIMa52e4592018-01-29 11:44:06 +0100676 string configName(extra_config_base);
677 configName += extra;
678 configName += extra_config_ext;
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700679
Arach MOHAMMED BRAHIMa52e4592018-01-29 11:44:06 +0100680 if (alternative_config_path[0] != '\0') {
681 strPath.assign(alternative_config_path);
682 strPath += configName;
683 } else {
684 findConfigFile(configName, strPath);
685 }
686
STMicroelectronics99e8a3f2017-10-12 14:32:47 -0700687 CNfcConfig::GetInstance().readConfig(strPath.c_str(), false);
688}