5 #include "gdcmHeader.h"
8 #include "gdcmDataImages.h"
12 typedef string EntryValueType; // same type as gdcmValEntry::value
13 typedef list<gdcmTagKey, EntryValueType> ListEntryValues;
14 typedef string FileNameType;
15 typedef map<FileNameType, ListEntryValues*> MapFileValuesType;
17 class ReferenceFileParser
19 istream& eatwhite(istream& is);
20 void eatwhite(string& toClean);
21 string ExtractFirstString(string& toSplit);
22 string ExtractValue(string& toSplit);
23 void CleanUpLine( string& line );
26 bool FirstPassReferenceFile();
27 bool SecondPassReferenceFile();
28 bool HandleFileName( string& line );
29 bool HandleKey( string& line );
30 bool HandleValue( string& line );
32 ReferenceFileParser();
33 bool Open( string& referenceFileName );
35 /// The ifstream attached to the file we parse:
38 /// True when things went wrong, false otherwise
41 /// String prefixing every output
44 /// The current line position within the stream:
47 string CurrentFileName;
50 string CurrentErrorMessage;
53 istream& ReferenceFileParser::eatwhite( istream& is )
65 void ReferenceFileParser::eatwhite( string& toClean )
67 while( toClean.find_first_of( " " ) == 0 )
68 toClean.erase( 0, toClean.find_first_of( " " ) + 1 );
71 string ReferenceFileParser::ExtractFirstString( string& toSplit )
73 std::string firstString;
75 if ( toSplit.find( " " ) == string::npos ) {
76 firstString = toSplit;
80 firstString = toSplit.substr( 0, toSplit.find(" ") );
81 toSplit.erase( 0, toSplit.find(" ") + 1);
86 string ReferenceFileParser::ExtractValue( string& toSplit )
89 string::size_type beginPos = toSplit.find_first_of( '"' );
90 string::size_type endPos = toSplit.find_last_of( '"' );
92 // Make sure we have at most to " in toSplit:
93 string noQuotes = toSplit.substr( beginPos + 1, endPos - beginPos - 1);
94 if ( noQuotes.find_first_of( '"' ) != string::npos )
96 CurrentErrorMessage = "more than two quote character";
100 // No leading quote means this is not a value:
101 if ( beginPos == string::npos )
106 if ( ( endPos == string::npos ) || ( beginPos == endPos ) )
108 CurrentErrorMessage = "unmatched \" (quote character)";
115 error << "leading character ["
116 << toSplit.substr(beginPos -1, 1)
117 << "] before opening \" ";
118 CurrentErrorMessage = error.str();
122 // When they are some extra characters at end of value, it must
124 if ( ( endPos != toSplit.length() - 1 )
125 && ( toSplit.substr(endPos + 1, 1) != " " ) )
128 error << "trailing character ["
129 << toSplit.substr(endPos + 1, 1)
130 << "] after value closing \" ";
131 CurrentErrorMessage = error.str();
135 string value = toSplit.substr( beginPos + 1, endPos - beginPos - 1 );
136 toSplit.erase( beginPos, endPos - beginPos + 1);
141 /// \brief Checks the block syntax of the incoming ifstream. Checks that
142 /// - no nested blocks are present
143 /// - we encounter a matching succesion of "[" and "]"
144 /// - when ifstream terminates the last block is closed.
145 /// - a block is not opened and close on the same line
146 /// @param from The incoming ifstream to be checked.
147 /// @return True when incoming ifstream has a correct syntax, false otherwise.
148 /// \warning The underlying file pointer is not preseved.
149 bool ReferenceFileParser::FirstPassReferenceFile()
153 bool inBlock = false;
154 from.seekg( 0, ios::beg );
156 while ( ! from.eof() )
158 getline( from, line );
160 /// This is how we usually end the parsing because we hit EOF:
167 cerr << Indent << "Syntax error: EOF reached when in block." << endl;
168 ParsingFailed = true;
173 // Don't try to parse comments (weed out anything after first "#"):
174 if ( line.find_first_of( "#" ) != string::npos )
176 line.erase( line.find_first_of( "#" ) );
179 // Two occurences of opening blocks on a single line implies nested
180 // blocks which is illegal:
181 if ( line.find_first_of( "[" ) != line.find_last_of( "[" ) )
184 << "Syntax error: nested block (open) in reference file"
186 << Indent << "at line " << lineNumber << endl;
187 ParsingFailed = true;
191 // Two occurences of closing blocks on a single line implies nested
192 // blocks which is illegal:
193 if ( line.find_first_of( "]" ) != line.find_last_of( "]" ) )
196 << "Syntax error: nested block (close) in reference file"
198 << Indent << "at line " << lineNumber << endl;
199 ParsingFailed = true;
203 bool beginBlock ( line.find_first_of("[") != string::npos );
204 bool endBlock ( line.find_last_of("]") != string::npos );
206 // Opening and closing of block on same line:
207 if ( beginBlock && endBlock )
210 << "Syntax error: opening and closing on block on same line "
211 << lineNumber++ << endl;
212 ParsingFailed = true;
216 // Illegal closing block when block not open:
217 if ( !inBlock && endBlock )
219 cerr << Indent << "Syntax error: unexpected end of block at line "
220 << lineNumber++ << endl;
221 ParsingFailed = true;
225 // Uncommented line outside of block is not clean:
226 if ( !inBlock && !beginBlock )
229 << "Syntax warning: outside of block [] data at line "
230 << lineNumber++ << " not considered." << endl;
234 if ( inBlock && beginBlock )
236 cerr << " Syntax error: illegal opening of nested block at line "
237 << lineNumber++ << endl;
238 ParsingFailed = true;
242 // Normal situation of opening block:
250 // Normal situation of closing block:
257 // This line had no block delimiter
261 // We need rewinding:
263 from.seekg( 0, ios::beg );
265 return ! ParsingFailed;
268 ReferenceFileParser::ReferenceFileParser()
271 ParsingFailed = false;
275 bool ReferenceFileParser::Open( string& referenceFileName )
277 from.open( referenceFileName.c_str(), ios::in );
278 if ( !from.is_open() )
280 cerr << Indent << "Can't open reference file." << endl;
281 ParsingFailed = true;
284 if ( !FirstPassReferenceFile() )
287 SecondPassReferenceFile();
291 void ReferenceFileParser::CleanUpLine( string& line )
293 // Cleanup from comments:
294 if ( line.find_first_of( "#" ) != string::npos )
295 line.erase( line.find_first_of( "#" ) );
297 // Cleanup everything after end block delimiter:
298 if ( line.find_last_of( "]" ) != string::npos )
299 line.erase( line.find_last_of( "]" ) + 1 );
301 // Cleanup leanding whites and skip empty lines:
305 bool ReferenceFileParser::HandleFileName( string& line )
307 if ( line.length() == 0 )
309 CurrentErrorMessage = "unfound filename";
312 if ( CurrentFileName.length() != 0 )
314 CurrentFileName = ExtractFirstString(line);
315 cout << Indent << "Found filename " << CurrentFileName << endl;
319 bool ReferenceFileParser::HandleKey( string& line )
321 if ( line.length() == 0 )
324 if ( CurrentKey.length() != 0 )
327 CurrentKey = ExtractFirstString(line);
328 if ( CurrentKey.find_first_of( "|" ) == string::npos )
331 error << "uncorrect key:" << CurrentKey;
332 CurrentErrorMessage = error.str();
335 cout << Indent << "Found key:" << CurrentKey << endl;
339 bool ReferenceFileParser::HandleValue( string& line )
341 if ( line.length() == 0 )
343 CurrentErrorMessage = "no value present";
347 if ( CurrentKey.length() == 0 )
349 cout << Indent << "No key present:" << CurrentKey << endl;
353 string newCurrentValue = ExtractValue(line);
354 if ( newCurrentValue.length() == 0 )
356 if ( CurrentErrorMessage.length() == 0 )
359 error << "missing value for key:" << CurrentKey;
360 CurrentErrorMessage = error.str();
365 cout << Indent << "Found value:" << newCurrentValue << endl;
366 CurrentValue += newCurrentValue;
370 void ReferenceFileParser::DisplayLine()
372 cerr << Indent << "Syntax error at line " << lineNumber
373 << ": " << CurrentErrorMessage << "." << endl;
376 bool ReferenceFileParser::SecondPassReferenceFile()
379 EntryValueType value;
381 bool inBlock = false;
384 while ( !from.eof() )
386 getline( from, line );
391 // Empty lines don't require any treatement:
392 if ( line.length() == 0 )
395 bool beginBlock ( line.find_first_of("[") != string::npos );
396 bool endBlock ( line.find_last_of("]") != string::npos );
398 // Waiting for a block to be opened. Meanwhile, drop everything:
399 if ( !inBlock && !beginBlock )
404 cout << Indent << "Begin block" << endl;
406 line.erase( 0, line.find_first_of( "[" ) + 1 );
411 cout << Indent << "Detected End block" << endl;
412 line.erase( line.find_last_of( "]" ) );
416 // Outside block lines are dropped:
420 cout << Indent << "Default case:" << line << endl;
422 // First thing is to get a filename:
423 if ( ( ! HandleFileName( line ) ) && ( line.length() != 0 ) )
429 // Second thing is to get a key:
430 if ( ( ! HandleKey( line ) ) && ( line.length() != 0 ) )
432 ParsingFailed = true;
435 // Third thing is to get a value:
436 if ( ( ! ParsingFailed )
437 && ( ! HandleValue( line ) )
438 && ( line.length() != 0) )
440 ParsingFailed = true;
443 if ( ( ! ParsingFailed )
444 && CurrentKey.length()
445 && CurrentValue.length() )
447 cout << Indent << "Need to handle pair ("
448 << CurrentKey << ", " << CurrentValue << ")." << endl;
450 CurrentValue.erase();
461 cout << Indent << "Need to handle end of block " << endl;
463 CurrentFileName.erase();
466 //key = TranslateToKey(group, element);
467 ///tb1[key] = name.c_str();
468 //cout << group << element << vr << fourth << name;
473 int TestAllEntryVerify(int argc, char* argv[])
477 cerr << " Usage: " << argv[0]
478 << " (no arguments needed)." << endl;
482 cout << " Description (Test::TestAllEntryVerify): "
484 cout << " For all images in gdcmData (and not blacklisted in "
485 "Test/CMakeLists.txt)"
487 cout << " apply the following to each filename.xxx: "
489 cout << " step 1: parse the image (as gdcmHeader) and call"
493 string referenceFilename = GDCM_DATA_ROOT;
494 referenceFilename += "/"; //doh!
495 referenceFilename += "TestAllEntryVerifyReference.txt";
497 ReferenceFileParser Parser;
498 Parser.Open(referenceFilename);
501 while( gdcmDataImages[i] != 0 )
503 string filename = GDCM_DATA_ROOT;
504 filename += "/"; //doh!
505 filename += gdcmDataImages[i++];
507 cout << " Testing: " << filename << endl;
509 gdcmHeader* tested = new gdcmHeader( filename.c_str(), false, true );
510 if( !tested->GetHeader()->IsReadable() )
512 cout << " Image not gdcm compatible:"
518 //////////////// Clean up: