1 /*=========================================================================
4 Module: $RCSfile: TestAllEntryVerify.cxx,v $
6 Date: $Date: 2005/07/08 13:39:56 $
7 Version: $Revision: 1.27 $
9 Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10 l'Image). All rights reserved. See Doc/License.txt or
11 http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
13 This software is distributed WITHOUT ANY WARRANTY; without even
14 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 PURPOSE. See the above copyright notices for more information.
17 =========================================================================*/
27 //#include "gdcmDataImages.h"
29 typedef std::string EntryValueType; // same type as ValEntry::value
30 typedef std::map< gdcm::TagKey, EntryValueType > MapEntryValues;
31 typedef MapEntryValues *MapEntryValuesPtr;
32 typedef std::string FileNameType;
33 typedef std::map< FileNameType, MapEntryValuesPtr > MapFileValuesType;
35 struct ParserException
38 static std::string Indent;
40 static std::string GetIndent() { return ParserException::Indent; }
41 ParserException( std::string ErrorMessage )
46 void Print() { std::cerr << Indent << error << std::endl; }
49 std::string ParserException::Indent = " ";
51 class ReferenceFileParser
54 ReferenceFileParser();
55 ~ReferenceFileParser();
57 bool Open( std::string &referenceFileName );
59 void SetDataPath(std::string&);
61 bool Check( std::string fileName );
64 bool AddKeyValuePairToMap( std::string &key, std::string &value );
66 std::istream &eatwhite(std::istream &is);
67 void eatwhite(std::string &toClean);
68 std::string ExtractFirstString(std::string &toSplit);
69 void CleanUpLine( std::string &line );
71 bool Check( MapFileValuesType::iterator &fileIt );
72 std::string ExtractValue(std::string &toSplit) throw ( ParserException );
73 void ParseRegularLine( std::string &line ) throw ( ParserException );
74 void FirstPassReferenceFile() throw ( ParserException );
75 bool SecondPassReferenceFile() throw ( ParserException );
76 void HandleFileName( std::string &line ) throw ( ParserException );
77 void HandleKey( std::string &line ) throw ( ParserException );
78 bool HandleValue( std::string &line ) throw ( ParserException );
79 static uint16_t axtoi( char* );
82 /// The directory containing the images to check:
85 /// The product of the parser:
86 MapFileValuesType ProducedMap;
88 /// The ifstream attached to the file we parse:
91 /// String prefixing every output
94 /// The current line position within the stream:
97 /// The currently parsed filename:
98 std::string CurrentFileName;
100 /// The currently parsed key:
101 std::string CurrentKey;
103 /// The currently parsed value:
104 std::string CurrentValue;
106 /// The current MapEntryValues pointer:
107 MapEntryValues *CurrentMapEntryValuesPtr;
110 ReferenceFileParser::ReferenceFileParser()
116 ReferenceFileParser::~ReferenceFileParser()
118 for (MapFileValuesType::iterator i = ProducedMap.begin();
119 i != ProducedMap.end();
127 /// http://community.borland.com/article/0,1410,17203,0.html
128 uint16_t ReferenceFileParser::axtoi(char *hexStg)
130 int n = 0; // position in string
131 int m = 0; // position in digit[] to shift
132 int count; // loop index
133 int intValue = 0; // integer value of hex string
134 int digit[5]; // hold values to convert
139 if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
140 digit[n] = hexStg[n] & 0x0f; //convert to int
141 else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
142 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
143 else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
144 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
153 // digit[n] is value of hex digit at position n
154 // (m << 2) is the number of positions to shift
155 // OR the bits into return value
156 intValue = intValue | (digit[n] << (m << 2));
157 m--; // adjust the position to set
158 n++; // next digit to process
160 return (uint16_t)intValue;
163 void ReferenceFileParser::SetDataPath( std::string &inDataPath )
165 DataPath = inDataPath;
168 bool ReferenceFileParser::AddKeyValuePairToMap( std::string &key,
171 if ( !CurrentMapEntryValuesPtr )
173 if ( CurrentMapEntryValuesPtr->count(key) != 0 )
175 (*CurrentMapEntryValuesPtr)[key] = value;
180 void ReferenceFileParser::Print()
182 for (MapFileValuesType::iterator i = ProducedMap.begin();
183 i != ProducedMap.end();
186 std::cout << Indent << "FileName: " << i->first << std::endl;
187 MapEntryValuesPtr KeyValues = i->second;
188 for (MapEntryValues::iterator j = KeyValues->begin();
189 j != KeyValues->end();
193 << " Key: " << j->first
194 << " Value: " << j->second
197 std::cout << Indent << std::endl;
199 std::cout << Indent << std::endl;
202 bool ReferenceFileParser::Check()
205 for (MapFileValuesType::iterator i = ProducedMap.begin();
206 i != ProducedMap.end();
211 std::cout << Indent << std::endl;
215 bool ReferenceFileParser::Check( std::string fileName )
217 MapFileValuesType::iterator it = ProducedMap.find(fileName);
218 if( it != ProducedMap.end() )
222 std::cerr << Indent << "Failed\n"
223 << Indent << "Image not found :"
224 << fileName << std::endl;
228 bool ReferenceFileParser::Check( MapFileValuesType::iterator &fileIt )
230 std::string fileName = DataPath + fileIt->first;
231 std::cout << Indent << "FileName: " << fileName << std::endl;
234 tested = new gdcm::File( );
235 tested->SetFileName( fileName.c_str() );
237 if( !tested->IsReadable() )
239 std::cerr << Indent << "Failed\n"
240 << Indent << "Image not gdcm compatible:"
241 << fileName << std::endl;
246 MapEntryValuesPtr KeyValues = fileIt->second;
247 for (MapEntryValues::iterator j = KeyValues->begin();
248 j != KeyValues->end();
251 std::string key = j->first;
253 std::string groupString = key.substr( 0, 4 );
254 std::string groupElement = key.substr( key.find_first_of( "|" ) + 1, 4 );
256 uint16_t group = axtoi( &(groupString[0]) );
257 uint16_t element = axtoi( &(groupElement[0]) );
259 std::string testedValue = tested->GetEntryValue(group, element);
260 if ( testedValue != j->second )
262 // Oops make sure this is only the \0 that differ
263 if( testedValue[j->second.size()] != '\0' ||
264 strncmp(testedValue.c_str(),
265 j->second.c_str(), j->second.size()) != 0)
267 std::cout << Indent << "Failed\n"
268 << Indent << "Uncorrect value for key "
270 << Indent << " read value ["
271 << testedValue << "]" << std::endl
272 << Indent << " reference value ["
273 << j->second << "]" << std::endl;
279 std::cout << Indent << " OK" << std::endl;
284 std::istream &ReferenceFileParser::eatwhite( std::istream &is )
296 void ReferenceFileParser::eatwhite( std::string &toClean )
298 while( toClean.find_first_of( " " ) == 0 )
299 toClean.erase( 0, toClean.find_first_of( " " ) + 1 );
302 std::string ReferenceFileParser::ExtractFirstString( std::string &toSplit )
304 std::string firstString;
306 if ( toSplit.find( " " ) == std::string::npos ) {
307 firstString = toSplit;
311 firstString = toSplit.substr( 0, toSplit.find(" ") );
312 toSplit.erase( 0, toSplit.find(" ") + 1);
317 std::string ReferenceFileParser::ExtractValue( std::string &toSplit )
318 throw ( ParserException )
321 std::string::size_type beginPos = toSplit.find_first_of( '"' );
322 std::string::size_type endPos = toSplit.find_last_of( '"' );
324 // Make sure we have at most two " in toSplit:
325 //std::string noQuotes = toSplit.substr( beginPos + 1, endPos - beginPos - 1);
326 //if ( noQuotes.find_first_of( '"' ) != std::string::npos )
327 // throw ParserException( "more than two quote character" );
328 if ( toSplit.find_first_of( '"',beginPos+1 ) != endPos )
329 throw ParserException( "more than two quote character" );
331 // No leading quote means this is not a value:
332 if ( beginPos == std::string::npos )
334 return std::string();
337 if ( ( endPos == std::string::npos ) || ( beginPos == endPos ) )
338 throw ParserException( "unmatched \" (quote character)" );
342 std::ostringstream error;
343 error << "leading character ["
344 << toSplit.substr(beginPos -1, 1)
345 << "] before opening \" ";
346 throw ParserException( error.str() );
349 // When they are some extra characters at end of value, it must
351 if ( ( endPos != toSplit.length() - 1 )
352 && ( toSplit.substr(endPos + 1, 1) != " " ) )
354 std::ostringstream error;
355 error << "trailing character ["
356 << toSplit.substr(endPos + 1, 1)
357 << "] after value closing \" ";
358 throw ParserException( error.str() );
361 std::string value = toSplit.substr( beginPos + 1, endPos - beginPos - 1 );
362 toSplit.erase( beginPos, endPos - beginPos + 1);
367 /// \brief Checks the block syntax of the incoming ifstream. Checks that
368 /// - no nested blocks are present
369 /// - we encounter a matching succesion of "[" and "]"
370 /// - when ifstream terminates the last block is closed.
371 /// - a block is not opened and close on the same line
372 /// @param from The incoming ifstream to be checked.
373 /// @return True when incoming ifstream has a correct syntax, false otherwise.
374 /// \warning The underlying file pointer is not preseved.
375 void ReferenceFileParser::FirstPassReferenceFile() throw ( ParserException )
379 bool inBlock = false;
380 from.seekg( 0, std::ios::beg );
382 while ( ! from.eof() )
384 std::getline( from, line );
386 /// This is how we usually end the parsing because we hit EOF:
392 throw ParserException( "Syntax error: EOF reached when in block.");
395 // Don't try to parse comments (weed out anything after first "#"):
396 if ( line.find_first_of( "#" ) != std::string::npos )
398 line.erase( line.find_first_of( "#" ) );
401 // Two occurences of opening blocks on a single line implies nested
402 // blocks which is illegal:
403 if ( line.find_first_of( "[" ) != line.find_last_of( "[" ) )
405 std::ostringstream error;
406 error << "Syntax error: nested block (open) in reference file"
408 << ParserException::GetIndent()
409 << " at line " << lineNumber << std::endl;
410 throw ParserException( error.str() );
413 // Two occurences of closing blocks on a single line implies nested
414 // blocks which is illegal:
415 if ( line.find_first_of( "]" ) != line.find_last_of( "]" ) )
417 std::ostringstream error;
418 error << "Syntax error: nested block (close) in reference file"
420 << ParserException::GetIndent()
421 << " at line " << lineNumber << std::endl;
422 throw ParserException( error.str() );
425 bool beginBlock ( line.find_first_of("[") != std::string::npos );
426 bool endBlock ( line.find_last_of("]") != std::string::npos );
428 // Opening and closing of block on same line:
429 if ( beginBlock && endBlock )
431 std::ostringstream error;
432 error << "Syntax error: opening and closing on block on same line "
433 << lineNumber++ << std::endl;
434 throw ParserException( error.str() );
437 // Illegal closing block when block not open:
438 if ( !inBlock && endBlock )
440 std::ostringstream error;
441 error << "Syntax error: unexpected end of block at line "
442 << lineNumber++ << std::endl;
443 throw ParserException( error.str() );
446 // Uncommented line outside of block is not clean:
447 if ( !inBlock && !beginBlock )
452 if ( inBlock && beginBlock )
454 std::ostringstream error;
455 error << " Syntax error: illegal opening of nested block at line "
456 << lineNumber++ << std::endl;
457 throw ParserException( error.str() );
460 // Normal situation of opening block:
468 // Normal situation of closing block:
475 // This line had no block delimiter
479 // We need rewinding:
481 from.seekg( 0, std::ios::beg );
484 bool ReferenceFileParser::Open( std::string &referenceFileName )
486 from.open( referenceFileName.c_str(), std::ios::in );
487 if ( !from.is_open() )
489 std::cerr << Indent << "Can't open reference file." << std::endl;
494 FirstPassReferenceFile();
495 SecondPassReferenceFile();
497 catch ( ParserException except )
507 void ReferenceFileParser::CleanUpLine( std::string &line )
509 // Cleanup from comments:
510 if ( line.find_first_of( "#" ) != std::string::npos )
511 line.erase( line.find_first_of( "#" ) );
513 // Cleanup everything after end block delimiter:
514 if ( line.find_last_of( "]" ) != std::string::npos )
515 line.erase( line.find_last_of( "]" ) + 1 );
517 // Cleanup leading whites and skip empty lines:
521 void ReferenceFileParser::HandleFileName( std::string &line )
522 throw ( ParserException )
524 if ( line.length() == 0 )
525 throw ParserException( "empty line on call of HandleFileName" );
527 if ( CurrentFileName.length() != 0 )
530 CurrentFileName = ExtractFirstString(line);
533 void ReferenceFileParser::HandleKey( std::string &line )
534 throw ( ParserException )
536 if ( CurrentKey.length() != 0 )
539 CurrentKey = ExtractFirstString(line);
540 if ( CurrentKey.find_first_of( "|" ) == std::string::npos )
542 std::ostringstream error;
543 error << "uncorrect key:" << CurrentKey;
544 throw ParserException( error.str() );
548 bool ReferenceFileParser::HandleValue( std::string &line )
549 throw ( ParserException )
551 if ( line.length() == 0 )
552 throw ParserException( "empty line in HandleValue" );
554 if ( CurrentKey.length() == 0 )
556 std::cout << Indent << "No key present:" << CurrentKey << std::endl;
560 std::string newCurrentValue = ExtractValue(line);
561 if ( newCurrentValue.length() == 0 )
563 std::cout << Indent << "Warning: empty value for key:"
564 << CurrentKey << std::endl;
567 CurrentValue += newCurrentValue;
571 void ReferenceFileParser::ParseRegularLine( std::string &line)
572 throw ( ParserException )
574 if ( line.length() == 0 )
577 // First thing is to get a filename:
578 HandleFileName( line );
580 if ( line.length() == 0 )
583 // Second thing is to get a key:
586 if ( line.length() == 0 )
589 // Third thing is to get a value:
590 if ( ! HandleValue( line ) )
593 if ( CurrentKey.length() && CurrentValue.length() )
595 if ( ! AddKeyValuePairToMap( CurrentKey, CurrentValue ) )
596 throw ParserException( "adding to map of (key, value) failed" );
598 CurrentValue.erase();
602 bool ReferenceFileParser::SecondPassReferenceFile()
603 throw ( ParserException )
606 EntryValueType value;
608 bool inBlock = false;
611 while ( !from.eof() )
613 std::getline( from, line );
618 // Empty lines don't require any treatement:
619 if ( line.length() == 0 )
622 bool beginBlock ( line.find_first_of("[") != std::string::npos );
623 bool endBlock ( line.find_last_of("]") != std::string::npos );
625 // Waiting for a block to be opened. Meanwhile, drop everything:
626 if ( !inBlock && !beginBlock )
632 line.erase( 0, line.find_first_of( "[" ) + 1 );
634 CurrentMapEntryValuesPtr = new MapEntryValues();
638 line.erase( line.find_last_of( "]" ) );
640 ParseRegularLine( line );
641 ProducedMap[CurrentFileName] = CurrentMapEntryValuesPtr;
643 CurrentFileName.erase();
646 // Outside block lines are dropped:
650 ParseRegularLine( line );
655 int TestAllEntryVerify(int argc, char *argv[])
659 std::cerr << " Usage: " << argv[0]
660 << " fileName" << std::endl;
664 std::string referenceDir = GDCM_DATA_ROOT;
666 std::string referenceFilename = referenceDir + "TestAllEntryVerifyReference.txt";
668 std::cout << " Description (Test::TestAllEntryVerify): "
670 std::cout << " For all images (not blacklisted in gdcm/Test/CMakeLists.txt)"
672 std::cout << " encountered in directory: " << GDCM_DATA_ROOT << std::endl;
673 std::cout << " apply the following tests : "<< std::endl;
674 std::cout << " step 1: parse the image and call IsReadable(). " << std::endl;
675 std::cout << " step 2: look for the entry corresponding to the image" << std::endl;
676 std::cout << " in the reference file: \n"
677 << " " << referenceFilename << std::endl;
678 std::cout << " step 3: check that each reference tag value listed for this"
680 std::cout << " entry matches the tag encountered at parsing step 1."
681 << std::endl << std::endl;
683 ReferenceFileParser Parser;
684 if ( !Parser.Open(referenceFilename) )
686 std::cout << " failed"
687 << " Corrupted reference file name: "
688 << referenceFilename << std::endl;
691 Parser.SetDataPath(referenceDir);
693 std::cout << "Reference file loaded -->\n"
694 << "Check files : \n";
699 ret = Parser.Check( argv[1] );
703 ret = Parser.Check();