/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <phNxpConfig.h> #include <stdio.h> #include <string> #include <vector> #include <list> #include <sys/stat.h> #include <phNxpLog.h> #if GENERIC_TARGET const char alternative_config_path[] = "/data/nfc/"; #else const char alternative_config_path[] = ""; #endif #if 1 const char transport_config_path[] = "/etc/"; #else const char transport_config_path[] = "res/"; #endif #define config_name "libnfc-nxp.conf" #define extra_config_base "libnfc-nxp-" #define extra_config_ext ".conf" #define IsStringValue 0x80000000 const char config_timestamp_path[] = "/data/nfc/libnfc-nxpConfigState.bin"; using namespace::std; class CNxpNfcParam : public string { public: CNxpNfcParam (); CNxpNfcParam (const char* name, const string& value); CNxpNfcParam (const char* name, unsigned long value); virtual ~CNxpNfcParam (); unsigned long numValue () const {return m_numValue;} const char* str_value () const {return m_str_value.c_str();} size_t str_len () const {return m_str_value.length();} private: string m_str_value; unsigned long m_numValue; }; class CNxpNfcConfig : public vector<const CNxpNfcParam*> { public: virtual ~CNxpNfcConfig (); static CNxpNfcConfig& GetInstance (); friend void readOptionalConfig (const char* optional); int checkTimestamp (); bool getValue (const char* name, char* pValue, size_t len) const; bool getValue (const char* name, unsigned long& rValue) const; bool getValue (const char* name, unsigned short & rValue) const; bool getValue (const char* name, char* pValue, long len, long* readlen) const; const CNxpNfcParam* find (const char* p_name) const; void clean (); private: CNxpNfcConfig (); bool readConfig (const char* name, bool bResetContent); void moveFromList (); void moveToList (); void add (const CNxpNfcParam* pParam); list<const CNxpNfcParam*> m_list; bool mValidFile; unsigned long m_timeStamp; unsigned long state; inline bool Is (unsigned long f) {return (state & f) == f;} inline void Set (unsigned long f) {state |= f;} inline void Reset (unsigned long f) {state &= ~f;} }; /******************************************************************************* ** ** Function: isPrintable() ** ** Description: determine if 'c' is printable ** ** Returns: 1, if printable, otherwise 0 ** *******************************************************************************/ inline bool isPrintable (char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-' || c == '.'; } /******************************************************************************* ** ** Function: isDigit() ** ** Description: determine if 'c' is numeral digit ** ** Returns: true, if numerical digit ** *******************************************************************************/ inline bool isDigit (char c, int base) { if ('0' <= c && c <= '9') return true; if (base == 16) { if (('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) return true; } return false; } /******************************************************************************* ** ** Function: getDigitValue() ** ** Description: return numerical value of a decimal or hex char ** ** Returns: numerical value if decimal or hex char, otherwise 0 ** *******************************************************************************/ inline int getDigitValue (char c, int base) { if ('0' <= c && c <= '9') return c - '0'; if (base == 16) { if ('A' <= c && c <= 'F') return c - 'A' + 10; else if ('a' <= c && c <= 'f') return c - 'a' + 10; } return 0; } /******************************************************************************* ** ** Function: CNxpNfcConfig::readConfig() ** ** Description: read Config settings and parse them into a linked list ** move the element from linked list to a array at the end ** ** Returns: 1, if there are any config data, 0 otherwise ** *******************************************************************************/ bool CNxpNfcConfig::readConfig (const char* name, bool bResetContent) { enum { BEGIN_LINE = 1, TOKEN, STR_VALUE, NUM_VALUE, BEGIN_HEX, BEGIN_QUOTE, END_LINE }; FILE* fd; struct stat buf; string token; string strValue; unsigned long numValue = 0; CNxpNfcParam* pParam = NULL; int i = 0; int base = 0; char c; int bflag = 0; state = BEGIN_LINE; /* open config file, read it into a buffer */ if ((fd = fopen (name, "rb")) == NULL) { ALOGE ("%s Cannot open config file %s\n", __func__, name); if (bResetContent) { ALOGE ("%s Using default value for all settings\n", __func__); mValidFile = false; } return false; } stat (name, &buf); m_timeStamp = (unsigned long) buf.st_mtime; mValidFile = true; if (size() > 0) { if (bResetContent) clean (); else moveToList (); } while (!feof (fd) && fread (&c, 1, 1, fd) == 1) { switch (state & 0xff) { case BEGIN_LINE: if (c == '#') { state = END_LINE; } else if (isPrintable (c)) { i = 0; token.erase (); strValue.erase (); state = TOKEN; token.push_back (c); } break; case TOKEN: if (c == '=') { token.push_back ('\0'); state = BEGIN_QUOTE; } else if (isPrintable (c)) { token.push_back (c); } else { state = END_LINE; } break; case BEGIN_QUOTE: if (c == '"') { state = STR_VALUE; base = 0; } else if (c == '0') { state = BEGIN_HEX; } else if (isDigit (c, 10)) { state = NUM_VALUE; base = 10; numValue = getDigitValue (c, base); i = 0; } else if (c == '{') { state = NUM_VALUE; bflag = 1; base = 16; i = 0; Set (IsStringValue); } else state = END_LINE; break; case BEGIN_HEX: if (c == 'x' || c == 'X') { state = NUM_VALUE; base = 16; numValue = 0; i = 0; break; } else if (isDigit (c, 10)) { state = NUM_VALUE; base = 10; numValue = getDigitValue (c, base); break; } else if (c != '\n' && c != '\r') { state = END_LINE; break; } // fall through to numValue to handle numValue case NUM_VALUE: if (isDigit (c, base)) { numValue *= base; numValue += getDigitValue (c, base); ++i; } else if(bflag == 1 && (c == ' ' || c == '\r' || c=='\n' || c=='\t')) { break; } else if (base == 16 && (c== ','|| c == ':' || c == '-' || c == ' ' || c == '}')) { if( c=='}' ) { bflag = 0; } if (i > 0) { int n = (i+1) / 2; while (n-- > 0) { numValue = numValue >> (n * 8); unsigned char c = (numValue) & 0xFF; strValue.push_back (c); } } Set (IsStringValue); numValue = 0; i = 0; } else { if (c == '\n' || c == '\r') { if (bflag == 0) { state = BEGIN_LINE; } } else { if (bflag == 0) { state = END_LINE; } } if (Is (IsStringValue) && base == 16 && i > 0) { int n = (i+1) / 2; while (n-- > 0) strValue.push_back (((numValue >> (n * 8)) & 0xFF)); } if (strValue.length() > 0) pParam = new CNxpNfcParam (token.c_str (), strValue); else pParam = new CNxpNfcParam (token.c_str (), numValue); add (pParam); strValue.erase (); numValue = 0; } break; case STR_VALUE: if (c == '"') { strValue.push_back('\0'); state = END_LINE; pParam = new CNxpNfcParam(token.c_str(), strValue); add(pParam); } else if (isPrintable(c)) { strValue.push_back(c); } break; case END_LINE: if (c == '\n' || c == '\r') { state = BEGIN_LINE; } break; default: break; } } fclose (fd); moveFromList (); return size () > 0; } /******************************************************************************* ** ** Function: CNxpNfcConfig::CNxpNfcConfig() ** ** Description: class constructor ** ** Returns: none ** *******************************************************************************/ CNxpNfcConfig::CNxpNfcConfig () : mValidFile (true), m_timeStamp (0), state (0) { } /******************************************************************************* ** ** Function: CNxpNfcConfig::~CNxpNfcConfig() ** ** Description: class destructor ** ** Returns: none ** *******************************************************************************/ CNxpNfcConfig::~CNxpNfcConfig () { } /******************************************************************************* ** ** Function: CNxpNfcConfig::GetInstance() ** ** Description: get class singleton object ** ** Returns: none ** *******************************************************************************/ CNxpNfcConfig& CNxpNfcConfig::GetInstance () { static CNxpNfcConfig theInstance; if (theInstance.size () == 0 && theInstance.mValidFile) { string strPath; if (alternative_config_path [0] != '\0') { strPath.assign (alternative_config_path); strPath += config_name; theInstance.readConfig (strPath.c_str (), true); if (!theInstance.empty ()) { return theInstance; } } strPath.assign (transport_config_path); strPath += config_name; theInstance.readConfig (strPath.c_str (), true); } return theInstance; } /******************************************************************************* ** ** Function: CNxpNfcConfig::getValue() ** ** Description: get a string value of a setting ** ** Returns: true if setting exists ** false if setting does not exist ** *******************************************************************************/ bool CNxpNfcConfig::getValue (const char* name, char* pValue, size_t len) const { const CNxpNfcParam* pParam = find (name); if (pParam == NULL) return false; if (pParam->str_len () > 0) { memset (pValue, 0, len); memcpy (pValue, pParam->str_value (), pParam->str_len ()); return true; } return false; } bool CNxpNfcConfig::getValue (const char* name, char* pValue, long len,long* readlen) const { const CNxpNfcParam* pParam = find (name); if (pParam == NULL) return false; if (pParam->str_len () > 0) { if(pParam->str_len () <= (unsigned long) len) { memset (pValue, 0, len); memcpy (pValue, pParam->str_value (), pParam->str_len ()); *readlen = pParam->str_len (); } else { *readlen = -1; } return true; } return false; } /******************************************************************************* ** ** Function: CNxpNfcConfig::getValue() ** ** Description: get a long numerical value of a setting ** ** Returns: true if setting exists ** false if setting does not exist ** *******************************************************************************/ bool CNxpNfcConfig::getValue (const char* name, unsigned long& rValue) const { const CNxpNfcParam* pParam = find (name); if (pParam == NULL) return false; if (pParam->str_len () == 0) { rValue = static_cast<unsigned long> (pParam->numValue ()); return true; } return false; } /******************************************************************************* ** ** Function: CNxpNfcConfig::getValue() ** ** Description: get a short numerical value of a setting ** ** Returns: true if setting exists ** false if setting does not exist ** *******************************************************************************/ bool CNxpNfcConfig::getValue (const char* name, unsigned short& rValue) const { const CNxpNfcParam* pParam = find (name); if (pParam == NULL) return false; if (pParam->str_len () == 0) { rValue = static_cast<unsigned short> (pParam->numValue ()); return true; } return false; } /******************************************************************************* ** ** Function: CNxpNfcConfig::find() ** ** Description: search if a setting exist in the setting array ** ** Returns: pointer to the setting object ** *******************************************************************************/ const CNxpNfcParam* CNxpNfcConfig::find (const char* p_name) const { if (size () == 0) return NULL; for (const_iterator it = begin (), itEnd = end (); it != itEnd; ++it) { if (**it < p_name) { continue; } else if (**it == p_name) { if ((*it)->str_len () > 0) { NXPLOG_EXTNS_D ("%s found %s=%s\n", __func__, p_name, (*it)->str_value()); } else { NXPLOG_EXTNS_D ("%s found %s=(0x%lx)\n", __func__, p_name, (*it)->numValue()); } return *it; } else break; } return NULL; } /******************************************************************************* ** ** Function: CNxpNfcConfig::clean() ** ** Description: reset the setting array ** ** Returns: none ** *******************************************************************************/ void CNxpNfcConfig::clean () { if (size () == 0) return; for (iterator it = begin (), itEnd = end (); it != itEnd; ++it) delete *it; clear (); } /******************************************************************************* ** ** Function: CNxpNfcConfig::Add() ** ** Description: add a setting object to the list ** ** Returns: none ** *******************************************************************************/ void CNxpNfcConfig::add (const CNxpNfcParam* pParam) { if (m_list.size () == 0) { m_list.push_back (pParam); return; } for (list<const CNxpNfcParam*>::iterator it = m_list.begin (), itEnd = m_list.end (); it != itEnd; ++it) { if (**it < pParam->c_str ()) continue; m_list.insert (it, pParam); return; } m_list.push_back (pParam); } /******************************************************************************* ** ** Function: CNxpNfcConfig::moveFromList() ** ** Description: move the setting object from list to array ** ** Returns: none ** *******************************************************************************/ void CNxpNfcConfig::moveFromList () { if (m_list.size () == 0) return; for (list<const CNxpNfcParam*>::iterator it = m_list.begin (), itEnd = m_list.end (); it != itEnd; ++it) push_back (*it); m_list.clear (); } /******************************************************************************* ** ** Function: CNxpNfcConfig::moveToList() ** ** Description: move the setting object from array to list ** ** Returns: none ** *******************************************************************************/ void CNxpNfcConfig::moveToList () { if (m_list.size () != 0) m_list.clear (); for (iterator it = begin (), itEnd = end (); it != itEnd; ++it) m_list.push_back (*it); clear(); } /******************************************************************************* ** ** Function: CNxpNfcConfig::checkTimestamp() ** ** Description: check if config file has modified ** ** Returns: 0 if not modified, 1 otherwise. ** *******************************************************************************/ int CNxpNfcConfig::checkTimestamp () { FILE* fd; struct stat st; unsigned long value = 0; int ret = 0; if (stat(config_timestamp_path, &st) != 0) { ALOGD ("%s file %s not exist, creat it.\n", __func__, config_timestamp_path); if ((fd = fopen (config_timestamp_path, "w+")) != NULL) { fwrite (&m_timeStamp, sizeof(unsigned long), 1, fd); fclose (fd); } return 1; } else { fd = fopen (config_timestamp_path, "r+"); if (fd == NULL) { ALOGE ("%s Cannot open file %s\n", __func__, config_timestamp_path); return 1; } fread (&value, sizeof(unsigned long), 1, fd); ret = (value != m_timeStamp); if (ret) { fseek (fd, 0, SEEK_SET); fwrite (&m_timeStamp, sizeof(unsigned long), 1, fd); } fclose (fd); } return ret; } /******************************************************************************* ** ** Function: CNxpNfcParam::CNxpNfcParam() ** ** Description: class constructor ** ** Returns: none ** *******************************************************************************/ CNxpNfcParam::CNxpNfcParam () : m_numValue (0) { } /******************************************************************************* ** ** Function: CNxpNfcParam::~CNxpNfcParam() ** ** Description: class destructor ** ** Returns: none ** *******************************************************************************/ CNxpNfcParam::~CNxpNfcParam () { } /******************************************************************************* ** ** Function: CNxpNfcParam::CNxpNfcParam() ** ** Description: class copy constructor ** ** Returns: none ** *******************************************************************************/ CNxpNfcParam::CNxpNfcParam (const char* name, const string& value) : string (name), m_str_value (value), m_numValue (0) { } /******************************************************************************* ** ** Function: CNxpNfcParam::CNxpNfcParam() ** ** Description: class copy constructor ** ** Returns: none ** *******************************************************************************/ CNxpNfcParam::CNxpNfcParam (const char* name, unsigned long value) : string (name), m_numValue (value) { } /******************************************************************************* ** ** Function: GetStrValue ** ** Description: API function for getting a string value of a setting ** ** Returns: True if found, otherwise False. ** *******************************************************************************/ extern "C" int GetNxpStrValue (const char* name, char* pValue, unsigned long len) { CNxpNfcConfig& rConfig = CNxpNfcConfig::GetInstance (); return rConfig.getValue (name, pValue, len); } /******************************************************************************* ** ** Function: GetByteArrayValue() ** ** Description: Read byte array value from the config file. ** ** Parameters: ** name - name of the config param to read. ** pValue - pointer to input buffer. ** bufflen - input buffer length. ** len - out parameter to return the number of bytes read from config file, ** return -1 in case bufflen is not enough. ** ** Returns: TRUE[1] if config param name is found in the config file, else FALSE[0] ** *******************************************************************************/ extern "C" int GetNxpByteArrayValue (const char* name, char* pValue, long bufflen, long *len) { CNxpNfcConfig& rConfig = CNxpNfcConfig::GetInstance (); return rConfig.getValue (name, pValue, bufflen,len); } /******************************************************************************* ** ** Function: GetNumValue ** ** Description: API function for getting a numerical value of a setting ** ** Returns: true, if successful ** *******************************************************************************/ extern "C" int GetNxpNumValue (const char* name, void* pValue, unsigned long len) { if (!pValue) return false; CNxpNfcConfig& rConfig = CNxpNfcConfig::GetInstance (); const CNxpNfcParam* pParam = rConfig.find (name); if (pParam == NULL) return false; unsigned long v = pParam->numValue (); if (v == 0 && pParam->str_len () > 0 && pParam->str_len () < 4) { const unsigned char* p = (const unsigned char*) pParam->str_value (); for (unsigned int i = 0 ; i < pParam->str_len (); ++i) { v *= 256; v += *p++; } } switch (len) { case sizeof(unsigned long): *(static_cast<unsigned long*>(pValue)) = (unsigned long) v; break; case sizeof(unsigned short): *(static_cast<unsigned short*>(pValue)) = (unsigned short) v; break; case sizeof(unsigned char): *(static_cast<unsigned char*> (pValue)) = (unsigned char) v; break; default: return false; } return true; } /******************************************************************************* ** ** Function: resetConfig ** ** Description: reset settings array ** ** Returns: none ** *******************************************************************************/ extern "C" void resetNxpConfig () { CNxpNfcConfig& rConfig = CNxpNfcConfig::GetInstance (); rConfig.clean (); } /******************************************************************************* ** ** Function: readOptionalConfig() ** ** Description: read Config settings from an optional conf file ** ** Returns: none ** *******************************************************************************/ void readOptionalConfig (const char* extra) { string strPath; strPath.assign (transport_config_path); if (alternative_config_path [0] != '\0') strPath.assign (alternative_config_path); strPath += extra_config_base; strPath += extra; strPath += extra_config_ext; CNxpNfcConfig::GetInstance ().readConfig (strPath.c_str (), false); } /******************************************************************************* ** ** Function: isNxpConfigModified() ** ** Description: check if config file has modified ** ** Returns: 0 if not modified, 1 otherwise. ** *******************************************************************************/ extern "C" int isNxpConfigModified () { CNxpNfcConfig& rConfig = CNxpNfcConfig::GetInstance (); return rConfig.checkTimestamp (); }