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