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 <android-base/properties.h>
24 #include <log/log.h>
25 #include <stdio.h>
26 #include <sys/stat.h>
27 #include <list>
28 #include <string>
29 #include <vector>
30 #include "android_logmsg.h"
31 const char alternative_config_path[] = "";
32 const char* transport_config_paths[] = {"/odm/etc/", "/vendor/etc/", "/etc/"};
33 
34 const int transport_config_path_size =
35     (sizeof(transport_config_paths) / sizeof(transport_config_paths[0]));
36 #define config_name "libnfc-hal-st.conf"
37 #define extra_config_base "libnfc-hal-st-"
38 #define extra_config_ext ".conf"
39 #define IsStringValue 0x80000000
40 
41 using namespace ::std;
42 
43 class CNfcParam : public string {
44  public:
45   CNfcParam();
46   CNfcParam(const char* name, const string& value);
47   CNfcParam(const char* name, unsigned long value);
48   virtual ~CNfcParam();
numValue() const49   unsigned long numValue() const { return m_numValue; }
str_value() const50   const char* str_value() const { return m_str_value.c_str(); }
str_len() const51   size_t str_len() const { return m_str_value.length(); }
52 
53  private:
54   string m_str_value;
55   unsigned long m_numValue;
56 };
57 
58 class CNfcConfig : public vector<const CNfcParam*> {
59  public:
60   virtual ~CNfcConfig();
61   static CNfcConfig& GetInstance();
62   friend void readOptionalConfig(const char* optional);
63 
64   bool getValue(const char* name, char* pValue, size_t& len) const;
65   bool getValue(const char* name, unsigned long& rValue) const;
66   bool getValue(const char* name, unsigned short& rValue) const;
67   bool getValue(const char* name, char* pValue, long len, long* readlen) const;
68   const CNfcParam* find(const char* p_name) const;
69   void clean();
70 
71  private:
72   CNfcConfig();
73   bool readConfig(const char* name, bool bResetContent);
74   void moveFromList();
75   void moveToList();
76   void add(const CNfcParam* pParam);
77   list<const CNfcParam*> m_list;
78   bool mValidFile;
79 
80   unsigned long state;
81 
Is(unsigned long f)82   inline bool Is(unsigned long f) { return (state & f) == f; }
Set(unsigned long f)83   inline void Set(unsigned long f) { state |= f; }
Reset(unsigned long f)84   inline void Reset(unsigned long f) { state &= ~f; }
85 };
86 
87 /*******************************************************************************
88 **
89 ** Function:    isPrintable()
90 **
91 ** Description: determine if 'c' is printable
92 **
93 ** Returns:     1, if printable, otherwise 0
94 **
95 *******************************************************************************/
isPrintable(char c)96 inline bool isPrintable(char c) {
97   return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
98          (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-' || c == '.';
99 }
100 
101 /*******************************************************************************
102 **
103 ** Function:    isDigit()
104 **
105 ** Description: determine if 'c' is numeral digit
106 **
107 ** Returns:     true, if numerical digit
108 **
109 *******************************************************************************/
isDigit(char c,int base)110 inline bool isDigit(char c, int base) {
111   if ('0' <= c && c <= '9') return true;
112   if (base == 16) {
113     if (('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) return true;
114   }
115   return false;
116 }
117 
118 /*******************************************************************************
119 **
120 ** Function:    getDigitValue()
121 **
122 ** Description: return numerical value of a decimal or hex char
123 **
124 ** Returns:     numerical value if decimal or hex char, otherwise 0
125 **
126 *******************************************************************************/
getDigitValue(char c,int base)127 inline int getDigitValue(char c, int base) {
128   if ('0' <= c && c <= '9') return c - '0';
129   if (base == 16) {
130     if ('A' <= c && c <= 'F')
131       return c - 'A' + 10;
132     else if ('a' <= c && c <= 'f')
133       return c - 'a' + 10;
134   }
135   return 0;
136 }
137 
138 /*******************************************************************************
139 **
140 ** Function:    findConfigFile()
141 **
142 ** Description: find config file among transport_config_paths**
143 **
144 ** Returns:     none
145 **
146 *******************************************************************************/
findConfigFile(const string & configName,string & filePath)147 bool findConfigFile(const string& configName, string& filePath) {
148   for (int i = 0; i < transport_config_path_size - 1; i++) {
149     if (configName.empty()) break;
150     filePath.assign(transport_config_paths[i]);
151     filePath += configName;
152     struct stat file_stat;
153     if (stat(filePath.c_str(), &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
154       return true;
155     }
156   }
157   filePath = "";
158   return false;
159 }
160 
161 /*******************************************************************************
162 **
163 ** Function:    CNfcConfig::readConfig()
164 **
165 ** Description: read Config settings and parse them into a linked list
166 **              move the element from linked list to a array at the end
167 **
168 ** Returns:     1, if there are any config data, 0 otherwise
169 **
170 *******************************************************************************/
readConfig(const char * name,bool bResetContent)171 bool CNfcConfig::readConfig(const char* name, bool bResetContent) {
172   enum {
173     BEGIN_LINE = 1,
174     TOKEN,
175     STR_VALUE,
176     NUM_VALUE,
177     BEGIN_HEX,
178     BEGIN_QUOTE,
179     END_LINE
180   };
181 
182   FILE* fd = NULL;
183   string token;
184   string strValue;
185   unsigned long numValue = 0;
186   CNfcParam* pParam = NULL;
187   int i = 0;
188   int base = 0;
189   char c = 0;
190   int bflag = 0;
191   state = BEGIN_LINE;
192   /* open config file, read it into a buffer */
193   if ((fd = fopen(name, "rb")) == NULL) {
194     STLOG_HAL_W("%s Cannot open config file %s\n", __func__, name);
195     if (bResetContent) {
196       STLOG_HAL_W("%s Using default value for all settings\n", __func__);
197       mValidFile = false;
198     }
199     return false;
200   }
201   STLOG_HAL_D("%s Opened %s config %s\n", __func__,
202               (bResetContent ? "base" : "optional"), name);
203 
204   mValidFile = true;
205   if (size() > 0) {
206     if (bResetContent)
207       clean();
208     else
209       moveToList();
210   }
211 
212   while (!feof(fd) && fread(&c, 1, 1, fd) == 1) {
213     switch (state & 0xff) {
214       case BEGIN_LINE:
215         if (c == '#')
216           state = END_LINE;
217         else if (isPrintable(c)) {
218           i = 0;
219           token.erase();
220           strValue.erase();
221           state = TOKEN;
222           token.push_back(c);
223         }
224         break;
225       case TOKEN:
226         if (c == '=') {
227           token.push_back('\0');
228           state = BEGIN_QUOTE;
229         } else if (isPrintable(c))
230           token.push_back(c);
231         else
232           state = END_LINE;
233         break;
234       case BEGIN_QUOTE:
235         if (c == '"') {
236           state = STR_VALUE;
237           base = 0;
238         } else if (c == '0')
239           state = BEGIN_HEX;
240         else if (isDigit(c, 10)) {
241           state = NUM_VALUE;
242           base = 10;
243           numValue = getDigitValue(c, base);
244           i = 0;
245         } else if (c == '{') {
246           state = NUM_VALUE;
247           bflag = 1;
248           base = 16;
249           i = 0;
250           Set(IsStringValue);
251         } else
252           state = END_LINE;
253         break;
254       case BEGIN_HEX:
255         if (c == 'x' || c == 'X') {
256           state = NUM_VALUE;
257           base = 16;
258           numValue = 0;
259           i = 0;
260           break;
261         } else if (isDigit(c, 10)) {
262           state = NUM_VALUE;
263           base = 10;
264           numValue = getDigitValue(c, base);
265           i = 0;
266           break;
267         } else if (c != '\n' && c != '\r') {
268           state = END_LINE;
269           break;
270         }
271         [[fallthrough]]; // fall through to numValue to handle numValue
272 
273       case NUM_VALUE:
274         if (isDigit(c, base)) {
275           numValue *= base;
276           numValue += getDigitValue(c, base);
277           ++i;
278         } else if (bflag == 1 &&
279                    (c == ' ' || c == '\r' || c == '\n' || c == '\t')) {
280           break;
281         } else if (base == 16 &&
282                    (c == ',' || c == ':' || c == '-' || c == ' ' || c == '}')) {
283           if (c == '}') {
284             bflag = 0;
285           }
286           if (i > 0) {
287             int n = (i + 1) / 2;
288             while (n-- > 0) {
289               unsigned char c = (numValue >> (n * 8)) & 0xFF;
290               strValue.push_back(c);
291             }
292           }
293           Set(IsStringValue);
294           numValue = 0;
295           i = 0;
296         } else {
297           if (c == '\n' || c == '\r') {
298             if (bflag == 0) {
299               state = BEGIN_LINE;
300             }
301           } else {
302             if (bflag == 0) {
303               state = END_LINE;
304             }
305           }
306           if (Is(IsStringValue) && base == 16 && i > 0) {
307             int n = (i + 1) / 2;
308             while (n-- > 0) strValue.push_back(((numValue >> (n * 8)) & 0xFF));
309           }
310           if (strValue.length() > 0)
311             pParam = new CNfcParam(token.c_str(), strValue);
312           else
313             pParam = new CNfcParam(token.c_str(), numValue);
314           add(pParam);
315           strValue.erase();
316           numValue = 0;
317         }
318         break;
319       case STR_VALUE:
320         if (c == '"') {
321           strValue.push_back('\0');
322           state = END_LINE;
323           pParam = new CNfcParam(token.c_str(), strValue);
324           add(pParam);
325         } else if (isPrintable(c))
326           strValue.push_back(c);
327         break;
328       case END_LINE:
329         if (c == '\n' || c == '\r') state = BEGIN_LINE;
330         break;
331       default:
332         break;
333     }
334   }
335 
336   fclose(fd);
337 
338   moveFromList();
339   return size() > 0;
340 }
341 
342 /*******************************************************************************
343 **
344 ** Function:    CNfcConfig::CNfcConfig()
345 **
346 ** Description: class constructor
347 **
348 ** Returns:     none
349 **
350 *******************************************************************************/
CNfcConfig()351 CNfcConfig::CNfcConfig() : mValidFile(true) {}
352 
353 /*******************************************************************************
354 **
355 ** Function:    CNfcConfig::~CNfcConfig()
356 **
357 ** Description: class destructor
358 **
359 ** Returns:     none
360 **
361 *******************************************************************************/
~CNfcConfig()362 CNfcConfig::~CNfcConfig() {}
363 
364 /*******************************************************************************
365 **
366 ** Function:    CNfcConfig::GetInstance()
367 **
368 ** Description: get class singleton object
369 **
370 ** Returns:     none
371 **
372 *******************************************************************************/
GetInstance()373 CNfcConfig& CNfcConfig::GetInstance() {
374   static CNfcConfig theInstance;
375 
376   if (theInstance.size() == 0 && theInstance.mValidFile) {
377     string strPath;
378     if (alternative_config_path[0] != '\0') {
379       strPath.assign(alternative_config_path);
380       strPath += config_name;
381       theInstance.readConfig(strPath.c_str(), true);
382       if (!theInstance.empty()) {
383         return theInstance;
384       }
385     }
386 
387     if (findConfigFile(android::base::GetProperty(
388                            "persist.vendor.nfc.config_file_name", ""),
389                        strPath)) {
390       STLOG_HAL_D("%s Get config file %s\n", __func__, strPath.c_str());
391     } else if (findConfigFile(extra_config_base +
392                                   android::base::GetProperty(
393                                       "ro.boot.product.hardware.sku", "") +
394                                   extra_config_ext,
395                               strPath)) {
396       STLOG_HAL_D("%s Get config file %s\n", __func__, strPath.c_str());
397     } else {
398       findConfigFile(config_name, strPath);
399     }
400     theInstance.readConfig(strPath.c_str(), true);
401   }
402 
403   return theInstance;
404 }
405 
406 /*******************************************************************************
407 **
408 ** Function:    CNfcConfig::getValue()
409 **
410 ** Description: get a string value of a setting
411 **
412 ** Returns:     true if setting exists
413 **              false if setting does not exist
414 **
415 *******************************************************************************/
getValue(const char * name,char * pValue,size_t & len) const416 bool CNfcConfig::getValue(const char* name, char* pValue, size_t& len) const {
417   const CNfcParam* pParam = find(name);
418   if (pParam == NULL || pValue == NULL) return false;
419 
420   if (pParam->str_len() > 0) {
421     memset(pValue, 0, len);
422     if (pParam->str_len() > len) {
423       return false;
424     } else {
425       len = pParam->str_len();
426     }
427     memcpy(pValue, pParam->str_value(), len);
428     return true;
429   }
430   return false;
431 }
432 /*******************************************************************************
433 **
434 ** Function:    CNfcConfig::getValue()
435 **
436 ** Description: get a string value of a setting and the length of it.
437 **
438 ** Returns:     true if setting exists
439 **              false if setting does not exist
440 **
441 *******************************************************************************/
getValue(const char * name,char * pValue,long len,long * readlen) const442 bool CNfcConfig::getValue(const char* name, char* pValue, long len,
443                           long* readlen) const {
444   const CNfcParam* pParam = find(name);
445   if (pParam == NULL) return false;
446   if (pParam->str_len() > 0) {
447     if (pParam->str_len() <= (unsigned long)len) {
448       memset(pValue, 0, len);
449       memcpy(pValue, pParam->str_value(), pParam->str_len());
450       *readlen = pParam->str_len();
451     } else {
452       *readlen = -1;
453     }
454     return true;
455   }
456   return false;
457 }
458 /*******************************************************************************
459 **
460 ** Function:    CNfcConfig::getValue()
461 **
462 ** Description: get a long numerical value of a setting
463 **
464 ** Returns:     true if setting exists
465 **              false if setting does not exist
466 **
467 *******************************************************************************/
getValue(const char * name,unsigned long & rValue) const468 bool CNfcConfig::getValue(const char* name, unsigned long& rValue) const {
469   const CNfcParam* pParam = find(name);
470   if (pParam == NULL) return false;
471 
472   if (pParam->str_len() == 0) {
473     rValue = static_cast<unsigned long>(pParam->numValue());
474     return true;
475   }
476   return false;
477 }
478 
479 /*******************************************************************************
480 **
481 ** Function:    CNfcConfig::getValue()
482 **
483 ** Description: get a short numerical value of a setting
484 **
485 ** Returns:     true if setting exists
486 **              false if setting does not exist
487 **
488 *******************************************************************************/
getValue(const char * name,unsigned short & rValue) const489 bool CNfcConfig::getValue(const char* name, unsigned short& rValue) const {
490   const CNfcParam* pParam = find(name);
491   if (pParam == NULL) return false;
492 
493   if (pParam->str_len() == 0) {
494     rValue = static_cast<unsigned short>(pParam->numValue());
495     return true;
496   }
497   return false;
498 }
499 
500 /*******************************************************************************
501 **
502 ** Function:    CNfcConfig::find()
503 **
504 ** Description: search if a setting exist in the setting array
505 **
506 ** Returns:     pointer to the setting object
507 **
508 *******************************************************************************/
find(const char * p_name) const509 const CNfcParam* CNfcConfig::find(const char* p_name) const {
510   if (size() == 0) return NULL;
511 
512   for (const_iterator it = begin(), itEnd = end(); it != itEnd; ++it) {
513     if (**it < p_name)
514       continue;
515     else if (**it == p_name) {
516       if ((*it)->str_len() > 0) {
517         STLOG_HAL_D("%s found %s=%s\n", __func__, p_name, (*it)->str_value());
518       } else {
519         STLOG_HAL_D("%s found %s=(0x%lX)\n", __func__, p_name,
520                     (*it)->numValue());
521       }
522       return *it;
523     } else
524       break;
525   }
526   return NULL;
527 }
528 
529 /*******************************************************************************
530 **
531 ** Function:    CNfcConfig::clean()
532 **
533 ** Description: reset the setting array
534 **
535 ** Returns:     none
536 **
537 *******************************************************************************/
clean()538 void CNfcConfig::clean() {
539   if (size() == 0) return;
540 
541   for (iterator it = begin(), itEnd = end(); it != itEnd; ++it) delete *it;
542   clear();
543 }
544 
545 /*******************************************************************************
546 **
547 ** Function:    CNfcConfig::Add()
548 **
549 ** Description: add a setting object to the list
550 **
551 ** Returns:     none
552 **
553 *******************************************************************************/
add(const CNfcParam * pParam)554 void CNfcConfig::add(const CNfcParam* pParam) {
555   if (m_list.size() == 0) {
556     m_list.push_back(pParam);
557     return;
558   }
559   for (list<const CNfcParam*>::iterator it = m_list.begin(),
560                                         itEnd = m_list.end();
561        it != itEnd; ++it) {
562     if (**it < pParam->c_str()) continue;
563     m_list.insert(it, pParam);
564     return;
565   }
566   m_list.push_back(pParam);
567 }
568 
569 /*******************************************************************************
570 **
571 ** Function:    CNfcConfig::moveFromList()
572 **
573 ** Description: move the setting object from list to array
574 **
575 ** Returns:     none
576 **
577 *******************************************************************************/
moveFromList()578 void CNfcConfig::moveFromList() {
579   if (m_list.size() == 0) return;
580 
581   for (list<const CNfcParam*>::iterator it = m_list.begin(),
582                                         itEnd = m_list.end();
583        it != itEnd; ++it)
584     push_back(*it);
585   m_list.clear();
586 }
587 
588 /*******************************************************************************
589 **
590 ** Function:    CNfcConfig::moveToList()
591 **
592 ** Description: move the setting object from array to list
593 **
594 ** Returns:     none
595 **
596 *******************************************************************************/
moveToList()597 void CNfcConfig::moveToList() {
598   if (m_list.size() != 0) m_list.clear();
599 
600   for (iterator it = begin(), itEnd = end(); it != itEnd; ++it)
601     m_list.push_back(*it);
602   clear();
603 }
604 
605 /*******************************************************************************
606 **
607 ** Function:    CNfcParam::CNfcParam()
608 **
609 ** Description: class constructor
610 **
611 ** Returns:     none
612 **
613 *******************************************************************************/
CNfcParam()614 CNfcParam::CNfcParam() : m_numValue(0) {}
615 
616 /*******************************************************************************
617 **
618 ** Function:    CNfcParam::~CNfcParam()
619 **
620 ** Description: class destructor
621 **
622 ** Returns:     none
623 **
624 *******************************************************************************/
~CNfcParam()625 CNfcParam::~CNfcParam() {}
626 
627 /*******************************************************************************
628 **
629 ** Function:    CNfcParam::CNfcParam()
630 **
631 ** Description: class copy constructor
632 **
633 ** Returns:     none
634 **
635 *******************************************************************************/
CNfcParam(const char * name,const string & value)636 CNfcParam::CNfcParam(const char* name, const string& value)
637     : string(name), m_str_value(value), m_numValue(0) {}
638 
639 /*******************************************************************************
640 **
641 ** Function:    CNfcParam::CNfcParam()
642 **
643 ** Description: class copy constructor
644 **
645 ** Returns:     none
646 **
647 *******************************************************************************/
CNfcParam(const char * name,unsigned long value)648 CNfcParam::CNfcParam(const char* name, unsigned long value)
649     : string(name), m_numValue(value) {}
650 
651 /*******************************************************************************
652 **
653 ** Function:    GetStrValue
654 **
655 ** Description: API function for getting a string value of a setting
656 **
657 ** Returns:     True if found, otherwise False.
658 **
659 *******************************************************************************/
GetStrValue(const char * name,char * pValue,unsigned long l)660 extern "C" int GetStrValue(const char* name, char* pValue, unsigned long l) {
661   size_t len = l;
662   CNfcConfig& rConfig = CNfcConfig::GetInstance();
663 
664   return rConfig.getValue(name, pValue, len);
665 }
666 
667 /*******************************************************************************
668 **
669 ** Function:    GetByteArrayValue()
670 **
671 ** Description: Read byte array value from the config file.
672 **
673 ** Parameters:
674 **              name - name of the config param to read.
675 **              pValue  - pointer to input buffer.
676 **              bufflen - input buffer length.
677 **              len - out parameter to return the number of bytes read from
678 **                    config file, return -1 in case bufflen is not enough.
679 **
680 ** Returns:     TRUE[1] if config param name is found in the config file, else
681 **              FALSE[0]
682 **
683 *******************************************************************************/
GetByteArrayValue(const char * name,char * pValue,long bufflen,long * len)684 extern "C" int GetByteArrayValue(const char* name, char* pValue, long bufflen,
685                                  long* len) {
686   CNfcConfig& rConfig = CNfcConfig::GetInstance();
687   return rConfig.getValue(name, pValue, bufflen, len);
688 }
689 
690 /*******************************************************************************
691 **
692 ** Function:    GetNumValue
693 **
694 ** Description: API function for getting a numerical value of a setting
695 **
696 ** Returns:     True if found, otherwise False.
697 **
698 *******************************************************************************/
GetNumValue(const char * name,void * pValue,unsigned long len)699 extern "C" int GetNumValue(const char* name, void* pValue, unsigned long len) {
700   if (!pValue) return false;
701 
702   CNfcConfig& rConfig = CNfcConfig::GetInstance();
703   const CNfcParam* pParam = rConfig.find(name);
704 
705   if (pParam == NULL) return false;
706   unsigned long v = pParam->numValue();
707   if (v == 0 && pParam->str_len() > 0 && pParam->str_len() < 4) {
708     const unsigned char* p = (const unsigned char*)pParam->str_value();
709     for (size_t i = 0; i < pParam->str_len(); ++i) {
710       v *= 256;
711       v += *p++;
712     }
713   }
714   switch (len) {
715     case sizeof(unsigned long):
716       *(static_cast<unsigned long*>(pValue)) = (unsigned long)v;
717       break;
718     case sizeof(unsigned short):
719       *(static_cast<unsigned short*>(pValue)) = (unsigned short)v;
720       break;
721     case sizeof(unsigned char):
722       *(static_cast<unsigned char*>(pValue)) = (unsigned char)v;
723       break;
724     default:
725       return false;
726   }
727   return true;
728 }
729 
730 /*******************************************************************************
731 **
732 ** Function:    resetConfig
733 **
734 ** Description: reset settings array
735 **
736 ** Returns:     none
737 **
738 *******************************************************************************/
resetConfig()739 extern void resetConfig() {
740   CNfcConfig& rConfig = CNfcConfig::GetInstance();
741 
742   rConfig.clean();
743 }
744 
745 /*******************************************************************************
746 **
747 ** Function:    readOptionalConfig()
748 **
749 ** Description: read Config settings from an optional conf file
750 **
751 ** Returns:     none
752 **
753 *******************************************************************************/
readOptionalConfig(const char * extra)754 void readOptionalConfig(const char* extra) {
755   string strPath;
756   string configName(extra_config_base);
757   configName += extra;
758   configName += extra_config_ext;
759 
760   if (alternative_config_path[0] != '\0') {
761     strPath.assign(alternative_config_path);
762     strPath += configName;
763   } else {
764     findConfigFile(configName, strPath);
765   }
766 
767   CNfcConfig::GetInstance().readConfig(strPath.c_str(), false);
768 }
769