]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
FIX: GDCM was not compiling with -W -Wall
[gdcm.git] / src / gdcmDicomDir.cxx
1 /*=========================================================================
2   
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDicomDir.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/06/23 02:13:14 $
7   Version:   $Revision: 1.51 $
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    (void)m; //??
700    
701    gdcmDocEntry * d;   
702    std::string v;
703    for(ListSQItem::iterator i=listItems.begin(); i !=listItems.end();++i) 
704    {  
705       d=(*i)->GetDocEntryByNumber(0x0004, 0x1430); // Directory Record Type   
706       if (gdcmValEntry* ValEntry = dynamic_cast< gdcmValEntry* >(d) )
707       {
708          v = ValEntry->GetValue();
709       }
710       else 
711       {
712          dbg.Verbose(0, "gdcmDicomDir::CreateDicomDir: not a ValEntry.");
713          continue;
714       } 
715
716       if(v=="PATIENT ") 
717       {  
718          AddDicomDirPatientToEnd(*i);
719          //AddObjectToEnd(type,*i);
720          type=gdcmDicomDir::GDCM_DICOMDIR_PATIENT;
721       }
722
723       else if(v=="STUDY ")
724       {
725          AddDicomDirStudyToEnd(*i);
726         // AddObjectToEnd(type,*i);
727          type=gdcmDicomDir::GDCM_DICOMDIR_STUDY;
728       }
729
730       else if(v=="SERIES") 
731       {
732          AddDicomDirSerieToEnd(*i);
733        //  AddObjectToEnd(type,*i);
734          type=gdcmDicomDir::GDCM_DICOMDIR_SERIE;
735       }
736
737       else if(v=="IMAGE ") 
738       {
739          AddDicomDirImageToEnd(*i);
740       //   AddObjectToEnd(type,*i);
741          type=gdcmDicomDir::GDCM_DICOMDIR_IMAGE;
742       }
743       
744       else
745          // It was not a 'PATIENT', nor a 'STUDY', nor a 'SERIE',
746          // neither an 'IMAGE' SQItem. Skip to next item.
747          continue;
748    }
749 }
750 /**
751  * \ingroup gdcmDicomDir
752  * \brief   AddObjectToEnd
753  * @param   type
754  * @param   begin iterator on the first DocEntry within the chained List
755  * @param   end iterator on the last DocEntry within the chained List
756  */
757  
758 // now  useless ?
759
760 /*void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,gdcmSQItem *s)
761 {
762    if(s==NULL) // ??
763       return;
764
765    switch(type)
766    {
767       case gdcmDicomDir::GDCM_DICOMDIR_META:
768          AddDicomDirMeta();
769          break;      
770       case gdcmDicomDir::GDCM_DICOMDIR_PATIENT:
771          AddDicomDirPatientToEnd(s);
772          break;
773       case gdcmDicomDir::GDCM_DICOMDIR_STUDY:
774          AddDicomDirStudyToEnd(s);
775          break;
776       case gdcmDicomDir::GDCM_DICOMDIR_SERIE:
777          AddDicomDirSerieToEnd(s);
778          break;
779       case gdcmDicomDir::GDCM_DICOMDIR_IMAGE:
780          AddDicomDirImageToEnd(s);
781          break;
782       case gdcmDicomDir::GDCM_DICOMDIR_NONE:
783          AddDicomDirImageToEnd(s);        //FIXME
784          break;
785    }
786 }
787
788 */
789
790 /**
791  * \ingroup gdcmDicomDir
792  * \brief Well ... there is only one occurence  
793 */
794 void gdcmDicomDir::AddDicomDirMeta()
795 {
796    if(metaElems)
797       delete metaElems;
798    metaElems = new gdcmDicomDirMeta(&tagHT);
799 }
800
801 /**
802  * \ingroup gdcmDicomDir
803  * \brief  AddDicomDirPatientToEnd 
804  * @param   s SQ Item to enqueue to the DicomPatient chained List
805 */
806 void gdcmDicomDir::AddDicomDirPatientToEnd(gdcmSQItem *s)
807 {
808    patients.push_back(new gdcmDicomDirPatient(s, &tagHT));
809 }
810
811 /**
812  * \ingroup gdcmDicomDir
813  * \brief  AddDicomDirStudyToEnd 
814  * @param   s SQ Item to enqueue to the DicomDirStudy chained List
815  */
816  void gdcmDicomDir::AddDicomDirStudyToEnd(gdcmSQItem *s)
817 {
818    if(patients.size()>0)
819    {
820       ListDicomDirPatient::iterator itp=patients.end();
821       itp--;
822      (*itp)->AddDicomDirStudy(new gdcmDicomDirStudy(s, &tagHT));
823    }
824 }
825 /**
826  * \ingroup gdcmDicomDir
827  * \brief  AddDicomDirSerieToEnd 
828  * @param   s SQ Item to enqueue to the DicomDirSerie chained List
829  */
830 void gdcmDicomDir::AddDicomDirSerieToEnd(gdcmSQItem *s)
831 {
832    if(patients.size()>0)
833    {
834       ListDicomDirPatient::iterator itp=patients.end();
835       itp--;
836
837       if((*itp)->GetDicomDirStudies().size()>0)
838       {
839          ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
840          itst--;
841         (*itst)->AddDicomDirSerie(new gdcmDicomDirSerie(s, &tagHT));
842       }
843    }
844 }
845
846 /**
847  * \ingroup gdcmDicomDir
848  * \brief   AddDicomDirImageToEnd
849  * @param   s SQ Item to enqueue to the DicomDirImage chained List
850  */
851  void gdcmDicomDir::AddDicomDirImageToEnd(gdcmSQItem *s)
852 {
853    if(patients.size()>0)
854    {
855       ListDicomDirPatient::iterator itp=patients.end();
856       itp--;
857
858       if((*itp)->GetDicomDirStudies().size()>0)
859       {
860          ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
861          itst--;
862
863          if((*itst)->GetDicomDirSeries().size()>0)
864          {
865             ListDicomDirSerie::iterator its=(*itst)->GetDicomDirSeries().end();
866             its--;
867            (*its)->AddDicomDirImage(new gdcmDicomDirImage(s, &tagHT));
868          }
869       }
870    }
871 }
872
873 /**
874  * \ingroup gdcmDicomDir
875  * \brief  for each Header of the chained list, add/update the Patient/Study/Serie/Image info 
876  * @param   path path of the root directory
877  * @param   list chained list of Headers
878  */
879 void gdcmDicomDir::SetElements(std::string &path, VectDocument &list)
880 {
881    std::string patPrevName="",         patPrevID="";
882    std::string studPrevInstanceUID="", studPrevID="";
883    std::string serPrevInstanceUID="",  serPrevID="";
884
885    std::string patCurName,         patCurID;
886    std::string studCurInstanceUID, studCurID;
887    std::string serCurInstanceUID,  serCurID;
888
889    SetElement(path,GDCM_DICOMDIR_META,NULL);
890
891    for(VectDocument::iterator it=list.begin();it!=list.end();++it) 
892    {
893       // get the current file characteristics
894       patCurName=        (*it)->GetEntryByNumber(0x0010,0x0010); 
895       patCurID=          (*it)->GetEntryByNumber(0x0010,0x0011); 
896       studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);            
897       studCurID=         (*it)->GetEntryByNumber(0x0020,0x0010);            
898       serCurInstanceUID= (*it)->GetEntryByNumber(0x0020,0x000e);            
899       serCurID=          (*it)->GetEntryByNumber(0x0020,0x0011);
900
901       if(patCurName!=patPrevName || patCurID!=patPrevID) 
902          SetElement(path,GDCM_DICOMDIR_PATIENT,*it);
903
904       // if new Study Deal with 'STUDY' Elements   
905       if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID) 
906          SetElement(path,GDCM_DICOMDIR_STUDY,*it);
907
908       // if new Serie Deal with 'SERIE' Elements   
909       if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID) 
910          SetElement(path,GDCM_DICOMDIR_SERIE,*it);
911       
912       // Always Deal with 'IMAGE' Elements  
913       SetElement(path,GDCM_DICOMDIR_IMAGE,*it);
914
915       patPrevName=        patCurName;
916       patPrevID=          patCurID;
917       studPrevInstanceUID=studCurInstanceUID;
918       studPrevID=         studCurID;
919       serPrevInstanceUID= serCurInstanceUID;
920       serPrevID=          serCurID;
921    }
922 }
923
924 /**
925  * \ingroup gdcmDicomDir
926  * \brief   compares two dgcmHeaders
927  */
928 bool gdcmDicomDir::HeaderLessThan(gdcmDocument *header1,gdcmDocument *header2)
929 {
930    return(*header1<*header2);
931 }
932
933 /**
934  * \ingroup gdcmDicomDir
935  * \brief   Sets the accurate value for the (0x0004,0x1220) element of a DICOMDIR
936  */
937
938 void gdcmDicomDir::UpdateDirectoryRecordSequenceLength() {
939
940 // FIXME : to go on compiling
941
942 // to be re written !
943 /*
944    int offset = 0;
945    ListTag::iterator it;
946    guint16 gr, el;
947    std::string vr;
948    for(it=listEntries.begin();it!=listEntries.end();++it) {
949       gr = (*it)->GetGroup();
950       el = (*it)->GetElement();
951       vr = (*it)->GetVR();      
952       if (gr !=0xfffe) {
953          if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {    
954             offset +=  4; // explicit VR AND OB, OW, SQ : 4 more bytes
955          }         
956          offset += 2 + 2 + 4 + (*it)->GetLength(); 
957       } else {
958          offset +=  4; // delimiters don't have a value.     
959       }            
960    }   
961    //bool res=SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
962     SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
963    return;
964    */
965 }
966
967 //-----------------------------------------------------------------------------