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