Home | History | Annotate | Download | only in adaptation
      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 "config.h"
     19 #include <stdio.h>
     20 #include <sys/stat.h>
     21 #include <list>
     22 #include <string>
     23 #include <vector>
     24 #include "_OverrideLog.h"
     25 
     26 #undef LOG_TAG
     27 #define LOG_TAG "NfcAdaptation"
     28 
     29 const char* transport_config_paths[] = {"/odm/etc/", "/vendor/etc/", "/etc/"};
     30 const int transport_config_path_size =
     31     (sizeof(transport_config_paths) / sizeof(transport_config_paths[0]));
     32 
     33 #define config_name "libnfc-brcm.conf"
     34 #define extra_config_base "libnfc-brcm-"
     35 #define extra_config_ext ".conf"
     36 #define IsStringValue 0x80000000
     37 
     38 using namespace ::std;
     39 
     40 class CNfcParam : public string {
     41  public:
     42   CNfcParam();
     43   CNfcParam(const char* name, const string& value);
     44   CNfcParam(const char* name, unsigned long value);
     45   virtual ~CNfcParam();
     46   unsigned long numValue() const { return m_numValue; }
     47   const char* str_value() const { return m_str_value.c_str(); }
     48   size_t str_len() const { return m_str_value.length(); }
     49 
     50  private:
     51   string m_str_value;
     52   unsigned long m_numValue;
     53 };
     54 
     55 class CNfcConfig : public vector<const CNfcParam*> {
     56  public:
     57   virtual ~CNfcConfig();
     58   static CNfcConfig& GetInstance();
     59   friend void readOptionalConfig(const char* optional);
     60 
     61   bool getValue(const char* name, char* pValue, size_t& len) const;
     62   bool getValue(const char* name, unsigned long& rValue) const;
     63   bool getValue(const char* name, unsigned short& rValue) const;
     64   const CNfcParam* find(const char* p_name) const;
     65   void clean();
     66 
     67  private:
     68   CNfcConfig();
     69   bool readConfig(const char* name, bool bResetContent);
     70   void moveFromList();
     71   void moveToList();
     72   void add(const CNfcParam* pParam);
     73   list<const CNfcParam*> m_list;
     74   bool mValidFile;
     75 
     76   unsigned long state;
     77 
     78   inline bool Is(unsigned long f) { return (state & f) == f; }
     79   inline void Set(unsigned long f) { state |= f; }
     80   inline void Reset(unsigned long f) { state &= ~f; }
     81 };
     82 
     83 /*******************************************************************************
     84 **
     85 ** Function:    isPrintable()
     86 **
     87 ** Description: detremine if a char is printable
     88 **
     89 ** Returns:     none
     90 **
     91 *******************************************************************************/
     92 inline bool isPrintable(char c) {
     93   return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
     94          (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-' || c == '.';
     95 }
     96 
     97 /*******************************************************************************
     98 **
     99 ** Function:    isDigit()
    100 **
    101 ** Description: detremine if a char is numeral digit
    102 **
    103 ** Returns:     none
    104 **
    105 *******************************************************************************/
    106 inline bool isDigit(char c, int base) {
    107   if ('0' <= c && c <= '9') return true;
    108   if (base == 16) {
    109     if (('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) return true;
    110   }
    111   return false;
    112 }
    113 
    114 /*******************************************************************************
    115 **
    116 ** Function:    getDigitValue()
    117 **
    118 ** Description: return numercal value of a char
    119 **
    120 ** Returns:     none
    121 **
    122 *******************************************************************************/
    123 inline int getDigitValue(char c, int base) {
    124   if ('0' <= c && c <= '9') return c - '0';
    125   if (base == 16) {
    126     if ('A' <= c && c <= 'F')
    127       return c - 'A' + 10;
    128     else if ('a' <= c && c <= 'f')
    129       return c - 'a' + 10;
    130   }
    131   return 0;
    132 }
    133 
    134 /*******************************************************************************
    135 **
    136 ** Function:    findConfigFilePathFromTransportConfigPaths()
    137 **
    138 ** Description: find a config file path with a given config name from transport
    139 **              config paths
    140 **
    141 ** Returns:     none
    142 **
    143 *******************************************************************************/
    144 void findConfigFilePathFromTransportConfigPaths(const string& configName,
    145                                                 string& filePath) {
    146   for (int i = 0; i < transport_config_path_size - 1; i++) {
    147     filePath.assign(transport_config_paths[i]);
    148     filePath += configName;
    149     struct stat file_stat;
    150     if (stat(filePath.c_str(), &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
    151       return;
    152     }
    153   }
    154   filePath.assign(transport_config_paths[transport_config_path_size - 1]);
    155   filePath += configName;
    156 }
    157 
    158 /*******************************************************************************
    159 **
    160 ** Function:    CNfcConfig::readConfig()
    161 **
    162 ** Description: read Config settings and parse them into a linked list
    163 **              move the element from linked list to a array at the end
    164 **
    165 ** Returns:     none
    166 **
    167 *******************************************************************************/
    168 bool CNfcConfig::readConfig(const char* name, bool bResetContent) {
    169   enum {
    170     BEGIN_LINE = 1,
    171     TOKEN,
    172     STR_VALUE,
    173     NUM_VALUE,
    174     BEGIN_HEX,
    175     BEGIN_QUOTE,
    176     END_LINE
    177   };
    178 
    179   FILE* fd = NULL;
    180   string token;
    181   string strValue;
    182   unsigned long numValue = 0;
    183   CNfcParam* pParam = NULL;
    184   int i = 0;
    185   int base = 0;
    186   char c = 0;
    187 
    188   state = BEGIN_LINE;
    189   /* open config file, read it into a buffer */
    190   if ((fd = fopen(name, "rb")) == NULL) {
    191     ALOGD("%s Cannot open config file %s\n", __func__, name);
    192     if (bResetContent) {
    193       ALOGD("%s Using default value for all settings\n", __func__);
    194       mValidFile = false;
    195     }
    196     return false;
    197   }
    198   ALOGD("%s Opened %s config %s\n", __func__,
    199         (bResetContent ? "base" : "optional"), name);
    200 
    201   mValidFile = true;
    202   if (size() > 0) {
    203     if (bResetContent)
    204       clean();
    205     else
    206       moveToList();
    207   }
    208 
    209   for (;;) {
    210     if (feof(fd) || fread(&c, 1, 1, fd) != 1) {
    211       if (state == BEGIN_LINE) break;
    212 
    213       // got to the EOF but not in BEGIN_LINE state so the file
    214       // probably does not end with a newline, so the parser has
    215       // not processed current line, simulate a newline in the file
    216       c = '\n';
    217     }
    218 
    219     switch (state & 0xff) {
    220       case BEGIN_LINE:
    221         if (c == '#')
    222           state = END_LINE;
    223         else if (isPrintable(c)) {
    224           i = 0;
    225           token.erase();
    226           strValue.erase();
    227           state = TOKEN;
    228           token.push_back(c);
    229         }
    230         break;
    231       case TOKEN:
    232         if (c == '=') {
    233           token.push_back('\0');
    234           state = BEGIN_QUOTE;
    235         } else if (isPrintable(c))
    236           token.push_back(c);
    237         else
    238           state = END_LINE;
    239         break;
    240       case BEGIN_QUOTE:
    241         if (c == '"') {
    242           state = STR_VALUE;
    243           base = 0;
    244         } else if (c == '0')
    245           state = BEGIN_HEX;
    246         else if (isDigit(c, 10)) {
    247           state = NUM_VALUE;
    248           base = 10;
    249           numValue = getDigitValue(c, base);
    250           i = 0;
    251         } else if (c == '{') {
    252           state = NUM_VALUE;
    253           base = 16;
    254           i = 0;
    255           Set(IsStringValue);
    256         } else
    257           state = END_LINE;
    258         break;
    259       case BEGIN_HEX:
    260         if (c == 'x' || c == 'X') {
    261           state = NUM_VALUE;
    262           base = 16;
    263           numValue = 0;
    264           i = 0;
    265           break;
    266         } else if (isDigit(c, 10)) {
    267           state = NUM_VALUE;
    268           base = 10;
    269           numValue = getDigitValue(c, base);
    270           break;
    271         } else if (c != '\n' && c != '\r') {
    272           state = END_LINE;
    273           break;
    274         }
    275       // fal through to numValue to handle numValue
    276 
    277       case NUM_VALUE:
    278         if (isDigit(c, base)) {
    279           numValue *= base;
    280           numValue += getDigitValue(c, base);
    281           ++i;
    282         } else if (base == 16 &&
    283                    (c == ':' || c == '-' || c == ' ' || c == '}')) {
    284           if (i > 0) {
    285             int n = (i + 1) / 2;
    286             while (n-- > 0) {
    287               unsigned char c = (numValue >> (n * 8)) & 0xFF;
    288               strValue.push_back(c);
    289             }
    290           }
    291           Set(IsStringValue);
    292           numValue = 0;
    293           i = 0;
    294         } else {
    295           if (c == '\n' || c == '\r')
    296             state = BEGIN_LINE;
    297           else
    298             state = END_LINE;
    299           if (Is(IsStringValue) && base == 16 && i > 0) {
    300             int n = (i + 1) / 2;
    301             while (n-- > 0) strValue.push_back(((numValue >> (n * 8)) & 0xFF));
    302           }
    303           if (strValue.length() > 0)
    304             pParam = new CNfcParam(token.c_str(), strValue);
    305           else
    306             pParam = new CNfcParam(token.c_str(), numValue);
    307           add(pParam);
    308           strValue.erase();
    309           numValue = 0;
    310         }
    311         break;
    312       case STR_VALUE:
    313         if (c == '"') {
    314           strValue.push_back('\0');
    315           state = END_LINE;
    316           pParam = new CNfcParam(token.c_str(), strValue);
    317           add(pParam);
    318         } else if (isPrintable(c))
    319           strValue.push_back(c);
    320         break;
    321       case END_LINE:
    322         if (c == '\n' || c == '\r') state = BEGIN_LINE;
    323         break;
    324       default:
    325         break;
    326     }
    327 
    328     if (feof(fd)) break;
    329   }
    330 
    331   fclose(fd);
    332 
    333   moveFromList();
    334   return size() > 0;
    335 }
    336 
    337 /*******************************************************************************
    338 **
    339 ** Function:    CNfcConfig::CNfcConfig()
    340 **
    341 ** Description: class constructor
    342 **
    343 ** Returns:     none
    344 **
    345 *******************************************************************************/
    346 CNfcConfig::CNfcConfig() : mValidFile(true), state(0) {}
    347 
    348 /*******************************************************************************
    349 **
    350 ** Function:    CNfcConfig::~CNfcConfig()
    351 **
    352 ** Description: class destructor
    353 **
    354 ** Returns:     none
    355 **
    356 *******************************************************************************/
    357 CNfcConfig::~CNfcConfig() {}
    358 
    359 /*******************************************************************************
    360 **
    361 ** Function:    CNfcConfig::GetInstance()
    362 **
    363 ** Description: get class singleton object
    364 **
    365 ** Returns:     none
    366 **
    367 *******************************************************************************/
    368 CNfcConfig& CNfcConfig::GetInstance() {
    369   static CNfcConfig theInstance;
    370 
    371   if (theInstance.size() == 0 && theInstance.mValidFile) {
    372     string strPath;
    373     findConfigFilePathFromTransportConfigPaths(config_name, strPath);
    374     theInstance.readConfig(strPath.c_str(), true);
    375   }
    376 
    377   return theInstance;
    378 }
    379 
    380 /*******************************************************************************
    381 **
    382 ** Function:    CNfcConfig::getValue()
    383 **
    384 ** Description: get a string value of a setting
    385 **
    386 ** Returns:     true if setting exists
    387 **              false if setting does not exist
    388 **
    389 *******************************************************************************/
    390 bool CNfcConfig::getValue(const char* name, char* pValue, size_t& len) const {
    391   const CNfcParam* pParam = find(name);
    392   if (pParam == NULL) return false;
    393 
    394   if (pParam->str_len() > 0) {
    395     memset(pValue, 0, len);
    396     if (len > pParam->str_len()) len = pParam->str_len();
    397     memcpy(pValue, pParam->str_value(), len);
    398     return true;
    399   }
    400   return false;
    401 }
    402 
    403 /*******************************************************************************
    404 **
    405 ** Function:    CNfcConfig::getValue()
    406 **
    407 ** Description: get a long numerical value of a setting
    408 **
    409 ** Returns:     true if setting exists
    410 **              false if setting does not exist
    411 **
    412 *******************************************************************************/
    413 bool CNfcConfig::getValue(const char* name, unsigned long& rValue) const {
    414   const CNfcParam* pParam = find(name);
    415   if (pParam == NULL) return false;
    416 
    417   if (pParam->str_len() == 0) {
    418     rValue = static_cast<unsigned long>(pParam->numValue());
    419     return true;
    420   }
    421   return false;
    422 }
    423 
    424 /*******************************************************************************
    425 **
    426 ** Function:    CNfcConfig::getValue()
    427 **
    428 ** Description: get a short numerical value of a setting
    429 **
    430 ** Returns:     true if setting exists
    431 **              false if setting does not exist
    432 **
    433 *******************************************************************************/
    434 bool CNfcConfig::getValue(const char* name, unsigned short& rValue) const {
    435   const CNfcParam* pParam = find(name);
    436   if (pParam == NULL) return false;
    437 
    438   if (pParam->str_len() == 0) {
    439     rValue = static_cast<unsigned short>(pParam->numValue());
    440     return true;
    441   }
    442   return false;
    443 }
    444 
    445 /*******************************************************************************
    446 **
    447 ** Function:    CNfcConfig::find()
    448 **
    449 ** Description: search if a setting exist in the setting array
    450 **
    451 ** Returns:     pointer to the setting object
    452 **
    453 *******************************************************************************/
    454 const CNfcParam* CNfcConfig::find(const char* p_name) const {
    455   if (size() == 0) return NULL;
    456 
    457   for (const_iterator it = begin(), itEnd = end(); it != itEnd; ++it) {
    458     if (**it < p_name)
    459       continue;
    460     else if (**it == p_name) {
    461       if ((*it)->str_len() > 0)
    462         ALOGD("%s found %s=%s\n", __func__, p_name, (*it)->str_value());
    463       else
    464         ALOGD("%s found %s=(0x%lX)\n", __func__, p_name, (*it)->numValue());
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    557 CNfcParam::CNfcParam() : m_numValue(0) {}
    558 
    559 /*******************************************************************************
    560 **
    561 ** Function:    CNfcParam::~CNfcParam()
    562 **
    563 ** Description: class destructor
    564 **
    565 ** Returns:     none
    566 **
    567 *******************************************************************************/
    568 CNfcParam::~CNfcParam() {}
    569 
    570 /*******************************************************************************
    571 **
    572 ** Function:    CNfcParam::CNfcParam()
    573 **
    574 ** Description: class copy constructor
    575 **
    576 ** Returns:     none
    577 **
    578 *******************************************************************************/
    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 *******************************************************************************/
    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:     none
    601 **
    602 *******************************************************************************/
    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   bool b = rConfig.getValue(name, pValue, len);
    608   return b ? len : 0;
    609 }
    610 
    611 /*******************************************************************************
    612 **
    613 ** Function:    GetNumValue
    614 **
    615 ** Description: API function for getting a numerical value of a setting
    616 **
    617 ** Returns:     none
    618 **
    619 *******************************************************************************/
    620 extern "C" int GetNumValue(const char* name, void* pValue, unsigned long len) {
    621   if (!pValue) return false;
    622 
    623   CNfcConfig& rConfig = CNfcConfig::GetInstance();
    624   const CNfcParam* pParam = rConfig.find(name);
    625 
    626   if (pParam == NULL) return false;
    627   unsigned long v = pParam->numValue();
    628   if (v == 0 && pParam->str_len() > 0 && pParam->str_len() < 4) {
    629     const unsigned char* p = (const unsigned char*)pParam->str_value();
    630     for (size_t i = 0; i < pParam->str_len(); ++i) {
    631       v *= 256;
    632       v += *p++;
    633     }
    634   }
    635   switch (len) {
    636     case sizeof(unsigned long):
    637       *(static_cast<unsigned long*>(pValue)) = (unsigned long)v;
    638       break;
    639     case sizeof(unsigned short):
    640       *(static_cast<unsigned short*>(pValue)) = (unsigned short)v;
    641       break;
    642     case sizeof(unsigned char):
    643       *(static_cast<unsigned char*>(pValue)) = (unsigned char)v;
    644       break;
    645     default:
    646       return false;
    647   }
    648   return true;
    649 }
    650 
    651 /*******************************************************************************
    652 **
    653 ** Function:    resetConfig
    654 **
    655 ** Description: reset settings array
    656 **
    657 ** Returns:     none
    658 **
    659 *******************************************************************************/
    660 extern void resetConfig() {
    661   CNfcConfig& rConfig = CNfcConfig::GetInstance();
    662 
    663   rConfig.clean();
    664 }
    665 
    666 /*******************************************************************************
    667 **
    668 ** Function:    readOptionalConfig()
    669 **
    670 ** Description: read Config settings from an optional conf file
    671 **
    672 ** Returns:     none
    673 **
    674 *******************************************************************************/
    675 void readOptionalConfig(const char* extra) {
    676   string strPath;
    677   string configName(extra_config_base);
    678   configName += extra;
    679   configName += extra_config_ext;
    680 
    681   findConfigFilePathFromTransportConfigPaths(configName, strPath);
    682   CNfcConfig::GetInstance().readConfig(strPath.c_str(), false);
    683 }
    684