]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
remove old mutimap related code
[gdcm.git] / src / gdcmDicomDir.cxx
1 /*=========================================================================
2   
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDicomDir.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/06/28 14:29:52 $
7   Version:   $Revision: 1.54 $
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  // 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  * \ingroup gdcmDicomDir
469  * \brief   adds a new Patient (with the basic elements) to a partially created DICOMDIR
470  */
471 gdcmDicomDirPatient * gdcmDicomDir::NewPatient(void) {
472    std::list<gdcmElement> elemList;
473    std::list<gdcmElement>::iterator it;
474    guint16 tmpGr,tmpEl;
475    gdcmDictEntry *dictEntry;
476    gdcmValEntry *entry;
477    
478    gdcmSQItem *s = new gdcmSQItem(0);
479    
480    elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();  
481    
482    // TODO : use FillObject !!!
483
484    // for all the DicomDirPatient Elements 
485      
486    for(it=elemList.begin();it!=elemList.end();++it) 
487    {
488       tmpGr=it->group;
489       tmpEl=it->elem;
490       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);      
491       entry=new gdcmValEntry(dictEntry);
492       entry->SetOffset(0); // just to avoid further missprinting
493       entry->SetValue(it->value); 
494
495       // dealing with value length ...
496       
497       if(dictEntry->GetGroup()==0xfffe) 
498          { 
499             entry->SetLength(entry->GetValue().length());
500          }
501       else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
502          {
503             entry->SetLength(4);
504          } 
505       else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
506          {
507             entry->SetLength(2); 
508          } 
509       else if(dictEntry->GetVR()=="SQ") 
510          {
511             entry->SetLength(0xffffffff);
512          }
513       else
514          {
515             entry->SetLength(entry->GetValue().length());
516          } 
517       s->AddDocEntry(entry);
518    }
519
520    gdcmDicomDirPatient *p = new gdcmDicomDirPatient(s, &tagHT);
521    patients.push_front(p);
522    return p;   
523 }
524
525 /**
526  * \brief   adds to the HTable 
527  *          the gdcmEntries (Dicom Elements) corresponding to the given type
528  * @param   path full path file name (only used when type = GDCM_DICOMDIR_IMAGE
529  * @param   type gdcmObject type to create (GDCM_DICOMDIR_PATIENT,
530  *          GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...)
531  * @param   header gdcmHeader of the current file
532  */
533 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,
534                               gdcmDocument *header)
535 {
536    std::list<gdcmElement> elemList;
537    std::list<gdcmElement>::iterator it;
538    guint16 tmpGr, tmpEl;
539    gdcmDictEntry *dictEntry;
540    gdcmValEntry *entry;
541    std::string val;
542
543    switch(type){
544       case GDCM_DICOMDIR_PATIENT:
545          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();
546          break;
547       case GDCM_DICOMDIR_STUDY:
548          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirStudyElements();
549          break;
550       case GDCM_DICOMDIR_SERIE:
551          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirSerieElements();
552          break;
553       case GDCM_DICOMDIR_IMAGE:
554          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirImageElements();
555          break;
556       case GDCM_DICOMDIR_META:
557          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirMetaElements();
558          break;
559       default:
560          return;
561    }
562
563    for(it=elemList.begin();it!=elemList.end();++it) {
564       tmpGr=it->group;
565       tmpEl=it->elem;
566       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
567       entry=new gdcmValEntry(dictEntry); // Be sure it's never a BinEntry !
568
569       entry->SetOffset(0); // just to avoid further missprinting
570
571       if(header)
572          val=header->GetEntryByNumber(tmpGr,tmpEl);
573       else
574          val=GDCM_UNFOUND;
575
576       if(val==GDCM_UNFOUND) 
577       {
578          if((tmpGr==0x0004) &&(tmpEl==0x1130) ) // File-set ID
579          {
580            // force to the *end* File Name
581            val=GetName(path);
582          }
583          else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
584          {
585             if(header->GetFileName().substr(0,path.length())!=path)
586             {
587                dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path"
588                               " of file name is incorrect");
589                val=header->GetFileName();
590             }
591             else
592             {
593                val=&(header->GetFileName().c_str()[path.length()]);
594             }   
595          }
596          else
597          {
598             val=it->value;
599          }
600       } 
601       else
602       {
603          if (header->GetEntryLengthByNumber(tmpGr,tmpEl)== 0)
604             val=it->value;
605       }
606             
607       entry->SetValue(val);
608
609       if(dictEntry)
610       {
611          if(dictEntry->GetGroup()==0xfffe)  {
612             entry->SetLength(entry->GetValue().length());
613       }
614      else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
615          {
616             entry->SetLength(4);
617          } 
618       else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
619          {
620             entry->SetLength(2); 
621          } 
622       else if(dictEntry->GetVR()=="SQ") 
623          {
624             entry->SetLength(0xffffffff);
625          }
626       else
627          {
628             entry->SetLength(entry->GetValue().length());
629          }
630       }
631       //AddDocEntry(entry); // both in H Table and in chained list
632       tagHT[entry->GetKey()] = entry;          // FIXME : use a SEQUENCE !
633    }     
634 }
635
636 /**
637  * \brief   CallStartMethod
638  */
639 void gdcmDicomDir::CallStartMethod(void)
640 {
641    progress=0.0f;
642    abort=false;
643    if(startMethod)
644       startMethod(startArg);
645 }
646 /**
647  * \ingroup gdcmDicomDir
648  * \brief   CallProgressMethod
649  */
650 void gdcmDicomDir::CallProgressMethod(void)
651 {
652    if(progressMethod)
653       progressMethod(progressArg);
654 }
655 /**
656  * \ingroup gdcmDicomDir
657  * \brief   CallEndMethod
658  */
659 void gdcmDicomDir::CallEndMethod(void)
660 {
661    progress=1.0f;
662    if(endMethod)
663       endMethod(endArg);
664 }
665
666 //-----------------------------------------------------------------------------
667 // Private
668 /**
669  * \ingroup gdcmDicomDir
670  * \brief create a 'gdcmDicomDir' from a DICOMDIR gdcmHeader 
671  */
672 void gdcmDicomDir::CreateDicomDir()
673 {
674    // The list is parsed. 
675    //  When a DicomDir tag ("PATIENT", "STUDY", "SERIE", "IMAGE") is found :
676    //  1 - we save the beginning iterator
677    //  2 - we continue to parse
678    //  3 - we find an other tag
679    //       + we create the object for the precedent tag
680    //       + loop to 1 -
681
682    gdcmDicomDirType type=gdcmDicomDir::GDCM_DICOMDIR_META;
683    
684    // Directory record sequence
685    gdcmDocEntry *e = GetDocEntryByNumber(0x0004, 0x1220);
686    if (e==NULL)
687    {
688       dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : NO Directory record"
689                      " sequence (0x0004,0x1220)");
690       /// \todo FIXME: what to do when the parsed file IS NOT a DICOMDIR file ? 
691       return;         
692    }
693    
694    gdcmSeqEntry* s = dynamic_cast<gdcmSeqEntry*>(e);
695    if (!s)
696    {
697       dbg.Verbose(0, "gdcmDicomDir::CreateDicomDir: no SeqEntry present");
698       return;
699    }
700
701    ListSQItem listItems = s->GetSQItems();
702    gdcmDicomDirMeta *m = new gdcmDicomDirMeta(&tagHT);
703    (void)m; //??
704    
705    gdcmDocEntry * d;   
706    std::string v;
707    for(ListSQItem::iterator i=listItems.begin(); i !=listItems.end();++i) 
708    {  
709       d=(*i)->GetDocEntryByNumber(0x0004, 0x1430); // Directory Record Type   
710       if (gdcmValEntry* ValEntry = dynamic_cast< gdcmValEntry* >(d) )
711       {
712          v = ValEntry->GetValue();
713       }
714       else 
715       {
716          dbg.Verbose(0, "gdcmDicomDir::CreateDicomDir: not a ValEntry.");
717          continue;
718       } 
719
720       if(v=="PATIENT ") 
721       {  
722          AddDicomDirPatientToEnd(*i);
723          //AddObjectToEnd(type,*i);
724          type=gdcmDicomDir::GDCM_DICOMDIR_PATIENT;
725       }
726
727       else if(v=="STUDY ")
728       {
729          AddDicomDirStudyToEnd(*i);
730         // AddObjectToEnd(type,*i);
731          type=gdcmDicomDir::GDCM_DICOMDIR_STUDY;
732       }
733
734       else if(v=="SERIES") 
735       {
736          AddDicomDirSerieToEnd(*i);
737        //  AddObjectToEnd(type,*i);
738          type=gdcmDicomDir::GDCM_DICOMDIR_SERIE;
739       }
740
741       else if(v=="IMAGE ") 
742       {
743          AddDicomDirImageToEnd(*i);
744       //   AddObjectToEnd(type,*i);
745          type=gdcmDicomDir::GDCM_DICOMDIR_IMAGE;
746       }
747       
748       else
749          // It was not a 'PATIENT', nor a 'STUDY', nor a 'SERIE',
750          // neither an 'IMAGE' SQItem. Skip to next item.
751          continue;
752    }
753 }
754 /**
755  * \ingroup gdcmDicomDir
756  * \brief   AddObjectToEnd
757  * @param   type
758  * @param   begin iterator on the first DocEntry within the chained List
759  * @param   end iterator on the last DocEntry within the chained List
760  */
761  
762 // now  useless ?
763
764 /*void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,gdcmSQItem *s)
765 {
766    if(s==NULL) // ??
767       return;
768
769    switch(type)
770    {
771       case gdcmDicomDir::GDCM_DICOMDIR_META:
772          AddDicomDirMeta();
773          break;      
774       case gdcmDicomDir::GDCM_DICOMDIR_PATIENT:
775          AddDicomDirPatientToEnd(s);
776          break;
777       case gdcmDicomDir::GDCM_DICOMDIR_STUDY:
778          AddDicomDirStudyToEnd(s);
779          break;
780       case gdcmDicomDir::GDCM_DICOMDIR_SERIE:
781          AddDicomDirSerieToEnd(s);
782          break;
783       case gdcmDicomDir::GDCM_DICOMDIR_IMAGE:
784          AddDicomDirImageToEnd(s);
785          break;
786       case gdcmDicomDir::GDCM_DICOMDIR_NONE:
787          AddDicomDirImageToEnd(s);        //FIXME
788          break;
789    }
790 }
791
792 */
793
794 /**
795  * \ingroup gdcmDicomDir
796  * \brief Well ... there is only one occurence  
797 */
798 void gdcmDicomDir::AddDicomDirMeta()
799 {
800    if(metaElems)
801       delete metaElems;
802    metaElems = new gdcmDicomDirMeta(&tagHT);
803 }
804
805 /**
806  * \ingroup gdcmDicomDir
807  * \brief  AddDicomDirPatientToEnd 
808  * @param   s SQ Item to enqueue to the DicomPatient chained List
809 */
810 void gdcmDicomDir::AddDicomDirPatientToEnd(gdcmSQItem *s)
811 {
812    patients.push_back(new gdcmDicomDirPatient(s, &tagHT));
813 }
814
815 /**
816  * \ingroup gdcmDicomDir
817  * \brief  AddDicomDirStudyToEnd 
818  * @param   s SQ Item to enqueue to the DicomDirStudy chained List
819  */
820  void gdcmDicomDir::AddDicomDirStudyToEnd(gdcmSQItem *s)
821 {
822    if(patients.size()>0)
823    {
824       ListDicomDirPatient::iterator itp=patients.end();
825       itp--;
826      (*itp)->AddDicomDirStudy(new gdcmDicomDirStudy(s, &tagHT));
827    }
828 }
829 /**
830  * \ingroup gdcmDicomDir
831  * \brief  AddDicomDirSerieToEnd 
832  * @param   s SQ Item to enqueue to the DicomDirSerie chained List
833  */
834 void gdcmDicomDir::AddDicomDirSerieToEnd(gdcmSQItem *s)
835 {
836    if(patients.size()>0)
837    {
838       ListDicomDirPatient::iterator itp=patients.end();
839       itp--;
840
841       if((*itp)->GetDicomDirStudies().size()>0)
842       {
843          ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
844          itst--;
845         (*itst)->AddDicomDirSerie(new gdcmDicomDirSerie(s, &tagHT));
846       }
847    }
848 }
849
850 /**
851  * \ingroup gdcmDicomDir
852  * \brief   AddDicomDirImageToEnd
853  * @param   s SQ Item to enqueue to the DicomDirImage chained List
854  */
855  void gdcmDicomDir::AddDicomDirImageToEnd(gdcmSQItem *s)
856 {
857    if(patients.size()>0)
858    {
859       ListDicomDirPatient::iterator itp=patients.end();
860       itp--;
861
862       if((*itp)->GetDicomDirStudies().size()>0)
863       {
864          ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
865          itst--;
866
867          if((*itst)->GetDicomDirSeries().size()>0)
868          {
869             ListDicomDirSerie::iterator its=(*itst)->GetDicomDirSeries().end();
870             its--;
871            (*its)->AddDicomDirImage(new gdcmDicomDirImage(s, &tagHT));
872          }
873       }
874    }
875 }
876
877 /**
878  * \ingroup gdcmDicomDir
879  * \brief  for each Header of the chained list, add/update the Patient/Study/Serie/Image info 
880  * @param   path path of the root directory
881  * @param   list chained list of Headers
882  */
883 void gdcmDicomDir::SetElements(std::string &path, VectDocument &list)
884 {
885    std::string patPrevName="",         patPrevID="";
886    std::string studPrevInstanceUID="", studPrevID="";
887    std::string serPrevInstanceUID="",  serPrevID="";
888
889    std::string patCurName,         patCurID;
890    std::string studCurInstanceUID, studCurID;
891    std::string serCurInstanceUID,  serCurID;
892
893    SetElement(path,GDCM_DICOMDIR_META,NULL);
894
895    for(VectDocument::iterator it=list.begin();it!=list.end();++it) 
896    {
897       // get the current file characteristics
898       patCurName=        (*it)->GetEntryByNumber(0x0010,0x0010); 
899       patCurID=          (*it)->GetEntryByNumber(0x0010,0x0011); 
900       studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);            
901       studCurID=         (*it)->GetEntryByNumber(0x0020,0x0010);            
902       serCurInstanceUID= (*it)->GetEntryByNumber(0x0020,0x000e);            
903       serCurID=          (*it)->GetEntryByNumber(0x0020,0x0011);
904
905       if(patCurName!=patPrevName || patCurID!=patPrevID) 
906          SetElement(path,GDCM_DICOMDIR_PATIENT,*it);
907
908       // if new Study Deal with 'STUDY' Elements   
909       if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID) 
910          SetElement(path,GDCM_DICOMDIR_STUDY,*it);
911
912       // if new Serie Deal with 'SERIE' Elements   
913       if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID) 
914          SetElement(path,GDCM_DICOMDIR_SERIE,*it);
915       
916       // Always Deal with 'IMAGE' Elements  
917       SetElement(path,GDCM_DICOMDIR_IMAGE,*it);
918
919       patPrevName=        patCurName;
920       patPrevID=          patCurID;
921       studPrevInstanceUID=studCurInstanceUID;
922       studPrevID=         studCurID;
923       serPrevInstanceUID= serCurInstanceUID;
924       serPrevID=          serCurID;
925    }
926 }
927
928 /**
929  * \ingroup gdcmDicomDir
930  * \brief   compares two dgcmHeaders
931  */
932 bool gdcmDicomDir::HeaderLessThan(gdcmDocument *header1,gdcmDocument *header2)
933 {
934    return(*header1<*header2);
935 }
936
937 /**
938  * \ingroup gdcmDicomDir
939  * \brief   Sets the accurate value for the (0x0004,0x1220) element of a DICOMDIR
940  */
941
942 void gdcmDicomDir::UpdateDirectoryRecordSequenceLength() {
943
944 // FIXME : to go on compiling
945
946 // to be re written !
947 /*
948    int offset = 0;
949    ListTag::iterator it;
950    guint16 gr, el;
951    std::string vr;
952    for(it=listEntries.begin();it!=listEntries.end();++it) {
953       gr = (*it)->GetGroup();
954       el = (*it)->GetElement();
955       vr = (*it)->GetVR();      
956       if (gr !=0xfffe) {
957          if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {    
958             offset +=  4; // explicit VR AND OB, OW, SQ : 4 more bytes
959          }         
960          offset += 2 + 2 + 4 + (*it)->GetLength(); 
961       } else {
962          offset +=  4; // delimiters don't have a value.     
963       }            
964    }   
965    //bool res=SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
966     SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
967    return;
968    */
969 }
970
971 //-----------------------------------------------------------------------------