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