1 #include "gdcmHeader.h"
9 #include "gdcmDataImages.h"
11 typedef std::string EntryValueType; // same type as ValEntry::value
12 typedef std::map< gdcm::TagKey, EntryValueType > MapEntryValues;
13 typedef MapEntryValues* MapEntryValuesPtr;
14 typedef std::string FileNameType;
15 typedef std::map< FileNameType, MapEntryValuesPtr > MapFileValuesType;
17 struct ParserException
20 static std::string Indent;
22 static std::string GetIndent() { return ParserException::Indent; }
23 ParserException( std::string ErrorMessage )
28 void Print() { std::cerr << Indent << error << std::endl; }
31 std::string ParserException::Indent = " ";
33 class ReferenceFileParser
35 bool AddKeyValuePairToMap( std::string& key, std::string& value );
37 std::istream& eatwhite(std::istream& is);
38 void eatwhite(std::string& toClean);
39 std::string ExtractFirstString(std::string& toSplit);
40 void CleanUpLine( std::string& line );
42 std::string ExtractValue(std::string& toSplit) throw ( ParserException );
43 void ParseRegularLine( std::string& line ) throw ( ParserException );
44 void FirstPassReferenceFile() throw ( ParserException );
45 bool SecondPassReferenceFile() throw ( ParserException );
46 void HandleFileName( std::string& line ) throw ( ParserException );
47 void HandleKey( std::string& line ) throw ( ParserException );
48 bool HandleValue( std::string& line ) throw ( ParserException );
49 static uint16_t axtoi( char* );
51 ReferenceFileParser();
52 bool Open( std::string& referenceFileName );
54 void SetDataPath(std::string&);
57 /// The directory containing the images to check:
60 /// The product of the parser:
61 MapFileValuesType ProducedMap;
63 /// The ifstream attached to the file we parse:
66 /// String prefixing every output
69 /// The current line position within the stream:
72 /// The currently parsed filename:
73 std::string CurrentFileName;
75 /// The currently parsed key:
76 std::string CurrentKey;
78 /// The currently parsed value:
79 std::string CurrentValue;
81 /// The current MapEntryValues pointer:
82 MapEntryValues* CurrentMapEntryValuesPtr;
86 /// http://community.borland.com/article/0,1410,17203,0.html
87 uint16_t ReferenceFileParser::axtoi(char *hexStg) {
88 int n = 0; // position in string
89 int m = 0; // position in digit[] to shift
90 int count; // loop index
91 int intValue = 0; // integer value of hex string
92 int digit[5]; // hold values to convert
96 if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
97 digit[n] = hexStg[n] & 0x0f; //convert to int
98 else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
99 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
100 else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
101 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
109 // digit[n] is value of hex digit at position n
110 // (m << 2) is the number of positions to shift
111 // OR the bits into return value
112 intValue = intValue | (digit[n] << (m << 2));
113 m--; // adjust the position to set
114 n++; // next digit to process
119 void ReferenceFileParser::SetDataPath( std::string& inDataPath )
121 DataPath = inDataPath;
124 bool ReferenceFileParser::AddKeyValuePairToMap( std::string& key, std::string& value )
126 if ( !CurrentMapEntryValuesPtr )
128 if ( CurrentMapEntryValuesPtr->count(key) != 0 )
130 (*CurrentMapEntryValuesPtr)[key] = value;
135 void ReferenceFileParser::Print()
137 for (MapFileValuesType::iterator i = ProducedMap.begin();
138 i != ProducedMap.end();
141 std::cout << Indent << "FileName: " << i->first << std::endl;
142 MapEntryValuesPtr KeyValues = i->second;
143 for (MapEntryValues::iterator j = KeyValues->begin();
144 j != KeyValues->end();
148 << " Key: " << j->first
149 << " Value: " << j->second
152 std::cout << Indent << std::endl;
154 std::cout << Indent << std::endl;
157 bool ReferenceFileParser::Check()
159 for (MapFileValuesType::iterator i = ProducedMap.begin();
160 i != ProducedMap.end();
163 std::string fileName = DataPath + i->first;
164 std::cout << Indent << "FileName: " << fileName << std::endl;
165 gdcm::Header* tested = new gdcm::Header( fileName.c_str() );
166 if( !tested->IsReadable() )
168 std::cerr << Indent << "Image not gdcm compatible:"
169 << fileName << std::endl;
174 MapEntryValuesPtr KeyValues = i->second;
175 for (MapEntryValues::iterator j = KeyValues->begin();
176 j != KeyValues->end();
179 std::string key = j->first;
181 std::string groupString = key.substr( 0, 4 );
183 groupCharPtr = new char(groupString.length() + 1);
184 strcpy( groupCharPtr, groupString.c_str() );
186 std::string groupElement = key.substr( key.find_first_of( "|" ) + 1, 4 );
187 char* groupElementPtr;
188 groupElementPtr = new char(groupElement.length() + 1);
189 strcpy( groupElementPtr, groupElement.c_str() );
191 uint16_t group = axtoi( groupCharPtr );
192 uint16_t element = axtoi( groupElementPtr );
194 std::string testedValue = tested->GetEntryByNumber(group, element);
195 if ( testedValue != j->second )
197 // Oops make sure this is only the \0 that differ
198 if( testedValue[j->second.size()] != '\0' ||
199 strncmp(testedValue.c_str(),
200 j->second.c_str(), j->second.size()) != 0)
202 std::cout << Indent << "Uncorrect value for key "
204 << Indent << " read value ["
205 << testedValue << "]" << std::endl
206 << Indent << " reference value ["
207 << j->second << "]" << std::endl;
213 std::cout << Indent << " OK" << std::endl;
215 std::cout << Indent << std::endl;
219 std::istream& ReferenceFileParser::eatwhite( std::istream& is )
231 void ReferenceFileParser::eatwhite( std::string& toClean )
233 while( toClean.find_first_of( " " ) == 0 )
234 toClean.erase( 0, toClean.find_first_of( " " ) + 1 );
237 std::string ReferenceFileParser::ExtractFirstString( std::string& toSplit )
239 std::string firstString;
241 if ( toSplit.find( " " ) == std::string::npos ) {
242 firstString = toSplit;
246 firstString = toSplit.substr( 0, toSplit.find(" ") );
247 toSplit.erase( 0, toSplit.find(" ") + 1);
252 std::string ReferenceFileParser::ExtractValue( std::string& toSplit )
253 throw ( ParserException )
256 std::string::size_type beginPos = toSplit.find_first_of( '"' );
257 std::string::size_type endPos = toSplit.find_last_of( '"' );
259 // Make sure we have at most two " in toSplit:
260 std::string noQuotes = toSplit.substr( beginPos + 1, endPos - beginPos - 1);
261 if ( noQuotes.find_first_of( '"' ) != std::string::npos )
262 throw ParserException( "more than two quote character" );
264 // No leading quote means this is not a value:
265 if ( beginPos == std::string::npos )
267 return std::string();
270 if ( ( endPos == std::string::npos ) || ( beginPos == endPos ) )
271 throw ParserException( "unmatched \" (quote character)" );
275 std::ostringstream error;
276 error << "leading character ["
277 << toSplit.substr(beginPos -1, 1)
278 << "] before opening \" ";
279 throw ParserException( error.str() );
282 // When they are some extra characters at end of value, it must
284 if ( ( endPos != toSplit.length() - 1 )
285 && ( toSplit.substr(endPos + 1, 1) != " " ) )
287 std::ostringstream error;
288 error << "trailing character ["
289 << toSplit.substr(endPos + 1, 1)
290 << "] after value closing \" ";
291 throw ParserException( error.str() );
294 std::string value = toSplit.substr( beginPos + 1, endPos - beginPos - 1 );
295 toSplit.erase( beginPos, endPos - beginPos + 1);
300 /// \brief Checks the block syntax of the incoming ifstream. Checks that
301 /// - no nested blocks are present
302 /// - we encounter a matching succesion of "[" and "]"
303 /// - when ifstream terminates the last block is closed.
304 /// - a block is not opened and close on the same line
305 /// @param from The incoming ifstream to be checked.
306 /// @return True when incoming ifstream has a correct syntax, false otherwise.
307 /// \warning The underlying file pointer is not preseved.
308 void ReferenceFileParser::FirstPassReferenceFile() throw ( ParserException )
312 bool inBlock = false;
313 from.seekg( 0, std::ios::beg );
315 while ( ! from.eof() )
317 std::getline( from, line );
319 /// This is how we usually end the parsing because we hit EOF:
325 throw ParserException( "Syntax error: EOF reached when in block.");
328 // Don't try to parse comments (weed out anything after first "#"):
329 if ( line.find_first_of( "#" ) != std::string::npos )
331 line.erase( line.find_first_of( "#" ) );
334 // Two occurences of opening blocks on a single line implies nested
335 // blocks which is illegal:
336 if ( line.find_first_of( "[" ) != line.find_last_of( "[" ) )
338 std::ostringstream error;
339 error << "Syntax error: nested block (open) in reference file"
341 << ParserException::GetIndent()
342 << " at line " << lineNumber << std::endl;
343 throw ParserException( error.str() );
346 // Two occurences of closing blocks on a single line implies nested
347 // blocks which is illegal:
348 if ( line.find_first_of( "]" ) != line.find_last_of( "]" ) )
350 std::ostringstream error;
351 error << "Syntax error: nested block (close) in reference file"
353 << ParserException::GetIndent()
354 << " at line " << lineNumber << std::endl;
355 throw ParserException( error.str() );
358 bool beginBlock ( line.find_first_of("[") != std::string::npos );
359 bool endBlock ( line.find_last_of("]") != std::string::npos );
361 // Opening and closing of block on same line:
362 if ( beginBlock && endBlock )
364 std::ostringstream error;
365 error << "Syntax error: opening and closing on block on same line "
366 << lineNumber++ << std::endl;
367 throw ParserException( error.str() );
370 // Illegal closing block when block not open:
371 if ( !inBlock && endBlock )
373 std::ostringstream error;
374 error << "Syntax error: unexpected end of block at line "
375 << lineNumber++ << std::endl;
376 throw ParserException( error.str() );
379 // Uncommented line outside of block is not clean:
380 if ( !inBlock && !beginBlock )
385 if ( inBlock && beginBlock )
387 std::ostringstream error;
388 error << " Syntax error: illegal opening of nested block at line "
389 << lineNumber++ << std::endl;
390 throw ParserException( error.str() );
393 // Normal situation of opening block:
401 // Normal situation of closing block:
408 // This line had no block delimiter
412 // We need rewinding:
414 from.seekg( 0, std::ios::beg );
417 ReferenceFileParser::ReferenceFileParser()
423 bool ReferenceFileParser::Open( std::string& referenceFileName )
425 from.open( referenceFileName.c_str(), std::ios::in );
426 if ( !from.is_open() )
428 std::cerr << Indent << "Can't open reference file." << std::endl;
433 FirstPassReferenceFile();
434 SecondPassReferenceFile();
436 catch ( ParserException except )
446 void ReferenceFileParser::CleanUpLine( std::string& line )
448 // Cleanup from comments:
449 if ( line.find_first_of( "#" ) != std::string::npos )
450 line.erase( line.find_first_of( "#" ) );
452 // Cleanup everything after end block delimiter:
453 if ( line.find_last_of( "]" ) != std::string::npos )
454 line.erase( line.find_last_of( "]" ) + 1 );
456 // Cleanup leading whites and skip empty lines:
460 void ReferenceFileParser::HandleFileName( std::string& line )
461 throw ( ParserException )
463 if ( line.length() == 0 )
464 throw ParserException( "empty line on call of HandleFileName" );
466 if ( CurrentFileName.length() != 0 )
469 CurrentFileName = ExtractFirstString(line);
472 void ReferenceFileParser::HandleKey( std::string& line )
473 throw ( ParserException )
475 if ( CurrentKey.length() != 0 )
478 CurrentKey = ExtractFirstString(line);
479 if ( CurrentKey.find_first_of( "|" ) == std::string::npos )
481 std::ostringstream error;
482 error << "uncorrect key:" << CurrentKey;
483 throw ParserException( error.str() );
487 bool ReferenceFileParser::HandleValue( std::string& line )
488 throw ( ParserException )
490 if ( line.length() == 0 )
491 throw ParserException( "empty line in HandleValue" );
493 if ( CurrentKey.length() == 0 )
495 std::cout << Indent << "No key present:" << CurrentKey << std::endl;
499 std::string newCurrentValue = ExtractValue(line);
500 if ( newCurrentValue.length() == 0 )
502 std::cout << Indent << "Warning: empty value for key:"
503 << CurrentKey << std::endl;
506 CurrentValue += newCurrentValue;
510 void ReferenceFileParser::ParseRegularLine( std::string& line)
511 throw ( ParserException )
513 if ( line.length() == 0 )
516 // First thing is to get a filename:
517 HandleFileName( line );
519 if ( line.length() == 0 )
522 // Second thing is to get a key:
525 if ( line.length() == 0 )
528 // Third thing is to get a value:
529 if ( ! HandleValue( line ) )
532 if ( CurrentKey.length() && CurrentValue.length() )
534 if ( ! AddKeyValuePairToMap( CurrentKey, CurrentValue ) )
535 throw ParserException( "adding to map of (key, value) failed" );
537 CurrentValue.erase();
541 bool ReferenceFileParser::SecondPassReferenceFile()
542 throw ( ParserException )
545 EntryValueType value;
547 bool inBlock = false;
550 while ( !from.eof() )
552 std::getline( from, line );
557 // Empty lines don't require any treatement:
558 if ( line.length() == 0 )
561 bool beginBlock ( line.find_first_of("[") != std::string::npos );
562 bool endBlock ( line.find_last_of("]") != std::string::npos );
564 // Waiting for a block to be opened. Meanwhile, drop everything:
565 if ( !inBlock && !beginBlock )
571 line.erase( 0, line.find_first_of( "[" ) + 1 );
573 CurrentMapEntryValuesPtr = new MapEntryValues();
577 line.erase( line.find_last_of( "]" ) );
579 ParseRegularLine( line );
580 ProducedMap[CurrentFileName] = CurrentMapEntryValuesPtr;
582 CurrentFileName.erase();
585 // Outside block lines are dropped:
589 ParseRegularLine( line );
594 int TestAllEntryVerify(int argc, char* argv[])
598 std::cerr << " Usage: " << argv[0]
599 << " (no arguments needed)." << std::endl;
603 std::string referenceDir = GDCM_DATA_ROOT;
605 std::string referenceFilename = referenceDir + "TestAllEntryVerifyReference.txt";
607 std::cout << " Description (Test::TestAllEntryVerify): "
609 std::cout << " For all images (not blacklisted in gdcm/Test/CMakeLists.txt)"
611 std::cout << " encountered in directory: " << GDCM_DATA_ROOT << std::endl;
612 std::cout << " apply the following tests : "<< std::endl;
613 std::cout << " step 1: parse the image and call IsReadable(). " << std::endl;
614 std::cout << " step 2: look for the entry corresponding to the image" << std::endl;
615 std::cout << " in the reference file: " << referenceFilename << std::endl;
616 std::cout << " step 3: check that each reference tag value listed for this"
618 std::cout << " entry matches the tag encountered at parsing step 1."
619 << std::endl << std::endl;
621 ReferenceFileParser Parser;
622 if ( !Parser.Open(referenceFilename) )
624 std::cout << " Corrupted reference file name: "
625 << referenceFilename << std::endl;
628 Parser.SetDataPath(referenceDir);
630 if ( Parser.Check() )