PhoenixProtocolBuffer  1.0.1
Set of tools to decode offset from protocol buffer
Loading...
Searching...
No Matches
FieldParser.cpp
Go to the documentation of this file.
1/***************************************
2 Auteur : Pierre Aubert
3 Mail : pierre.aubert@lapp.in2p3.fr
4 Licence : CeCILL-C
5****************************************/
6
7
8#include <string.h>
9#include "phoenix_varint.h"
10
11#include "FieldParser.h"
12
13
18
23
25
29FieldParser * FieldParser::addSubMessage(size_t fieldId, const PString & fieldName){
30 FieldParser* parser = createSubFieldParser(fieldId, fieldName);
32 p_vecChildren.push_back(parser);
33 return parser;
34}
35
37
41 if(!checkInputType(FieldType::SUBMESSAGE, field)){return NULL;}
42 return addSubMessage(field.getId(), field.getName());
43}
44
46
50FieldParser * FieldParser::addSubMessage(const FieldConfig & field, const PString & childName){
51 const std::map<PString, FieldConfig> & mapChildren = field.getVecChildren();
52 std::map<PString, FieldConfig>::const_iterator itFind = mapChildren.find(childName);
53 if(itFind != mapChildren.end()){
54 return addSubMessage(itFind->second);
55 }else{
56 std::cerr << "FieldParser::addSubMessage : FieldConfig has no child named '"<<childName<<"'" << std::endl;
57 return NULL;
58 }
59}
60
62
67FieldParser * FieldParser::addSubMessage(FieldConfig & childConfig, const FieldConfig & field, const PString & childName){
68 const std::map<PString, FieldConfig> & mapChildren = field.getVecChildren();
69 std::map<PString, FieldConfig>::const_iterator itFind = mapChildren.find(childName);
70 if(itFind != mapChildren.end()){
71 childConfig = itFind->second;
72 return addSubMessage(itFind->second);
73 }else{
74 std::cerr << "FieldParser::addSubMessage : FieldConfig has no child named '"<<childName<<"'" << std::endl;
75 return NULL;
76 }
77}
78
80
85void FieldParser::addParseFieldEnum(size_t* varPtr, size_t fieldId, const PString & fieldName){
86 FieldParser* parser = createSubFieldParser(fieldId, fieldName);
88 parser->p_field.setNbElement(0lu);
89 parser->p_field.setTypeSize(sizeof(size_t));
90 parser->p_field.setVarPtr(varPtr);
91 parser->p_field.setIsArray(false);
92 parser->p_field.setOffset(0lu);
93 parser->p_field.setIsOffsetReady(false);
94 p_vecChildren.push_back(parser);
95}
96
98
102bool FieldParser::addParseFieldEnum(size_t* varPtr, const FieldConfig & field){
103 if(!checkInputType(FieldType::ENUM_TYPE, field)){return false;}
104 addParseFieldEnum(varPtr, field.getId(), field.getName());
105 return true;
106}
107
109
114bool FieldParser::addParseFieldEnum(size_t* varPtr, const FieldConfig & field, const PString & childName){
115 const std::map<PString, FieldConfig> & mapChildren = field.getVecChildren();
116 std::map<PString, FieldConfig>::const_iterator itFind = mapChildren.find(childName);
117 if(itFind != mapChildren.end()){
118 return addParseFieldEnum(varPtr, itFind->second);
119 }else{
120 std::cerr << "FieldParser::addParseFieldEnum : FieldConfig has no child named '"<<childName<<"'" << std::endl;
121 return false;
122 }
123}
124
126
130bool FieldParser::load(const std::vector<char> & message, std::ostream & out){
131 return load(message.data(), message.size(), out);
132}
133
135
140bool FieldParser::load(const char * message, size_t nbByte, std::ostream & out){
141 char* iter = (char*)message;
142 const char* endMessage = message + nbByte;
143 if(!p_field.getIsOffsetReady()){ //If we do not have the offsets, we commute them
144 return loadComputeOffset(iter, endMessage, message, out);
145 }else{ //If we have the offset, we use them directly
146 return loadFromOffset(iter);
147 }
148}
149
152 p_field.setOffset(0lu);
153 p_field.setIsOffsetReady(false);
154 for(VecFieldParser::iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
155 (*it)->resetOffset();
156 }
157}
158
161 for(VecFieldParser::iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
162 delete (*it);
163 }
164 p_vecChildren.clear();
165}
166
168
171void FieldParser::print(std::ostream & out, const PString & indentation) const{
172 if(p_vecChildren.size() != 0lu){
173 out << indentation << "Field";
174
175 if(p_field.getId() != 0lu){
176 out << "(Id = " << p_field.getId();
177 if(p_field.getName() != ""){
178 out << ", '" << p_field.getName() << "'";
179 }
180 if(p_field.getIsOffsetReady()){
181 out << ", offset = " << p_field.getOffset();
182 }else{
183 out << ", NOT_RESOLVED";
184 }
185 out << ")";
186 }
187 out << "{" << std::endl;
188 for(VecFieldParser::const_iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
189 (*it)->print(out, indentation + "\t");
190 }
191 out << indentation << "}" << std::endl;
192 }else{
193 out << indentation << "Field(Id = " << p_field.getId();
194 if(p_field.getName() != ""){
195 out << ", '"<<p_field.getName()<<"'";
196 }
197 if(p_field.getIsOffsetReady()){
198 out << ", offset = " << p_field.getOffset();
199 }else{
200 out << ", NOT_RESOLVED";
201 }
202 if(p_field.getIsArray()){
203 out << ", arrayPtr = " << p_field.getArrayPtr() << ", sizePtr = " << p_field.getNbElement();
204 }else{
205 out << ", varPtr = " << p_field.getVarPtr();
206 }
207 out << ")" << std::endl;
208 }
209}
210
215
217
221FieldParser * FieldParser::createSubFieldParser(size_t fieldId, const PString & fieldName){
222 FieldParser* parser = new FieldParser;
223 parser->setBaseField(fieldId, fieldName);
224 return parser;
225}
226
228
231void FieldParser::setBaseField(size_t fieldId, const PString & fieldName){
232 p_field.setId(fieldId);
233 p_field.setName(fieldName);
234}
235
237
242 if(type != field.getType()){
243 std::cerr << "checkInputType : cannot add field '"<<field.getName()<<"' wrong type " << phoenix_fieldTypeToStr(type) << " of variables, expected type " << phoenix_fieldTypeToStr(field.getType()) << std::endl;
244 return false;
245 }
246 return true;
247}
248
250
256bool FieldParser::loadComputeOffset(char* & iter, const char* endMessage, const char * message, std::ostream & out){
257 //We have to read the message from begining to end and each time we find a Field, we have to check if we want to read this particular field
258 MapFieldParser mapFieldParser;
259 createMapFieldParser(mapFieldParser);
260
261 //Then, we have to call the parseField to get the type and id of the current field
262 do{
263 size_t fieldId(0lu), fieldType(0lu);
264 phoenix_field(fieldId, fieldType, iter);
265 MapFieldParser::iterator itFind = mapFieldParser.find(fieldId);
266 if(itFind != mapFieldParser.end()){ //The field has to be read
267 if((*itFind).second->loadComputeFieldOffset(iter, endMessage, message, fieldId, fieldType, out)){
268 mapFieldParser.erase(itFind); //The parsing it OK, so we can remove the FieldParser from the mapFieldParser
269 }else{ //Error when parsing the field
270 out << "FieldParser::loadComputeOffset : error when parsing field " << fieldId << " of type " << phoenix_fieldTypeToStr(phoenix_pbTypeToFieldType(fieldType)) << std::endl;
271 return false;
272 }
273 }else{ //The field has to be skipped
274 if(iter < endMessage){
275 phoenix_fieldSkip(iter, fieldType);
276 }
277 }
278 }while(iter < endMessage && mapFieldParser.size() != 0lu);
279
280 //When the field is parsed successfully, we can compute the offset and remove it from the mapFieldParser
281
282 //Check if all fields were parsed successfully (we can just check if mapFieldParser.size() == 0lu)
283 bool b(mapFieldParser.size() == 0lu);
284 p_field.setIsOffsetReady(b);
285 //Then we can print the unresolved Fields by iterating the mapFieldParser
286 if(!b){
287 out << "FieldParser::loadComputeOffset : there are "<<mapFieldParser.size()<<" unresolved Fields in '"<<p_field.getName()<<"', id = "<<p_field.getId()<<" (those without offset) :" << std::endl;
288 print(out);
289 }
290 return b;
291}
292
294
302bool FieldParser::loadComputeFieldOffset(char* & iter, const char* endMessage, const char * message, size_t fieldId, size_t fieldType, std::ostream & out){
303 bool b(false);
304 switch(fieldType){
305 case 0lu: //This is an enum, and its value is in a varint
306 p_field.setOffset((const char*)iter - message);
307 *((size_t*)p_field.getVarPtr()) = phoenix_readVarInt(iter);
308 b = true;
309 break;
310 case 1lu: //This is a uint64_t
311 case 5lu: //This is a uint32_t
312 p_field.setOffset((const char*)iter - message);
313 memcpy(p_field.getVarPtr(), iter, p_field.getTypeSize());
314 iter += p_field.getTypeSize();
315 b = true;
316 break;
317 case 2lu: //This is a binary array, which starts by a varint
318 //It can be a sub message
319 b = loadComputeFieldOffsetArray(iter, endMessage, message, out);
320 break;
321 default:
322 b = false;
323 out << "FieldParser::loadComputeFieldOffset : unknown type of Field " << fieldId << std::endl;
324 break;
325 }
326 p_field.setIsOffsetReady(b);
327 return b;
328}
329
331
337bool FieldParser::loadComputeFieldOffsetArray(char* & iter, const char* endMessage, const char * message, std::ostream & out){
338 size_t nbByte = phoenix_readVarInt(iter);
339 if(nbByte == 0lu){return true;} //Whatever it is, this it empty
340 bool b(true);
341 if(p_field.getType() == FieldType::SUBMESSAGE){ //If this is a sub message, we parse it
342 //We have to load the sub message
343 b &= loadComputeOffset(iter, iter + nbByte, message, out);
344 if(!b){
345 out << "FieldParser::loadComputeFieldOffsetArray : cannot parse submessage at offset " << ((const char*)iter - message) << std::endl;
346 }
347 }else{ //If it is not a sub message, we skip it
348 *p_field.getNbElement() = nbByte/p_field.getTypeSize(); //Let's compute the number of element in the array
349 p_field.setOffset((const char*)iter - message);
350 *p_field.getArrayPtr() = (void*)iter;
351 iter += nbByte;
352 p_field.setIsOffsetReady(true);
353 }
354 return b;
355}
356
358
361 for(VecFieldParser::iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
362 mapFieldParser[(*it)->p_field.getId()] = (*it);
363 }
364}
365
367
371 bool b(true);
372 if(p_vecChildren.size() != 0lu){
373 for(VecFieldParser::iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
374 b &= (*it)->loadFromOffset(iter);
375 }
376 }else{
377 b &= loadFieldFromOffset(iter);
378 }
379 return b;
380}
381
383
387 if(p_field.getIsArray()){
388 (*p_field.getArrayPtr()) = (void*)(iter + p_field.getOffset()); //We just set the address of the array with respect to the offset
389 }else{
390 if(p_field.getType() == FieldType::ENUM_TYPE){
391 char * tmp = iter + p_field.getOffset();
392 *((size_t*)p_field.getVarPtr()) = phoenix_readVarInt(tmp);
393 }else{
394 memcpy(p_field.getVarPtr(), iter + p_field.getOffset(), p_field.getTypeSize()); //We copy the Field value into the variable pointer
395 }
396 }
397 return true;
398}
399
400
std::map< size_t, FieldParser * > MapFieldParser
Definition FieldParser.h:16
std::string phoenix_fieldTypeToStr(FieldType::FieldType type)
Convert a FieldType into a string.
Definition FieldType.cpp:99
FieldType::FieldType phoenix_pbTypeToFieldType(size_t fieldType)
Convert a FIeld Type from protocol buffer to FieldType.
void setType(const FieldType::FieldType &type)
Sets the type of the AbtractField.
void setVarPtr(void *varPtr)
Sets the varPtr of the AbtractField.
void setIsOffsetReady(bool isOffsetReady)
Sets the isOffsetReady of the AbtractField.
void setNbElement(size_t *nbElement)
Sets the nbElement of the AbtractField.
void setIsArray(bool isArray)
Sets the isArray of the AbtractField.
void setOffset(size_t offset)
Sets the offset of the AbtractField.
void setTypeSize(size_t typeSize)
Sets the typeSize of the AbtractField.
Configuration to be used to create a field from a yml file.
const PString & getName() const
Gets the name of the FieldConfig.
size_t getId() const
Gets the id of the FieldConfig.
const FieldType::FieldType & getType() const
Gets the type of the FieldConfig.
const std::map< PString, FieldConfig > & getVecChildren() const
Gets the vecChildren of the FieldConfig.
void resetOffset()
Reset the offset of the FieldParser.
void createMapFieldParser(MapFieldParser &mapFieldParser)
Create the map of Field parser.
AbtractField p_field
Field to be parsed.
Definition FieldParser.h:69
void print(std::ostream &out=std::cout, const PString &indentation="") const
Print the FieldParser.
void setBaseField(size_t fieldId, const PString &fieldName)
Set the basis of a Field to be parsed.
bool checkInputType(const FieldConfig &field)
Check the template type with the FieldConfig.
virtual ~FieldParser()
Destructor of FieldParser.
bool load(const std::vector< char > &message, std::ostream &out=std::cerr)
Load the Fields of the FieldParser (without offset on the first time and with offsets after)
bool loadComputeFieldOffset(char *&iter, const char *endMessage, const char *message, size_t fieldId, size_t fieldType, std::ostream &out)
Compute FIeld offset.
void clear()
Clear all the children of the FieldParser.
FieldParser * addSubMessage(size_t fieldId, const PString &fieldName="")
Add a sub message into the FieldParser.
bool loadFromOffset(char *&iter)
Load the Fields directly from the offset.
void addParseFieldEnum(size_t *varPtr, size_t fieldId, const PString &fieldName="")
Add a sub FieldParser for a enum type.
bool loadComputeFieldOffsetArray(char *&iter, const char *endMessage, const char *message, std::ostream &out)
Compute FIeld offset of an array.
void initialisationFieldParser()
Initialisation function of the class FieldParser.
bool loadComputeOffset(char *&iter, const char *endMessage, const char *message, std::ostream &out)
Load the Fields and compute the offset.
FieldParser()
Default constructor of FieldParser.
bool loadFieldFromOffset(char *&iter)
Load the Field directly from the offset.
VecFieldParser p_vecChildren
Children used to parse other field and sub messages.
Definition FieldParser.h:71
FieldParser * createSubFieldParser(size_t fieldId, const PString &fieldName)
Add a sub FieldParser.
FieldType
Type of the Field.
Definition FieldType.h:14
void phoenix_field(size_t &fieldId, size_t &fieldType, char *&iter)
Reads a Field header.
void phoenix_fieldSkip(char *&iter, size_t fieldType)
Skip the current field.
size_t phoenix_readVarInt(char *&iter)
Reads and print a varint from protocol buffer.