1 /*=========================================================================
4 Module: $RCSfile: TestAllEntryVerify.cxx,v $
6 Date: $Date: 2004/12/10 13:49:06 $
7 Version: $Revision: 1.17 $
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 =========================================================================*/
18 #include "gdcmHeader.h"
26 #include "gdcmDataImages.h"
28 typedef std::string EntryValueType; // same type as ValEntry::value
29 typedef std::map< gdcm::TagKey, EntryValueType > MapEntryValues;
30 typedef MapEntryValues* MapEntryValuesPtr;
31 typedef std::string FileNameType;
32 typedef std::map< FileNameType, MapEntryValuesPtr > MapFileValuesType;
34 struct ParserException
37 static std::string Indent;
39 static std::string GetIndent() { return ParserException::Indent; }
40 ParserException( std::string ErrorMessage )
45 void Print() { std::cerr << Indent << error << std::endl; }
48 std::string ParserException::Indent = " ";
50 class ReferenceFileParser
53 ReferenceFileParser();
54 bool Open( std::string& referenceFileName );
56 void SetDataPath(std::string&);
58 bool Check( std::string fileName );
61 bool AddKeyValuePairToMap( std::string& key, std::string& value );
63 std::istream& eatwhite(std::istream& is);
64 void eatwhite(std::string& toClean);
65 std::string ExtractFirstString(std::string& toSplit);
66 void CleanUpLine( std::string& line );
68 bool Check( MapFileValuesType::iterator &fileIt );
69 std::string ExtractValue(std::string& toSplit) throw ( ParserException );
70 void ParseRegularLine( std::string& line ) throw ( ParserException );
71 void FirstPassReferenceFile() throw ( ParserException );
72 bool SecondPassReferenceFile() throw ( ParserException );
73 void HandleFileName( std::string& line ) throw ( ParserException );
74 void HandleKey( std::string& line ) throw ( ParserException );
75 bool HandleValue( std::string& line ) throw ( ParserException );
76 static uint16_t axtoi( char* );
78 /// The directory containing the images to check:
81 /// The product of the parser:
82 MapFileValuesType ProducedMap;
84 /// The ifstream attached to the file we parse:
87 /// String prefixing every output
90 /// The current line position within the stream:
93 /// The currently parsed filename:
94 std::string CurrentFileName;
96 /// The currently parsed key:
97 std::string CurrentKey;
99 /// The currently parsed value:
100 std::string CurrentValue;
102 /// The current MapEntryValues pointer:
103 MapEntryValues* CurrentMapEntryValuesPtr;
107 /// http://community.borland.com/article/0,1410,17203,0.html
108 uint16_t ReferenceFileParser::axtoi(char *hexStg) {
109 int n = 0; // position in string
110 int m = 0; // position in digit[] to shift
111 int count; // loop index
112 int intValue = 0; // integer value of hex string
113 int digit[5]; // hold values to convert
117 if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
118 digit[n] = hexStg[n] & 0x0f; //convert to int
119 else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
120 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
121 else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
122 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
130 // digit[n] is value of hex digit at position n
131 // (m << 2) is the number of positions to shift
132 // OR the bits into return value
133 intValue = intValue | (digit[n] << (m << 2));
134 m--; // adjust the position to set
135 n++; // next digit to process
140 void ReferenceFileParser::SetDataPath( std::string& inDataPath )
142 DataPath = inDataPath;
145 bool ReferenceFileParser::AddKeyValuePairToMap( std::string& key,
148 if ( !CurrentMapEntryValuesPtr )
150 if ( CurrentMapEntryValuesPtr->count(key) != 0 )
152 (*CurrentMapEntryValuesPtr)[key] = value;
157 void ReferenceFileParser::Print()
159 for (MapFileValuesType::iterator i = ProducedMap.begin();
160 i != ProducedMap.end();
163 std::cout << Indent << "FileName: " << i->first << std::endl;
164 MapEntryValuesPtr KeyValues = i->second;
165 for (MapEntryValues::iterator j = KeyValues->begin();
166 j != KeyValues->end();
170 << " Key: " << j->first
171 << " Value: " << j->second
174 std::cout << Indent << std::endl;
176 std::cout << Indent << std::endl;
179 bool ReferenceFileParser::Check()
182 for (MapFileValuesType::iterator i = ProducedMap.begin();
183 i != ProducedMap.end();
188 std::cout << Indent << std::endl;
192 bool ReferenceFileParser::Check( std::string fileName )
194 MapFileValuesType::iterator it = ProducedMap.find(fileName);
195 if( it != ProducedMap.end() )
199 std::cerr << Indent << "Failed\n"
200 << Indent << "Image not found :"
201 << fileName << std::endl;
205 bool ReferenceFileParser::Check( MapFileValuesType::iterator &fileIt )
207 std::string fileName = DataPath + fileIt->first;
208 std::cout << Indent << "FileName: " << fileName << std::endl;
209 gdcm::Header* tested = new gdcm::Header( fileName.c_str() );
210 if( !tested->IsReadable() )
212 std::cerr << Indent << "Failed\n"
213 << Indent << "Image not gdcm compatible:"
214 << fileName << std::endl;
219 MapEntryValuesPtr KeyValues = fileIt->second;
220 for (MapEntryValues::iterator j = KeyValues->begin();
221 j != KeyValues->end();
224 std::string key = j->first;
226 std::string groupString = key.substr( 0, 4 );
227 std::string groupElement = key.substr( key.find_first_of( "|" ) + 1, 4 );
229 uint16_t group = axtoi( &(groupString[0]) );
230 uint16_t element = axtoi( &(groupElement[0]) );
232 std::string testedValue = tested->GetEntryByNumber(group, element);
233 if ( testedValue != j->second )
235 // Oops make sure this is only the \0 that differ
236 if( testedValue[j->second.size()] != '\0' ||
237 strncmp(testedValue.c_str(),
238 j->second.c_str(), j->second.size()) != 0)
240 std::cout << Indent << "Failed\n"
241 << Indent << "Uncorrect value for key "
243 << Indent << " read value ["
244 << testedValue << "]" << std::endl
245 << Indent << " reference value ["
246 << j->second << "]" << std::endl;
252 std::cout << Indent << " OK" << std::endl;
257 std::istream& ReferenceFileParser::eatwhite( std::istream& is )
269 void ReferenceFileParser::eatwhite( std::string& toClean )
271 while( toClean.find_first_of( " " ) == 0 )
272 toClean.erase( 0, toClean.find_first_of( " " ) + 1 );
275 std::string ReferenceFileParser::ExtractFirstString( std::string& toSplit )
277 std::string firstString;
279 if ( toSplit.find( " " ) == std::string::npos ) {
280 firstString = toSplit;
284 firstString = toSplit.substr( 0, toSplit.find(" ") );
285 toSplit.erase( 0, toSplit.find(" ") + 1);
290 std::string ReferenceFileParser::ExtractValue( std::string& toSplit )
291 throw ( ParserException )
294 std::string::size_type beginPos = toSplit.find_first_of( '"' );
295 std::string::size_type endPos = toSplit.find_last_of( '"' );
297 // Make sure we have at most two " in toSplit:
298 //std::string noQuotes = toSplit.substr( beginPos + 1, endPos - beginPos - 1);
299 //if ( noQuotes.find_first_of( '"' ) != std::string::npos )
300 // throw ParserException( "more than two quote character" );
301 if ( toSplit.find_first_of( '"',beginPos+1 ) != endPos )
302 throw ParserException( "more than two quote character" );
304 // No leading quote means this is not a value:
305 if ( beginPos == std::string::npos )
307 return std::string();
310 if ( ( endPos == std::string::npos ) || ( beginPos == endPos ) )
311 throw ParserException( "unmatched \" (quote character)" );
315 std::ostringstream error;
316 error << "leading character ["
317 << toSplit.substr(beginPos -1, 1)
318 << "] before opening \" ";
319 throw ParserException( error.str() );
322 // When they are some extra characters at end of value, it must
324 if ( ( endPos != toSplit.length() - 1 )
325 && ( toSplit.substr(endPos + 1, 1) != " " ) )
327 std::ostringstream error;
328 error << "trailing character ["
329 << toSplit.substr(endPos + 1, 1)
330 << "] after value closing \" ";
331 throw ParserException( error.str() );
334 std::string value = toSplit.substr( beginPos + 1, endPos - beginPos - 1 );
335 toSplit.erase( beginPos, endPos - beginPos + 1);
340 /// \brief Checks the block syntax of the incoming ifstream. Checks that
341 /// - no nested blocks are present
342 /// - we encounter a matching succesion of "[" and "]"
343 /// - when ifstream terminates the last block is closed.
344 /// - a block is not opened and close on the same line
345 /// @param from The incoming ifstream to be checked.
346 /// @return True when incoming ifstream has a correct syntax, false otherwise.
347 /// \warning The underlying file pointer is not preseved.
348 void ReferenceFileParser::FirstPassReferenceFile() throw ( ParserException )
352 bool inBlock = false;
353 from.seekg( 0, std::ios::beg );
355 while ( ! from.eof() )
357 std::getline( from, line );
359 /// This is how we usually end the parsing because we hit EOF:
365 throw ParserException( "Syntax error: EOF reached when in block.");
368 // Don't try to parse comments (weed out anything after first "#"):
369 if ( line.find_first_of( "#" ) != std::string::npos )
371 line.erase( line.find_first_of( "#" ) );
374 // Two occurences of opening blocks on a single line implies nested
375 // blocks which is illegal:
376 if ( line.find_first_of( "[" ) != line.find_last_of( "[" ) )
378 std::ostringstream error;
379 error << "Syntax error: nested block (open) in reference file"
381 << ParserException::GetIndent()
382 << " at line " << lineNumber << std::endl;
383 throw ParserException( error.str() );
386 // Two occurences of closing blocks on a single line implies nested
387 // blocks which is illegal:
388 if ( line.find_first_of( "]" ) != line.find_last_of( "]" ) )
390 std::ostringstream error;
391 error << "Syntax error: nested block (close) in reference file"
393 << ParserException::GetIndent()
394 << " at line " << lineNumber << std::endl;
395 throw ParserException( error.str() );
398 bool beginBlock ( line.find_first_of("[") != std::string::npos );
399 bool endBlock ( line.find_last_of("]") != std::string::npos );
401 // Opening and closing of block on same line:
402 if ( beginBlock && endBlock )
404 std::ostringstream error;
405 error << "Syntax error: opening and closing on block on same line "
406 << lineNumber++ << std::endl;
407 throw ParserException( error.str() );
410 // Illegal closing block when block not open:
411 if ( !inBlock && endBlock )
413 std::ostringstream error;
414 error << "Syntax error: unexpected end of block at line "
415 << lineNumber++ << std::endl;
416 throw ParserException( error.str() );
419 // Uncommented line outside of block is not clean:
420 if ( !inBlock && !beginBlock )
425 if ( inBlock && beginBlock )
427 std::ostringstream error;
428 error << " Syntax error: illegal opening of nested block at line "
429 << lineNumber++ << std::endl;
430 throw ParserException( error.str() );
433 // Normal situation of opening block:
441 // Normal situation of closing block:
448 // This line had no block delimiter
452 // We need rewinding:
454 from.seekg( 0, std::ios::beg );
457 ReferenceFileParser::ReferenceFileParser()
463 bool ReferenceFileParser::Open( std::string& referenceFileName )
465 from.open( referenceFileName.c_str(), std::ios::in );
466 if ( !from.is_open() )
468 std::cerr << Indent << "Can't open reference file." << std::endl;
473 FirstPassReferenceFile();
474 SecondPassReferenceFile();
476 catch ( ParserException except )
486 void ReferenceFileParser::CleanUpLine( std::string& line )
488 // Cleanup from comments:
489 if ( line.find_first_of( "#" ) != std::string::npos )
490 line.erase( line.find_first_of( "#" ) );
492 // Cleanup everything after end block delimiter:
493 if ( line.find_last_of( "]" ) != std::string::npos )
494 line.erase( line.find_last_of( "]" ) + 1 );
496 // Cleanup leading whites and skip empty lines:
500 void ReferenceFileParser::HandleFileName( std::string& line )
501 throw ( ParserException )
503 if ( line.length() == 0 )
504 throw ParserException( "empty line on call of HandleFileName" );
506 if ( CurrentFileName.length() != 0 )
509 CurrentFileName = ExtractFirstString(line);
512 void ReferenceFileParser::HandleKey( std::string& line )
513 throw ( ParserException )
515 if ( CurrentKey.length() != 0 )
518 CurrentKey = ExtractFirstString(line);
519 if ( CurrentKey.find_first_of( "|" ) == std::string::npos )
521 std::ostringstream error;
522 error << "uncorrect key:" << CurrentKey;
523 throw ParserException( error.str() );
527 bool ReferenceFileParser::HandleValue( std::string& line )
528 throw ( ParserException )
530 if ( line.length() == 0 )
531 throw ParserException( "empty line in HandleValue" );
533 if ( CurrentKey.length() == 0 )
535 std::cout << Indent << "No key present:" << CurrentKey << std::endl;
539 std::string newCurrentValue = ExtractValue(line);
540 if ( newCurrentValue.length() == 0 )
542 std::cout << Indent << "Warning: empty value for key:"
543 << CurrentKey << std::endl;
546 CurrentValue += newCurrentValue;
550 void ReferenceFileParser::ParseRegularLine( std::string& line)
551 throw ( ParserException )
553 if ( line.length() == 0 )
556 // First thing is to get a filename:
557 HandleFileName( line );
559 if ( line.length() == 0 )
562 // Second thing is to get a key:
565 if ( line.length() == 0 )
568 // Third thing is to get a value:
569 if ( ! HandleValue( line ) )
572 if ( CurrentKey.length() && CurrentValue.length() )
574 if ( ! AddKeyValuePairToMap( CurrentKey, CurrentValue ) )
575 throw ParserException( "adding to map of (key, value) failed" );
577 CurrentValue.erase();
581 bool ReferenceFileParser::SecondPassReferenceFile()
582 throw ( ParserException )
585 EntryValueType value;
587 bool inBlock = false;
590 while ( !from.eof() )
592 std::getline( from, line );
597 // Empty lines don't require any treatement:
598 if ( line.length() == 0 )
601 bool beginBlock ( line.find_first_of("[") != std::string::npos );
602 bool endBlock ( line.find_last_of("]") != std::string::npos );
604 // Waiting for a block to be opened. Meanwhile, drop everything:
605 if ( !inBlock && !beginBlock )
611 line.erase( 0, line.find_first_of( "[" ) + 1 );
613 CurrentMapEntryValuesPtr = new MapEntryValues();
617 line.erase( line.find_last_of( "]" ) );
619 ParseRegularLine( line );
620 ProducedMap[CurrentFileName] = CurrentMapEntryValuesPtr;
622 CurrentFileName.erase();
625 // Outside block lines are dropped:
629 ParseRegularLine( line );
634 int TestAllEntryVerify(int argc, char* argv[])
638 std::cerr << " Usage: " << argv[0]
639 << " fileName" << std::endl;
643 std::string referenceDir = GDCM_DATA_ROOT;
645 std::string referenceFilename = referenceDir + "TestAllEntryVerifyReference.txt";
647 std::cout << " Description (Test::TestAllEntryVerify): "
649 std::cout << " For all images (not blacklisted in gdcm/Test/CMakeLists.txt)"
651 std::cout << " encountered in directory: " << GDCM_DATA_ROOT << std::endl;
652 std::cout << " apply the following tests : "<< std::endl;
653 std::cout << " step 1: parse the image and call IsReadable(). " << std::endl;
654 std::cout << " step 2: look for the entry corresponding to the image" << std::endl;
655 std::cout << " in the reference file: \n"
656 << " " << referenceFilename << std::endl;
657 std::cout << " step 3: check that each reference tag value listed for this"
659 std::cout << " entry matches the tag encountered at parsing step 1."
660 << std::endl << std::endl;
662 ReferenceFileParser Parser;
663 if ( !Parser.Open(referenceFilename) )
665 std::cout << " failed"
666 << " Corrupted reference file name: "
667 << referenceFilename << std::endl;
670 Parser.SetDataPath(referenceDir);
672 std::cout << "Reference file loaded -->\n"
673 << "Check files : \n";
678 ret = Parser.Check( argv[1] );
682 ret = Parser.Check();