• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
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>
27 #include <log/log.h>
28 #include "android_logmsg.h"
29 #include <sys/stat.h>
30 const char alternative_config_path[] = "";
31 const char* transport_config_paths[] = {"/odm/etc/", "/vendor/etc/", "/etc/"};
32 
33 const int transport_config_path_size =
34     (sizeof(transport_config_paths) / sizeof(transport_config_paths[0]));
35 #define config_name "libnfc-st.conf"
36 #define extra_config_base "libnfc-st-"
37 #define extra_config_ext ".conf"
38 #define IsStringValue 0x80000000
39 
40 using namespace ::std;
41 
42 class 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();
numValue() const48   unsigned long numValue() const { return m_numValue; }
str_value() const49   const char* str_value() const { return m_str_value.c_str(); }
str_len() const50   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 
57 class 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 
Is(unsigned long f)80   inline bool Is(unsigned long f) { return (state & f) == f; }
Set(unsigned long f)81   inline void Set(unsigned long f) { state |= f; }
Reset(unsigned long f)82   inline void Reset(unsigned long f) { state &= ~f; }
83 };
84 
85 /*******************************************************************************
86 **
87 ** Function:    isPrintable()
88 **
89 ** Description: determine if 'c' is printable
90 **
91 ** Returns:     1, if printable, otherwise 0
92 **
93 *******************************************************************************/
isPrintable(char c)94 inline 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 **
103 ** Description: determine if 'c' is numeral digit
104 **
105 ** Returns:     true, if numerical digit
106 **
107 *******************************************************************************/
isDigit(char c,int base)108 inline 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 **
120 ** Description: return numerical value of a decimal or hex char
121 **
122 ** Returns:     numerical value if decimal or hex char, otherwise 0
123 **
124 *******************************************************************************/
getDigitValue(char c,int base)125 inline 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 **
138 ** Function:    findConfigFile()
139 **
140 ** Description: find config file among transport_config_paths**
141 **
142 ** Returns:     none
143 **
144 *******************************************************************************/
findConfigFile(const string & configName,string & filePath)145 void 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 **
161 ** 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 **
166 ** Returns:     1, if there are any config data, 0 otherwise
167 **
168 *******************************************************************************/
readConfig(const char * name,bool bResetContent)169 bool 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);
262           i=0;
263           break;
264         } else if (c != '\n' && c != '\r') {
265           state = END_LINE;
266           break;
267         }
268         [[fallthrough]]; // fall through to numValue to handle numValue
269 
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 *******************************************************************************/
CNfcConfig()337 CNfcConfig::CNfcConfig() : mValidFile(true) {}
338 
339 /*******************************************************************************
340 **
341 ** Function:    CNfcConfig::~CNfcConfig()
342 **
343 ** Description: class destructor
344 **
345 ** Returns:     none
346 **
347 *******************************************************************************/
~CNfcConfig()348 CNfcConfig::~CNfcConfig() {}
349 
350 /*******************************************************************************
351 **
352 ** Function:    CNfcConfig::GetInstance()
353 **
354 ** Description: get class singleton object
355 **
356 ** Returns:     none
357 **
358 *******************************************************************************/
GetInstance()359 CNfcConfig& 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     }
372     findConfigFile(config_name, strPath);
373     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 *******************************************************************************/
getValue(const char * name,char * pValue,size_t & len) const389 bool CNfcConfig::getValue(const char* name, char* pValue, size_t& len) const {
390   const CNfcParam* pParam = find(name);
391   if (pParam == NULL || pValue== NULL) return false;
392 
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 *******************************************************************************/
getValue(const char * name,unsigned long & rValue) const412 bool 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 *******************************************************************************/
getValue(const char * name,unsigned short & rValue) const433 bool 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 *******************************************************************************/
find(const char * p_name) const453 const 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 *******************************************************************************/
clean()481 void 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 *******************************************************************************/
add(const CNfcParam * pParam)497 void 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 *******************************************************************************/
moveFromList()521 void 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 *******************************************************************************/
moveToList()540 void 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 *******************************************************************************/
CNfcParam()557 CNfcParam::CNfcParam() : m_numValue(0) {}
558 
559 /*******************************************************************************
560 **
561 ** Function:    CNfcParam::~CNfcParam()
562 **
563 ** Description: class destructor
564 **
565 ** Returns:     none
566 **
567 *******************************************************************************/
~CNfcParam()568 CNfcParam::~CNfcParam() {}
569 
570 /*******************************************************************************
571 **
572 ** Function:    CNfcParam::CNfcParam()
573 **
574 ** Description: class copy constructor
575 **
576 ** Returns:     none
577 **
578 *******************************************************************************/
CNfcParam(const char * name,const string & value)579 CNfcParam::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 *******************************************************************************/
CNfcParam(const char * name,unsigned long value)591 CNfcParam::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 **
600 ** Returns:     True if found, otherwise False.
601 **
602 *******************************************************************************/
GetStrValue(const char * name,char * pValue,unsigned long l)603 extern "C" int GetStrValue(const char* name, char* pValue, unsigned long l) {
604   size_t len = l;
605   CNfcConfig& rConfig = CNfcConfig::GetInstance();
606 
607   return rConfig.getValue(name, pValue, len);
608 }
609 
610 /*******************************************************************************
611 **
612 ** Function:    GetNumValue
613 **
614 ** Description: API function for getting a numerical value of a setting
615 **
616 ** Returns:     True if found, otherwise False.
617 **
618 *******************************************************************************/
GetNumValue(const char * name,void * pValue,unsigned long len)619 extern "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 *******************************************************************************/
resetConfig()659 extern 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 *******************************************************************************/
readOptionalConfig(const char * extra)674 void readOptionalConfig(const char* extra) {
675   string strPath;
676   string configName(extra_config_base);
677   configName += extra;
678   configName += extra_config_ext;
679 
680   if (alternative_config_path[0] != '\0') {
681     strPath.assign(alternative_config_path);
682     strPath += configName;
683   } else {
684     findConfigFile(configName, strPath);
685   }
686 
687   CNfcConfig::GetInstance().readConfig(strPath.c_str(), false);
688 }
689