]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
ENH: Apply cleanup patch
[gdcm.git] / src / gdcmDicomDir.cxx
1 /*=========================================================================
2   
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDicomDir.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/07/19 03:34:11 $
7   Version:   $Revision: 1.57 $
8   
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.htm for details.
12   
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.
16   
17 =========================================================================*/
18
19 #include <string>
20 #include <algorithm>
21 #include <sys/types.h>
22 #include <errno.h>
23
24 #ifdef _MSC_VER 
25    #include <direct.h>
26 #else
27    #include <unistd.h>
28 #endif
29
30 #include "gdcmDicomDir.h"
31 #include "gdcmDicomDirStudy.h"
32 #include "gdcmDicomDirSerie.h"
33 #include "gdcmDicomDirImage.h"
34 #include "gdcmDirList.h"
35 #include "gdcmUtil.h"
36 #include "gdcmDebug.h"
37 #include "gdcmGlobal.h"
38 #include "gdcmHeader.h"
39 #include "gdcmSeqEntry.h"
40 #include "gdcmSQItem.h"
41 #include "gdcmValEntry.h"
42
43 //-----------------------------------------------------------------------------
44 //  For full DICOMDIR description, see:
45 //  PS 3.3-2003, pages 731-750
46 //-----------------------------------------------------------------------------
47 // Constructor / Destructor
48
49 void gdcmDicomDir::Initialize()
50 {
51    startMethod             = NULL;
52    progressMethod          = NULL;
53    endMethod               = NULL;
54    startMethodArgDelete    = NULL;
55    progressMethodArgDelete = NULL;
56    endMethodArgDelete      = NULL;
57    startArg                = NULL;
58    progressArg             = NULL;
59    endArg                  = NULL;
60
61    progress = 0.0;
62    abort = false;
63
64    metaElems = (gdcmDicomDirMeta *)0;   
65 }
66
67
68 /**
69  * \brief Constructor Parses recursively the directory and creates the DicomDir
70  *        or uses an already built DICOMDIR, depending on 'parseDir' value.
71  * @param FileName        name 
72  *                      - of the root directory (parseDir = true)
73  *                      - of the DICOMDIR       (parseDir = false)
74  * @param parseDir boolean
75  *                      - true if user passed an entry point 
76  *                        and wants to explore recursively the directories
77  *                      - false if user passed an already built DICOMDIR file
78  *                        and wants to use it 
79  * @param exception_on_error whether we want to throw an exception or not
80  */
81 gdcmDicomDir::gdcmDicomDir(std::string const & fileName, bool parseDir,
82                            bool exception_on_error):
83    gdcmDocument( fileName, exception_on_error, true) // true : enable SeQuences
84 {
85    // que l'on ai passe un root directory ou un DICOMDIR
86    // et quelle que soit la valeur de parseDir,
87    // on a deja lance gdcmDocument 
88    Initialize();
89
90    // gdcmDocument already executed
91    // if user passed a root directory, sure we didn't get anything
92
93    if( TagHT.begin() == TagHT.end() ) 
94    {
95       dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry HT empty");
96
97       if( fileName.size() == 1 && fileName[0] == '.' )
98       {
99          // user passed '.' as Name
100          // we get current directory name
101          char* dummy = new char[1000];
102          getcwd(dummy, (size_t)1000);
103          SetFileName( dummy ); // will be converted into a string
104          delete[] dummy;     // no longer needed   
105       }
106
107       if( parseDir )
108       {
109          dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : Parse directory"
110                         " and create the DicomDir");
111          ParseDirectory();
112       }
113       else
114       {
115          /// \todo if parseDir == false, it should be tagged as an error
116       }
117    }
118    else
119    {
120       // Directory record sequence
121       gdcmDocEntry *e = GetDocEntryByNumber(0x0004, 0x1220);
122       if ( !e )
123       {
124          dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : NO Directory record"
125                         " sequence (0x0004,0x1220)");
126          /// \todo FIXME : what do we do when the parsed file IS NOT a
127          ///       DICOMDIR file ?         
128       }
129       CreateDicomDir();
130    }
131 }
132
133 /**
134  * \ingroup gdcmDicomDir
135  * \brief   Constructor : creates an empty gdcmDicomDir
136  * @param   exception_on_error whether we want to throw an exception or not
137  */
138 gdcmDicomDir::gdcmDicomDir(bool exception_on_error):                           
139    gdcmDocument( exception_on_error )
140
141    Initialize();
142
143    std::string pathBidon = "Bidon"; // Sorry, NULL not allowed ...
144    SetElement(pathBidon, GDCM_DICOMDIR_META, NULL); // Set the META elements
145    AddDicomDirMeta();
146 }
147
148 /**
149  * \brief  Canonical destructor 
150  */
151 gdcmDicomDir::~gdcmDicomDir() 
152 {
153    SetStartMethod(NULL);
154    SetProgressMethod(NULL);
155    SetEndMethod(NULL);
156
157    if( metaElems )
158    {
159       delete metaElems;
160    }
161    
162    for(ListDicomDirPatient::iterator cc = patients.begin();
163                                      cc!= patients.end();
164                                    ++cc)
165    {
166       delete *cc;
167    }
168 }
169
170 //-----------------------------------------------------------------------------
171 // Print
172 /**
173  * \brief  Canonical Printer 
174  */
175 void gdcmDicomDir::Print(std::ostream &os)
176 {
177    if(metaElems)
178    {
179       metaElems->SetPrintLevel(PrintLevel);
180       metaElems->Print(os);   
181    }   
182    for(ListDicomDirPatient::iterator cc  = patients.begin();
183                                      cc != patients.end();
184                                    ++cc)
185    {
186      (*cc)->SetPrintLevel( PrintLevel );
187      (*cc)->Print( os );
188    }
189 }
190
191 //-----------------------------------------------------------------------------
192 // Public
193 /**
194  * \brief  This predicate, based on hopefully reasonable heuristics,
195  *         decides whether or not the current header was properly parsed
196  *         and contains the mandatory information for being considered as
197  *         a well formed and usable DicomDir.
198  * @return true when gdcmDocument is the one of a reasonable DicomDir,
199  *         false otherwise. 
200  */
201 bool gdcmDicomDir::IsReadable()
202 {
203    if( !gdcmDocument::IsReadable() )
204    {
205       return false;
206    }
207    if( !metaElems )
208    {
209       return false;
210    }
211    if( patients.size() <= 0 )
212    {
213       return false;
214    }
215
216    return true;
217 }
218
219 /**
220  * \ingroup gdcmDicomDir
221  * \brief  fills the whole structure, starting from a root Directory
222  */
223 void gdcmDicomDir::ParseDirectory()
224 {
225    CreateDicomDirChainedList( GetFileName() );
226    CreateDicomDir();
227 }
228
229 /**
230  * \ingroup gdcmDicomDir
231  * \brief   Set the start method to call when the parsing of the directory starts
232  * @param   method Method to call
233  * @param   arg    Argument to pass to the method
234  * @param   argDelete    Argument 
235  * \warning In python : the arg parameter isn't considered
236  */
237 void gdcmDicomDir::SetStartMethod(gdcmMethod *method, void *arg, 
238                                   gdcmMethod *argDelete )
239 {
240    if( startArg && startMethodArgDelete )
241    {
242       startMethodArgDelete( startArg );
243    }
244
245    startMethod          = method;
246    startArg             = arg;
247    startMethodArgDelete = argDelete;
248 }
249
250 /**
251  * \ingroup gdcmDicomDir
252  * \brief   Set the method to delete the argument
253  *          The argument is destroyed when the method is changed or when the
254  *          class is destroyed
255  * @param   method Method to call to delete the argument
256  */
257 void gdcmDicomDir::SetStartMethodArgDelete(gdcmMethod *method) 
258 {
259    startMethodArgDelete = method;
260 }
261
262 /**
263  * \ingroup gdcmDicomDir
264  * \brief   Set the progress method to call when the parsing of the directory progress
265  * @param   method Method to call
266  * @param   arg    Argument to pass to the method
267  * @param   argDelete    Argument  
268  * \warning In python : the arg parameter isn't considered
269  */
270 void gdcmDicomDir::SetProgressMethod(gdcmMethod *method, void *arg, 
271                                      gdcmMethod *argDelete )
272 {
273    if( progressArg && progressMethodArgDelete )
274    {
275       progressMethodArgDelete( progressArg );
276    }
277
278    progressMethod          = method;
279    progressArg             = arg;
280    progressMethodArgDelete = argDelete;
281 }
282
283 /**
284  * \ingroup gdcmDicomDir
285  * \brief   Set the method to delete the argument
286  *          The argument is destroyed when the method is changed or when the 
287  *          class is destroyed          
288  * @param   method Method to call to delete the argument
289  */
290 void gdcmDicomDir::SetProgressMethodArgDelete(gdcmMethod *method)
291 {
292    progressMethodArgDelete = method;
293 }
294
295 /**
296  * \ingroup gdcmDicomDir
297  * \brief   Set the end method to call when the parsing of the directory ends
298  * @param   method Method to call
299  * @param   arg    Argument to pass to the method
300  * @param   argDelete    Argument 
301  * \warning In python : the arg parameter isn't considered
302  */
303 void gdcmDicomDir::SetEndMethod(gdcmMethod *method, void *arg, 
304                                 gdcmMethod *argDelete )
305 {
306    if( endArg && endMethodArgDelete )
307    {
308       endMethodArgDelete( endArg );
309    }
310
311    endMethod          = method;
312    endArg             = arg;
313    endMethodArgDelete = argDelete;
314 }
315
316 /**
317  * \ingroup gdcmDicomDir
318  * \brief   Set the method to delete the argument
319  *          The argument is destroyed when the method is changed or when the class
320  *          is destroyed
321  * @param   method Method to call to delete the argument
322  */
323 void gdcmDicomDir::SetEndMethodArgDelete(gdcmMethod *method)
324 {
325    endMethodArgDelete = method;
326 }
327
328 /**
329  * \ingroup gdcmDicomDir
330  * \brief   writes on disc a DICOMDIR
331  * \ warning does NOT add the missing elements in the header :
332  *           it's up to the user doing it !
333  * \todo : to be re-written using the DICOMDIR tree-like structure
334  *         *not* the chained list
335  *         (does NOT exist if the DICOMDIR is user-forged !)
336  * @param  fileName file to be written to 
337  * @return false only when fail to open
338  */
339  
340 bool gdcmDicomDir::Write(std::string const & fileName) 
341 {
342    FILE * fp1;
343
344    fp1 = fopen(fileName.c_str(), "wb");
345    if( !fp1 ) 
346    {
347       printf("Failed to open(write) File [%s] \n", fileName.c_str());
348       return false;
349    }
350
351    char * filePreamble = new char[128];
352    fwrite(filePreamble,128,1,fp1);
353    fwrite("DICM",4,1,fp1);
354    delete[] filePreamble;
355    UpdateDirectoryRecordSequenceLength();
356    WriteEntries(fp1);
357
358    fclose( fp1 );
359    return true;
360 }
361
362 /**
363  * \brief   Writes in a file using the tree-like structure.
364  * @param   _fp already open file pointer
365  */
366
367 void gdcmDicomDir::WriteEntries(FILE *) //_fp
368 {   
369    /// \todo (?) tester les echecs en ecriture 
370    ///          (apres chaque fwrite, dans le WriteEntry)
371
372
373 /* TODO : to go on compiling
374
375    gdcmDicomDirMeta *ptrMeta;
376    ListDicomDirPatient::iterator  itPatient;
377    ListDicomDirStudy::iterator    itStudy;
378    ListDicomDirSerie::iterator    itSerie;
379    ListDicomDirImage::iterator    itImage; 
380    ListTag::iterator i; 
381    
382    ptrMeta= GetDicomDirMeta();
383    for(i=ptrMeta->debut();i!=ptrMeta->fin();++i) {
384       WriteEntry(*i,_fp, gdcmExplicitVR);
385    }   
386     
387    itPatient = GetDicomDirPatients().begin(); 
388    while ( itPatient != GetDicomDirPatients().end() ) {
389       for(i=(*itPatient)->debut();i!=(*itPatient)->fin();++i) {
390          WriteEntry(*i,_fp, gdcmExplicitVR);
391       }
392       itStudy = ((*itPatient)->GetDicomDirStudies()).begin();     
393       while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {
394          for(i=(*itStudy)->debut();i!=(*itStudy)->fin();++i) {
395             WriteEntry(*i,_fp, gdcmExplicitVR);
396          } 
397          itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
398          while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
399             for(i=(*itSerie)->debut();i!=(*itSerie)->fin();++i) {
400                WriteEntry(*i,_fp, gdcmExplicitVR);
401             }
402             itImage = ((*itSerie)->GetDicomDirImages()).begin();
403             while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
404                for(i=(*itImage)->debut();i!=(*itImage)->fin();++i) {
405                   WriteEntry(*i,_fp, gdcmExplicitVR);
406                }
407                ++itImage;
408             }
409             ++itSerie;
410          }
411          ++itStudy;
412       } 
413       ++itPatient;     
414    }
415    */
416 }   
417    
418 //-----------------------------------------------------------------------------
419 // Protected
420
421 /**
422  * \ingroup gdcmDicomDir
423  * \brief create a gdcmDocument-like chained list from a root Directory 
424  * @param path entry point of the tree-like structure
425  */
426 void gdcmDicomDir::CreateDicomDirChainedList(std::string const & path)
427 {
428    CallStartMethod();
429    gdcmDirList fileList(path,1); // gets recursively the file list
430    unsigned int count = 0;
431    VectDocument list;
432    gdcmHeader *header;
433
434    TagHT.clear();
435    patients.clear();
436
437    for( gdcmDirList::iterator it  = fileList.begin();
438                               it != fileList.end();
439                               ++it )
440    {
441       progress = (float)(count+1)/(float)fileList.size();
442       CallProgressMethod();
443       if( abort )
444       {
445          break;
446       }
447
448       header = new gdcmHeader(it->c_str(),false,true);
449       if(!header) {
450          std::cout << "echec new Header " << it->c_str() << std::endl; // JPR
451       }
452       if(header->IsReadable()) {
453          list.push_back(header);  // adds the file header to the chained list
454          std::cout << "readable : " <<it->c_str() << std::endl; // JPR
455        }
456       else
457       {
458          delete header;
459       }
460       count++;
461
462    }
463    // sorts Patient/Study/Serie/
464    std::sort(list.begin(), list.end(), gdcmDicomDir::HeaderLessThan );
465
466    std::string tmp = fileList.GetDirName();
467       
468    //for each Header of the chained list, add/update the Patient/Study/Serie/Image info
469    SetElements(tmp, list);
470       
471    CallEndMethod();
472 }
473
474 /**
475  * \ingroup gdcmDicomDir
476  * \brief   adds *the* Meta to a partially created DICOMDIR
477  */
478  
479  /// \todo FIXME : Heuuuuu ! Il prend les Entries du Document deja parse,
480  ///                  il ne fabrique rien !
481   
482 gdcmDicomDirMeta * gdcmDicomDir::NewMeta()
483 {
484    gdcmDicomDirMeta *m = new gdcmDicomDirMeta( &TagHT );
485    for ( TagDocEntryHT::iterator cc  = TagHT.begin(); 
486                                  cc != TagHT.end(); ++cc)
487    {
488       m->AddDocEntry( cc->second );
489    }
490    return m;  
491 }
492
493
494 /**
495  * \brief   adds a new Patient (with the basic elements) to a partially created DICOMDIR
496  */
497 gdcmDicomDirPatient * gdcmDicomDir::NewPatient()
498 {
499    std::list<gdcmElement>::iterator it;
500    uint16_t tmpGr,tmpEl;
501    gdcmDictEntry *dictEntry;
502    gdcmValEntry *entry;
503    
504    gdcmSQItem *s = new gdcmSQItem(0);
505    
506    std::list<gdcmElement> elemList = 
507          gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();  
508    
509    /// \todo TODO : use FillObject !!!
510
511    // for all the DicomDirPatient Elements 
512      
513    for( it = elemList.begin(); it != elemList.end(); ++it ) 
514    {
515       tmpGr     = it->group;
516       tmpEl     = it->elem;
517       dictEntry = GetPubDict()->GetDictEntryByNumber(tmpGr, tmpEl);
518       entry     = new gdcmValEntry( dictEntry );
519       entry->SetOffset(0); // just to avoid further missprinting
520       entry->SetValue( it->value );
521
522       // dealing with value length ...
523       
524       if( dictEntry->GetGroup() == 0xfffe)
525       {
526          entry->SetLength(entry->GetValue().length());
527       }
528       else if( dictEntry->GetVR() == "UL" || dictEntry->GetVR() == "SL" )
529       {
530          entry->SetLength( 4 );
531       } 
532       else if( dictEntry->GetVR() == "US" || dictEntry->GetVR() == "SS" )
533       {
534          entry->SetLength(2); 
535       } 
536       else if( dictEntry->GetVR() == "SQ" )
537       {
538          entry->SetLength( 0xffffffff );
539       }
540       else
541       {
542          entry->SetLength( entry->GetValue().length() );
543       }
544       s->AddDocEntry( entry );
545    }
546
547    gdcmDicomDirPatient *p = new gdcmDicomDirPatient(s, &TagHT);
548    patients.push_front( p );
549
550    return p;   
551 }
552
553 /**
554  * \brief   adds to the HTable 
555  *          the gdcmEntries (Dicom Elements) corresponding to the given type
556  * @param   path full path file name (only used when type = GDCM_DICOMDIR_IMAGE
557  * @param   type gdcmObject type to create (GDCM_DICOMDIR_PATIENT,
558  *          GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...)
559  * @param   header gdcmHeader of the current file
560  */
561 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,
562                               gdcmDocument *header)
563 {
564    std::list<gdcmElement> elemList;
565    std::list<gdcmElement>::iterator it;
566    uint16_t tmpGr, tmpEl;
567    gdcmDictEntry *dictEntry;
568    gdcmValEntry *entry;
569    std::string val;
570
571    switch( type )
572    {
573       case GDCM_DICOMDIR_PATIENT:
574          elemList = gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();
575          break;
576       case GDCM_DICOMDIR_STUDY:
577          elemList = gdcmGlobal::GetDicomDirElements()->GetDicomDirStudyElements();
578          break;
579       case GDCM_DICOMDIR_SERIE:
580          elemList = gdcmGlobal::GetDicomDirElements()->GetDicomDirSerieElements();
581          break;
582       case GDCM_DICOMDIR_IMAGE:
583          elemList = gdcmGlobal::GetDicomDirElements()->GetDicomDirImageElements();
584          break;
585       case GDCM_DICOMDIR_META:
586          elemList = gdcmGlobal::GetDicomDirElements()->GetDicomDirMetaElements();
587          break;
588       default:
589          return;
590    }
591
592    for( it = elemList.begin(); it != elemList.end(); ++it)
593    {
594       tmpGr     = it->group;
595       tmpEl     = it->elem;
596       dictEntry = GetPubDict()->GetDictEntryByNumber(tmpGr, tmpEl);
597       entry     = new gdcmValEntry( dictEntry ); // Be sure it's never a BinEntry !
598
599       entry->SetOffset(0); // just to avoid further missprinting
600
601       if( header )
602       {
603          val = header->GetEntryByNumber(tmpGr, tmpEl);
604       }
605       else
606       {
607          val = GDCM_UNFOUND;
608       }
609
610       if( val == GDCM_UNFOUND) 
611       {
612          if( tmpGr == 0x0004 && tmpEl == 0x1130 ) // File-set ID
613          {
614            // force to the *end* File Name
615            val = GetName( path );
616          }
617          else if( tmpGr == 0x0004 && tmpEl == 0x1500 ) // Only used for image
618          {
619             if( header->GetFileName().substr(0, path.length()) != path )
620             {
621                dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path"
622                               " of file name is incorrect");
623                val = header->GetFileName();
624             }
625             else
626             {
627                val = &(header->GetFileName().c_str()[path.length()]);
628             }   
629          }
630          else
631          {
632             val = it->value;
633          }
634       }
635       else
636       {
637          if ( header->GetEntryLengthByNumber(tmpGr,tmpEl) == 0 )
638          {
639             val = it->value;
640          }
641       }
642
643       entry->SetValue( val );
644
645       if( dictEntry )
646       {
647          if( dictEntry->GetGroup() == 0xfffe )
648          {
649             entry->SetLength( entry->GetValue().length() );
650          }
651          else if( dictEntry->GetVR() == "UL" || dictEntry->GetVR() == "SL" )
652          {
653             entry->SetLength(4);
654          }
655          else if( dictEntry->GetVR() == "US" || dictEntry->GetVR() == "SS" )
656          {
657             entry->SetLength(2); 
658          }
659          else if( dictEntry->GetVR() == "SQ" )
660          {
661             entry->SetLength( 0xffffffff );
662          }
663          else
664          {
665             entry->SetLength( entry->GetValue().length() );
666          }
667       }
668       //AddDocEntry(entry); // both in H Table and in chained list
669       TagHT[entry->GetKey()] = entry;          // FIXME : use a SEQUENCE !
670    }
671 }
672
673 /**
674  * \brief   CallStartMethod
675  */
676 void gdcmDicomDir::CallStartMethod()
677 {
678    progress = 0.0f;
679    abort    = false;
680    if( startMethod )
681    {
682       startMethod( startArg );
683    }
684 }
685
686 /**
687  * \ingroup gdcmDicomDir
688  * \brief   CallProgressMethod
689  */
690 void gdcmDicomDir::CallProgressMethod()
691 {
692    if( progressMethod )
693    {
694       progressMethod( progressArg );
695    }
696 }
697
698 /**
699  * \ingroup gdcmDicomDir
700  * \brief   CallEndMethod
701  */
702 void gdcmDicomDir::CallEndMethod()
703 {
704    progress = 1.0f;
705    if( endMethod )
706    {
707       endMethod( endArg );
708    }
709 }
710
711 //-----------------------------------------------------------------------------
712 // Private
713 /**
714  * \ingroup gdcmDicomDir
715  * \brief create a 'gdcmDicomDir' from a DICOMDIR gdcmHeader 
716  */
717 void gdcmDicomDir::CreateDicomDir()
718 {
719    // The list is parsed. 
720    //  When a DicomDir tag ("PATIENT", "STUDY", "SERIE", "IMAGE") is found :
721    //  1 - we save the beginning iterator
722    //  2 - we continue to parse
723    //  3 - we find an other tag
724    //       + we create the object for the precedent tag
725    //       + loop to 1 -
726
727    gdcmDicomDirType type = gdcmDicomDir::GDCM_DICOMDIR_META;
728    
729    // Directory record sequence
730    gdcmDocEntry *e = GetDocEntryByNumber(0x0004, 0x1220);
731    if ( !e )
732    {
733       dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : NO Directory record"
734                      " sequence (0x0004,0x1220)");
735       /// \todo FIXME: what to do when the parsed file IS NOT a DICOMDIR file ? 
736       return;         
737    }
738    
739    gdcmSeqEntry* s = dynamic_cast<gdcmSeqEntry*>(e);
740    if ( !s )
741    {
742       dbg.Verbose(0, "gdcmDicomDir::CreateDicomDir: no SeqEntry present");
743       return;
744    }
745
746    ListSQItem listItems = s->GetSQItems();
747    gdcmDicomDirMeta *m  = new gdcmDicomDirMeta(&TagHT);
748    (void)m; //??
749    
750    gdcmDocEntry * d;
751    std::string v;
752    for( ListSQItem::iterator i = listItems.begin(); 
753                              i !=listItems.end(); ++i ) 
754    {
755       d = (*i)->GetDocEntryByNumber(0x0004, 0x1430); // Directory Record Type
756       if ( gdcmValEntry* ValEntry = dynamic_cast< gdcmValEntry* >(d) )
757       {
758          v = ValEntry->GetValue();
759       }
760       else
761       {
762          dbg.Verbose(0, "gdcmDicomDir::CreateDicomDir: not a ValEntry.");
763          continue;
764       }
765
766       if( v == "PATIENT " )
767       {
768          AddDicomDirPatientToEnd( *i );
769          //AddObjectToEnd(type,*i);
770          type = gdcmDicomDir::GDCM_DICOMDIR_PATIENT;
771       }
772       else if( v == "STUDY " )
773       {
774          AddDicomDirStudyToEnd( *i );
775         // AddObjectToEnd(type,*i);
776          type = gdcmDicomDir::GDCM_DICOMDIR_STUDY;
777       }
778       else if( v == "SERIES" )
779       {
780          AddDicomDirSerieToEnd( *i );
781          //  AddObjectToEnd(type,*i);
782          type = gdcmDicomDir::GDCM_DICOMDIR_SERIE;
783       }
784       else if( v == "IMAGE " ) 
785       {
786          AddDicomDirImageToEnd( *i );
787          //   AddObjectToEnd(type,*i);
788          type = gdcmDicomDir::GDCM_DICOMDIR_IMAGE;
789       }
790       else
791       {
792          // It was not a 'PATIENT', nor a 'STUDY', nor a 'SERIE',
793          // neither an 'IMAGE' SQItem. Skip to next item.
794          continue;
795       }
796    }
797 }
798
799 /**
800  * \ingroup gdcmDicomDir
801  * \brief   AddObjectToEnd
802  * @param   type
803  * @param   begin iterator on the first DocEntry within the chained List
804  * @param   end iterator on the last DocEntry within the chained List
805  */
806  
807 // now  useless ?
808
809 /*void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,gdcmSQItem *s)
810 {
811    if(s==NULL) // ??
812       return;
813
814    switch(type)
815    {
816       case gdcmDicomDir::GDCM_DICOMDIR_META:
817          AddDicomDirMeta();
818          break;      
819       case gdcmDicomDir::GDCM_DICOMDIR_PATIENT:
820          AddDicomDirPatientToEnd(s);
821          break;
822       case gdcmDicomDir::GDCM_DICOMDIR_STUDY:
823          AddDicomDirStudyToEnd(s);
824          break;
825       case gdcmDicomDir::GDCM_DICOMDIR_SERIE:
826          AddDicomDirSerieToEnd(s);
827          break;
828       case gdcmDicomDir::GDCM_DICOMDIR_IMAGE:
829          AddDicomDirImageToEnd(s);
830          break;
831       case gdcmDicomDir::GDCM_DICOMDIR_NONE:
832          AddDicomDirImageToEnd(s);        //FIXME
833          break;
834    }
835 }
836
837 */
838
839 /**
840  * \ingroup gdcmDicomDir
841  * \brief Well ... there is only one occurence  
842  */
843 void gdcmDicomDir::AddDicomDirMeta()
844 {
845    if( metaElems )
846    {
847       delete metaElems;
848    }
849    metaElems = new gdcmDicomDirMeta( &TagHT );
850 }
851
852 /**
853  * \ingroup gdcmDicomDir
854  * \brief  AddDicomDirPatientToEnd 
855  * @param   s SQ Item to enqueue to the DicomPatient chained List
856  */
857 void gdcmDicomDir::AddDicomDirPatientToEnd(gdcmSQItem *s)
858 {
859    patients.push_back(new gdcmDicomDirPatient(s, &TagHT));
860 }
861
862 /**
863  * \ingroup gdcmDicomDir
864  * \brief  AddDicomDirStudyToEnd 
865  * @param   s SQ Item to enqueue to the DicomDirStudy chained List
866  */
867  void gdcmDicomDir::AddDicomDirStudyToEnd(gdcmSQItem *s)
868 {
869    if( patients.size() > 0 )
870    {
871       ListDicomDirPatient::iterator itp = patients.end();
872       itp--;
873       (*itp)->AddDicomDirStudy(new gdcmDicomDirStudy(s, &TagHT));
874    }
875 }
876
877 /**
878  * \ingroup gdcmDicomDir
879  * \brief  AddDicomDirSerieToEnd 
880  * @param   s SQ Item to enqueue to the DicomDirSerie chained List
881  */
882 void gdcmDicomDir::AddDicomDirSerieToEnd(gdcmSQItem *s)
883 {
884    if( patients.size() > 0 )
885    {
886       ListDicomDirPatient::iterator itp = patients.end();
887       itp--;
888
889       if( (*itp)->GetDicomDirStudies().size() > 0 )
890       {
891          ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
892          itst--;
893          (*itst)->AddDicomDirSerie(new gdcmDicomDirSerie(s, &TagHT));
894       }
895    }
896 }
897
898 /**
899  * \ingroup gdcmDicomDir
900  * \brief   AddDicomDirImageToEnd
901  * @param   s SQ Item to enqueue to the DicomDirImage chained List
902  */
903  void gdcmDicomDir::AddDicomDirImageToEnd(gdcmSQItem *s)
904 {
905    if( patients.size() > 0 )
906    {
907       ListDicomDirPatient::iterator itp = patients.end();
908       itp--;
909
910       if( (*itp)->GetDicomDirStudies().size() > 0 )
911       {
912          ListDicomDirStudy::iterator itst = (*itp)->GetDicomDirStudies().end();
913          itst--;
914
915          if( (*itst)->GetDicomDirSeries().size() > 0 )
916          {
917             ListDicomDirSerie::iterator its = (*itst)->GetDicomDirSeries().end();
918             its--;
919             (*its)->AddDicomDirImage(new gdcmDicomDirImage(s, &TagHT));
920          }
921       }
922    }
923 }
924
925 /**
926  * \ingroup gdcmDicomDir
927  * \brief  for each Header of the chained list, add/update the Patient/Study/Serie/Image info 
928  * @param   path path of the root directory
929  * @param   list chained list of Headers
930  */
931 void gdcmDicomDir::SetElements(std::string &path, VectDocument &list)
932 {
933    std::string patPrevName         = "", patPrevID  = "";
934    std::string studPrevInstanceUID = "", studPrevID = "";
935    std::string serPrevInstanceUID  = "", serPrevID  = "";
936
937    std::string patCurName,         patCurID;
938    std::string studCurInstanceUID, studCurID;
939    std::string serCurInstanceUID,  serCurID;
940
941    SetElement( path, GDCM_DICOMDIR_META,NULL);
942
943    for( VectDocument::iterator it = list.begin();
944                               it != list.end(); ++it )
945    {
946       // get the current file characteristics
947       patCurName         = (*it)->GetEntryByNumber(0x0010,0x0010); 
948       patCurID           = (*it)->GetEntryByNumber(0x0010,0x0011); 
949       studCurInstanceUID = (*it)->GetEntryByNumber(0x0020,0x000d);            
950       studCurID          = (*it)->GetEntryByNumber(0x0020,0x0010);            
951       serCurInstanceUID  = (*it)->GetEntryByNumber(0x0020,0x000e);            
952       serCurID           = (*it)->GetEntryByNumber(0x0020,0x0011);
953
954       if( patCurName != patPrevName || patCurID != patPrevID)
955       {
956          SetElement(path, GDCM_DICOMDIR_PATIENT, *it);
957       }
958
959       // if new Study Deal with 'STUDY' Elements   
960       if( studCurInstanceUID != studPrevInstanceUID || studCurID != studPrevID )
961       {
962          SetElement(path, GDCM_DICOMDIR_STUDY, *it);
963       }
964
965       // if new Serie Deal with 'SERIE' Elements   
966       if( serCurInstanceUID != serPrevInstanceUID || serCurID != serPrevID )
967       {
968          SetElement(path, GDCM_DICOMDIR_SERIE, *it);
969       }
970       
971       // Always Deal with 'IMAGE' Elements  
972       SetElement(path, GDCM_DICOMDIR_IMAGE, *it);
973
974       patPrevName         = patCurName;
975       patPrevID           = patCurID;
976       studPrevInstanceUID = studCurInstanceUID;
977       studPrevID          = studCurID;
978       serPrevInstanceUID  = serCurInstanceUID;
979       serPrevID           = serCurID;
980    }
981 }
982
983 /**
984  * \ingroup gdcmDicomDir
985  * \brief   compares two dgcmHeaders
986  */
987 bool gdcmDicomDir::HeaderLessThan(gdcmDocument *header1, gdcmDocument *header2)
988 {
989    return *header1 < *header2;
990 }
991
992 /**
993  * \brief   Sets the accurate value for the (0x0004,0x1220) element of a DICOMDIR
994  */
995 void gdcmDicomDir::UpdateDirectoryRecordSequenceLength()
996 {
997
998 /// \todo FIXME : to go on compiling
999 ///
1000 /// to be re written !
1001 ///   int offset = 0;
1002 ///   ListTag::iterator it;
1003 ///   uint16_t gr, el;
1004 ///   std::string vr;
1005 ///   for(it=listEntries.begin();it!=listEntries.end();++it) {
1006 ///      gr = (*it)->GetGroup();
1007 ///      el = (*it)->GetElement();
1008 ///      vr = (*it)->GetVR();      
1009 ///      if (gr !=0xfffe) {
1010 ///         if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {    
1011 ///            offset +=  4; // explicit VR AND OB, OW, SQ : 4 more bytes
1012 ///         }         
1013 ///         offset += 2 + 2 + 4 + (*it)->GetLength(); 
1014 ///      } else {
1015 ///         offset +=  4; // delimiters don't have a value.     
1016 ///      }            
1017 ///   }   
1018 ///   //bool res=SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
1019 ///    SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
1020 ///   return;
1021 ///
1022 }
1023
1024 //-----------------------------------------------------------------------------