| /* |
| * 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 <android-base/stringprintf.h> |
| #include <base/logging.h> |
| #include <errno.h> |
| #include <sys/stat.h> |
| |
| /* NOTE: |
| * This has to be included AFTER the android-base includes since |
| * android-base/macros.h defines ATTRIBUTE_UNUSED, also used in the |
| * tiny XML library. |
| */ |
| #include "RouteDataSet.h" |
| |
| #include "libxml/xmlmemory.h" |
| |
| using android::base::StringPrintf; |
| |
| extern std::string nfc_storage_path; |
| extern bool nfc_debug_enabled; |
| |
| /******************************************************************************* |
| ** |
| ** 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_t[aid.length()]; |
| while (true) { |
| num = 0; |
| if (pos2 == std::string::npos) { |
| sscanf(aid.substr(pos1).c_str(), "%x", &num); |
| mBuffer[mBufferLen] = (uint8_t)num; |
| mBufferLen++; |
| break; |
| } else { |
| sscanf(aid.substr(pos1, pos2 - pos1 + 1).c_str(), "%x", &num); |
| mBuffer[mBufferLen] = (uint8_t)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() { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: enter", "RouteDataSet::initialize"); |
| // check that the libxml2 version in use is compatible |
| // with the version the software has been compiled with |
| LIBXML_TEST_VERSION |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: exit; return=true", "RouteDataSet::initialize"); |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: deleteDatabase |
| ** |
| ** Description: Delete all routes stored in all databases. |
| ** |
| ** Returns: None. |
| ** |
| *******************************************************************************/ |
| void RouteDataSet::deleteDatabase() { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: default db size=%zu; sec elem db size=%zu", |
| "RouteDataSet::deleteDatabase", 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"; |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", fn); |
| bool retval = false; |
| xmlDocPtr doc; |
| xmlNodePtr node1; |
| std::string strFilename(nfc_storage_path); |
| strFilename += sConfigFile; |
| |
| deleteDatabase(); |
| |
| doc = xmlParseFile(strFilename.c_str()); |
| if (doc == NULL) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: fail parse", fn); |
| goto TheEnd; |
| } |
| |
| node1 = xmlDocGetRootElement(doc); |
| if (node1 == NULL) { |
| LOG(ERROR) << StringPrintf("%s: fail root element", fn); |
| goto TheEnd; |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%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)) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%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)) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%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(); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%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(nfc_storage_path); |
| int stat = 0; |
| |
| filename.append(sConfigFile); |
| fh = fopen(filename.c_str(), "w"); |
| if (fh == NULL) { |
| LOG(ERROR) << StringPrintf("%s: fail to open file", fn); |
| return false; |
| } |
| |
| actualWritten = fwrite(routesXml, sizeof(char), strlen(routesXml), fh); |
| retval = actualWritten == strlen(routesXml); |
| fclose(fh); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: wrote %zu bytes", fn, actualWritten); |
| if (retval == false) LOG(ERROR) << StringPrintf("%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) LOG(ERROR) << StringPrintf("%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) { |
| FILE* fh = NULL; |
| size_t actual = 0; |
| char buffer[1024]; |
| std::string filename(nfc_storage_path); |
| |
| filename.append(sConfigFile); |
| fh = fopen(filename.c_str(), "r"); |
| if (fh == NULL) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: fail to open file", "RouteDataSet::loadFromFile"); |
| return false; |
| } |
| |
| while (true) { |
| actual = fread(buffer, sizeof(char), sizeof(buffer), fh); |
| if (actual == 0) break; |
| routesXml.append(buffer, actual); |
| } |
| fclose(fh); |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: read %zu bytes", "RouteDataSet::loadFromFile", 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) { |
| 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; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: element=%s", "RouteDataSet::importProtocolRoute", 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); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: %s=0x%X", "RouteDataSet::importProtocolRoute", 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; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: %s=0x%X", "RouteDataSet::importProtocolRoute", |
| 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) { |
| 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; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "%s: element=%s", "RouteDataSet::importTechnologyRoute", 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); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: %s=0x%X", "RouteDataSet::importTechnologyRoute", |
| 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; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: %s=0x%X", "RouteDataSet::importTechnologyRoute", |
| 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(nfc_storage_path); |
| filename.append(sConfigFile); |
| int stat = remove(filename.c_str()); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%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); |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%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; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: ee h=0x%X; protocol=0x%X", fn, |
| proto->mNfaEeHandle, proto->mProtocol); |
| } break; |
| case RouteData::TechnologyRoute: { |
| RouteDataForTechnology* tech = (RouteDataForTechnology*)routeData; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: ee h=0x%X; technology=0x%X", fn, |
| tech->mNfaEeHandle, tech->mTechnology); |
| } break; |
| } |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%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; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: ee h=0x%X; protocol=0x%X", fn, |
| proto->mNfaEeHandle, proto->mProtocol); |
| } break; |
| case RouteData::TechnologyRoute: { |
| RouteDataForTechnology* tech = (RouteDataForTechnology*)routeData; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("%s: ee h=0x%X; technology=0x%X", fn, |
| tech->mNfaEeHandle, tech->mTechnology); |
| } break; |
| } |
| } |
| } |