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