1 /*=========================================================================
4 Module: $RCSfile: TestAllEntryVerify.cxx,v $
6 Date: $Date: 2005/01/21 11:40:53 $
7 Version: $Revision: 1.20 $
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 bool Open( std::string& referenceFileName );
57 void SetDataPath(std::string&);
59 bool Check( std::string fileName );
62 bool AddKeyValuePairToMap( std::string& key, std::string& value );
64 std::istream& eatwhite(std::istream& is);
65 void eatwhite(std::string& toClean);
66 std::string ExtractFirstString(std::string& toSplit);
67 void CleanUpLine( std::string& line );
69 bool Check( MapFileValuesType::iterator &fileIt );
70 std::string ExtractValue(std::string& toSplit) throw ( ParserException );
71 void ParseRegularLine( std::string& line ) throw ( ParserException );
72 void FirstPassReferenceFile() throw ( ParserException );
73 bool SecondPassReferenceFile() throw ( ParserException );
74 void HandleFileName( std::string& line ) throw ( ParserException );
75 void HandleKey( std::string& line ) throw ( ParserException );
76 bool HandleValue( std::string& line ) throw ( ParserException );
77 static uint16_t axtoi( char* );
79 /// The directory containing the images to check:
82 /// The product of the parser:
83 MapFileValuesType ProducedMap;
85 /// The ifstream attached to the file we parse:
88 /// String prefixing every output
91 /// The current line position within the stream:
94 /// The currently parsed filename:
95 std::string CurrentFileName;
97 /// The currently parsed key:
98 std::string CurrentKey;
100 /// The currently parsed value:
101 std::string CurrentValue;
103 /// The current MapEntryValues pointer:
104 MapEntryValues* CurrentMapEntryValuesPtr;
108 /// http://community.borland.com/article/0,1410,17203,0.html
109 uint16_t ReferenceFileParser::axtoi(char *hexStg) {
110 int n = 0; // position in string
111 int m = 0; // position in digit[] to shift
112 int count; // loop index
113 int intValue = 0; // integer value of hex string
114 int digit[5]; // hold values to convert
118 if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
119 digit[n] = hexStg[n] & 0x0f; //convert to int
120 else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
121 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
122 else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
123 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
131 // digit[n] is value of hex digit at position n
132 // (m << 2) is the number of positions to shift
133 // OR the bits into return value
134 intValue = intValue | (digit[n] << (m << 2));
135 m--; // adjust the position to set
136 n++; // next digit to process
141 void ReferenceFileParser::SetDataPath( std::string& inDataPath )
143 DataPath = inDataPath;
146 bool ReferenceFileParser::AddKeyValuePairToMap( std::string& key,
149 if ( !CurrentMapEntryValuesPtr )
151 if ( CurrentMapEntryValuesPtr->count(key) != 0 )
153 (*CurrentMapEntryValuesPtr)[key] = value;
158 void ReferenceFileParser::Print()
160 for (MapFileValuesType::iterator i = ProducedMap.begin();
161 i != ProducedMap.end();
164 std::cout << Indent << "FileName: " << i->first << std::endl;
165 MapEntryValuesPtr KeyValues = i->second;
166 for (MapEntryValues::iterator j = KeyValues->begin();
167 j != KeyValues->end();
171 << " Key: " << j->first
172 << " Value: " << j->second
175 std::cout << Indent << std::endl;
177 std::cout << Indent << std::endl;
180 bool ReferenceFileParser::Check()
183 for (MapFileValuesType::iterator i = ProducedMap.begin();
184 i != ProducedMap.end();
189 std::cout << Indent << std::endl;
193 bool ReferenceFileParser::Check( std::string fileName )
195 MapFileValuesType::iterator it = ProducedMap.find(fileName);
196 if( it != ProducedMap.end() )
200 std::cerr << Indent << "Failed\n"
201 << Indent << "Image not found :"
202 << fileName << std::endl;
206 bool ReferenceFileParser::Check( MapFileValuesType::iterator &fileIt )
208 std::string fileName = DataPath + fileIt->first;
209 std::cout << Indent << "FileName: " << fileName << std::endl;
210 gdcm::File* tested = new gdcm::File( fileName.c_str() );
211 if( !tested->IsReadable() )
213 std::cerr << Indent << "Failed\n"
214 << Indent << "Image not gdcm compatible:"
215 << fileName << std::endl;
220 MapEntryValuesPtr KeyValues = fileIt->second;
221 for (MapEntryValues::iterator j = KeyValues->begin();
222 j != KeyValues->end();
225 std::string key = j->first;
227 std::string groupString = key.substr( 0, 4 );
228 std::string groupElement = key.substr( key.find_first_of( "|" ) + 1, 4 );
230 uint16_t group = axtoi( &(groupString[0]) );
231 uint16_t element = axtoi( &(groupElement[0]) );
233 std::string testedValue = tested->GetEntry(group, element);
234 if ( testedValue != j->second )
236 // Oops make sure this is only the \0 that differ
237 if( testedValue[j->second.size()] != '\0' ||
238 strncmp(testedValue.c_str(),
239 j->second.c_str(), j->second.size()) != 0)
241 std::cout << Indent << "Failed\n"
242 << Indent << "Uncorrect value for key "
244 << Indent << " read value ["
245 << testedValue << "]" << std::endl
246 << Indent << " reference value ["
247 << j->second << "]" << std::endl;
253 std::cout << Indent << " OK" << std::endl;
258 std::istream& ReferenceFileParser::eatwhite( std::istream& is )
270 void ReferenceFileParser::eatwhite( std::string& toClean )
272 while( toClean.find_first_of( " " ) == 0 )
273 toClean.erase( 0, toClean.find_first_of( " " ) + 1 );
276 std::string ReferenceFileParser::ExtractFirstString( std::string& toSplit )
278 std::string firstString;
280 if ( toSplit.find( " " ) == std::string::npos ) {
281 firstString = toSplit;
285 firstString = toSplit.substr( 0, toSplit.find(" ") );
286 toSplit.erase( 0, toSplit.find(" ") + 1);
291 std::string ReferenceFileParser::ExtractValue( std::string& toSplit )
292 throw ( ParserException )
295 std::string::size_type beginPos = toSplit.find_first_of( '"' );
296 std::string::size_type endPos = toSplit.find_last_of( '"' );
298 // Make sure we have at most two " in toSplit:
299 //std::string noQuotes = toSplit.substr( beginPos + 1, endPos - beginPos - 1);
300 //if ( noQuotes.find_first_of( '"' ) != std::string::npos )
301 // throw ParserException( "more than two quote character" );
302 if ( toSplit.find_first_of( '"',beginPos+1 ) != endPos )
303 throw ParserException( "more than two quote character" );
305 // No leading quote means this is not a value:
306 if ( beginPos == std::string::npos )
308 return std::string();
311 if ( ( endPos == std::string::npos ) || ( beginPos == endPos ) )
312 throw ParserException( "unmatched \" (quote character)" );
316 std::ostringstream error;
317 error << "leading character ["
318 << toSplit.substr(beginPos -1, 1)
319 << "] before opening \" ";
320 throw ParserException( error.str() );
323 // When they are some extra characters at end of value, it must
325 if ( ( endPos != toSplit.length() - 1 )
326 && ( toSplit.substr(endPos + 1, 1) != " " ) )
328 std::ostringstream error;
329 error << "trailing character ["
330 << toSplit.substr(endPos + 1, 1)
331 << "] after value closing \" ";
332 throw ParserException( error.str() );
335 std::string value = toSplit.substr( beginPos + 1, endPos - beginPos - 1 );
336 toSplit.erase( beginPos, endPos - beginPos + 1);
341 /// \brief Checks the block syntax of the incoming ifstream. Checks that
342 /// - no nested blocks are present
343 /// - we encounter a matching succesion of "[" and "]"
344 /// - when ifstream terminates the last block is closed.
345 /// - a block is not opened and close on the same line
346 /// @param from The incoming ifstream to be checked.
347 /// @return True when incoming ifstream has a correct syntax, false otherwise.
348 /// \warning The underlying file pointer is not preseved.
349 void ReferenceFileParser::FirstPassReferenceFile() throw ( ParserException )
353 bool inBlock = false;
354 from.seekg( 0, std::ios::beg );
356 while ( ! from.eof() )
358 std::getline( from, line );
360 /// This is how we usually end the parsing because we hit EOF:
366 throw ParserException( "Syntax error: EOF reached when in block.");
369 // Don't try to parse comments (weed out anything after first "#"):
370 if ( line.find_first_of( "#" ) != std::string::npos )
372 line.erase( line.find_first_of( "#" ) );
375 // Two occurences of opening blocks on a single line implies nested
376 // blocks which is illegal:
377 if ( line.find_first_of( "[" ) != line.find_last_of( "[" ) )
379 std::ostringstream error;
380 error << "Syntax error: nested block (open) in reference file"
382 << ParserException::GetIndent()
383 << " at line " << lineNumber << std::endl;
384 throw ParserException( error.str() );
387 // Two occurences of closing blocks on a single line implies nested
388 // blocks which is illegal:
389 if ( line.find_first_of( "]" ) != line.find_last_of( "]" ) )
391 std::ostringstream error;
392 error << "Syntax error: nested block (close) in reference file"
394 << ParserException::GetIndent()
395 << " at line " << lineNumber << std::endl;
396 throw ParserException( error.str() );
399 bool beginBlock ( line.find_first_of("[") != std::string::npos );
400 bool endBlock ( line.find_last_of("]") != std::string::npos );
402 // Opening and closing of block on same line:
403 if ( beginBlock && endBlock )
405 std::ostringstream error;
406 error << "Syntax error: opening and closing on block on same line "
407 << lineNumber++ << std::endl;
408 throw ParserException( error.str() );
411 // Illegal closing block when block not open:
412 if ( !inBlock && endBlock )
414 std::ostringstream error;
415 error << "Syntax error: unexpected end of block at line "
416 << lineNumber++ << std::endl;
417 throw ParserException( error.str() );
420 // Uncommented line outside of block is not clean:
421 if ( !inBlock && !beginBlock )
426 if ( inBlock && beginBlock )
428 std::ostringstream error;
429 error << " Syntax error: illegal opening of nested block at line "
430 << lineNumber++ << std::endl;
431 throw ParserException( error.str() );
434 // Normal situation of opening block:
442 // Normal situation of closing block:
449 // This line had no block delimiter
453 // We need rewinding:
455 from.seekg( 0, std::ios::beg );
458 ReferenceFileParser::ReferenceFileParser()
464 bool ReferenceFileParser::Open( std::string& referenceFileName )
466 from.open( referenceFileName.c_str(), std::ios::in );
467 if ( !from.is_open() )
469 std::cerr << Indent << "Can't open reference file." << std::endl;
474 FirstPassReferenceFile();
475 SecondPassReferenceFile();
477 catch ( ParserException except )
487 void ReferenceFileParser::CleanUpLine( std::string& line )
489 // Cleanup from comments:
490 if ( line.find_first_of( "#" ) != std::string::npos )
491 line.erase( line.find_first_of( "#" ) );
493 // Cleanup everything after end block delimiter:
494 if ( line.find_last_of( "]" ) != std::string::npos )
495 line.erase( line.find_last_of( "]" ) + 1 );
497 // Cleanup leading whites and skip empty lines:
501 void ReferenceFileParser::HandleFileName( std::string& line )
502 throw ( ParserException )
504 if ( line.length() == 0 )
505 throw ParserException( "empty line on call of HandleFileName" );
507 if ( CurrentFileName.length() != 0 )
510 CurrentFileName = ExtractFirstString(line);
513 void ReferenceFileParser::HandleKey( std::string& line )
514 throw ( ParserException )
516 if ( CurrentKey.length() != 0 )
519 CurrentKey = ExtractFirstString(line);
520 if ( CurrentKey.find_first_of( "|" ) == std::string::npos )
522 std::ostringstream error;
523 error << "uncorrect key:" << CurrentKey;
524 throw ParserException( error.str() );
528 bool ReferenceFileParser::HandleValue( std::string& line )
529 throw ( ParserException )
531 if ( line.length() == 0 )
532 throw ParserException( "empty line in HandleValue" );
534 if ( CurrentKey.length() == 0 )
536 std::cout << Indent << "No key present:" << CurrentKey << std::endl;
540 std::string newCurrentValue = ExtractValue(line);
541 if ( newCurrentValue.length() == 0 )
543 std::cout << Indent << "Warning: empty value for key:"
544 << CurrentKey << std::endl;
547 CurrentValue += newCurrentValue;
551 void ReferenceFileParser::ParseRegularLine( std::string& line)
552 throw ( ParserException )
554 if ( line.length() == 0 )
557 // First thing is to get a filename:
558 HandleFileName( line );
560 if ( line.length() == 0 )
563 // Second thing is to get a key:
566 if ( line.length() == 0 )
569 // Third thing is to get a value:
570 if ( ! HandleValue( line ) )
573 if ( CurrentKey.length() && CurrentValue.length() )
575 if ( ! AddKeyValuePairToMap( CurrentKey, CurrentValue ) )
576 throw ParserException( "adding to map of (key, value) failed" );
578 CurrentValue.erase();
582 bool ReferenceFileParser::SecondPassReferenceFile()
583 throw ( ParserException )
586 EntryValueType value;
588 bool inBlock = false;
591 while ( !from.eof() )
593 std::getline( from, line );
598 // Empty lines don't require any treatement:
599 if ( line.length() == 0 )
602 bool beginBlock ( line.find_first_of("[") != std::string::npos );
603 bool endBlock ( line.find_last_of("]") != std::string::npos );
605 // Waiting for a block to be opened. Meanwhile, drop everything:
606 if ( !inBlock && !beginBlock )
612 line.erase( 0, line.find_first_of( "[" ) + 1 );
614 CurrentMapEntryValuesPtr = new MapEntryValues();
618 line.erase( line.find_last_of( "]" ) );
620 ParseRegularLine( line );
621 ProducedMap[CurrentFileName] = CurrentMapEntryValuesPtr;
623 CurrentFileName.erase();
626 // Outside block lines are dropped:
630 ParseRegularLine( line );
635 int TestAllEntryVerify(int argc, char* argv[])
639 std::cerr << " Usage: " << argv[0]
640 << " fileName" << std::endl;
644 std::string referenceDir = GDCM_DATA_ROOT;
646 std::string referenceFilename = referenceDir + "TestAllEntryVerifyReference.txt";
648 std::cout << " Description (Test::TestAllEntryVerify): "
650 std::cout << " For all images (not blacklisted in gdcm/Test/CMakeLists.txt)"
652 std::cout << " encountered in directory: " << GDCM_DATA_ROOT << std::endl;
653 std::cout << " apply the following tests : "<< std::endl;
654 std::cout << " step 1: parse the image and call IsReadable(). " << std::endl;
655 std::cout << " step 2: look for the entry corresponding to the image" << std::endl;
656 std::cout << " in the reference file: \n"
657 << " " << referenceFilename << std::endl;
658 std::cout << " step 3: check that each reference tag value listed for this"
660 std::cout << " entry matches the tag encountered at parsing step 1."
661 << std::endl << std::endl;
663 ReferenceFileParser Parser;
664 if ( !Parser.Open(referenceFilename) )
666 std::cout << " failed"
667 << " Corrupted reference file name: "
668 << referenceFilename << std::endl;
671 Parser.SetDataPath(referenceDir);
673 std::cout << "Reference file loaded -->\n"
674 << "Check files : \n";
679 ret = Parser.Check( argv[1] );
683 ret = Parser.Check();