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
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    while (!feof(fd) && fread(&c, 1, 1, fd) == 1)
196    {
197        switch (state & 0xff)
198        {
199        case BEGIN_LINE:
200            if (c == '#')
201                state = END_LINE;
202            else if (isPrintable(c))
203            {
204                i = 0;
205                token.erase();
206                strValue.erase();
207                state = TOKEN;
208                token.push_back(c);
209            }
210            break;
211        case TOKEN:
212            if (c == '=')
213            {
214                token.push_back('\0');
215                state = BEGIN_QUOTE;
216            }
217            else if (isPrintable(c))
218                token.push_back(c);
219            else
220                state = END_LINE;
221            break;
222        case BEGIN_QUOTE:
223            if (c == '"')
224            {
225                state = STR_VALUE;
226                base = 0;
227            }
228            else if (c == '0')
229                state = BEGIN_HEX;
230            else if (isDigit(c, 10))
231            {
232                state = NUM_VALUE;
233                base = 10;
234                numValue = getDigitValue(c, base);
235                i = 0;
236            }
237            else if (c == '{')
238            {
239                state = NUM_VALUE;
240                base = 16;
241                i = 0;
242                Set(IsStringValue);
243            }
244            else
245                state = END_LINE;
246            break;
247        case BEGIN_HEX:
248            if (c == 'x' || c == 'X')
249            {
250                state = NUM_VALUE;
251                base = 16;
252                numValue = 0;
253                i = 0;
254                break;
255            }
256            else if (isDigit(c, 10))
257            {
258                state = NUM_VALUE;
259                base = 10;
260                numValue = getDigitValue(c, base);
261                break;
262            }
263            else if (c != '\n' && c != '\r')
264            {
265                state = END_LINE;
266                break;
267            }
268            // fal through to numValue to handle numValue
269
270        case NUM_VALUE:
271            if (isDigit(c, base))
272            {
273                numValue *= base;
274                numValue += getDigitValue(c, base);
275                ++i;
276            }
277            else if (base == 16 && (c == ':' || c == '-' || c == ' ' || c == '}'))
278            {
279                if (i > 0)
280                {
281                    int n = (i+1) / 2;
282                    while (n-- > 0)
283                    {
284                        unsigned char c = (numValue >> (n * 8))  & 0xFF;
285                        strValue.push_back(c);
286                    }
287                }
288                Set(IsStringValue);
289                numValue = 0;
290                i = 0;
291            }
292            else
293            {
294                if (c == '\n' || c == '\r')
295                    state = BEGIN_LINE;
296                else
297                    state = END_LINE;
298                if (Is(IsStringValue) && base == 16 && i > 0)
299                {
300                    int n = (i+1) / 2;
301                    while (n-- > 0)
302                        strValue.push_back(((numValue >> (n * 8))  & 0xFF));
303                }
304                if (strValue.length() > 0)
305                    pParam = new CNfcParam(token.c_str(), strValue);
306                else
307                    pParam = new CNfcParam(token.c_str(), numValue);
308                add(pParam);
309                strValue.erase();
310                numValue = 0;
311            }
312            break;
313        case STR_VALUE:
314            if (c == '"')
315            {
316                strValue.push_back('\0');
317                state = END_LINE;
318                pParam = new CNfcParam(token.c_str(), strValue);
319                add(pParam);
320            }
321            else if (isPrintable(c))
322                strValue.push_back(c);
323            break;
324        case END_LINE:
325            if (c == '\n' || c == '\r')
326                state = BEGIN_LINE;
327            break;
328        default:
329            break;
330        }
331    }
332
333    fclose(fd);
334
335    moveFromList();
336    return size() > 0;
337}
338
339/*******************************************************************************
340**
341** Function:    CNfcConfig::CNfcConfig()
342**
343** Description: class constructor
344**
345** Returns:     none
346**
347*******************************************************************************/
348CNfcConfig::CNfcConfig() :
349    mValidFile(true)
350{
351}
352
353/*******************************************************************************
354**
355** Function:    CNfcConfig::~CNfcConfig()
356**
357** Description: class destructor
358**
359** Returns:     none
360**
361*******************************************************************************/
362CNfcConfig::~CNfcConfig()
363{
364}
365
366/*******************************************************************************
367**
368** Function:    CNfcConfig::GetInstance()
369**
370** Description: get class singleton object
371**
372** Returns:     none
373**
374*******************************************************************************/
375CNfcConfig& CNfcConfig::GetInstance()
376{
377    static CNfcConfig theInstance;
378
379    if (theInstance.size() == 0 && theInstance.mValidFile)
380    {
381        string strPath;
382        strPath.assign(transport_config_path);
383        strPath += config_name;
384        theInstance.readConfig(strPath.c_str(), true);
385    }
386
387    return theInstance;
388}
389
390/*******************************************************************************
391**
392** Function:    CNfcConfig::getValue()
393**
394** Description: get a string value of a setting
395**
396** Returns:     true if setting exists
397**              false if setting does not exist
398**
399*******************************************************************************/
400bool CNfcConfig::getValue(const char* name, char* pValue, size_t& len) const
401{
402    const CNfcParam* pParam = find(name);
403    if (pParam == NULL)
404        return false;
405
406    if (pParam->str_len() > 0)
407    {
408        memset(pValue, 0, len);
409        if (len > pParam->str_len())
410            len  = pParam->str_len();
411        memcpy(pValue, pParam->str_value(), len);
412        return true;
413    }
414    return false;
415}
416
417/*******************************************************************************
418**
419** Function:    CNfcConfig::getValue()
420**
421** Description: get a long numerical value of a setting
422**
423** Returns:     true if setting exists
424**              false if setting does not exist
425**
426*******************************************************************************/
427bool CNfcConfig::getValue(const char* name, unsigned long& rValue) const
428{
429    const CNfcParam* pParam = find(name);
430    if (pParam == NULL)
431        return false;
432
433    if (pParam->str_len() == 0)
434    {
435        rValue = static_cast<unsigned long>(pParam->numValue());
436        return true;
437    }
438    return false;
439}
440
441/*******************************************************************************
442**
443** Function:    CNfcConfig::getValue()
444**
445** Description: get a short numerical value of a setting
446**
447** Returns:     true if setting exists
448**              false if setting does not exist
449**
450*******************************************************************************/
451bool CNfcConfig::getValue(const char* name, unsigned short& rValue) const
452{
453    const CNfcParam* pParam = find(name);
454    if (pParam == NULL)
455        return false;
456
457    if (pParam->str_len() == 0)
458    {
459        rValue = static_cast<unsigned short>(pParam->numValue());
460        return true;
461    }
462    return false;
463}
464
465/*******************************************************************************
466**
467** Function:    CNfcConfig::find()
468**
469** Description: search if a setting exist in the setting array
470**
471** Returns:     pointer to the setting object
472**
473*******************************************************************************/
474const CNfcParam* CNfcConfig::find(const char* p_name) const
475{
476    if (size() == 0)
477        return NULL;
478
479    for (const_iterator it = begin(), itEnd = end(); it != itEnd; ++it)
480    {
481        if (**it < p_name)
482            continue;
483        else if (**it == p_name)
484        {
485            if((*it)->str_len() > 0)
486                ALOGD("%s found %s=%s\n", __func__, p_name, (*it)->str_value());
487            else
488                ALOGD("%s found %s=(0x%lX)\n", __func__, p_name, (*it)->numValue());
489            return *it;
490        }
491        else
492            break;
493    }
494    return NULL;
495}
496
497/*******************************************************************************
498**
499** Function:    CNfcConfig::clean()
500**
501** Description: reset the setting array
502**
503** Returns:     none
504**
505*******************************************************************************/
506void CNfcConfig::clean()
507{
508    if (size() == 0)
509        return;
510
511    for (iterator it = begin(), itEnd = end(); it != itEnd; ++it)
512        delete *it;
513    clear();
514}
515
516/*******************************************************************************
517**
518** Function:    CNfcConfig::Add()
519**
520** Description: add a setting object to the list
521**
522** Returns:     none
523**
524*******************************************************************************/
525void CNfcConfig::add(const CNfcParam* pParam)
526{
527    if (m_list.size() == 0)
528    {
529        m_list.push_back(pParam);
530        return;
531    }
532    for (list<const CNfcParam*>::iterator it = m_list.begin(), itEnd = m_list.end(); it != itEnd; ++it)
533    {
534        if (**it < pParam->c_str())
535            continue;
536        m_list.insert(it, pParam);
537        return;
538    }
539    m_list.push_back(pParam);
540}
541
542/*******************************************************************************
543**
544** Function:    CNfcConfig::moveFromList()
545**
546** Description: move the setting object from list to array
547**
548** Returns:     none
549**
550*******************************************************************************/
551void CNfcConfig::moveFromList()
552{
553    if (m_list.size() == 0)
554        return;
555
556    for (list<const CNfcParam*>::iterator it = m_list.begin(), itEnd = m_list.end(); it != itEnd; ++it)
557        push_back(*it);
558    m_list.clear();
559}
560
561/*******************************************************************************
562**
563** Function:    CNfcConfig::moveToList()
564**
565** Description: move the setting object from array to list
566**
567** Returns:     none
568**
569*******************************************************************************/
570void CNfcConfig::moveToList()
571{
572    if (m_list.size() != 0)
573        m_list.clear();
574
575    for (iterator it = begin(), itEnd = end(); it != itEnd; ++it)
576        m_list.push_back(*it);
577    clear();
578}
579
580/*******************************************************************************
581**
582** Function:    CNfcParam::CNfcParam()
583**
584** Description: class constructor
585**
586** Returns:     none
587**
588*******************************************************************************/
589CNfcParam::CNfcParam() :
590    m_numValue(0)
591{
592}
593
594/*******************************************************************************
595**
596** Function:    CNfcParam::~CNfcParam()
597**
598** Description: class destructor
599**
600** Returns:     none
601**
602*******************************************************************************/
603CNfcParam::~CNfcParam()
604{
605}
606
607/*******************************************************************************
608**
609** Function:    CNfcParam::CNfcParam()
610**
611** Description: class copy constructor
612**
613** Returns:     none
614**
615*******************************************************************************/
616CNfcParam::CNfcParam(const char* name,  const string& value) :
617    string(name),
618    m_str_value(value),
619    m_numValue(0)
620{
621}
622
623/*******************************************************************************
624**
625** Function:    CNfcParam::CNfcParam()
626**
627** Description: class copy constructor
628**
629** Returns:     none
630**
631*******************************************************************************/
632CNfcParam::CNfcParam(const char* name,  unsigned long value) :
633    string(name),
634    m_numValue(value)
635{
636}
637
638/*******************************************************************************
639**
640** Function:    GetStrValue
641**
642** Description: API function for getting a string value of a setting
643**
644** Returns:     none
645**
646*******************************************************************************/
647extern "C" int GetStrValue(const char* name, char* pValue, unsigned long l)
648{
649    size_t len = l;
650    CNfcConfig& rConfig = CNfcConfig::GetInstance();
651
652    bool b = rConfig.getValue(name, pValue, len);
653    return b ? len : 0;
654}
655
656/*******************************************************************************
657**
658** Function:    GetNumValue
659**
660** Description: API function for getting a numerical value of a setting
661**
662** Returns:     none
663**
664*******************************************************************************/
665extern "C" int GetNumValue(const char* name, void* pValue, unsigned long len)
666{
667    if (!pValue)
668        return false;
669
670    CNfcConfig& rConfig = CNfcConfig::GetInstance();
671    const CNfcParam* pParam = rConfig.find(name);
672
673    if (pParam == NULL)
674        return false;
675    unsigned long v = pParam->numValue();
676    if (v == 0 && pParam->str_len() > 0 && pParam->str_len() < 4)
677    {
678        const unsigned char* p = (const unsigned char*)pParam->str_value();
679        for (size_t i = 0 ; i < pParam->str_len(); ++i)
680        {
681            v *= 256;
682            v += *p++;
683        }
684    }
685    switch (len)
686    {
687    case sizeof(unsigned long):
688        *(static_cast<unsigned long*>(pValue)) = (unsigned long)v;
689        break;
690    case sizeof(unsigned short):
691        *(static_cast<unsigned short*>(pValue)) = (unsigned short)v;
692        break;
693    case sizeof(unsigned char):
694        *(static_cast<unsigned char*> (pValue)) = (unsigned char)v;
695        break;
696    default:
697        return false;
698    }
699    return true;
700}
701
702/*******************************************************************************
703**
704** Function:    resetConfig
705**
706** Description: reset settings array
707**
708** Returns:     none
709**
710*******************************************************************************/
711extern void resetConfig()
712{
713    CNfcConfig& rConfig = CNfcConfig::GetInstance();
714
715    rConfig.clean();
716}
717
718/*******************************************************************************
719**
720** Function:    readOptionalConfig()
721**
722** Description: read Config settings from an optional conf file
723**
724** Returns:     none
725**
726*******************************************************************************/
727void readOptionalConfig(const char* extra)
728{
729    string strPath;
730    strPath.assign(transport_config_path);
731    strPath += extra_config_base;
732    strPath += extra;
733    strPath += extra_config_ext;
734    CNfcConfig::GetInstance().readConfig(strPath.c_str(), false);
735}
736
737