]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
* src/gdcmHeader.[cxx|h]:
[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 #include "gdcmHeader.h"
23
24 #include "gdcmSeqEntry.h"
25 #include "gdcmSQItem.h"
26 #include "gdcmValEntry.h"
27
28 //-----------------------------------------------------------------------------
29 //  For full DICOMDIR description, see:
30 //  PS 3.3-2003, pages 731-750
31 //-----------------------------------------------------------------------------
32
33
34 // Constructor / Destructor
35
36 /**
37  * \brief Constructor Parses recursively the directory and creates the DicomDir
38  *        or uses an already built DICOMDIR, depending on 'parseDir' value.
39  * @param FileName        name 
40  *                      - of the root directory (parseDir = true)
41  *                      - of the DICOMDIR       (parseDir = false)
42  * @param parseDir boolean
43  *                      - true if user passed an entry point 
44  *                        and wants to explore recursively the directories
45  *                      - false if user passed an already built DICOMDIR file
46  *                        and wants to use it 
47  * @param exception_on_error whether we want to throw an exception or not
48  */
49 gdcmDicomDir::gdcmDicomDir(const char *FileName, bool parseDir,
50                            bool exception_on_error):
51    gdcmDocument(FileName,exception_on_error,true) // true : enable SeQuences
52 {
53  // que l'on ai passe un root directory ou un DICOMDIR
54  // et quelle que soit la valeur de parseDir,
55  // on a lance gdcmDocument 
56       
57    startMethod=            NULL;
58    progressMethod=         NULL;
59    endMethod=              NULL;
60    startMethodArgDelete=   NULL;
61    progressMethodArgDelete=NULL;
62    endMethodArgDelete=     NULL;
63    startArg=               NULL;
64    progressArg=            NULL;
65    endArg=                 NULL;
66
67    progress=0.0;
68    abort=false;
69
70    metaElems=NULL;   
71
72 // gdcmDocument already executed
73 // if user passed a root directory, sure we didn't get anything
74
75    if( GetEntry().begin()==GetEntry().end() ) 
76    {
77      // if parseDir == false, it should be tagged as an error
78       dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry HT empty");
79
80       if(strlen(FileName)==1 && FileName[0]=='.') { // user passed '.' as Name
81                                             // we get current directory name
82          char* dummy= new char[1000];
83          getcwd(dummy, (size_t)1000);
84          SetFileName(dummy); // will be converted into a string
85          delete[] dummy;     // no longer needed   
86       }
87
88       if(parseDir)
89       {
90          dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : Parse directory"
91                         " and create the DicomDir");
92          ParseDirectory();
93       }
94    }
95    else {
96       gdcmDocEntry *e = GetDocEntryByNumber(0x0004, 0x1220); // Directory record sequence
97       if (e==NULL) {
98          dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : NO Directory record sequence (0x0004,0x1220)"
99                      );
100          // FIXME : what to do when the parsed file IS NOT a DICOMDIR file ?         
101       }      
102       CreateDicomDir();
103    } 
104 }
105
106 /**
107  * \ingroup gdcmDicomDir
108  * \brief   Constructor : creates an empty gdcmDicomDir
109  * @param   exception_on_error whether we want to throw an exception or not
110  */
111 gdcmDicomDir::gdcmDicomDir(bool exception_on_error):                           
112    gdcmDocument(exception_on_error)
113
114    startMethod=            NULL;
115    progressMethod=         NULL;
116    endMethod=              NULL;
117    startMethodArgDelete=   NULL;
118    progressMethodArgDelete=NULL;
119    endMethodArgDelete=     NULL;
120    startArg=               NULL;
121    progressArg=            NULL;
122    endArg=                 NULL;
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    AddDicomDirMeta();
128 }
129
130
131 /**
132  * \ingroup gdcmDicomDir
133  * \brief  Canonical destructor 
134  */
135 gdcmDicomDir::~gdcmDicomDir() 
136 {
137    SetStartMethod(NULL);
138    SetProgressMethod(NULL);
139    SetEndMethod(NULL);
140
141    if(metaElems)
142       delete metaElems;
143    
144    for(ListDicomDirPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
145    {
146       delete *cc;
147    }
148 }
149
150 //-----------------------------------------------------------------------------
151 // Print
152 /**
153  * \ingroup gdcmDicomDir
154  * \brief  Canonical Printer 
155  */
156 void gdcmDicomDir::Print(std::ostream &os)
157 {
158    if(metaElems)
159    {
160       metaElems->SetPrintLevel(printLevel);
161       metaElems->Print(os);   
162    }   
163    for(ListDicomDirPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
164    {
165      (*cc)->SetPrintLevel(printLevel);
166      (*cc)->Print(os);     
167    }
168 }
169
170 //-----------------------------------------------------------------------------
171 // Public
172 /**
173  * \ingroup gdcmDicomDir
174  * \brief  This predicate, based on hopefully reasonable heuristics,
175  *         decides whether or not the current header was properly parsed
176  *         and contains the mandatory information for being considered as
177  *         a well formed and usable DicomDir.
178  * @return true when gdcmDocument is the one of a reasonable DicomDir,
179  *         false otherwise. 
180  */
181 bool gdcmDicomDir::IsReadable(void)
182 {
183    if(!gdcmDocument::IsReadable())
184       return(false);
185    if(!metaElems)
186       return(false);
187    if(patients.size()<=0)
188       return(false);
189
190    return(true);
191 }
192
193 /**
194  * \ingroup gdcmDicomDir
195  * \brief  fills the whole structure, starting from a root Directory
196  */
197 void gdcmDicomDir::ParseDirectory(void)
198 {
199    CreateDicomDirChainedList(GetFileName());
200    CreateDicomDir();
201 }
202
203 /**
204  * \ingroup gdcmDicomDir
205  * \brief   Set the start method to call when the parsing of the directory starts
206  * @param   method Method to call
207  * @param   arg    Argument to pass to the method
208  * @param   argDelete    Argument 
209  * \warning In python : the arg parameter isn't considered
210  */
211 void gdcmDicomDir::SetStartMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
212 {
213    if((startArg)&&(startMethodArgDelete))
214       startMethodArgDelete(startArg);
215
216    startMethod=method;
217    startArg=arg;
218    startMethodArgDelete=argDelete;
219 }
220
221 /**
222  * \ingroup gdcmDicomDir
223  * \brief   Set the method to delete the argument
224  *          The argument is destroyed when the method is changed or when the
225  *          class is destroyed
226  * @param   method Method to call to delete the argument
227  */
228 void gdcmDicomDir::SetStartMethodArgDelete(gdcmMethod *method) 
229 {
230    startMethodArgDelete=method;
231 }
232
233 /**
234  * \ingroup gdcmDicomDir
235  * \brief   Set the progress method to call when the parsing of the directory progress
236  * @param   method Method to call
237  * @param   arg    Argument to pass to the method
238  * @param   argDelete    Argument  
239  * \warning In python : the arg parameter isn't considered
240  */
241 void gdcmDicomDir::SetProgressMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
242 {
243    if((progressArg)&&(progressMethodArgDelete))
244       progressMethodArgDelete(progressArg);
245
246    progressMethod=method;
247    progressArg=arg;
248    progressMethodArgDelete=argDelete;
249 }
250
251 /**
252  * \ingroup gdcmDicomDir
253  * \brief   Set the method to delete the argument
254  *          The argument is destroyed when the method is changed or when the 
255  *          class is destroyed          
256  * @param   method Method to call to delete the argument
257  */
258 void gdcmDicomDir::SetProgressMethodArgDelete(gdcmMethod *method)
259 {
260    progressMethodArgDelete=method;
261 }
262
263 /**
264  * \ingroup gdcmDicomDir
265  * \brief   Set the end method to call when the parsing of the directory ends
266  * @param   method Method to call
267  * @param   arg    Argument to pass to the method
268  * @param   argDelete    Argument 
269  * \warning In python : the arg parameter isn't considered
270  */
271 void gdcmDicomDir::SetEndMethod(gdcmMethod *method, void *arg, gdcmMethod *argDelete)
272 {
273    if((endArg)&&(endMethodArgDelete))
274       endMethodArgDelete(endArg);
275
276    endMethod=method;
277    endArg=arg;
278    endMethodArgDelete=argDelete;
279 }
280
281 /**
282  * \ingroup gdcmDicomDir
283  * \brief   Set the method to delete the argument
284  *          The argument is destroyed when the method is changed or when the class
285  *          is destroyed
286  * @param   method Method to call to delete the argument
287  */
288 void gdcmDicomDir::SetEndMethodArgDelete(gdcmMethod *method)
289 {
290    endMethodArgDelete=method;
291 }
292
293 /**
294  * \ingroup gdcmDicomDir
295  * \brief   writes on disc a DICOMDIR
296  * \ warning does NOT add the missing elements in the header :
297  *           it's up to the user doing it !
298  * \todo : to be re-written using the DICOMDIR tree-like structure
299  *         *not* the chained list
300  *         (does NOT exist if the DICOMDIR is user-forged !)
301  * @param  fileName file to be written to 
302  * @return false only when fail to open
303  */
304  
305 bool gdcmDicomDir::Write(std::string fileName) 
306 {
307    FILE * fp1;
308
309    fp1=fopen(fileName.c_str(),"wb");
310    if(fp1==NULL) 
311    {
312       printf("Failed to open(write) File [%s] \n",fileName.c_str());
313       return(false);
314    }
315
316    char * filePreamble = new char[128];
317    fwrite(filePreamble,128,1,fp1);
318    fwrite("DICM",4,1,fp1);
319    delete[] filePreamble;
320    UpdateDirectoryRecordSequenceLength();
321    WriteEntries(fp1);
322
323    fclose(fp1);
324    return true;
325 }
326
327 /**
328  * \brief   Writes in a file using the tree-like structure.
329  * @param   _fp already open file pointer
330  */
331
332 void gdcmDicomDir::WriteEntries(FILE *_fp)
333 {   
334    /// \todo (?) tester les echecs en ecriture 
335    ///          (apres chaque fwrite, dans le WriteEntry)
336
337
338 /* TODO : to go on compiling
339
340    gdcmDicomDirMeta *ptrMeta;
341    ListDicomDirPatient::iterator  itPatient;
342    ListDicomDirStudy::iterator    itStudy;
343    ListDicomDirSerie::iterator    itSerie;
344    ListDicomDirImage::iterator    itImage; 
345    ListTag::iterator i; 
346    
347    ptrMeta= GetDicomDirMeta();
348    for(i=ptrMeta->debut();i!=ptrMeta->fin();++i) {
349       WriteEntry(*i,_fp, gdcmExplicitVR);
350    }   
351     
352    itPatient = GetDicomDirPatients().begin(); 
353    while ( itPatient != GetDicomDirPatients().end() ) {
354       for(i=(*itPatient)->debut();i!=(*itPatient)->fin();++i) {
355          WriteEntry(*i,_fp, gdcmExplicitVR);
356       }
357       itStudy = ((*itPatient)->GetDicomDirStudies()).begin();         
358       while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {    
359          for(i=(*itStudy)->debut();i!=(*itStudy)->fin();++i) {
360             WriteEntry(*i,_fp, gdcmExplicitVR);
361          } 
362          itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
363          while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
364             for(i=(*itSerie)->debut();i!=(*itSerie)->fin();++i) {
365                WriteEntry(*i,_fp, gdcmExplicitVR);
366             }
367             itImage = ((*itSerie)->GetDicomDirImages()).begin();
368             while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
369                for(i=(*itImage)->debut();i!=(*itImage)->fin();++i) {
370                   WriteEntry(*i,_fp, gdcmExplicitVR);
371                }
372                ++itImage;                   
373             }
374             ++itSerie;                                
375          }
376          ++itStudy;            
377       } 
378       ++itPatient;     
379    }
380    */
381 }   
382    
383 //-----------------------------------------------------------------------------
384 // Protected
385
386 /**
387  * \ingroup gdcmDicomDir
388  * \brief create a gdcmDocument-like chained list from a root Directory 
389  * @param path entry point of the tree-like structure
390  */
391 void gdcmDicomDir::CreateDicomDirChainedList(std::string path)
392 {
393    CallStartMethod();
394
395    gdcmDirList fileList(path,1); // gets recursively the file list
396    unsigned int count=0;
397    VectDocument list;
398    gdcmHeader *header;
399
400    tagHT.clear();
401    patients.clear();
402
403    for(gdcmDirList::iterator it=fileList.begin(); 
404                              it!=fileList.end(); 
405                              ++it) 
406    {
407       progress=(float)(count+1)/(float)fileList.size();
408       CallProgressMethod();
409       if(abort)
410          break;
411
412       header=new gdcmHeader(it->c_str());
413       if(header->IsReadable())
414          list.push_back(header);  // adds the file header to the chained list
415       else
416          delete header;
417
418       count++;
419    }
420    // sorts Patient/Study/Serie/
421    std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan);
422
423    std::string tmp=fileList.GetDirName();
424       
425    //for each Header of the chained list, add/update the Patient/Study/Serie/Image info
426    SetElements(tmp,list);
427       
428    CallEndMethod();
429 }
430
431 /**
432  * \ingroup gdcmDicomDir
433  * \brief   adds *the* Meta to a partially created DICOMDIR
434  */
435  
436  // FIXME : Heuuuuu ! Il prend les Entries du Document deja parse,
437  //                   il ne fabrique rien !
438   
439 gdcmDicomDirMeta * gdcmDicomDir::NewMeta(void) {
440    gdcmDicomDirMeta *m = new gdcmDicomDirMeta(&tagHT);   
441    for (TagDocEntryHT::iterator cc = tagHT.begin();cc != tagHT.end();++cc) {
442       m->AddDocEntry(cc->second);
443    }
444    return m;  
445 }
446
447
448 /**
449  * \ingroup gdcmDicomDir
450  * \brief   adds a new Patient (with the basic elements) to a partially created DICOMDIR
451  */
452 gdcmDicomDirPatient * gdcmDicomDir::NewPatient(void) {
453    std::list<gdcmElement> elemList;
454    std::list<gdcmElement>::iterator it;
455    guint16 tmpGr,tmpEl;
456    gdcmDictEntry *dictEntry;
457    gdcmValEntry *entry;
458    
459    gdcmSQItem *s = new gdcmSQItem(0);
460    
461    elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();  
462    
463    // TODO : use FillObject !!!
464
465    // for all the DicomDirPatient Elements 
466      
467    for(it=elemList.begin();it!=elemList.end();++it) 
468    {
469       tmpGr=it->group;
470       tmpEl=it->elem;
471       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);      
472       entry=new gdcmValEntry(dictEntry);
473       entry->SetOffset(0); // just to avoid further missprinting
474       entry->SetValue(it->value); 
475
476       // dealing with value length ...
477       
478       if(dictEntry->GetGroup()==0xfffe) 
479          { 
480             entry->SetLength(entry->GetValue().length());
481          }
482       else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
483          {
484             entry->SetLength(4);
485          } 
486       else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
487          {
488             entry->SetLength(2); 
489          } 
490       else if(dictEntry->GetVR()=="SQ") 
491          {
492             entry->SetLength(0xffffffff);
493          }
494       else
495          {
496             entry->SetLength(entry->GetValue().length());        
497          } 
498       s->AddDocEntry(entry);
499    }
500
501    gdcmDicomDirPatient *p = new gdcmDicomDirPatient(s, &tagHT);
502    patients.push_front(p);
503    return p;   
504 }
505
506
507 /**
508  * \ingroup gdcmDicomDir
509  * \brief   adds to the HTable 
510  *          the gdcmEntries (Dicom Elements) corresponding to the given type
511  * @param   path full path file name (only used when type = GDCM_DICOMDIR_IMAGE
512  * @param   type gdcmObject type to create (GDCM_DICOMDIR_PATIENT, GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...)
513  * @param   header gdcmHeader of the current file
514  */
515 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,
516                               gdcmDocument *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, VectDocument &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(VectDocument::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(gdcmDocument *header1,gdcmDocument *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 //-----------------------------------------------------------------------------