Home | History | Annotate | Download | only in utils
      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 
     19 /******************************************************************************
     20  *
     21  *  The original Work has been changed by NXP Semiconductors.
     22  *
     23  *  Copyright (C) 2013-2014 NXP Semiconductors
     24  *
     25  *  Licensed under the Apache License, Version 2.0 (the "License");
     26  *  you may not use this file except in compliance with the License.
     27  *  You may obtain a copy of the License at
     28  *
     29  *  http://www.apache.org/licenses/LICENSE-2.0
     30  *
     31  *  Unless required by applicable law or agreed to in writing, software
     32  *  distributed under the License is distributed on an "AS IS" BASIS,
     33  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     34  *  See the License for the specific language governing permissions and
     35  *  limitations under the License.
     36  *
     37  ******************************************************************************/
     38 
     39 #include <stdio.h>
     40 #include <sys/stat.h>
     41 #include <list>
     42 #include <string>
     43 #include <vector>
     44 
     45 #include <phNxpConfig.h>
     46 #include <phNxpLog.h>
     47 #include "sparse_crc32.h"
     48 
     49 #if GENERIC_TARGET
     50 const char alternative_config_path[] = "/data/vendor/nfc/";
     51 #else
     52 const char alternative_config_path[] = "";
     53 #endif
     54 
     55 #if 1
     56 const char* transport_config_paths[] = {"/odm/etc/", "/vendor/etc/", "/etc/"};
     57 #else
     58 const char* transport_config_paths[] = {"res/"};
     59 #endif
     60 const int transport_config_path_size =
     61     (sizeof(transport_config_paths) / sizeof(transport_config_paths[0]));
     62 
     63 #define config_name "libnfc-nxp.conf"
     64 #define extra_config_base "libnfc-nxp-"
     65 #define extra_config_ext ".conf"
     66 #define IsStringValue 0x80000000
     67 
     68 const char config_timestamp_path[] =
     69     "/data/vendor/nfc/libnfc-nxpConfigState.bin";
     70 
     71 namespace {
     72 
     73 size_t readConfigFile(const char* fileName, uint8_t** p_data) {
     74   FILE* fd = fopen(fileName, "rb");
     75   if (fd == nullptr) return 0;
     76 
     77   fseek(fd, 0L, SEEK_END);
     78   const size_t file_size = ftell(fd);
     79   rewind(fd);
     80 
     81   uint8_t* buffer = new uint8_t[file_size];
     82   size_t read = fread(buffer, file_size, 1, fd);
     83   fclose(fd);
     84 
     85   if (read == 1) {
     86     *p_data = buffer;
     87     return file_size;
     88   }
     89 
     90   return 0;
     91 }
     92 
     93 }  // namespace
     94 
     95 using namespace ::std;
     96 
     97 class CNfcParam : public string {
     98  public:
     99   CNfcParam();
    100   CNfcParam(const char* name, const string& value);
    101   CNfcParam(const char* name, unsigned long value);
    102   virtual ~CNfcParam();
    103   unsigned long numValue() const { return m_numValue; }
    104   const char* str_value() const { return m_str_value.c_str(); }
    105   size_t str_len() const { return m_str_value.length(); }
    106 
    107  private:
    108   string m_str_value;
    109   unsigned long m_numValue;
    110 };
    111 
    112 class CNfcConfig : public vector<const CNfcParam*> {
    113  public:
    114   virtual ~CNfcConfig();
    115   static CNfcConfig& GetInstance();
    116   friend void readOptionalConfig(const char* optional);
    117   bool isModified();
    118   void resetModified();
    119 
    120   bool getValue(const char* name, char* pValue, size_t len) const;
    121   bool getValue(const char* name, unsigned long& rValue) const;
    122   bool getValue(const char* name, unsigned short& rValue) const;
    123   bool getValue(const char* name, char* pValue, long len, long* readlen) const;
    124   const CNfcParam* find(const char* p_name) const;
    125   void clean();
    126 
    127  private:
    128   CNfcConfig();
    129   bool readConfig(const char* name, bool bResetContent);
    130   void moveFromList();
    131   void moveToList();
    132   void add(const CNfcParam* pParam);
    133   list<const CNfcParam*> m_list;
    134   bool mValidFile;
    135   uint32_t config_crc32_;
    136 
    137   unsigned long state;
    138 
    139   inline bool Is(unsigned long f) { return (state & f) == f; }
    140   inline void Set(unsigned long f) { state |= f; }
    141   inline void Reset(unsigned long f) { state &= ~f; }
    142 };
    143 
    144 /*******************************************************************************
    145 **
    146 ** Function:    isPrintable()
    147 **
    148 ** Description: determine if 'c' is printable
    149 **
    150 ** Returns:     1, if printable, otherwise 0
    151 **
    152 *******************************************************************************/
    153 inline bool isPrintable(char c) {
    154   return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
    155          (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-' || c == '.';
    156 }
    157 
    158 /*******************************************************************************
    159 **
    160 ** Function:    isDigit()
    161 **
    162 ** Description: determine if 'c' is numeral digit
    163 **
    164 ** Returns:     true, if numerical digit
    165 **
    166 *******************************************************************************/
    167 inline bool isDigit(char c, int base) {
    168   if ('0' <= c && c <= '9') return true;
    169   if (base == 16) {
    170     if (('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) return true;
    171   }
    172   return false;
    173 }
    174 
    175 /*******************************************************************************
    176 **
    177 ** Function:    getDigitValue()
    178 **
    179 ** Description: return numerical value of a decimal or hex char
    180 **
    181 ** Returns:     numerical value if decimal or hex char, otherwise 0
    182 **
    183 *******************************************************************************/
    184 inline int getDigitValue(char c, int base) {
    185   if ('0' <= c && c <= '9') return c - '0';
    186   if (base == 16) {
    187     if ('A' <= c && c <= 'F')
    188       return c - 'A' + 10;
    189     else if ('a' <= c && c <= 'f')
    190       return c - 'a' + 10;
    191   }
    192   return 0;
    193 }
    194 
    195 /*******************************************************************************
    196 **
    197 ** Function:    findConfigFilePathFromTransportConfigPaths()
    198 **
    199 ** Description: find a config file path with a given config name from transport
    200 **              config paths
    201 **
    202 ** Returns:     none
    203 **
    204 *******************************************************************************/
    205 void findConfigFilePathFromTransportConfigPaths(const string& configName,
    206                                                 string& filePath) {
    207   for (int i = 0; i < transport_config_path_size - 1; i++) {
    208     filePath.assign(transport_config_paths[i]);
    209     filePath += configName;
    210     struct stat file_stat;
    211     if (stat(filePath.c_str(), &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
    212       return;
    213     }
    214   }
    215   filePath.assign(transport_config_paths[transport_config_path_size - 1]);
    216   filePath += configName;
    217 }
    218 
    219 /*******************************************************************************
    220 **
    221 ** Function:    CNfcConfig::readConfig()
    222 **
    223 ** Description: read Config settings and parse them into a linked list
    224 **              move the element from linked list to a array at the end
    225 **
    226 ** Returns:     1, if there are any config data, 0 otherwise
    227 **
    228 *******************************************************************************/
    229 bool CNfcConfig::readConfig(const char* name, bool bResetContent) {
    230   enum {
    231     BEGIN_LINE = 1,
    232     TOKEN,
    233     STR_VALUE,
    234     NUM_VALUE,
    235     BEGIN_HEX,
    236     BEGIN_QUOTE,
    237     END_LINE
    238   };
    239 
    240   uint8_t* p_config = nullptr;
    241   size_t config_size = readConfigFile(name, &p_config);
    242   if (p_config == nullptr) {
    243     ALOGE("%s Cannot open config file %s\n", __func__, name);
    244     if (bResetContent) {
    245       ALOGE("%s Using default value for all settings\n", __func__);
    246       mValidFile = false;
    247     }
    248     return false;
    249   }
    250 
    251   string token;
    252   string strValue;
    253   unsigned long numValue = 0;
    254   CNfcParam* pParam = NULL;
    255   int i = 0;
    256   int base = 0;
    257   char c;
    258   int bflag = 0;
    259   state = BEGIN_LINE;
    260 
    261   config_crc32_ = sparse_crc32(0, p_config, config_size);
    262   mValidFile = true;
    263   if (size() > 0) {
    264     if (bResetContent)
    265       clean();
    266     else
    267       moveToList();
    268   }
    269 
    270   for (size_t offset = 0; offset != config_size; ++offset) {
    271     c = p_config[offset];
    272     switch (state & 0xff) {
    273       case BEGIN_LINE:
    274         if (c == '#')
    275           state = END_LINE;
    276         else if (isPrintable(c)) {
    277           i = 0;
    278           token.erase();
    279           strValue.erase();
    280           state = TOKEN;
    281           token.push_back(c);
    282         }
    283         break;
    284       case TOKEN:
    285         if (c == '=') {
    286           token.push_back('\0');
    287           state = BEGIN_QUOTE;
    288         } else if (isPrintable(c))
    289           token.push_back(c);
    290         else
    291           state = END_LINE;
    292         break;
    293       case BEGIN_QUOTE:
    294         if (c == '"') {
    295           state = STR_VALUE;
    296           base = 0;
    297         } else if (c == '0')
    298           state = BEGIN_HEX;
    299         else if (isDigit(c, 10)) {
    300           state = NUM_VALUE;
    301           base = 10;
    302           numValue = getDigitValue(c, base);
    303           i = 0;
    304         } else if (c == '{') {
    305           state = NUM_VALUE;
    306           bflag = 1;
    307           base = 16;
    308           i = 0;
    309           Set(IsStringValue);
    310         } else
    311           state = END_LINE;
    312         break;
    313       case BEGIN_HEX:
    314         if (c == 'x' || c == 'X') {
    315           state = NUM_VALUE;
    316           base = 16;
    317           numValue = 0;
    318           i = 0;
    319           break;
    320         } else if (isDigit(c, 10)) {
    321           state = NUM_VALUE;
    322           base = 10;
    323           numValue = getDigitValue(c, base);
    324           break;
    325         } else if (c != '\n' && c != '\r') {
    326           state = END_LINE;
    327           break;
    328         }
    329       // fall through to numValue to handle numValue
    330 
    331       case NUM_VALUE:
    332         if (isDigit(c, base)) {
    333           numValue *= base;
    334           numValue += getDigitValue(c, base);
    335           ++i;
    336         } else if (bflag == 1 &&
    337                    (c == ' ' || c == '\r' || c == '\n' || c == '\t')) {
    338           break;
    339         } else if (base == 16 &&
    340                    (c == ',' || c == ':' || c == '-' || c == ' ' || c == '}')) {
    341           if (c == '}') {
    342             bflag = 0;
    343           }
    344           if (i > 0) {
    345             int n = (i + 1) / 2;
    346             while (n-- > 0) {
    347               numValue = numValue >> (n * 8);
    348               unsigned char c = (numValue)&0xFF;
    349               strValue.push_back(c);
    350             }
    351           }
    352 
    353           Set(IsStringValue);
    354           numValue = 0;
    355           i = 0;
    356         } else {
    357           if (c == '\n' || c == '\r') {
    358             if (bflag == 0) {
    359               state = BEGIN_LINE;
    360             }
    361           } else {
    362             if (bflag == 0) {
    363               state = END_LINE;
    364             }
    365           }
    366           if (Is(IsStringValue) && base == 16 && i > 0) {
    367             int n = (i + 1) / 2;
    368             while (n-- > 0) strValue.push_back(((numValue >> (n * 8)) & 0xFF));
    369           }
    370           if (strValue.length() > 0)
    371             pParam = new CNfcParam(token.c_str(), strValue);
    372           else
    373             pParam = new CNfcParam(token.c_str(), numValue);
    374           add(pParam);
    375           strValue.erase();
    376           numValue = 0;
    377         }
    378         break;
    379       case STR_VALUE:
    380         if (c == '"') {
    381           strValue.push_back('\0');
    382           state = END_LINE;
    383           pParam = new CNfcParam(token.c_str(), strValue);
    384           add(pParam);
    385         } else if (isPrintable(c))
    386           strValue.push_back(c);
    387         break;
    388       case END_LINE:
    389         if (c == '\n' || c == '\r') state = BEGIN_LINE;
    390         break;
    391       default:
    392         break;
    393     }
    394   }
    395 
    396   delete[] p_config;
    397 
    398   moveFromList();
    399   return size() > 0;
    400 }
    401 
    402 /*******************************************************************************
    403 **
    404 ** Function:    CNfcConfig::CNfcConfig()
    405 **
    406 ** Description: class constructor
    407 **
    408 ** Returns:     none
    409 **
    410 *******************************************************************************/
    411 CNfcConfig::CNfcConfig() : mValidFile(true), state(0) {}
    412 
    413 /*******************************************************************************
    414 **
    415 ** Function:    CNfcConfig::~CNfcConfig()
    416 **
    417 ** Description: class destructor
    418 **
    419 ** Returns:     none
    420 **
    421 *******************************************************************************/
    422 CNfcConfig::~CNfcConfig() {}
    423 
    424 /*******************************************************************************
    425 **
    426 ** Function:    CNfcConfig::GetInstance()
    427 **
    428 ** Description: get class singleton object
    429 **
    430 ** Returns:     none
    431 **
    432 *******************************************************************************/
    433 CNfcConfig& CNfcConfig::GetInstance() {
    434   static CNfcConfig theInstance;
    435 
    436   if (theInstance.size() == 0 && theInstance.mValidFile) {
    437     string strPath;
    438     if (alternative_config_path[0] != '\0') {
    439       strPath.assign(alternative_config_path);
    440       strPath += config_name;
    441       theInstance.readConfig(strPath.c_str(), true);
    442       if (!theInstance.empty()) {
    443         return theInstance;
    444       }
    445     }
    446     findConfigFilePathFromTransportConfigPaths(config_name, strPath);
    447     theInstance.readConfig(strPath.c_str(), true);
    448   }
    449 
    450   return theInstance;
    451 }
    452 
    453 /*******************************************************************************
    454 **
    455 ** Function:    CNfcConfig::getValue()
    456 **
    457 ** Description: get a string value of a setting
    458 **
    459 ** Returns:     true if setting exists
    460 **              false if setting does not exist
    461 **
    462 *******************************************************************************/
    463 bool CNfcConfig::getValue(const char* name, char* pValue, size_t len) const {
    464   const CNfcParam* pParam = find(name);
    465   if (pParam == NULL) return false;
    466 
    467   if (pParam->str_len() > 0) {
    468     memset(pValue, 0, len);
    469     memcpy(pValue, pParam->str_value(), pParam->str_len());
    470     return true;
    471   }
    472   return false;
    473 }
    474 
    475 bool CNfcConfig::getValue(const char* name, char* pValue, long len,
    476                           long* readlen) const {
    477   const CNfcParam* pParam = find(name);
    478   if (pParam == NULL) return false;
    479 
    480   if (pParam->str_len() > 0) {
    481     if (pParam->str_len() <= (unsigned long)len) {
    482       memset(pValue, 0, len);
    483       memcpy(pValue, pParam->str_value(), pParam->str_len());
    484       *readlen = pParam->str_len();
    485     } else {
    486       *readlen = -1;
    487     }
    488 
    489     return true;
    490   }
    491   return false;
    492 }
    493 
    494 /*******************************************************************************
    495 **
    496 ** Function:    CNfcConfig::getValue()
    497 **
    498 ** Description: get a long numerical value of a setting
    499 **
    500 ** Returns:     true if setting exists
    501 **              false if setting does not exist
    502 **
    503 *******************************************************************************/
    504 bool CNfcConfig::getValue(const char* name, unsigned long& rValue) const {
    505   const CNfcParam* pParam = find(name);
    506   if (pParam == NULL) return false;
    507 
    508   if (pParam->str_len() == 0) {
    509     rValue = static_cast<unsigned long>(pParam->numValue());
    510     return true;
    511   }
    512   return false;
    513 }
    514 
    515 /*******************************************************************************
    516 **
    517 ** Function:    CNfcConfig::getValue()
    518 **
    519 ** Description: get a short numerical value of a setting
    520 **
    521 ** Returns:     true if setting exists
    522 **              false if setting does not exist
    523 **
    524 *******************************************************************************/
    525 bool CNfcConfig::getValue(const char* name, unsigned short& rValue) const {
    526   const CNfcParam* pParam = find(name);
    527   if (pParam == NULL) return false;
    528 
    529   if (pParam->str_len() == 0) {
    530     rValue = static_cast<unsigned short>(pParam->numValue());
    531     return true;
    532   }
    533   return false;
    534 }
    535 
    536 /*******************************************************************************
    537 **
    538 ** Function:    CNfcConfig::find()
    539 **
    540 ** Description: search if a setting exist in the setting array
    541 **
    542 ** Returns:     pointer to the setting object
    543 **
    544 *******************************************************************************/
    545 const CNfcParam* CNfcConfig::find(const char* p_name) const {
    546   if (size() == 0) return NULL;
    547 
    548   for (const_iterator it = begin(), itEnd = end(); it != itEnd; ++it) {
    549     if (**it < p_name) {
    550       continue;
    551     } else if (**it == p_name) {
    552       if ((*it)->str_len() > 0) {
    553         NXPLOG_EXTNS_D("%s found %s=%s\n", __func__, p_name,
    554                        (*it)->str_value());
    555       } else {
    556         NXPLOG_EXTNS_D("%s found %s=(0x%lx)\n", __func__, p_name,
    557                        (*it)->numValue());
    558       }
    559       return *it;
    560     } else
    561       break;
    562   }
    563   return NULL;
    564 }
    565 
    566 /*******************************************************************************
    567 **
    568 ** Function:    CNfcConfig::clean()
    569 **
    570 ** Description: reset the setting array
    571 **
    572 ** Returns:     none
    573 **
    574 *******************************************************************************/
    575 void CNfcConfig::clean() {
    576   if (size() == 0) return;
    577 
    578   for (iterator it = begin(), itEnd = end(); it != itEnd; ++it) delete *it;
    579   clear();
    580 }
    581 
    582 /*******************************************************************************
    583 **
    584 ** Function:    CNfcConfig::Add()
    585 **
    586 ** Description: add a setting object to the list
    587 **
    588 ** Returns:     none
    589 **
    590 *******************************************************************************/
    591 void CNfcConfig::add(const CNfcParam* pParam) {
    592   if (m_list.size() == 0) {
    593     m_list.push_back(pParam);
    594     return;
    595   }
    596   for (list<const CNfcParam *>::iterator it = m_list.begin(),
    597                                          itEnd = m_list.end();
    598        it != itEnd; ++it) {
    599     if (**it < pParam->c_str()) continue;
    600     m_list.insert(it, pParam);
    601     return;
    602   }
    603   m_list.push_back(pParam);
    604 }
    605 
    606 /*******************************************************************************
    607 **
    608 ** Function:    CNfcConfig::moveFromList()
    609 **
    610 ** Description: move the setting object from list to array
    611 **
    612 ** Returns:     none
    613 **
    614 *******************************************************************************/
    615 void CNfcConfig::moveFromList() {
    616   if (m_list.size() == 0) return;
    617 
    618   for (list<const CNfcParam *>::iterator it = m_list.begin(),
    619                                          itEnd = m_list.end();
    620        it != itEnd; ++it)
    621     push_back(*it);
    622   m_list.clear();
    623 }
    624 
    625 /*******************************************************************************
    626 **
    627 ** Function:    CNfcConfig::moveToList()
    628 **
    629 ** Description: move the setting object from array to list
    630 **
    631 ** Returns:     none
    632 **
    633 *******************************************************************************/
    634 void CNfcConfig::moveToList() {
    635   if (m_list.size() != 0) m_list.clear();
    636 
    637   for (iterator it = begin(), itEnd = end(); it != itEnd; ++it)
    638     m_list.push_back(*it);
    639   clear();
    640 }
    641 
    642 bool CNfcConfig::isModified() {
    643   FILE* fd = fopen(config_timestamp_path, "r+");
    644   if (fd == nullptr) {
    645     ALOGE("%s Unable to open file '%s' - assuming modified", __func__,
    646           config_timestamp_path);
    647     return true;
    648   }
    649 
    650   uint32_t stored_crc32 = 0;
    651   fread(&stored_crc32, sizeof(uint32_t), 1, fd);
    652   fclose(fd);
    653 
    654   return stored_crc32 != config_crc32_;
    655 }
    656 
    657 void CNfcConfig::resetModified() {
    658   FILE* fd = fopen(config_timestamp_path, "w+");
    659   if (fd == nullptr) {
    660     ALOGE("%s Unable to open file '%s' for writing", __func__,
    661           config_timestamp_path);
    662     return;
    663   }
    664 
    665   fwrite(&config_crc32_, sizeof(uint32_t), 1, fd);
    666   fclose(fd);
    667 }
    668 
    669 /*******************************************************************************
    670 **
    671 ** Function:    CNfcParam::CNfcParam()
    672 **
    673 ** Description: class constructor
    674 **
    675 ** Returns:     none
    676 **
    677 *******************************************************************************/
    678 CNfcParam::CNfcParam() : m_numValue(0) {}
    679 
    680 /*******************************************************************************
    681 **
    682 ** Function:    CNfcParam::~CNfcParam()
    683 **
    684 ** Description: class destructor
    685 **
    686 ** Returns:     none
    687 **
    688 *******************************************************************************/
    689 CNfcParam::~CNfcParam() {}
    690 
    691 /*******************************************************************************
    692 **
    693 ** Function:    CNfcParam::CNfcParam()
    694 **
    695 ** Description: class copy constructor
    696 **
    697 ** Returns:     none
    698 **
    699 *******************************************************************************/
    700 CNfcParam::CNfcParam(const char* name, const string& value)
    701     : string(name), m_str_value(value), m_numValue(0) {}
    702 
    703 /*******************************************************************************
    704 **
    705 ** Function:    CNfcParam::CNfcParam()
    706 **
    707 ** Description: class copy constructor
    708 **
    709 ** Returns:     none
    710 **
    711 *******************************************************************************/
    712 CNfcParam::CNfcParam(const char* name, unsigned long value)
    713     : string(name), m_numValue(value) {}
    714 
    715 /*******************************************************************************
    716 **
    717 ** Function:    GetStrValue
    718 **
    719 ** Description: API function for getting a string value of a setting
    720 **
    721 ** Returns:     True if found, otherwise False.
    722 **
    723 *******************************************************************************/
    724 extern "C" int GetNxpStrValue(const char* name, char* pValue,
    725                               unsigned long len) {
    726   CNfcConfig& rConfig = CNfcConfig::GetInstance();
    727 
    728   return rConfig.getValue(name, pValue, len);
    729 }
    730 
    731 /*******************************************************************************
    732 **
    733 ** Function:    GetByteArrayValue()
    734 **
    735 ** Description: Read byte array value from the config file.
    736 **
    737 ** Parameters:
    738 **              name - name of the config param to read.
    739 **              pValue  - pointer to input buffer.
    740 **              bufflen - input buffer length.
    741 **              len - out parameter to return the number of bytes read from
    742 **                    config file, return -1 in case bufflen is not enough.
    743 **
    744 ** Returns:     TRUE[1] if config param name is found in the config file, else
    745 **              FALSE[0]
    746 **
    747 *******************************************************************************/
    748 extern "C" int GetNxpByteArrayValue(const char* name, char* pValue,
    749                                     long bufflen, long* len) {
    750   CNfcConfig& rConfig = CNfcConfig::GetInstance();
    751 
    752   return rConfig.getValue(name, pValue, bufflen, len);
    753 }
    754 
    755 /*******************************************************************************
    756 **
    757 ** Function:    GetNumValue
    758 **
    759 ** Description: API function for getting a numerical value of a setting
    760 **
    761 ** Returns:     true, if successful
    762 **
    763 *******************************************************************************/
    764 extern "C" int GetNxpNumValue(const char* name, void* pValue,
    765                               unsigned long len) {
    766   if (!pValue) return false;
    767 
    768   CNfcConfig& rConfig = CNfcConfig::GetInstance();
    769   const CNfcParam* pParam = rConfig.find(name);
    770 
    771   if (pParam == NULL) return false;
    772   unsigned long v = pParam->numValue();
    773   if (v == 0 && pParam->str_len() > 0 && pParam->str_len() < 4) {
    774     const unsigned char* p = (const unsigned char*)pParam->str_value();
    775     for (unsigned int i = 0; i < pParam->str_len(); ++i) {
    776       v *= 256;
    777       v += *p++;
    778     }
    779   }
    780   switch (len) {
    781     case sizeof(unsigned long):
    782       *(static_cast<unsigned long*>(pValue)) = (unsigned long)v;
    783       break;
    784     case sizeof(unsigned short):
    785       *(static_cast<unsigned short*>(pValue)) = (unsigned short)v;
    786       break;
    787     case sizeof(unsigned char):
    788       *(static_cast<unsigned char*>(pValue)) = (unsigned char)v;
    789       break;
    790     default:
    791       return false;
    792   }
    793   return true;
    794 }
    795 
    796 /*******************************************************************************
    797 **
    798 ** Function:    resetConfig
    799 **
    800 ** Description: reset settings array
    801 **
    802 ** Returns:     none
    803 **
    804 *******************************************************************************/
    805 extern "C" void resetNxpConfig()
    806 
    807 {
    808   CNfcConfig& rConfig = CNfcConfig::GetInstance();
    809 
    810   rConfig.clean();
    811 }
    812 
    813 /*******************************************************************************
    814 **
    815 ** Function:    readOptionalConfig()
    816 **
    817 ** Description: read Config settings from an optional conf file
    818 **
    819 ** Returns:     none
    820 **
    821 *******************************************************************************/
    822 void readOptionalConfig(const char* extra) {
    823   string strPath;
    824   string configName(extra_config_base);
    825   configName += extra;
    826   configName += extra_config_ext;
    827 
    828   if (alternative_config_path[0] != '\0') {
    829     strPath.assign(alternative_config_path);
    830     strPath += configName;
    831   } else {
    832     findConfigFilePathFromTransportConfigPaths(configName, strPath);
    833   }
    834 
    835   CNfcConfig::GetInstance().readConfig(strPath.c_str(), false);
    836 }
    837 
    838 /*******************************************************************************
    839 **
    840 ** Function:    isNxpConfigModified()
    841 **
    842 ** Description: check if config file has modified
    843 **
    844 ** Returns:     0 if not modified, 1 otherwise.
    845 **
    846 *******************************************************************************/
    847 extern "C" int isNxpConfigModified() {
    848   CNfcConfig& rConfig = CNfcConfig::GetInstance();
    849   return rConfig.isModified();
    850 }
    851 
    852 /*******************************************************************************
    853 **
    854 ** Function:    updateNxpConfigTimestamp()
    855 **
    856 ** Description: update if config file has modified
    857 **
    858 ** Returns:     0 if not modified, 1 otherwise.
    859 **
    860 *******************************************************************************/
    861 extern "C" int updateNxpConfigTimestamp() {
    862   CNfcConfig& rConfig = CNfcConfig::GetInstance();
    863   rConfig.resetModified();
    864   return 0;
    865 }
    866