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