]> Creatis software - gdcm.git/blob - Testing/TestAllEntryVerify.cxx
* gdcmPython/testSuite.py checks on CR-MONO1-10-chest.dcm moved to
[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 map< gdcmTagKey, EntryValueType > MapEntryValues;
14 typedef MapEntryValues* MapEntryValuesPtr;
15 typedef string FileNameType;
16 typedef map< FileNameType, MapEntryValuesPtr > MapFileValuesType;
17
18 struct ParserException
19 {
20    string error;
21    static string Indent;
22
23    static string GetIndent() { return ParserException::Indent; }
24    ParserException( string ErrorMessage )
25    {
26       error = ErrorMessage;
27       Indent = "      ";
28    }
29    void Print() { cerr << Indent << error << endl; }
30 };
31
32 string ParserException::Indent = "      ";
33
34 class ReferenceFileParser
35 {
36    bool AddKeyValuePairToMap( string& key, string& value );
37
38    istream& eatwhite(istream& is);
39    void eatwhite(string& toClean);
40    string ExtractFirstString(string& toSplit);
41    void CleanUpLine( string& line );
42
43    string ExtractValue(string& toSplit)  throw ( ParserException );
44    void ParseRegularLine( string& line ) throw ( ParserException );
45    void FirstPassReferenceFile()         throw ( ParserException );
46    bool SecondPassReferenceFile()        throw ( ParserException );
47    void HandleFileName( string& line )   throw ( ParserException );
48    void HandleKey( string& line )        throw ( ParserException );
49    bool HandleValue( string& line )      throw ( ParserException );
50    static uint16_t axtoi( char* );
51 public:
52    ReferenceFileParser();
53    bool Open( string& referenceFileName );
54    void Print();
55    void SetDataPath(string&);
56    bool Check();
57 private:
58    /// The directory containing the images to check:
59    string DataPath;
60
61    /// The product of the parser:
62    MapFileValuesType ProducedMap;
63
64    /// The ifstream attached to the file we parse:
65    ifstream from;
66
67    /// String prefixing every output
68    string Indent;
69
70    /// The current line position within the stream:
71    int lineNumber;
72
73    /// The currently parsed filename:
74    string CurrentFileName;
75
76    /// The currently parsed key:
77    string CurrentKey;
78
79    /// The currently parsed value:
80    string CurrentValue;
81
82    /// The current MapEntryValues pointer:
83    MapEntryValues* CurrentMapEntryValuesPtr;
84 };
85
86 /// As gotten from:
87 /// http://community.borland.com/article/0,1410,17203,0.html
88 uint16_t ReferenceFileParser::axtoi(char *hexStg) {
89   int n = 0;         // position in string
90   int m = 0;         // position in digit[] to shift
91   int count;         // loop index
92   int intValue = 0;  // integer value of hex string
93   int digit[5];      // hold values to convert
94   while (n < 4) {
95      if (hexStg[n]=='\0')
96         break;
97      if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
98         digit[n] = hexStg[n] & 0x0f;            //convert to int
99      else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
100         digit[n] = (hexStg[n] & 0x0f) + 9;      //convert to int
101      else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
102         digit[n] = (hexStg[n] & 0x0f) + 9;      //convert to int
103      else break;
104     n++;
105   }
106   count = n;
107   m = n - 1;
108   n = 0;
109   while(n < count) {
110      // digit[n] is value of hex digit at position n
111      // (m << 2) is the number of positions to shift
112      // OR the bits into return value
113      intValue = intValue | (digit[n] << (m << 2));
114      m--;   // adjust the position to set
115      n++;   // next digit to process
116   }
117   return (intValue);
118 }
119
120 void ReferenceFileParser::SetDataPath( string& inDataPath )
121 {
122    DataPath = inDataPath;
123 }
124
125 bool ReferenceFileParser::AddKeyValuePairToMap( string& key, string& value )
126 {
127    if ( !CurrentMapEntryValuesPtr )
128       return false;
129    if ( CurrentMapEntryValuesPtr->count(key) != 0 )
130       return false;
131    (*CurrentMapEntryValuesPtr)[key] = value;
132    
133    return true; //??
134 }
135
136 void ReferenceFileParser::Print()
137 {
138    for (MapFileValuesType::iterator i  = ProducedMap.begin();
139                                     i != ProducedMap.end();
140                                     ++i)
141    {
142       cout << Indent << "FileName: " << i->first << endl;
143       MapEntryValuesPtr KeyValues = i->second;
144       for (MapEntryValues::iterator j  = KeyValues->begin();
145                                     j != KeyValues->end();
146                                     ++j)
147       {
148          cout << Indent
149               << "  Key: " << j->first
150               << "  Value: " << j->second
151               << endl;
152       }
153       cout << Indent << endl;
154    }
155    cout << Indent << endl;
156 }
157
158 bool ReferenceFileParser::Check()
159 {
160    for (MapFileValuesType::iterator i  = ProducedMap.begin();
161                                     i != ProducedMap.end();
162                                     ++i)
163    {
164       string fileName = DataPath + i->first;
165       cout << Indent << "FileName: " << fileName << endl;
166       gdcmHeader* tested = new gdcmHeader( fileName.c_str() );
167       if( !tested->IsReadable() )
168       {
169         cerr << Indent << "Image not gdcm compatible:"
170              << fileName << endl;
171         delete tested;
172         return false;
173       }
174
175       MapEntryValuesPtr KeyValues = i->second;
176       for (MapEntryValues::iterator j  = KeyValues->begin();
177                                     j != KeyValues->end();
178                                     ++j)
179       {
180          string key = j->first;
181
182          string groupString  = key.substr( 0, 4 );
183          char* groupCharPtr;
184          groupCharPtr = new char(groupString.length() + 1);
185          strcpy( groupCharPtr, groupString.c_str() ); 
186
187          string groupElement = key.substr( key.find_first_of( "|" ) + 1, 4 );
188          char* groupElementPtr;
189          groupElementPtr = new char(groupElement.length() + 1);
190          strcpy( groupElementPtr, groupElement.c_str() ); 
191
192          uint16_t group   = axtoi( groupCharPtr );
193          uint16_t element = axtoi( groupElementPtr );
194
195          string testedValue = tested->GetEntryByNumber(group, element);
196          if ( testedValue != j->second )
197          {
198             cout << Indent << "Uncorrect value for key " << key << endl
199                  << Indent << "   read value " << testedValue << endl
200                  << Indent << "   reference value " << j->second << endl;
201             return false;
202          }
203       }
204       delete tested;
205       cout << Indent << "  OK" << endl;
206    }
207    cout << Indent << endl;
208    return true;
209 }
210
211 istream& ReferenceFileParser::eatwhite( istream& is )
212 {
213    char c;
214    while (is.get(c)) {
215       if (!isspace(c)) {
216          is.putback(c);
217          break;
218       }
219    }
220    return is;
221 }
222
223 void ReferenceFileParser::eatwhite( string& toClean )
224 {
225    while( toClean.find_first_of( " " ) == 0  )
226       toClean.erase( 0, toClean.find_first_of( " " ) + 1 );
227 }
228
229 string ReferenceFileParser::ExtractFirstString( string& toSplit )
230 {
231    std::string firstString;
232    eatwhite( toSplit );
233    if ( toSplit.find( " " ) == string::npos ) {
234       firstString = toSplit;
235       toSplit.erase();
236       return firstString;
237    }
238    firstString = toSplit.substr( 0, toSplit.find(" ") );
239    toSplit.erase( 0, toSplit.find(" ") + 1);
240    eatwhite( toSplit );
241    return firstString;
242 }
243
244 string ReferenceFileParser::ExtractValue( string& toSplit )
245    throw ( ParserException )
246 {
247    eatwhite( toSplit );
248    string::size_type beginPos = toSplit.find_first_of( '"' );
249    string::size_type   endPos = toSplit.find_last_of( '"' );
250
251    // Make sure we have at most to " in toSplit:
252    string noQuotes = toSplit.substr( beginPos + 1, endPos - beginPos - 1);
253    if ( noQuotes.find_first_of( '"' ) != string::npos )
254       throw ParserException( "more than two quote character" );
255
256    // No leading quote means this is not a value:
257    if ( beginPos == string::npos )
258    {
259       return string();
260    }
261
262    if ( ( endPos == string::npos ) || ( beginPos == endPos ) )
263       throw ParserException( "unmatched \" (quote character)" );
264
265    if ( beginPos != 0 )
266    {
267       ostringstream error;
268       error  << "leading character ["
269              << toSplit.substr(beginPos -1, 1)
270              << "] before opening \" ";
271       throw ParserException( error.str() );
272    }
273
274    // When they are some extra characters at end of value, it must
275    // be a space:
276    if (   ( endPos != toSplit.length() - 1 )
277        && ( toSplit.substr(endPos + 1, 1) != " " ) )
278    {
279       ostringstream error;
280       error  << "trailing character ["
281              << toSplit.substr(endPos + 1, 1)
282              << "] after value closing \" ";
283       throw ParserException( error.str() );
284    }
285
286    string value = toSplit.substr( beginPos + 1, endPos - beginPos - 1 );
287    toSplit.erase(  beginPos, endPos - beginPos + 1);
288    eatwhite( toSplit );
289    return value;
290 }
291
292 /// \brief   Checks the block syntax of the incoming ifstream. Checks that
293 ///          - no nested blocks are present
294 ///          - we encounter a matching succesion of "[" and "]"
295 ///          - when ifstream terminates the last block is closed.
296 ///          - a block is not opened and close on the same line
297 /// @param   from The incoming ifstream to be checked.
298 /// @return  True when incoming ifstream has a correct syntax, false otherwise.
299 /// \warning The underlying file pointer is not preseved.
300 void ReferenceFileParser::FirstPassReferenceFile() throw ( ParserException )
301 {
302    string line;
303    lineNumber = 1;
304    bool inBlock = false;
305    from.seekg( 0, ios::beg );
306
307    while ( ! from.eof() )
308    {
309       getline( from, line );
310
311       /// This is how we usually end the parsing because we hit EOF:
312       if ( ! from.good() )
313       {
314          if ( ! inBlock )
315             break;
316          else
317             throw ParserException( "Syntax error: EOF reached when in block.");
318       }
319
320       // Don't try to parse comments (weed out anything after first "#"):
321       if ( line.find_first_of( "#" ) != string::npos )
322       {
323          line.erase( line.find_first_of( "#" ) );
324       }
325
326       // Two occurences of opening blocks on a single line implies nested
327       // blocks which is illegal:
328       if ( line.find_first_of( "[" ) != line.find_last_of( "[" ) )
329       {
330          ostringstream error;
331          error << "Syntax error: nested block (open) in reference file"
332                << endl
333                << ParserException::GetIndent()
334                << "   at line " << lineNumber << endl;
335          throw ParserException( error.str() );
336       }
337
338       // Two occurences of closing blocks on a single line implies nested
339       // blocks which is illegal:
340       if ( line.find_first_of( "]" ) != line.find_last_of( "]" ) )
341       {
342          ostringstream error;
343          error << "Syntax error: nested block (close) in reference file"
344                << endl
345                << ParserException::GetIndent()
346                << "   at line " << lineNumber << endl;
347          throw ParserException( error.str() );
348       }
349
350       bool beginBlock ( line.find_first_of("[") != string::npos );
351       bool endBlock   ( line.find_last_of("]")  != string::npos );
352
353       // Opening and closing of block on same line:
354       if ( beginBlock && endBlock )
355       {
356          ostringstream error;
357          error << "Syntax error: opening and closing on block on same line "
358                << lineNumber++ << endl;
359          throw ParserException( error.str() );
360       }
361
362       // Illegal closing block when block not open:
363       if ( !inBlock && endBlock )
364       {
365          ostringstream error;
366          error << "Syntax error: unexpected end of block at line "
367                << lineNumber++ << endl;
368          throw ParserException( error.str() );
369       }
370   
371       // Uncommented line outside of block is not clean:
372       if ( !inBlock && !beginBlock )
373       {
374          continue;
375       }
376
377       if ( inBlock && beginBlock )
378       {
379          ostringstream error;
380          error << "   Syntax error: illegal opening of nested block at line "
381                << lineNumber++ << endl;
382          throw ParserException( error.str() );
383       }
384
385       // Normal situation of opening block:
386       if ( beginBlock )
387       {
388          inBlock = true;
389          lineNumber++;
390          continue;
391       }
392
393       // Normal situation of closing block:
394       if ( endBlock )
395       {
396          inBlock = false;
397          lineNumber++;
398          continue;
399       }
400       // This line had no block delimiter
401       lineNumber++;
402    }
403
404    // We need rewinding:
405    from.clear();
406    from.seekg( 0, ios::beg );
407 }
408
409 ReferenceFileParser::ReferenceFileParser()
410 {
411    lineNumber = 1;
412    Indent = "      ";
413 }
414
415 bool ReferenceFileParser::Open( string& referenceFileName )
416 {
417    from.open( referenceFileName.c_str(), ios::in );
418    if ( !from.is_open() )
419    {
420       cerr << Indent << "Can't open reference file." << endl;
421    }
422    
423    try
424    {
425       FirstPassReferenceFile();
426       SecondPassReferenceFile();
427    }
428    catch ( ParserException except )
429    {
430       except.Print();
431       return false;
432    }
433
434    from.close();
435    return true; //??
436 }
437
438 void ReferenceFileParser::CleanUpLine( string& line )
439 {
440    // Cleanup from comments:
441    if ( line.find_first_of( "#" ) != string::npos )
442       line.erase( line.find_first_of( "#" ) );
443
444    // Cleanup everything after end block delimiter:
445    if ( line.find_last_of( "]" ) != string::npos )
446       line.erase( line.find_last_of( "]" ) + 1 );
447
448    // Cleanup leanding whites and skip empty lines:
449    eatwhite( line );
450 }
451
452 void ReferenceFileParser::HandleFileName( string& line )
453    throw ( ParserException )
454 {
455    if ( line.length() == 0 )
456       throw ParserException( "empty line on call of HandleFileName" );
457
458    if ( CurrentFileName.length() != 0 )
459       return;
460
461    CurrentFileName = ExtractFirstString(line);
462 }
463
464 void ReferenceFileParser::HandleKey( string& line )
465    throw ( ParserException )
466 {
467    if ( CurrentKey.length() != 0 )
468       return;
469
470    CurrentKey = ExtractFirstString(line);
471    if ( CurrentKey.find_first_of( "|" ) == string::npos )
472    {
473       ostringstream error;
474       error  << "uncorrect key:" << CurrentKey;
475       throw ParserException( error.str() );
476    }
477 }
478
479 bool ReferenceFileParser::HandleValue( string& line )
480    throw ( ParserException )
481 {
482    if ( line.length() == 0 )
483       throw ParserException( "empty line in HandleValue" );
484
485    if ( CurrentKey.length() == 0 )
486    {
487       cout << Indent << "No key present:" << CurrentKey << endl;
488       return false;
489    }
490    
491    string newCurrentValue = ExtractValue(line);
492    if ( newCurrentValue.length() == 0 )
493    {
494       ostringstream error;
495       error  << "missing value for key:" << CurrentKey;
496       throw ParserException( error.str() );
497    }
498
499    CurrentValue += newCurrentValue;
500    return true;
501 }
502
503 void ReferenceFileParser::ParseRegularLine(string& line)
504    throw ( ParserException )
505 {
506    if ( line.length() == 0 )
507       return;
508
509    // First thing is to get a filename:
510    HandleFileName( line );
511
512    if ( line.length() == 0 )
513       return;
514
515    // Second thing is to get a key:
516    HandleKey( line );
517        
518    if ( line.length() == 0 )
519       return;
520
521    // Third thing is to get a value:
522    if ( ! HandleValue( line ) )
523       return;
524
525    if ( CurrentKey.length() && CurrentValue.length() )
526    {
527       if ( ! AddKeyValuePairToMap( CurrentKey, CurrentValue ) )
528          throw ParserException( "adding to map of (key, value) failed" );
529       CurrentKey.erase();
530       CurrentValue.erase();
531    }
532 }
533
534 bool ReferenceFileParser::SecondPassReferenceFile()
535    throw ( ParserException )
536 {
537    gdcmTagKey key;
538    EntryValueType value;
539    string line;
540    bool inBlock = false;
541    lineNumber = 0;
542
543    while ( !from.eof() )
544    {
545       getline( from, line );
546       lineNumber++;
547
548       CleanUpLine( line );
549
550       // Empty lines don't require any treatement:
551       if ( line.length() == 0 )
552          continue;
553
554       bool beginBlock ( line.find_first_of("[") != string::npos );
555       bool endBlock   ( line.find_last_of("]")  != string::npos );
556
557       // Waiting for a block to be opened. Meanwhile, drop everything:
558       if ( !inBlock && !beginBlock )
559          continue;
560
561       if ( beginBlock )
562       {
563          inBlock = true;
564          line.erase( 0, line.find_first_of( "[" ) + 1 );
565          eatwhite( line );
566          CurrentMapEntryValuesPtr = new MapEntryValues();
567       }
568       else if ( endBlock )
569       {
570          line.erase( line.find_last_of( "]" ) );
571          eatwhite( line );
572          ParseRegularLine( line );
573          ProducedMap[CurrentFileName] = CurrentMapEntryValuesPtr;
574          inBlock = false;
575          CurrentFileName.erase();
576       }
577    
578       // Outside block lines are dropped:
579       if ( ! inBlock )
580          continue;
581
582       ParseRegularLine( line );
583    }
584    return true; //??
585 }
586
587 int TestAllEntryVerify(int argc, char* argv[]) 
588 {
589    if ( argc > 1 )
590    {
591       cerr << "   Usage: " << argv[0]
592                 << " (no arguments needed)." << endl;
593       return 1;
594    }
595    
596    cout << "   Description (Test::TestAllEntryVerify): "
597              << endl;
598    cout << "   For all images in gdcmData (and not blacklisted in "
599                 "Test/CMakeLists.txt)"
600              << endl;
601    cout << "   apply the following to each filename.xxx: "
602              << endl;
603    cout << "   step 1: parse the image (as gdcmHeader) and call"
604              << " IsReadable(). "
605              << endl;
606
607    string referenceDir = GDCM_DATA_ROOT;
608    referenceDir       += "/";
609    string referenceFilename = referenceDir + "TestAllEntryVerifyReference.txt";
610
611    ReferenceFileParser Parser;
612    Parser.Open(referenceFilename);
613    Parser.SetDataPath(referenceDir);
614    // Parser.Print();
615    if ( Parser.Check() )
616       return 0;
617    return 1;
618 }