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