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