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