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