GCC Code Coverage Report


Directory: ./
File: src/FieldParser.cpp
Date: 2026-01-15 15:40:41
Exec Total Coverage
Lines: 166 188 88.3%
Functions: 24 25 96.0%
Branches: 96 155 61.9%

Line Branch Exec Source
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
14 ///Default constructor of FieldParser
15 49 FieldParser::FieldParser(){
16
1/1
✓ Branch 0 (4→5) taken 49 times.
49 initialisationFieldParser();
17 49 }
18
19 ///Destructor of FieldParser
20 93 FieldParser::~FieldParser(){
21 49 clear();
22 93 }
23
24 ///Add a sub message into the FieldParser
25 /** @param fieldId : id of the field that contain the sub message
26 * @param fieldName : name of the field
27 * @return pointer to the parser which will be used to parse the sub message
28 */
29 8 FieldParser * FieldParser::addSubMessage(size_t fieldId, const PString & fieldName){
30
1/1
✓ Branch 0 (2→3) taken 8 times.
8 FieldParser* parser = createSubFieldParser(fieldId, fieldName);
31
1/1
✓ Branch 0 (3→4) taken 8 times.
8 parser->p_field.setType(FieldType::SUBMESSAGE);
32
1/1
✓ Branch 0 (4→5) taken 8 times.
8 p_vecChildren.push_back(parser);
33 8 return parser;
34 }
35
36 ///Add a sub message into the FieldParser
37 /** @param field : description of the field
38 * @return pointer to the parser which will be used to parse the sub message, of NULL if the field is not coherent
39 */
40 4 FieldParser * FieldParser::addSubMessage(const FieldConfig & field){
41
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 4 times.
4 if(!checkInputType(FieldType::SUBMESSAGE, field)){return NULL;}
42 4 return addSubMessage(field.getId(), field.getName());
43 }
44
45 ///Add a sub message into the FieldParser
46 /** @param field : main description of the field
47 * @param childName : name of the child of the field to be used as description
48 * @return pointer to the parser which will be used to parse the sub message, of NULL if the field is not coherent
49 */
50 FieldParser * 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
61 ///Add a sub message into the FieldParser
62 /** @param childConfig : configuration of the child with name childName
63 * @param field : main description of the field
64 * @param childName : name of the child of the field to be used as description
65 * @return pointer to the parser which will be used to parse the sub message, of NULL if the field is not coherent
66 */
67 1 FieldParser * FieldParser::addSubMessage(FieldConfig & childConfig, const FieldConfig & field, const PString & childName){
68
1/1
✓ Branch 0 (2→3) taken 1 times.
1 const std::map<PString, FieldConfig> & mapChildren = field.getVecChildren();
69
1/1
✓ Branch 0 (3→4) taken 1 times.
1 std::map<PString, FieldConfig>::const_iterator itFind = mapChildren.find(childName);
70
1/2
✓ Branch 0 (6→7) taken 1 times.
✗ Branch 1 (6→12) not taken.
1 if(itFind != mapChildren.end()){
71
1/1
✓ Branch 0 (8→9) taken 1 times.
1 childConfig = itFind->second;
72
1/1
✓ Branch 0 (10→11) taken 1 times.
1 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
79 ///Add a sub FieldParser for a enum type
80 /** @param varPtr : pointer to the variable to be updated on the parsing of the protocol buffer message
81 * @param fieldId : id of the field that contain the sub message
82 * @param fieldName : name of the field
83 * @return pointer to the parser which will be used to parse the sub message
84 */
85 5 void FieldParser::addParseFieldEnum(size_t* varPtr, size_t fieldId, const PString & fieldName){
86
1/1
✓ Branch 0 (2→3) taken 5 times.
5 FieldParser* parser = createSubFieldParser(fieldId, fieldName);
87
1/1
✓ Branch 0 (3→4) taken 5 times.
5 parser->p_field.setType(FieldType::ENUM_TYPE);
88
1/1
✓ Branch 0 (4→5) taken 5 times.
5 parser->p_field.setNbElement(0lu);
89
1/1
✓ Branch 0 (5→6) taken 5 times.
5 parser->p_field.setTypeSize(sizeof(size_t));
90
1/1
✓ Branch 0 (6→7) taken 5 times.
5 parser->p_field.setVarPtr(varPtr);
91
1/1
✓ Branch 0 (7→8) taken 5 times.
5 parser->p_field.setIsArray(false);
92
1/1
✓ Branch 0 (8→9) taken 5 times.
5 parser->p_field.setOffset(0lu);
93
1/1
✓ Branch 0 (9→10) taken 5 times.
5 parser->p_field.setIsOffsetReady(false);
94
1/1
✓ Branch 0 (10→11) taken 5 times.
5 p_vecChildren.push_back(parser);
95 5 }
96
97 ///Add a sub FieldParser for a enum type
98 /** @param varPtr : pointer to the variable to be updated on the parsing of the protocol buffer message
99 * @param field : FieldConfig which describes the field
100 * @return pointer to the parser which will be used to parse the sub message
101 */
102 2 bool FieldParser::addParseFieldEnum(size_t* varPtr, const FieldConfig & field){
103
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 2 times.
2 if(!checkInputType(FieldType::ENUM_TYPE, field)){return false;}
104 2 addParseFieldEnum(varPtr, field.getId(), field.getName());
105 2 return true;
106 }
107
108 ///Add a sub FieldParser for a enum type
109 /** @param varPtr : pointer to the variable to be updated on the parsing of the protocol buffer message
110 * @param field : FieldConfig which describes the field
111 * @param childName : name of the child of the field to be used as description
112 * @return pointer to the parser which will be used to parse the sub message
113 */
114 1 bool FieldParser::addParseFieldEnum(size_t* varPtr, const FieldConfig & field, const PString & childName){
115
1/1
✓ Branch 0 (2→3) taken 1 times.
1 const std::map<PString, FieldConfig> & mapChildren = field.getVecChildren();
116
1/1
✓ Branch 0 (3→4) taken 1 times.
1 std::map<PString, FieldConfig>::const_iterator itFind = mapChildren.find(childName);
117
1/2
✓ Branch 0 (6→7) taken 1 times.
✗ Branch 1 (6→10) not taken.
1 if(itFind != mapChildren.end()){
118
1/1
✓ Branch 0 (8→9) taken 1 times.
1 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
125 ///Load the Fields of the FieldParser (without offset on the first time and with offsets after)
126 /** @param message : message to be parsed
127 * @param out : output stream to be used
128 * @return true on success, false otherwise
129 */
130 50 bool FieldParser::load(const std::vector<char> & message, std::ostream & out){
131 50 return load(message.data(), message.size(), out);
132 }
133
134 ///Load the Fields of the FieldParser (without offset on the first time and with offsets after)
135 /** @param message : message to be parsed
136 * @param nbByte : number of bytes of the message
137 * @param out : output stream to be used
138 * @return true on success, false otherwise
139 */
140 50 bool FieldParser::load(const char * message, size_t nbByte, std::ostream & out){
141 50 char* iter = (char*)message;
142 50 const char* endMessage = message + nbByte;
143
3/3
✓ Branch 0 (2→3) taken 50 times.
✓ Branch 2 (3→4) taken 5 times.
✓ Branch 3 (3→6) taken 45 times.
50 if(!p_field.getIsOffsetReady()){ //If we do not have the offsets, we commute them
144
1/1
✓ Branch 0 (4→5) taken 5 times.
5 return loadComputeOffset(iter, endMessage, message, out);
145 }else{ //If we have the offset, we use them directly
146
1/1
✓ Branch 0 (6→7) taken 45 times.
45 return loadFromOffset(iter);
147 }
148 }
149
150 ///Reset the offset of the FieldParser
151 36 void FieldParser::resetOffset(){
152 36 p_field.setOffset(0lu);
153 36 p_field.setIsOffsetReady(false);
154
2/2
✓ Branch 0 (18→5) taken 33 times.
✓ Branch 1 (18→19) taken 36 times.
138 for(VecFieldParser::iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
155
1/1
✓ Branch 0 (7→8) taken 33 times.
33 (*it)->resetOffset();
156 }
157 36 }
158
159 ///Clear all the children of the FieldParser
160 49 void FieldParser::clear(){
161
2/2
✓ Branch 0 (17→3) taken 44 times.
✓ Branch 1 (17→18) taken 49 times.
186 for(VecFieldParser::iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
162
1/2
✓ Branch 0 (5→6) taken 44 times.
✗ Branch 1 (5→7) not taken.
44 delete (*it);
163 }
164 49 p_vecChildren.clear();
165 49 }
166
167 ///Print the FieldParser
168 /** @param[out] out : output stream to be used to print FieldParser information
169 * @param indentation : indentatio to be used for the print
170 */
171 128 void FieldParser::print(std::ostream & out, const PString & indentation) const{
172
2/2
✓ Branch 0 (3→4) taken 33 times.
✓ Branch 1 (3→49) taken 95 times.
128 if(p_vecChildren.size() != 0lu){
173 33 out << indentation << "Field";
174
175
2/2
✓ Branch 0 (7→8) taken 22 times.
✓ Branch 1 (7→25) taken 11 times.
33 if(p_field.getId() != 0lu){
176 22 out << "(Id = " << p_field.getId();
177
1/2
✓ Branch 0 (13→14) taken 22 times.
✗ Branch 1 (13→18) not taken.
22 if(p_field.getName() != ""){
178 22 out << ", '" << p_field.getName() << "'";
179 }
180
2/2
✓ Branch 0 (19→20) taken 8 times.
✓ Branch 1 (19→23) taken 14 times.
22 if(p_field.getIsOffsetReady()){
181 8 out << ", offset = " << p_field.getOffset();
182 }else{
183 14 out << ", NOT_RESOLVED";
184 }
185 22 out << ")";
186 }
187 33 out << "{" << std::endl;
188
2/2
✓ Branch 0 (45→28) taken 117 times.
✓ Branch 1 (45→46) taken 33 times.
300 for(VecFieldParser::const_iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
189
3/3
✓ Branch 0 (30→31) taken 117 times.
✓ Branch 2 (31→32) taken 117 times.
✓ Branch 4 (32→33) taken 117 times.
117 (*it)->print(out, indentation + "\t");
190 }
191 33 out << indentation << "}" << std::endl;
192 }else{
193 95 out << indentation << "Field(Id = " << p_field.getId();
194
1/2
✓ Branch 0 (55→56) taken 95 times.
✗ Branch 1 (55→60) not taken.
95 if(p_field.getName() != ""){
195 95 out << ", '"<<p_field.getName()<<"'";
196 }
197
2/2
✓ Branch 0 (61→62) taken 34 times.
✓ Branch 1 (61→65) taken 61 times.
95 if(p_field.getIsOffsetReady()){
198 34 out << ", offset = " << p_field.getOffset();
199 }else{
200 61 out << ", NOT_RESOLVED";
201 }
202
2/2
✓ Branch 0 (67→68) taken 11 times.
✓ Branch 1 (67→74) taken 84 times.
95 if(p_field.getIsArray()){
203 11 out << ", arrayPtr = " << p_field.getArrayPtr() << ", sizePtr = " << p_field.getNbElement();
204 }else{
205 84 out << ", varPtr = " << p_field.getVarPtr();
206 }
207 95 out << ")" << std::endl;
208 }
209 128 }
210
211 ///Initialisation function of the class FieldParser
212 49 void FieldParser::initialisationFieldParser(){
213
214 49 }
215
216 ///Add a sub FieldParser
217 /** @param fieldId : id of the field that contain the sub message
218 * @param fieldName : name of the field
219 * @return pointer to the parser which will be used to parse sub Fields
220 */
221 44 FieldParser * FieldParser::createSubFieldParser(size_t fieldId, const PString & fieldName){
222
2/5
✓ Branch 0 (3→4) taken 44 times.
✗ Branch 2 (4→5) not taken.
✓ Branch 3 (4→6) taken 44 times.
✗ Branch 4 (9→10) not taken.
✗ Branch 5 (9→11) not taken.
44 FieldParser* parser = new FieldParser;
223 44 parser->setBaseField(fieldId, fieldName);
224 44 return parser;
225 }
226
227 ///Set the basis of a Field to be parsed
228 /** @param fieldId : id of the field that contain the sub message
229 * @param fieldName : name of the field
230 */
231 44 void FieldParser::setBaseField(size_t fieldId, const PString & fieldName){
232 44 p_field.setId(fieldId);
233 44 p_field.setName(fieldName);
234 44 }
235
236 ///Check if the type is compatible with the type in the FieldConfig
237 /** @param type : type to be checked
238 * @param field : configuration to be used
239 * @return true if the type is compatible with the field, false otherwise
240 */
241 22 bool FieldParser::checkInputType(FieldType::FieldType type, const FieldConfig & field){
242
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→18) taken 22 times.
22 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 22 return true;
247 }
248
249 ///Load the Fields and compute the offset
250 /** @param[out] iter : iterator over the message to be parsed
251 * @param endMessage : address of the end of the message
252 * @param message : message to be read
253 * @param out : ostream to be used
254 * @return true on success, false otherwise
255 */
256 13 bool 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 13 MapFieldParser mapFieldParser;
259
1/1
✓ Branch 0 (3→4) taken 13 times.
13 createMapFieldParser(mapFieldParser);
260
261 //Then, we have to call the parseField to get the type and id of the current field
262 do{
263 55 size_t fieldId(0lu), fieldType(0lu);
264
1/1
✓ Branch 0 (5→6) taken 55 times.
55 phoenix_field(fieldId, fieldType, iter);
265
1/1
✓ Branch 0 (6→7) taken 55 times.
55 MapFieldParser::iterator itFind = mapFieldParser.find(fieldId);
266
2/2
✓ Branch 0 (9→10) taken 44 times.
✓ Branch 1 (9→23) taken 11 times.
55 if(itFind != mapFieldParser.end()){ //The field has to be read
267
2/3
✓ Branch 0 (11→12) taken 44 times.
✓ Branch 2 (12→13) taken 44 times.
✗ Branch 3 (12→14) not taken.
44 if((*itFind).second->loadComputeFieldOffset(iter, endMessage, message, fieldId, fieldType, out)){
268
1/1
✓ Branch 0 (13→25) taken 44 times.
44 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
1/2
✓ Branch 0 (23→24) taken 11 times.
✗ Branch 1 (23→25) not taken.
11 if(iter < endMessage){
275
1/1
✓ Branch 0 (24→25) taken 11 times.
11 phoenix_fieldSkip(iter, fieldType);
276 }
277 }
278
6/6
✓ Branch 0 (26→27) taken 51 times.
✓ Branch 1 (26→30) taken 4 times.
✓ Branch 2 (28→29) taken 42 times.
✓ Branch 3 (28→30) taken 9 times.
✓ Branch 4 (31→32) taken 42 times.
✓ Branch 5 (31→33) taken 13 times.
55 }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 13 bool b(mapFieldParser.size() == 0lu);
284
1/1
✓ Branch 0 (34→35) taken 13 times.
13 p_field.setIsOffsetReady(b);
285 //Then we can print the unresolved Fields by iterating the mapFieldParser
286
1/2
✗ Branch 0 (35→36) not taken.
✓ Branch 1 (35→51) taken 13 times.
13 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 13 return b;
291 13 }
292
293 ///Compute FIeld offset
294 /** @param[out] iter : iterator on the message to be used
295 * @param endMessage : end of the message
296 * @param message : message to be read
297 * @param fieldId : id of the current field
298 * @param fieldType : type of the current field
299 * @param out : ostream to be used
300 * @return true on success, false otherwise
301 */
302 44 bool FieldParser::loadComputeFieldOffset(char* & iter, const char* endMessage, const char * message, size_t fieldId, size_t fieldType, std::ostream & out){
303 44 bool b(false);
304
3/4
✓ Branch 0 (2→3) taken 5 times.
✓ Branch 1 (2→7) taken 27 times.
✓ Branch 2 (2→12) taken 12 times.
✗ Branch 3 (2→14) not taken.
44 switch(fieldType){
305 5 case 0lu: //This is an enum, and its value is in a varint
306 5 p_field.setOffset((const char*)iter - message);
307 5 *((size_t*)p_field.getVarPtr()) = phoenix_readVarInt(iter);
308 5 b = true;
309 5 break;
310 27 case 1lu: //This is a uint64_t
311 case 5lu: //This is a uint32_t
312 27 p_field.setOffset((const char*)iter - message);
313 27 memcpy(p_field.getVarPtr(), iter, p_field.getTypeSize());
314 27 iter += p_field.getTypeSize();
315 27 b = true;
316 27 break;
317 12 case 2lu: //This is a binary array, which starts by a varint
318 //It can be a sub message
319 12 b = loadComputeFieldOffsetArray(iter, endMessage, message, out);
320 12 break;
321 default:
322 b = false;
323 out << "FieldParser::loadComputeFieldOffset : unknown type of Field " << fieldId << std::endl;
324 break;
325 }
326 44 p_field.setIsOffsetReady(b);
327 44 return b;
328 }
329
330 ///Compute FIeld offset of an array
331 /** @param[out] iter : iterator on the message to be used
332 * @param endMessage : end of the message
333 * @param message : message to be read
334 * @param out : ostream to be used
335 * @return true on success, false otherwise
336 */
337 12 bool FieldParser::loadComputeFieldOffsetArray(char* & iter, const char* endMessage, const char * message, std::ostream & out){
338 12 size_t nbByte = phoenix_readVarInt(iter);
339
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 12 times.
12 if(nbByte == 0lu){return true;} //Whatever it is, this it empty
340 12 bool b(true);
341
2/2
✓ Branch 0 (6→7) taken 8 times.
✓ Branch 1 (6→12) taken 4 times.
12 if(p_field.getType() == FieldType::SUBMESSAGE){ //If this is a sub message, we parse it
342 //We have to load the sub message
343 8 b &= loadComputeOffset(iter, iter + nbByte, message, out);
344
1/2
✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→17) taken 8 times.
8 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 4 *p_field.getNbElement() = nbByte/p_field.getTypeSize(); //Let's compute the number of element in the array
349 4 p_field.setOffset((const char*)iter - message);
350 4 *p_field.getArrayPtr() = (void*)iter;
351 4 iter += nbByte;
352 4 p_field.setIsOffsetReady(true);
353 }
354 12 return b;
355 }
356
357 ///Create the map of Field parser
358 /** @param[out] mapFieldParser : Map of FieldParser to be created
359 */
360 13 void FieldParser::createMapFieldParser(MapFieldParser & mapFieldParser){
361
2/2
✓ Branch 0 (19→3) taken 44 times.
✓ Branch 1 (19→20) taken 13 times.
114 for(VecFieldParser::iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
362
2/2
✓ Branch 0 (7→8) taken 44 times.
✓ Branch 2 (8→9) taken 44 times.
88 mapFieldParser[(*it)->p_field.getId()] = (*it);
363 }
364 13 }
365
366 ///Load the Fields directly from the offset
367 /** @param[out] iter : iterator over the message to be parsed
368 * @return true on success, false otherwise
369 */
370 441 bool FieldParser::loadFromOffset(char* & iter){
371 441 bool b(true);
372
2/2
✓ Branch 0 (3→4) taken 117 times.
✓ Branch 1 (3→20) taken 324 times.
441 if(p_vecChildren.size() != 0lu){
373
2/2
✓ Branch 0 (18→5) taken 396 times.
✓ Branch 1 (18→19) taken 117 times.
1026 for(VecFieldParser::iterator it(p_vecChildren.begin()); it != p_vecChildren.end(); ++it){
374
1/1
✓ Branch 0 (7→8) taken 396 times.
396 b &= (*it)->loadFromOffset(iter);
375 }
376 }else{
377 324 b &= loadFieldFromOffset(iter);
378 }
379 441 return b;
380 }
381
382 ///Load the Field directly from the offset
383 /** @param[out] iter : iterator over the message to be parsed
384 * @return true on success, false otherwise
385 */
386 324 bool FieldParser::loadFieldFromOffset(char* & iter){
387
2/2
✓ Branch 0 (3→4) taken 36 times.
✓ Branch 1 (3→7) taken 288 times.
324 if(p_field.getIsArray()){
388 36 (*p_field.getArrayPtr()) = (void*)(iter + p_field.getOffset()); //We just set the address of the array with respect to the offset
389 }else{
390
2/2
✓ Branch 0 (8→9) taken 45 times.
✓ Branch 1 (8→13) taken 243 times.
288 if(p_field.getType() == FieldType::ENUM_TYPE){
391
1/1
✓ Branch 0 (9→10) taken 45 times.
45 char * tmp = iter + p_field.getOffset();
392
2/2
✓ Branch 0 (10→11) taken 45 times.
✓ Branch 2 (11→12) taken 45 times.
45 *((size_t*)p_field.getVarPtr()) = phoenix_readVarInt(tmp);
393 }else{
394 243 memcpy(p_field.getVarPtr(), iter + p_field.getOffset(), p_field.getTypeSize()); //We copy the Field value into the variable pointer
395 }
396 }
397 324 return true;
398 }
399
400
401