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