]> Creatis software - gdcm.git/blob - Testing/TestAllEntryVerify.cxx
386e952b6f09e56d467fa0ab45e890c44ac8c46f
[gdcm.git] / Testing / TestAllEntryVerify.cxx
1 #include <map>
2 #include <list>
3 #include <fstream>
4 #include <iostream>
5 #include "gdcmHeader.h"
6
7 //Generated file:
8 #include "gdcmDataImages.h"
9
10 using namespace std;
11
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;
16
17 class ReferenceFileParser
18 {
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 );
24    void DisplayLine();
25
26    bool FirstPassReferenceFile();
27    bool SecondPassReferenceFile();
28    bool HandleFileName( string& line );
29    bool HandleKey( string& line );
30    bool HandleValue( string& line );
31 public:
32    ReferenceFileParser();
33    bool Open( string& referenceFileName );
34 private:
35    /// The ifstream attached to the file we parse:
36    ifstream from;
37
38    /// True when things went wrong, false otherwise
39    bool ParsingFailed;
40    
41    /// String prefixing every output
42    string Indent;
43
44    /// The current line position within the stream:
45    int lineNumber;
46
47    string CurrentFileName;
48    string CurrentKey;
49    string CurrentValue;
50    string CurrentErrorMessage;
51 };
52
53 istream& ReferenceFileParser::eatwhite( istream& is )
54 {
55    char c;
56    while (is.get(c)) {
57       if (!isspace(c)) {
58          is.putback(c);
59          break;
60       }
61    }
62    return is;
63 }
64
65 void ReferenceFileParser::eatwhite( string& toClean )
66 {
67    while( toClean.find_first_of( " " ) == 0  )
68       toClean.erase( 0, toClean.find_first_of( " " ) + 1 );
69 }
70
71 string ReferenceFileParser::ExtractFirstString( string& toSplit )
72 {
73    std::string firstString;
74    eatwhite( toSplit );
75    if ( toSplit.find( " " ) == string::npos ) {
76       firstString = toSplit;
77       toSplit.erase();
78       return firstString;
79    }
80    firstString = toSplit.substr( 0, toSplit.find(" ") );
81    toSplit.erase( 0, toSplit.find(" ") + 1);
82    eatwhite( toSplit );
83    return firstString;
84 }
85
86 string ReferenceFileParser::ExtractValue( string& toSplit )
87 {
88    eatwhite( toSplit );
89    string::size_type beginPos = toSplit.find_first_of( '"' );
90    string::size_type   endPos = toSplit.find_last_of( '"' );
91
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 )
95    {
96       CurrentErrorMessage = "more than two quote character";
97       return string();
98    }
99
100    // No leading quote means this is not a value:
101    if ( beginPos == string::npos )
102    {
103       return string();
104    }
105
106    if ( ( endPos == string::npos ) || ( beginPos == endPos ) )
107    {
108       CurrentErrorMessage = "unmatched \" (quote character)";
109       return string();
110    }
111
112    if ( beginPos != 0 )
113    {
114       ostringstream error;
115       error  << "leading character ["
116              << toSplit.substr(beginPos -1, 1)
117              << "] before opening \" ";
118       CurrentErrorMessage = error.str();
119       return string();
120    }
121
122    // When they are some extra characters at end of value, it must
123    // be a space:
124    if (   ( endPos != toSplit.length() - 1 )
125        && ( toSplit.substr(endPos + 1, 1) != " " ) )
126    {
127       ostringstream error;
128       error  << "trailing character ["
129              << toSplit.substr(endPos + 1, 1)
130              << "] after value closing \" ";
131       CurrentErrorMessage = error.str();
132       return string();
133    }
134
135    string value = toSplit.substr( beginPos + 1, endPos - beginPos - 1 );
136    toSplit.erase(  beginPos, endPos - beginPos + 1);
137    eatwhite( toSplit );
138    return value;
139 }
140
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()
150 {
151    string line;
152    lineNumber = 1;
153    bool inBlock = false;
154    from.seekg( 0, ios::beg );
155
156    while ( ! from.eof() )
157    {
158       getline( from, line );
159
160       /// This is how we usually end the parsing because we hit EOF:
161       if ( ! from.good() )
162       {
163          if ( ! inBlock )
164             break;
165          else
166          {
167            cerr << Indent << "Syntax error: EOF reached when in block." << endl;
168            ParsingFailed = true;
169            break;
170          }
171       }
172
173       // Don't try to parse comments (weed out anything after first "#"):
174       if ( line.find_first_of( "#" ) != string::npos )
175       {
176          line.erase( line.find_first_of( "#" ) );
177       }
178
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( "[" ) )
182       {
183          cerr << Indent
184               << "Syntax error: nested block (open) in reference file"
185               << endl
186               << Indent << "at line " << lineNumber << endl;
187          ParsingFailed = true;
188          break;
189       }
190
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( "]" ) )
194       {
195          cerr << Indent
196               << "Syntax error: nested block (close) in reference file"
197               << endl
198               <<  Indent << "at line " << lineNumber << endl;
199          ParsingFailed = true;
200          break;
201       }
202
203       bool beginBlock ( line.find_first_of("[") != string::npos );
204       bool endBlock   ( line.find_last_of("]")  != string::npos );
205
206       // Opening and closing of block on same line:
207       if ( beginBlock && endBlock )
208       {
209          cerr << Indent
210               << "Syntax error: opening and closing on block on same line "
211               << lineNumber++ << endl;
212          ParsingFailed = true;
213          break;
214       }
215
216       // Illegal closing block when block not open:
217       if ( !inBlock && endBlock )
218       {
219          cerr << Indent << "Syntax error: unexpected end of block at line "
220               << lineNumber++ << endl;
221          ParsingFailed = true;
222          break;
223       }
224   
225       // Uncommented line outside of block is not clean:
226       if ( !inBlock && !beginBlock )
227       {
228          cout << Indent
229               << "Syntax warning: outside of block [] data at line "
230               << lineNumber++ << " not considered." << endl;
231          continue;
232       }
233
234       if ( inBlock && beginBlock )
235       {
236          cerr << "   Syntax error: illegal opening of nested block at line "
237               << lineNumber++ << endl;
238          ParsingFailed = true;
239          break;
240       }
241
242       // Normal situation of opening block:
243       if ( beginBlock )
244       {
245          inBlock = true;
246          lineNumber++;
247          continue;
248       }
249
250       // Normal situation of closing block:
251       if ( endBlock )
252       {
253          inBlock = false;
254          lineNumber++;
255          continue;
256       }
257       // This line had no block delimiter
258       lineNumber++;
259    }
260
261    // We need rewinding:
262    from.clear();
263    from.seekg( 0, ios::beg );
264
265    return ! ParsingFailed;
266 }
267
268 ReferenceFileParser::ReferenceFileParser()
269 {
270    lineNumber = 1;
271    ParsingFailed = false;
272    Indent = "      ";
273 }
274
275 bool ReferenceFileParser::Open( string& referenceFileName )
276 {
277    from.open( referenceFileName.c_str(), ios::in );
278    if ( !from.is_open() )
279    {
280       cerr << Indent << "Can't open reference file." << endl;
281       ParsingFailed = true;
282    }
283    
284    if ( !FirstPassReferenceFile() )
285       return false;
286
287    SecondPassReferenceFile();
288    from.close();
289 }
290
291 void ReferenceFileParser::CleanUpLine( string& line )
292 {
293    // Cleanup from comments:
294    if ( line.find_first_of( "#" ) != string::npos )
295       line.erase( line.find_first_of( "#" ) );
296
297    // Cleanup everything after end block delimiter:
298    if ( line.find_last_of( "]" ) != string::npos )
299       line.erase( line.find_last_of( "]" ) + 1 );
300
301    // Cleanup leanding whites and skip empty lines:
302    eatwhite( line );
303 }
304
305 bool ReferenceFileParser::HandleFileName( string& line )
306 {
307    if ( line.length() == 0 )
308    {
309       CurrentErrorMessage = "unfound filename";
310       return false;
311    }
312    if ( CurrentFileName.length() != 0 )
313       return true;
314    CurrentFileName = ExtractFirstString(line);
315    cout << Indent << "Found filename " << CurrentFileName << endl;
316    return true;
317 }
318
319 bool ReferenceFileParser::HandleKey( string& line )
320 {
321    if ( line.length() == 0 )
322       return false;
323
324    if ( CurrentKey.length() != 0 )
325       return false;
326
327    CurrentKey = ExtractFirstString(line);
328    if ( CurrentKey.find_first_of( "|" ) == string::npos )
329    {
330       ostringstream error;
331       error  << "uncorrect key:" << CurrentKey;
332       CurrentErrorMessage = error.str();
333       return false;
334    }
335    cout << Indent << "Found key:" << CurrentKey << endl;
336    return true;
337 }
338
339 bool ReferenceFileParser::HandleValue( string& line )
340 {
341    if ( line.length() == 0 )
342    {
343       CurrentErrorMessage = "no value present";
344       return false;
345    }
346
347    if ( CurrentKey.length() == 0 )
348    {
349       cout << Indent << "No key present:" << CurrentKey << endl;
350       return false;
351    }
352    
353    string newCurrentValue = ExtractValue(line);
354    if ( newCurrentValue.length() == 0 )
355    {
356       if ( CurrentErrorMessage.length() == 0 )
357       {
358          ostringstream error;
359          error  << "missing value for key:" << CurrentKey;
360          CurrentErrorMessage = error.str();
361       }
362       return false;
363    }
364
365    cout << Indent << "Found value:" << newCurrentValue << endl;
366    CurrentValue += newCurrentValue;
367    return true;
368 }
369
370 void ReferenceFileParser::DisplayLine()
371 {
372       cerr << Indent << "Syntax error at line " << lineNumber
373            << ": " << CurrentErrorMessage << "." << endl;
374 }
375
376 bool ReferenceFileParser::SecondPassReferenceFile()
377 {
378    gdcmTagKey key;
379    EntryValueType value;
380    string line;
381    bool inBlock = false;
382    lineNumber = 0;
383
384    while ( !from.eof() )
385    {
386       getline( from, line );
387       lineNumber++;
388
389       CleanUpLine( line );
390
391       // Empty lines don't require any treatement:
392       if ( line.length() == 0 )
393          continue;
394
395       bool beginBlock ( line.find_first_of("[") != string::npos );
396       bool endBlock   ( line.find_last_of("]")  != string::npos );
397
398       // Waiting for a block to be opened. Meanwhile, drop everything:
399       if ( !inBlock && !beginBlock )
400          continue;
401
402       if ( beginBlock )
403       {
404          cout << Indent << "Begin block" << endl;
405          inBlock = true;
406          line.erase( 0, line.find_first_of( "[" ) + 1 );
407          eatwhite( line );
408       }
409       else if ( endBlock )
410       {
411          cout << Indent << "Detected End block" << endl;
412          line.erase( line.find_last_of( "]" ) );
413          eatwhite( line );
414       }
415
416       // Outside block lines are dropped:
417       if ( ! inBlock )
418          continue;
419
420       cout << Indent << "Default case:" << line << endl;
421
422       // First thing is to get a filename:
423       if ( ( ! HandleFileName( line ) ) && ( line.length() != 0 ) )
424       {
425          DisplayLine();
426          return false;
427       }
428
429       // Second thing is to get a key:
430       if ( ( ! HandleKey( line ) ) && ( line.length() != 0 ) )
431       {
432          ParsingFailed = true;
433       }
434        
435       // Third thing is to get a value:
436       if (    ( ! ParsingFailed )
437           &&  ( ! HandleValue( line ) )
438           && ( line.length() != 0) )
439       {
440          ParsingFailed = true;
441       }
442
443       if (   ( ! ParsingFailed )
444           && CurrentKey.length()
445           && CurrentValue.length() )
446       {
447          cout << Indent << "Need to handle pair ("
448               << CurrentKey << ", " << CurrentValue << ")." << endl;
449          CurrentKey.erase();
450          CurrentValue.erase();
451       }
452
453       if ( ParsingFailed )
454       {
455          DisplayLine();
456          return false;
457       }
458
459       if ( endBlock )
460       {
461          cout << Indent << "Need to handle end of block " << endl;
462          inBlock = false;
463          CurrentFileName.erase();
464       }
465
466       //key     = TranslateToKey(group, element);
467       ///tb1[key] = name.c_str();
468       //cout << group << element << vr << fourth << name;
469       //tb1[key] = "bozo";
470    }
471 }
472
473 int TestAllEntryVerify(int argc, char* argv[]) 
474 {
475    if ( argc > 1 )
476    {
477       cerr << "   Usage: " << argv[0]
478                 << " (no arguments needed)." << endl;
479       return 1;
480    }
481    
482    cout << "   Description (Test::TestAllEntryVerify): "
483              << endl;
484    cout << "   For all images in gdcmData (and not blacklisted in "
485                 "Test/CMakeLists.txt)"
486              << endl;
487    cout << "   apply the following to each filename.xxx: "
488              << endl;
489    cout << "   step 1: parse the image (as gdcmHeader) and call"
490              << " IsReadable(). "
491              << endl;
492
493    string referenceFilename = GDCM_DATA_ROOT;
494    referenceFilename += "/";  //doh!
495    referenceFilename += "TestAllEntryVerifyReference.txt";
496
497    ReferenceFileParser Parser;
498    Parser.Open(referenceFilename);
499 /*
500    int i = 0;
501    while( gdcmDataImages[i] != 0 )
502    {
503       string filename = GDCM_DATA_ROOT;
504       filename += "/";  //doh!
505       filename += gdcmDataImages[i++];
506    
507       cout << "   Testing: " << filename << endl;
508
509       gdcmHeader* tested = new gdcmHeader( filename.c_str(), false, true );
510       if( !tested->GetHeader()->IsReadable() )
511       {
512         cout << "      Image not gdcm compatible:"
513                   << filename << endl;
514         delete tested;
515         return 1;
516       }
517
518       //////////////// Clean up:
519       delete tested;
520    }
521 */
522
523    return 0;
524 }