/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Import and export general routing data using a XML file.
*/
#include "OverrideLog.h"
#include "RouteDataSet.h"
#include "libxml/xmlmemory.h"
#include <errno.h>
#include <sys/stat.h>
extern char bcm_nfc_location[];
/*******************************************************************************
**
** Function: AidBuffer
**
** Description: Parse a string of hex numbers. Store result in an array of
** bytes.
** aid: string of hex numbers.
**
** Returns: None.
**
*******************************************************************************/
AidBuffer::AidBuffer (std::string& aid)
: mBuffer (NULL),
mBufferLen (0)
{
unsigned int num = 0;
const char delimiter = ':';
std::string::size_type pos1 = 0;
std::string::size_type pos2 = aid.find_first_of (delimiter);
//parse the AID string; each hex number is separated by a colon;
mBuffer = new UINT8 [aid.length()];
while (true)
{
num = 0;
if (pos2 == std::string::npos)
{
sscanf (aid.substr(pos1).c_str(), "%x", &num);
mBuffer [mBufferLen] = (UINT8) num;
mBufferLen++;
break;
}
else
{
sscanf (aid.substr(pos1, pos2-pos1+1).c_str(), "%x", &num);
mBuffer [mBufferLen] = (UINT8) num;
mBufferLen++;
pos1 = pos2 + 1;
pos2 = aid.find_first_of (delimiter, pos1);
}
}
}
/*******************************************************************************
**
** Function: ~AidBuffer
**
** Description: Release all resources.
**
** Returns: None.
**
*******************************************************************************/
AidBuffer::~AidBuffer ()
{
delete [] mBuffer;
}
/*******************************************************************************/
/*******************************************************************************/
const char* RouteDataSet::sConfigFile = "/param/route.xml";
/*******************************************************************************
**
** Function: ~RouteDataSet
**
** Description: Release all resources.
**
** Returns: None.
**
*******************************************************************************/
RouteDataSet::~RouteDataSet ()
{
deleteDatabase ();
}
/*******************************************************************************
**
** Function: initialize
**
** Description: Initialize resources.
**
** Returns: True if ok.
**
*******************************************************************************/
bool RouteDataSet::initialize ()
{
static const char fn [] = "RouteDataSet::initialize";
ALOGD ("%s: enter", fn);
//check that the libxml2 version in use is compatible
//with the version the software has been compiled with
LIBXML_TEST_VERSION
ALOGD ("%s: exit; return=true", fn);
return true;
}
/*******************************************************************************
**
** Function: deleteDatabase
**
** Description: Delete all routes stored in all databases.
**
** Returns: None.
**
*******************************************************************************/
void RouteDataSet::deleteDatabase ()
{
static const char fn [] = "RouteDataSet::deleteDatabase";
ALOGD ("%s: default db size=%zu; sec elem db size=%zu", fn, mDefaultRouteDatabase.size(), mSecElemRouteDatabase.size());
Database::iterator it;
for (it = mDefaultRouteDatabase.begin(); it != mDefaultRouteDatabase.end(); it++)
delete (*it);
mDefaultRouteDatabase.clear ();
for (it = mSecElemRouteDatabase.begin(); it != mSecElemRouteDatabase.end(); it++)
delete (*it);
mSecElemRouteDatabase.clear ();
}
/*******************************************************************************
**
** Function: import
**
** Description: Import data from an XML file. Fill the databases.
**
** Returns: True if ok.
**
*******************************************************************************/
bool RouteDataSet::import ()
{
static const char fn [] = "RouteDataSet::import";
ALOGD ("%s: enter", fn);
bool retval = false;
xmlDocPtr doc;
xmlNodePtr node1;
std::string strFilename(bcm_nfc_location);
strFilename += sConfigFile;
deleteDatabase ();
doc = xmlParseFile (strFilename.c_str());
if (doc == NULL)
{
ALOGD ("%s: fail parse", fn);
goto TheEnd;
}
node1 = xmlDocGetRootElement (doc);
if (node1 == NULL)
{
ALOGE ("%s: fail root element", fn);
goto TheEnd;
}
ALOGD ("%s: root=%s", fn, node1->name);
node1 = node1->xmlChildrenNode;
while (node1) //loop through all elements in <Routes ...
{
if (xmlStrcmp(node1->name, (const xmlChar*) "Route")==0)
{
xmlChar* value = xmlGetProp (node1, (const xmlChar*) "Type");
if (value && (xmlStrcmp (value, (const xmlChar*) "SecElemSelectedRoutes") == 0))
{
ALOGD ("%s: found SecElemSelectedRoutes", fn);
xmlNodePtr node2 = node1->xmlChildrenNode;
while (node2) //loop all elements in <Route Type="SecElemSelectedRoutes" ...
{
if (xmlStrcmp(node2->name, (const xmlChar*) "Proto")==0)
importProtocolRoute (node2, mSecElemRouteDatabase);
else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0)
importTechnologyRoute (node2, mSecElemRouteDatabase);
node2 = node2->next;
} //loop all elements in <Route Type="SecElemSelectedRoutes" ...
}
else if (value && (xmlStrcmp (value, (const xmlChar*) "DefaultRoutes") == 0))
{
ALOGD ("%s: found DefaultRoutes", fn);
xmlNodePtr node2 = node1->xmlChildrenNode;
while (node2) //loop all elements in <Route Type="DefaultRoutes" ...
{
if (xmlStrcmp(node2->name, (const xmlChar*) "Proto")==0)
importProtocolRoute (node2, mDefaultRouteDatabase);
else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0)
importTechnologyRoute (node2, mDefaultRouteDatabase);
node2 = node2->next;
} //loop all elements in <Route Type="DefaultRoutes" ...
}
if (value)
xmlFree (value);
} //check <Route ...
node1 = node1->next;
} //loop through all elements in <Routes ...
retval = true;
TheEnd:
xmlFreeDoc (doc);
xmlCleanupParser ();
ALOGD ("%s: exit; return=%u", fn, retval);
return retval;
}
/*******************************************************************************
**
** Function: saveToFile
**
** Description: Save XML data from a string into a file.
** routesXml: XML that represents routes.
**
** Returns: True if ok.
**
*******************************************************************************/
bool RouteDataSet::saveToFile (const char* routesXml)
{
static const char fn [] = "RouteDataSet::saveToFile";
FILE* fh = NULL;
size_t actualWritten = 0;
bool retval = false;
std::string filename (bcm_nfc_location);
int stat = 0;
filename.append (sConfigFile);
fh = fopen (filename.c_str (), "w");
if (fh == NULL)
{
ALOGE ("%s: fail to open file", fn);
return false;
}
actualWritten = fwrite (routesXml, sizeof(char), strlen(routesXml), fh);
retval = actualWritten == strlen(routesXml);
fclose (fh);
ALOGD ("%s: wrote %zu bytes", fn, actualWritten);
if (retval == false)
ALOGE ("%s: error during write", fn);
//set file permission to
//owner read, write; group read; other read
stat = chmod (filename.c_str (), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (stat == -1)
ALOGE ("%s: error during chmod", fn);
return retval;
}
/*******************************************************************************
**
** Function: loadFromFile
**
** Description: Load XML data from file into a string.
** routesXml: string to receive XML data.
**
** Returns: True if ok.
**
*******************************************************************************/
bool RouteDataSet::loadFromFile (std::string& routesXml)
{
static const char fn [] = "RouteDataSet::loadFromFile";
FILE* fh = NULL;
size_t actual = 0;
char buffer [1024];
std::string filename (bcm_nfc_location);
filename.append (sConfigFile);
fh = fopen (filename.c_str (), "r");
if (fh == NULL)
{
ALOGD ("%s: fail to open file", fn);
return false;
}
while (true)
{
actual = fread (buffer, sizeof(char), sizeof(buffer), fh);
if (actual == 0)
break;
routesXml.append (buffer, actual);
}
fclose (fh);
ALOGD ("%s: read %zu bytes", fn, routesXml.length());
return true;
}
/*******************************************************************************
**
** Function: importProtocolRoute
**
** Description: Parse data for protocol routes.
** element: XML node for one protocol route.
** database: store data in this database.
**
** Returns: None.
**
*******************************************************************************/
void RouteDataSet::importProtocolRoute (xmlNodePtr& element, Database& database)
{
static const char fn [] = "RouteDataSet::importProtocolRoute";
const xmlChar* id = (const xmlChar*) "Id";
const xmlChar* secElem = (const xmlChar*) "SecElem";
const xmlChar* trueString = (const xmlChar*) "true";
const xmlChar* switchOn = (const xmlChar*) "SwitchOn";
const xmlChar* switchOff = (const xmlChar*) "SwitchOff";
const xmlChar* batteryOff = (const xmlChar*) "BatteryOff";
RouteDataForProtocol* data = new RouteDataForProtocol;
xmlChar* value = NULL;
ALOGD_IF (sDebug, "%s: element=%s", fn, element->name);
value = xmlGetProp (element, id);
if (value)
{
if (xmlStrcmp (value, (const xmlChar*) "T1T") == 0)
data->mProtocol = NFA_PROTOCOL_MASK_T1T;
else if (xmlStrcmp (value, (const xmlChar*) "T2T") == 0)
data->mProtocol = NFA_PROTOCOL_MASK_T2T;
else if (xmlStrcmp (value, (const xmlChar*) "T3T") == 0)
data->mProtocol = NFA_PROTOCOL_MASK_T3T;
else if (xmlStrcmp (value, (const xmlChar*) "IsoDep") == 0)
data->mProtocol = NFA_PROTOCOL_MASK_ISO_DEP;
xmlFree (value);
ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mProtocol);
}
value = xmlGetProp (element, secElem);
if (value)
{
data->mNfaEeHandle = strtol ((char*) value, NULL, 16);
xmlFree (value);
data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle);
}
value = xmlGetProp (element, switchOn);
if (value)
{
data->mSwitchOn = (xmlStrcmp (value, trueString) == 0);
xmlFree (value);
}
value = xmlGetProp (element, switchOff);
if (value)
{
data->mSwitchOff = (xmlStrcmp (value, trueString) == 0);
xmlFree (value);
}
value = xmlGetProp (element, batteryOff);
if (value)
{
data->mBatteryOff = (xmlStrcmp (value, trueString) == 0);
xmlFree (value);
}
database.push_back (data);
}
/*******************************************************************************
**
** Function: importTechnologyRoute
**
** Description: Parse data for technology routes.
** element: XML node for one technology route.
** database: store data in this database.
**
** Returns: None.
**
*******************************************************************************/
void RouteDataSet::importTechnologyRoute (xmlNodePtr& element, Database& database)
{
static const char fn [] = "RouteDataSet::importTechnologyRoute";
const xmlChar* id = (const xmlChar*) "Id";
const xmlChar* secElem = (const xmlChar*) "SecElem";
const xmlChar* trueString = (const xmlChar*) "true";
const xmlChar* switchOn = (const xmlChar*) "SwitchOn";
const xmlChar* switchOff = (const xmlChar*) "SwitchOff";
const xmlChar* batteryOff = (const xmlChar*) "BatteryOff";
RouteDataForTechnology* data = new RouteDataForTechnology;
xmlChar* value = NULL;
ALOGD_IF (sDebug, "%s: element=%s", fn, element->name);
value = xmlGetProp (element, id);
if (value)
{
if (xmlStrcmp (value, (const xmlChar*) "NfcA") == 0)
data->mTechnology = NFA_TECHNOLOGY_MASK_A;
else if (xmlStrcmp (value, (const xmlChar*) "NfcB") == 0)
data->mTechnology = NFA_TECHNOLOGY_MASK_B;
else if (xmlStrcmp (value, (const xmlChar*) "NfcF") == 0)
data->mTechnology = NFA_TECHNOLOGY_MASK_F;
xmlFree (value);
ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mTechnology);
}
value = xmlGetProp (element, secElem);
if (value)
{
data->mNfaEeHandle = strtol ((char*) value, NULL, 16);
xmlFree (value);
data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle);
}
value = xmlGetProp (element, switchOn);
if (value)
{
data->mSwitchOn = (xmlStrcmp (value, trueString) == 0);
xmlFree (value);
}
value = xmlGetProp (element, switchOff);
if (value)
{
data->mSwitchOff = (xmlStrcmp (value, trueString) == 0);
xmlFree (value);
}
value = xmlGetProp (element, batteryOff);
if (value)
{
data->mBatteryOff = (xmlStrcmp (value, trueString) == 0);
xmlFree (value);
}
database.push_back (data);
}
/*******************************************************************************
**
** Function: deleteFile
**
** Description: Delete route data XML file.
**
** Returns: True if ok.
**
*******************************************************************************/
bool RouteDataSet::deleteFile ()
{
static const char fn [] = "RouteDataSet::deleteFile";
std::string filename (bcm_nfc_location);
filename.append (sConfigFile);
int stat = remove (filename.c_str());
ALOGD ("%s: exit %u", fn, stat==0);
return stat == 0;
}
/*******************************************************************************
**
** Function: getDatabase
**
** Description: Obtain a database of routing data.
** selection: which database.
**
** Returns: Pointer to database.
**
*******************************************************************************/
RouteDataSet::Database* RouteDataSet::getDatabase (DatabaseSelection selection)
{
switch (selection)
{
case DefaultRouteDatabase:
return &mDefaultRouteDatabase;
case SecElemRouteDatabase:
return &mSecElemRouteDatabase;
}
return NULL;
}
/*******************************************************************************
**
** Function: printDiagnostic
**
** Description: Print some diagnostic output.
**
** Returns: None.
**
*******************************************************************************/
void RouteDataSet::printDiagnostic ()
{
static const char fn [] = "RouteDataSet::printDiagnostic";
Database* db = getDatabase (DefaultRouteDatabase);
ALOGD ("%s: default route database", fn);
for (Database::iterator iter = db->begin(); iter != db->end(); iter++)
{
RouteData* routeData = *iter;
switch (routeData->mRouteType)
{
case RouteData::ProtocolRoute:
{
RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData;
ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol);
}
break;
case RouteData::TechnologyRoute:
{
RouteDataForTechnology* tech = (RouteDataForTechnology*) routeData;
ALOGD ("%s: ee h=0x%X; technology=0x%X", fn, tech->mNfaEeHandle, tech->mTechnology);
}
break;
}
}
ALOGD ("%s: sec elem route database", fn);
db = getDatabase (SecElemRouteDatabase);
for (Database::iterator iter2 = db->begin(); iter2 != db->end(); iter2++)
{
RouteData* routeData = *iter2;
switch (routeData->mRouteType)
{
case RouteData::ProtocolRoute:
{
RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData;
ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol);
}
break;
case RouteData::TechnologyRoute:
{
RouteDataForTechnology* tech = (RouteDataForTechnology*) routeData;
ALOGD ("%s: ee h=0x%X; technology=0x%X", fn, tech->mNfaEeHandle, tech->mTechnology);
}
break;
}
}
}