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 29const char* transport_config_paths[] = {"/odm/etc/", "/vendor/etc/", "/etc/"}; 30const 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 38using namespace ::std; 39 40class 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 55class 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*******************************************************************************/ 92inline 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*******************************************************************************/ 106inline 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*******************************************************************************/ 123inline 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*******************************************************************************/ 144void 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*******************************************************************************/ 168bool 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*******************************************************************************/ 346CNfcConfig::CNfcConfig() : mValidFile(true), state(0) {} 347 348/******************************************************************************* 349** 350** Function: CNfcConfig::~CNfcConfig() 351** 352** Description: class destructor 353** 354** Returns: none 355** 356*******************************************************************************/ 357CNfcConfig::~CNfcConfig() {} 358 359/******************************************************************************* 360** 361** Function: CNfcConfig::GetInstance() 362** 363** Description: get class singleton object 364** 365** Returns: none 366** 367*******************************************************************************/ 368CNfcConfig& 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*******************************************************************************/ 390bool 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*******************************************************************************/ 413bool 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*******************************************************************************/ 434bool 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*******************************************************************************/ 454const 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*******************************************************************************/ 481void 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*******************************************************************************/ 497void 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*******************************************************************************/ 521void 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*******************************************************************************/ 540void 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*******************************************************************************/ 557CNfcParam::CNfcParam() : m_numValue(0) {} 558 559/******************************************************************************* 560** 561** Function: CNfcParam::~CNfcParam() 562** 563** Description: class destructor 564** 565** Returns: none 566** 567*******************************************************************************/ 568CNfcParam::~CNfcParam() {} 569 570/******************************************************************************* 571** 572** Function: CNfcParam::CNfcParam() 573** 574** Description: class copy constructor 575** 576** Returns: none 577** 578*******************************************************************************/ 579CNfcParam::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*******************************************************************************/ 591CNfcParam::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*******************************************************************************/ 603extern "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*******************************************************************************/ 620extern "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*******************************************************************************/ 660extern 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*******************************************************************************/ 675void 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