/*************************************************************************** PacketStream.cpp - description ------------------- begin : Thu Nov 29 2001 copyright : (C) 2001, 2013 by Andrea Bulgarelli email : bulgarelli@iasfbo.inaf.it ***************************************************************************/ /*************************************************************************** * * * This program is free software for non commercial purpose * * and for public research institutes; you can redistribute it and/or * * modify it under the terms of the GNU General Public License. * * For commercial purpose see appropriate license terms * * * ***************************************************************************/ #include "PacketStream.h" #include "ConfigurationFile.h" #include "PacketExceptionFileFormat.h" #include "PacketExceptionIO.h" #include "PacketNotRecognized.h" #include "PacketLibDemo.h" #include <sstream> using namespace PacketLib; PacketStream::PacketStream(string fileNameConfig) { filenameConfig = realpath(fileNameConfig.c_str(), NULL); numberOfPacketType = 0; headerReference = 0; //TODO packetType = new Packet* [255]; //TODO memset(packetType, 0, sizeof(Packet*)*255); pathFileNameConfig = 0; dimHeader = 0; std::cout << "Loading config file " << filenameConfig << " ..." << std::endl; createStreamStructure(); std::cout << "Load complete." << std::endl; } PacketStream::PacketStream() : filenameConfig("") { numberOfPacketType = 0; headerReference = 0; //TODO packetType = new Packet* [255]; //TODO memset(packetType, 0, sizeof(Packet*)*255); pathFileNameConfig = 0; dimHeader = 0; } PacketStream::~PacketStream() { for(int i=0; i< numberOfPacketType; i++) delete packetType[i]; delete[] packetType; delete headerReference; free(pathFileNameConfig); } dword PacketStream::getPacketDimension(ByteStreamPtr stream) { dword dimPre = 0; if(prefix) dimPre += dimPrefix; //ByteStreamPtr prefix = new ByteStream(stream, dimPre, bigendian); dword dim = 0; dword dimHeader = headerReference->size(); dim += dimHeader; ByteStreamPtr tempHeader = ByteStreamPtr(new ByteStream()); tempHeader->setStream(stream->stream+dimPre, dimHeader, bigendian); headerReference->setByteStream(tempHeader); dim += headerReference->getPacketLength(); return dim; } int PacketStream::detPacketType(ByteStreamPtr prefix, ByteStreamPtr packetHeader, ByteStreamPtr packetDataField) { /// Iterate through list and output each element. /// The packetType 0 is the packet not recognized for (int i = 1; i<numberOfPacketType; i++) { Packet* p = getPacketType(i); p->decode(prefix, packetHeader, packetDataField); if(p->verify()) return i; } return 0; } int PacketStream::detPacketType(ByteStreamPtr prefix, ByteStreamPtr packet) { /// Iterate through list and output each element. /// The packetType 0 is the packet not recognized for (dword i = 1; i<numberOfPacketType; i++) { Packet* p = getPacketType(i); p->decode(prefix, packet); if(p->verify()) return i; } return 0; } int PacketStream::detPacketType(ByteStreamPtr packet) { /// Iterate through list and output each element. /// The packetType 0 is the packet not recognized for (dword i = 1; i<numberOfPacketType; i++) { Packet* p = getPacketType(i); p->decode(packet); if(p->verify()) return i; } return 0; } Packet* PacketStream::getPacket(ByteStreamPtr stream) throw(PacketException*){ int index = detPacketType(stream); if(index > 0) { Packet* p = getPacketType(index); if(!p->decode(stream)) //gli stream diventano del packet throw new PacketExceptionIO("it is impossible to resolve the packet."); return p; } else return 0; } const std::string fixed32[] = { "uint32", "int32", "float" }; const std::string fixed64[] = { "uint64", "int64", "double" }; void PacketStream::cachePhysicalIndexes(pugi::xml_node node, std::map<pugi::xml_node, int>& physicalIndex) { int index = 0; for(pugi::xml_node_iterator it=node.begin(); it != node.end(); ++it) { if(string(it->name()).compare("field") != 0) continue; #ifdef DEBUG std::cout << "Physical index of " << it->attribute("name").value() << " is " << index << std::endl; #endif physicalIndex[*it] = index; // if 32bits fields string typeStr = it->attribute("type").value(); bool found = false; for(unsigned int i=0; i<3; i++) { if(typeStr.compare(fixed32[i]) == 0) { index+=2; found = true; break; } } if(found) continue; // if 64bits fields for(unsigned int i=0; i<3; i++) { if(typeStr.compare(fixed64[i]) == 0) { index+=4; found = true; break; } } if(found) continue; // else (<= 16bits fields) index++; } } void PacketStream::createStreamStructureXml() { std::map<pugi::xml_node, int> physicalIndex; pugi::xml_document doc; // open the config file if (!doc.load_file(filenameConfig.c_str())) { std::stringstream ss; ss << "Cannot open " << filenameConfig; throw new PacketExceptionFileFormat(ss.str().c_str()); } // cache all the field physical indexes pugi::xpath_node_set fieldParents = doc.select_nodes("//*[field]"); for(pugi::xpath_node_set::const_iterator it = fieldParents.begin(); it != fieldParents.end(); ++it) cachePhysicalIndexes(it->node(), physicalIndex); // get the stream node pugi::xml_node sNode = doc.child("stream"); if(!sNode) throw new PacketExceptionFileFormat("<stream> not found."); if(pathFileNameConfig) free(pathFileNameConfig); pathFileNameConfig = getcwd(NULL, 512L); bigendian = false; pugi::xml_attribute beAttr = sNode.attribute("bigendian"); if(beAttr && strcmp(beAttr.value(), "true") == 0) bigendian = true; #ifdef DEBUG std::cout << "big endian? " << beAttr.value() << std::endl; #endif dimPrefix = 0; prefix = false; pugi::xml_attribute preAttr = sNode.attribute("prefixSize"); if(preAttr) { prefix = true; dimPrefix = atoi(preAttr.value()); } #ifdef DEBUG std::cout << "prefix size: " << dimPrefix << std::endl; #endif // get the header node pugi::xml_node hNode = sNode.child("header"); if(!hNode) throw new PacketExceptionFileFormat("<header> not found."); // get the packet length physical index std::string query = std::string("//field[@id=\"") + hNode.attribute("idref").value()+"\"]"; pugi::xml_node plNode = hNode.select_nodes(query.c_str())[0].node(); int plIndex = physicalIndex[plNode]; // get the packet length bit width std::string typeStr = plNode.attribute("type").value(); std::string::size_type spos = typeStr.find_first_of("0123456789"); std::string::size_type epos = typeStr.find_last_of("0123456789"); int nbits = atoi(typeStr.substr(spos, epos+1).c_str()); // load the header delete headerReference; headerReference = new PacketHeader(); headerReference->loadHeader(hNode, plIndex, nbits); dimHeader = headerReference->size(); // load the packet not recognized PacketNotRecognized* p = new PacketNotRecognized(bigendian); p->createPacketType(hNode, prefix, dimPrefix); packetType[numberOfPacketType] = p; numberOfPacketType++; // load packet types pugi::xml_node pNode = sNode.child("packet"); while(pNode) { if(pNode.attribute("name") != 0) { Packet* p = new Packet(bigendian); p->createPacketType(doc, hNode, plIndex, nbits, pNode, prefix, dimPrefix, physicalIndex); packetType[numberOfPacketType] = p; p->setPacketID(numberOfPacketType); numberOfPacketType++; } pNode = pNode.next_sibling(); } } bool PacketStream::createStreamStructure() throw(PacketException*) { if(filenameConfig.find(".xml") != std::string::npos) { createStreamStructureXml(); return true; } ConfigurationFile config; char* line; char **argv = new char* [1]; argv[0] = (char*) filenameConfig.c_str(); //cout << "@@@@@@@@@@OPEN " << filenameConfig << endl; try { if(config.open(argv)) { //delete[] argv; if(pathFileNameConfig) free(pathFileNameConfig); pathFileNameConfig = getcwd(NULL, 512L); /// prefix config.setpos(0); line = config.getLine(); if(strcmp(line, "[Configuration]") == 0) { //delete[] line; line = config.getLine(); if(strcmp(line, "false") == 0) prefix = false; else { if(strcmp(line, "true") == 0) prefix = true; else { //delete[] line; throw new PacketExceptionFileFormat("Prefix selector format not correct. It's possible only true or false value."); return false; } } //delete[] line; /// bigendian line = config.getLine(); if(strcmp(line, "false") == 0) bigendian = false; else { if(strcmp(line, "true") == 0) bigendian = true; else { throw new PacketExceptionFileFormat("Bigendian selector format not correct. It's possible only true or false value."); return false; } } /// dimensione of prefix //delete[] line; line = config.getLine(); if(prefix == false) dimPrefix = 0; else dimPrefix = atoi(line); } else throw new PacketExceptionFileFormat("No [Configuration] section found."); /// [Header Format] section //delete[] line; line = config.getLine(); if(strcmp(line, "[Header Format]") == 0) { //delete[] line; /// Create headerReference of PacketHeader type. The method reads the structure of header from configuration file (named in filenameConfig) line = config.getLine(); delete headerReference; headerReference = (PacketHeader*) new PacketHeader(); if(!headerReference->loadHeader(line)) { //delete[] line; throw new PacketExceptionFileFormat("No parameters in file header format"); return false; } dimHeader = headerReference->size(); /// It creates the PACKET NOT RECOGNIZED PacketNotRecognized* p = new PacketNotRecognized(bigendian); if(!p->createPacketType(line, prefix, dimPrefix)) { //delete[] line; throw new PacketExceptionFileFormat("Packet Not Recognized not created."); } else { packetType[numberOfPacketType] = p; numberOfPacketType++; } //delete[] line; } else { throw new PacketExceptionFileFormat("No [Header format] section"); return false; } /// [Packet Format] line = config.getLine(); if(strcmp(line, "[Packet Format]") == 0) { char* packetFileName = config.getLine(); while(strlen(packetFileName) != 0) { Packet* p; p = new Packet(bigendian); p->createPacketType(packetFileName, prefix, dimPrefix); packetType[numberOfPacketType] = p; p->setPacketID(numberOfPacketType); numberOfPacketType++; //delete[] packetFileName; packetFileName = config.getLine(); } } else { throw new PacketExceptionFileFormat("No [Packet Format] section"); return false; } config.close(); } else throw new PacketExceptionFileFormat("Header file configuration not found."); return true; } catch(PacketExceptionIO* e) { e->add(" - "); e->add(filenameConfig.c_str()); e->add("Configuration file: "); throw e; } catch(PacketExceptionFileFormat* e) { e->add(" - "); e->add(filenameConfig.c_str()); e->add("Configuration file: "); throw e; } } word PacketStream::getPrefixDimension() const { if(prefix) return dimPrefix; else return 0; } word PacketStream::getHeaderDimension() const { return dimHeader; } word PacketStream::getNumberOfPacketType() { return numberOfPacketType; } Packet* PacketStream::getPacketType(int index) { return packetType[index]; } Packet* PacketStream::getPacketType(string name) { for(int i=1; i<numberOfPacketType; i++) { string pname = packetType[i]->getName(); if(pname.compare(name) == 0) return packetType[i]; } throw new PacketException("Packet type not found in the PacketStream"); } bool PacketStream::isBigEndian() { return (bool) this->bigendian; } void PacketStream::setFileNameConfig(const char* f) { this->filenameConfig = (char*) f; //this->pathFileNameConfig = Utility::extractPath(filenameConfig); } bool PacketStream::thereIsPrefix() { return prefix; }