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