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