/* * FileReaderVOTable.cc * * Created on: Nov 24, 2014 * Author: AKKA */ #include #include #include #include #include "TimeUtil.hh" #include "FileReaderVOTable.hh" namespace AMDA { namespace LocalFileInterface { // 32 KB is the maximum supported line size int FileReaderVOTable::MaxLineSize = 32 * 1024; FileReaderVOTable::FileReaderVOTable() : _votFilePath(), _dataFloat(NULL), _dataDouble(NULL), _dataShort(NULL), _dataInt(NULL), _data( NULL) { } FileReaderVOTable::~FileReaderVOTable() { } /** * Parses XML file and looks for FIELD and PARAM element containing parameters informations */ void FileReaderVOTable::getVOTableInfo(void) { const xmlChar *fieldId; const xmlChar *fieldName; const xmlChar *fieldXType; const xmlChar *fieldArraySize; const xmlChar *fieldDataType; const xmlChar *fieldUCD; const xmlChar *fieldUnit; const xmlChar *groupId; const xmlChar *paramName; const xmlChar *paramSize; const xmlChar *paramValue; bool parsingTable = false; bool parsingField = false; bool parsingGroup = false; bool parsingParam = false; int fieldIndex = 0; std::string crtGroupId; // Clear current field informations _fieldsInfo.clear(); //Clear current param informations _paramsInfo.clear(); // created XML reader xmlTextReaderPtr reader = xmlReaderForFile(_votFilePath.c_str(), NULL, 0); // read xml file tag by tag while (xmlTextReaderRead(reader) == 1) { // -- read tag const xmlChar *name = xmlTextReaderConstName(reader); if (name != NULL) { // get tag name to easily handle it std::string tagName = std::string((const char*) name); if (tagName == "TABLE") { parsingTable = !parsingTable; } if ((parsingTable == true) && (tagName == "GROUP")) { // parsing group is set when we are on the start element only, // this will prevent problems if GROUP tag ends width /> parsingGroup = (xmlTextReaderNodeType(reader) == 1); if (parsingGroup == true) { groupId = xmlTextReaderGetAttribute(reader, (const xmlChar*) "ID"); if (groupId != NULL) { crtGroupId = std::string((const char*) groupId); xmlFree((xmlChar *) groupId); } else crtGroupId = ""; } else crtGroupId = ""; } if ((parsingTable == true) && (tagName == "PARAM")) { // parsing param is set when we are on the start element only, // this will prevent problems if PARAM tag ends width /> parsingParam = (xmlTextReaderNodeType(reader) == 1); if (parsingParam == true) { // Create e new param Info boost::shared_ptr paramInfo(new ParamInfo); paramName = xmlTextReaderGetAttribute(reader, (const xmlChar*) "name"); paramSize = xmlTextReaderGetAttribute(reader, (const xmlChar*) "arraysize"); paramValue = xmlTextReaderGetAttribute(reader, (const xmlChar*) "value"); paramInfo->setGroupId(crtGroupId); if (paramName != NULL) { paramInfo->setName((const char *) paramName); xmlFree((xmlChar *) paramName); } if (paramSize != NULL) { paramInfo->setSize((const char *) paramSize); xmlFree((xmlChar *) paramSize); } if (paramValue != NULL) { paramInfo->setValue((const char *) paramValue); xmlFree((xmlChar *) paramValue); } LOG4CXX_INFO(gLogger, "PARAM : " << tagName << ", GROUP ID = " << paramInfo->getGroupId() << ", name = " << paramInfo->getName() << ", arraysize = " << paramInfo->getSize() << ", value = " << paramInfo->getValue()); _paramsInfo.push_back(paramInfo); } } if ((parsingTable == true) && (tagName == "FIELD")) { // parsing field is set when we are on the start element only, // this will prevent problems if FIELD tag ends width /> parsingField = (xmlTextReaderNodeType(reader) == 1); if (parsingField == true) { // Create e new field Info boost::shared_ptr fieldInfo(new FieldInfo); fieldId = xmlTextReaderGetAttribute(reader, (const xmlChar*) "ID"); fieldName = xmlTextReaderGetAttribute(reader, (const xmlChar*) "name"); fieldXType = xmlTextReaderGetAttribute(reader, (const xmlChar*) "xtype"); fieldArraySize = xmlTextReaderGetAttribute(reader, (const xmlChar*) "arraysize"); fieldDataType = xmlTextReaderGetAttribute(reader, (const xmlChar*) "datatype"); fieldUCD = xmlTextReaderGetAttribute(reader, (const xmlChar*) "ucd"); fieldUnit = xmlTextReaderGetAttribute(reader, (const xmlChar*) "unit"); if (fieldId != NULL) { fieldInfo->setId((const char *) fieldId); xmlFree((xmlChar *) fieldId); } else { std::string autoId = "col"; autoId += std::to_string(fieldIndex+1); fieldInfo->setId(autoId.c_str()); } if (fieldName != NULL) { fieldInfo->setName((const char *) fieldName); xmlFree((xmlChar *) fieldName); } if (fieldXType != NULL) { fieldInfo->setXtype((const char *) fieldXType); xmlFree((xmlChar *) fieldXType); } if (fieldArraySize != NULL) { fieldInfo->setSize((const char *) fieldArraySize); xmlFree((xmlChar *) fieldArraySize); } if (fieldDataType != NULL) { fieldInfo->setType((const char *) fieldDataType); xmlFree((xmlChar *) fieldDataType); } if (fieldUCD != NULL) { fieldInfo->setUCD((const char *) fieldUCD); xmlFree((xmlChar *) fieldUCD); } if (fieldUnit != NULL) { fieldInfo->setUnit((const char *) fieldUnit); xmlFree((xmlChar *) fieldUnit); } LOG4CXX_INFO(gLogger, "FIELD : " << tagName << ", ID = " << fieldInfo->getId() << ", name = " << fieldInfo->getName() << ", xtype = " << fieldInfo->getXtype() << ", arraysize = " << fieldInfo->getSize() << ", datatype = " << fieldInfo->getType() << ", UCD ) " << fieldInfo->getUCD() << ", unit = " << fieldInfo->getUnit()); _fieldsInfo.push_back(fieldInfo); ++fieldIndex; } } // Stop reading fields informations when data starts if (tagName == "TABLEDATA") break; } } xmlFreeTextReader(reader); } /** * Retrieve TR line position in the VOTable file where time >= timeStart */ int FileReaderVOTable::getStartTimePos(int timeColumn, double timeStart) { bool parsingTableData = false; bool parsingTR = false; bool parsingTD = false; int curTR = -1; int curTD = -1; // created XML reader xmlTextReaderPtr reader = xmlReaderForFile(_votFilePath.c_str(), NULL, 0); // read xml file tag by tag while (xmlTextReaderRead(reader) == 1) { // -- read tag const xmlChar *name = xmlTextReaderConstName(reader); if (name != NULL) { // get tag name to easily handle it std::string tagName = std::string((const char*) name); if (tagName == "TABLEDATA") { parsingTableData = !parsingTableData; } // Detect start TR element if ((parsingTableData == true) && (tagName == "TR")) { parsingTR = !parsingTR; // Increment TR count // Reset TD count if (parsingTR == true) { curTR++; curTD = -1; } } // Detect start TD element if ((parsingTR == true) && (tagName == "TD")) { parsingTD = !parsingTD; // Increment TD count if (parsingTD == true) curTD++; } // Detect TD #text element if ((parsingTD == true) && (tagName == "#text")) { const xmlChar *text = xmlTextReaderConstValue(reader); // Current TD correspond with timeColumn ? if (curTD == timeColumn) { // Convert ISO time double lineTime = TimeUtil::readTimeInIso((char *) text); // Current line time is >= requested time start ? if (lineTime >= timeStart) { xmlFreeTextReader(reader); return (curTR); } } } } } xmlFreeTextReader(reader); LOG4CXX_ERROR(gLogger, "FileReaderVOTable::getFieldsStartTimePos - Cannot get record index"); return (-1); } std::vector &FileReaderVOTable::split(const std::string &s, char delim, std::vector &elems) { std::stringstream ss(s); std::string item; while (std::getline(ss, item, delim)) { if (item.empty()) continue; elems.push_back(item); } return elems; } FileReaderStatus FileReaderVOTable::getParamPacketData(int timeColumn, int paramColumn, int recordIndex, double stopTime, LocalParamDataPacket *packet) { bool parsingTableData = false; bool parsingTR = false; bool parsingTD = false; int curTR = -1; int curTD = -1; double lineTime = 0; bool packetFull; std::string columnValues; // created XML reader xmlTextReaderPtr reader = xmlReaderForFile(_votFilePath.c_str(), NULL, 0); // read xml file tag by tag while (xmlTextReaderRead(reader) == 1) { // -- read tag const xmlChar *name = xmlTextReaderConstName(reader); if (name != NULL) { // get tag name to easily handle it std::string tagName = std::string((const char*) name); if (tagName == "TABLEDATA") { parsingTableData = !parsingTableData; } // Detect start TR element if ((parsingTableData == true) && (tagName == "TR")) { parsingTR = !parsingTR; // Increment TR count // Reset TD count if (parsingTR == true) { curTR++; curTD = -1; } // Detect the end of a TR element ? // If so, and current time is not 0, write packet if ((parsingTR == false) && (lineTime != 0)) { std::vector paramList; split (columnValues, ' ', paramList); if (((int) paramList.size()) == packet->getDimsSize()) { // Extract values on the line depending on their type for (int p=0;p<(int) paramList.size(); p++) { if (packet->getType() == TYPE_FLOAT) _dataFloat[p] = std::stof(paramList.at(p)); else if (packet->getType() == TYPE_DOUBLE) _dataDouble[p] = std::stod(paramList.at(p)); else if (packet->getType() == TYPE_SHORT) _dataShort[p] = (short) std::stof(paramList.at(p)); else if (packet->getType() == TYPE_INT) _dataInt[p] = (int) std::stoi(paramList.at(p)); } } else { LOG4CXX_ERROR(gLogger, "FileReaderASCII::getParamPacketData - Wrong dimension for parameter"); xmlFreeTextReader(reader); return FRS_ERROR; } //add data record in the packet if (!packet->addData(lineTime, _data, packetFull)) { if (packetFull) { xmlFreeTextReader(reader); return FRS_MORE; } LOG4CXX_ERROR(gLogger, "FileReaderASCII::getParamPacketData - Error to add data in packet"); xmlFreeTextReader(reader); return FRS_ERROR; } } } // Detect start TD element if ((parsingTR == true) && (tagName == "TD")) { parsingTD = !parsingTD; // Increment TD count if (parsingTD == true) curTD++; } // Wait for recordIndex TR to start extraction if (curTR < recordIndex) continue; // time for the current line is greater than stopTime // we have finished ! if (lineTime > stopTime) { xmlFreeTextReader(reader); return FRS_FINISH; } // Detect TD #text element if ((parsingTD == true) && (tagName == "#text")) { const xmlChar *text = xmlTextReaderConstValue(reader); // Current TD correspond with timeColumn ? // Yes record current time if (curTD == timeColumn) { lineTime = TimeUtil::readTimeInIso((char *) text); } // Current TD correspond with parameter columns ? // Yes record them if (curTD == paramColumn) { columnValues = std::string((const char *) text); } } } } xmlFreeTextReader(reader); return FRS_EOF; } bool FileReaderVOTable::open(std::string filePath) { // Store votTable filePath _votFilePath = filePath; return (boost::filesystem::exists(filePath)); } bool FileReaderVOTable::close(void) { return (true); } bool FileReaderVOTable::isOpened(void) { return (false); } std::string FileReaderVOTable::getTimeParamId(void) { LOG4CXX_DEBUG(gLogger, "FileReaderVOTable::getTimeParamId"); // Read fields informations from the VOTable file getVOTableInfo(); for (auto fieldInfo : _fieldsInfo) { if ((fieldInfo->getXtype() == "dateTime") || ((fieldInfo->getUCD() == "TIME") && (fieldInfo->getUnit() == "iso-8601"))) { if (fieldInfo->getId().empty() == false) return fieldInfo->getId(); else return fieldInfo->getName(); } } // Time parameter id is always at the first position in text files return std::string(""); } bool FileReaderVOTable::getParamInfo(std::string& paramId, LocalParamType& paramType, int& dim1Size, int& dim2Size) { LOG4CXX_DEBUG(gLogger, "FileReaderVOTable::getParamInfo"); // Read fields informations from the VOTable file getVOTableInfo(); for (auto fieldInfo : _fieldsInfo) { // if Id is set check for corresponding paramId with Id, otherwise, use Name if ((fieldInfo->getId() == paramId) || (fieldInfo->getName() == paramId)) { if (fieldInfo->getType() == "float") paramType = LocalParamType::TYPE_FLOAT; else if (fieldInfo->getType() == "double") paramType = LocalParamType::TYPE_DOUBLE; else if (fieldInfo->getType() == "short") paramType = LocalParamType::TYPE_SHORT; else if (fieldInfo->getType() == "int") paramType = LocalParamType::TYPE_INT; else // If field (data)type is not supported, suppose it's double paramType = LocalParamType::TYPE_DOUBLE; std::vector dims; boost::split(dims, fieldInfo->getSize(), boost::is_any_of("*")); if (dims.empty()) { dim1Size = 1; dim2Size = 1; } else if (dims.size() == 1) { dim1Size = std::stoi(dims[0]); dim2Size = 1; } else if (dims.size() == 2) { dim1Size = std::stoi(dims[0]); dim2Size = std::stoi(dims[1]); } else { LOG4CXX_ERROR(gLogger, "FileReaderVOTable::getParamInfo - Unknown dimensions"); return false; } return true; } } // Parameter types and size can't be determined by the reader return false; } int FileReaderVOTable::getRecordIndex(std::string& timeId, double time) { LOG4CXX_DEBUG(gLogger, "FileReaderVOTable::getRecordIndex"); // Read fields informations from the VOTable file getVOTableInfo(); int timeColumn = -1; for (int f = 0; f < (int) _fieldsInfo.size(); f++) { if ((_fieldsInfo.at(f)->getId() == timeId) || (_fieldsInfo.at(f)->getName() == timeId)) { timeColumn = f; } } if (timeColumn != -1) return getStartTimePos(timeColumn, time); else { LOG4CXX_ERROR(gLogger, "FileReaderVOTable::getRecordIndex - timeColumn was not found : " << timeId); return -1; } } FileReaderStatus FileReaderVOTable::getParamPacketData(std::string& timeId, std::string& paramId, int recordIndex, double stopTime, LocalParamDataPacket *packet) { LOG4CXX_DEBUG(gLogger, "FileReaderVOTable::getParamPacketData"); // Read fields informations from the VOTable file getVOTableInfo(); int timeColumn = -1; for (int f = 0; f < (int) _fieldsInfo.size(); f++) { if ((_fieldsInfo.at(f)->getId() == timeId) || (_fieldsInfo.at(f)->getName() == timeId)) { timeColumn = f; } } if (timeColumn == -1) { LOG4CXX_ERROR(gLogger, "FileReaderVOTable::getParamPacketData - timeColumn was not found : " << timeId); return FRS_ERROR; } int paramColumn = -1; for (int f = 0; f < (int) _fieldsInfo.size(); f++) { if ((_fieldsInfo.at(f)->getId() == paramId) || (_fieldsInfo.at(f)->getName() == paramId)) { paramColumn = f; } } // Prepare buffers used by packet->addData if ((packet->getType() != TYPE_FLOAT) && (packet->getType() != TYPE_DOUBLE) && (packet->getType() != TYPE_SHORT) && (packet->getType() != TYPE_INT)) { LOG4CXX_ERROR(gLogger, "FileReaderVOTable::getParamPacketData - Not supported packet type"); return FRS_ERROR; } _dataFloat = NULL; _dataDouble = NULL; _dataShort = NULL; _dataInt = NULL; if (packet->getType() == TYPE_FLOAT) { _dataFloat = new float[packet->getDimsSize()]; _data = _dataFloat; } else if (packet->getType() == TYPE_DOUBLE) { _dataDouble = new double[packet->getDimsSize()]; _data = _dataDouble; } else if (packet->getType() == TYPE_SHORT) { _dataShort = new short[packet->getDimsSize()]; _data = _dataShort; } else if (packet->getType() == TYPE_INT) { _dataInt = new int[packet->getDimsSize()]; _data = _dataInt; } // Get values from VOTable file by parsint it FileReaderStatus ret = getParamPacketData(timeColumn, paramColumn, recordIndex, stopTime, packet); delete[] _dataFloat; delete[] _dataDouble; delete[] _dataShort; delete[] _dataInt; return ret; } /* * @brief Get an information */ bool FileReaderVOTable::getInfo(const char* pInfoName, std::vector& res) { res.clear(); // Read fields and params informations from the VOTable file getVOTableInfo(); for (auto paramInfo : _paramsInfo) { if (strcmp(paramInfo->getName().c_str(), pInfoName) == 0) { std::vector valueList; split (paramInfo->getValue(), ' ', valueList); for (auto val : valueList) { res.push_back(std::stof(val)); } return true; } } return false; } } /* LocalFileInterface */ } /* AMDA */