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