]> Creatis software - gdcm.git/blob - src/gdcmDicomDir.cxx
* src/gdcmCommon.h: FileType enum entry DICOMDIR removed (since
[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    WriteDicomDirEntries(fp1);
317
318    fclose(fp1);
319    return true;
320 }
321
322 /**
323  * \ingroup gdcmParser
324  * \brief   writes on disc according to the DICOMDIR format
325  *          using the tree-like structure
326  * @param   _fp already open file pointer
327  */
328
329 void gdcmDicomDir::WriteDicomDirEntries(FILE *_fp)
330 {   
331    // TODO (?) tester les echecs en ecriture 
332    //          (apres chaque fwrite, dans le WriteEntry)
333
334    gdcmDicomDirMeta *ptrMeta;
335    ListDicomDirPatient::iterator  itPatient;
336    ListDicomDirStudy::iterator    itStudy;
337    ListDicomDirSerie::iterator    itSerie;
338    ListDicomDirImage::iterator    itImage; 
339    ListTag::iterator i; 
340    
341    ptrMeta= GetDicomDirMeta();
342    for(i=ptrMeta->debut();i!=ptrMeta->fin();++i) {
343       WriteEntry(*i,_fp, ExplicitVR);
344    }   
345     
346    itPatient = GetDicomDirPatients().begin(); 
347    while ( itPatient != GetDicomDirPatients().end() ) {
348       for(i=(*itPatient)->debut();i!=(*itPatient)->fin();++i) {
349          WriteEntry(*i,_fp, ExplicitVR);
350       }
351       itStudy = ((*itPatient)->GetDicomDirStudies()).begin();         
352       while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {    
353          for(i=(*itStudy)->debut();i!=(*itStudy)->fin();++i) {
354             WriteEntry(*i,_fp, ExplicitVR);
355          } 
356          itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
357          while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
358             for(i=(*itSerie)->debut();i!=(*itSerie)->fin();++i) {
359                WriteEntry(*i,_fp, ExplicitVR);
360             }
361             itImage = ((*itSerie)->GetDicomDirImages()).begin();
362             while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
363                for(i=(*itImage)->debut();i!=(*itImage)->fin();++i) {
364                   WriteEntry(*i,_fp, ExplicitVR);
365                }
366                ++itImage;                   
367             }
368             ++itSerie;                                
369          }
370          ++itStudy;            
371       } 
372       ++itPatient;     
373    }
374 }   
375    
376 //-----------------------------------------------------------------------------
377 // Protected
378
379 /**
380  * \ingroup gdcmDicomDir
381  * \brief create a gdcmHeader-like chained list from a root Directory 
382  * @param path entry point of the tree-like structure
383  */
384 void gdcmDicomDir::CreateDicomDirChainedList(std::string path)
385 {
386    CallStartMethod();
387
388    gdcmDirList fileList(path,1); // gets recursively the file list
389    unsigned int count=0;
390    ListHeader list;
391    gdcmHeader *header;
392
393    listEntries.clear();
394    patients.clear();
395
396    for(gdcmDirList::iterator it=fileList.begin(); 
397                              it!=fileList.end(); 
398                              ++it) 
399    {
400       progress=(float)(count+1)/(float)fileList.size();
401       CallProgressMethod();
402       if(abort)
403          break;
404
405       header=new gdcmHeader(it->c_str());
406       if(header->IsReadable())
407          list.push_back(header);  // adds the file header to the chained list
408       else
409          delete header;
410
411       count++;
412    }
413    // sorts Patient/Study/Serie/
414    std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan);
415
416    std::string tmp=fileList.GetDirName();
417       
418    //for each Header of the chained list, add/update the Patient/Study/Serie/Image info
419    SetElements(tmp,list);
420       
421    CallEndMethod();
422 }
423
424 /**
425  * \ingroup gdcmDicomDir
426  * \brief modifies the limits of a gdcmObject, created from a DICOMDIR file  
427  */
428
429 void gdcmDicomDir::CheckBoundaries()
430 {   
431    ListDicomDirPatient::iterator  itPatient;
432    ListDicomDirStudy::iterator    itStudy;
433    ListDicomDirSerie::iterator    itSerie;
434    ListDicomDirImage::iterator    itImage; 
435    ListTag::iterator i,j; 
436    
437    GetDicomDirMeta()->ResetBoundaries(0);   
438
439    itPatient = GetDicomDirPatients().begin(); 
440    while ( itPatient != GetDicomDirPatients().end() ) {
441       (*itPatient)->ResetBoundaries(1);            
442       itStudy = ((*itPatient)->GetDicomDirStudies()).begin();         
443       while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {    
444          (*itStudy)->ResetBoundaries(1); 
445          itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
446          while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
447             (*itSerie)->ResetBoundaries(1);
448             itImage = ((*itSerie)->GetDicomDirImages()).begin();
449             while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
450                (*itImage)->ResetBoundaries(1);
451                ++itImage;
452        }
453        ++itSerie;
454          }
455       ++itStudy;
456       } 
457       ++itPatient;     
458    }
459
460
461
462 /**
463  * \ingroup gdcmDicomDir
464  * \brief   adds a new Patient 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    gdcmHeaderEntry *entry;
472    
473    elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();  
474    std::list<gdcmHeaderEntry *>::iterator debInsertion, finInsertion, i,j; 
475          
476    debInsertion = metaElems->fin(); 
477    ++debInsertion;
478    finInsertion=debInsertion;
479
480    // for all the DicomDirPatient Elements   
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 gdcmHeaderEntry(dictEntry);
487       entry->SetOffset(0); // just to avoid missprinting
488       entry->SetValue(it->value);
489
490       if(dictEntry->GetGroup()==0xfffe) 
491       {
492             entry->SetLength(entry->GetValue().length());
493       }
494       else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
495          {
496             entry->SetLength(4);
497          } 
498       else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
499          {
500             entry->SetLength(2); 
501          } 
502       else if(dictEntry->GetVR()=="SQ") 
503          {
504             entry->SetLength(0xffffffff);
505          }
506       else
507          {
508             entry->SetLength(entry->GetValue().length());        
509          } 
510                                               
511       tagHT.insert( PairHT(entry->GetKey(),entry) ); // add in the (multimap) H Table
512       listEntries.insert(debInsertion ,entry);       // en tete de liste des Patients                                            
513       ++finInsertion;
514    }
515
516    i=metaElems->fin();
517    i++;
518
519    gdcmDicomDirPatient *p = new gdcmDicomDirPatient(i, --debInsertion,
520                                                     &tagHT, &listEntries);
521    patients.push_front(p);
522    return p;   
523 }
524
525 /**
526  * \ingroup gdcmDicomDir
527  * \brief   CallStartMethod
528  */
529 void gdcmDicomDir::CallStartMethod(void)
530 {
531    progress=0.0f;
532    abort=false;
533    if(startMethod)
534       startMethod(startArg);
535 }
536 /**
537  * \ingroup gdcmDicomDir
538  * \brief   CallProgressMethod
539  */
540 void gdcmDicomDir::CallProgressMethod(void)
541 {
542    if(progressMethod)
543       progressMethod(progressArg);
544 }
545 /**
546  * \ingroup gdcmDicomDir
547  * \brief   CallEndMethod
548  */
549 void gdcmDicomDir::CallEndMethod(void)
550 {
551    progress=1.0f;
552    if(endMethod)
553       endMethod(endArg);
554 }
555
556 //-----------------------------------------------------------------------------
557 // Private
558 /**
559  * \ingroup gdcmDicomDir
560  * \brief create a 'gdcmDicomDir' from a DICOMDIR gdcmHeader 
561  */
562 void gdcmDicomDir::CreateDicomDir()
563 {
564    // The list is parsed. 
565    //  When a DicomDir tag ("PATIENT", "STUDY", "SERIE", "IMAGE") is found :
566    //  1 - we save the beginning iterator
567    //  2 - we continue to parse
568    //  3 - we find an other tag
569    //       + we create the object for the precedent tag
570    //       + loop to 1 -
571
572    gdcmDicomDirType type=gdcmDicomDir::GDCM_DICOMDIR_META;
573    ListTag::iterator begin;
574    ListTag::iterator end, end2;
575
576    begin=listEntries.begin();
577    end=begin;
578    for(ListTag::iterator i=end;i !=listEntries.end();++i) 
579    {
580       std::string v=(*i)->GetValue();
581       if(v=="PATIENT ") 
582       {
583          end=end2=i;
584          AddObjectToEnd(type,begin,--end2);
585          type=gdcmDicomDir::GDCM_DICOMDIR_PATIENT;
586          begin=end;
587       } 
588
589       if(v=="STUDY ")
590       {
591          end=end2=i;
592          AddObjectToEnd(type,begin,--end2);
593          type=gdcmDicomDir::GDCM_DICOMDIR_STUDY;
594          begin=end;
595       }
596
597       if(v=="SERIES") 
598       {
599          end=end2=i;
600          AddObjectToEnd(type,begin,--end2);
601          type=gdcmDicomDir::GDCM_DICOMDIR_SERIE;
602          begin=end;
603       }
604
605       if(v=="IMAGE ") 
606       {
607          end=end2=i;
608          AddObjectToEnd(type,begin,--end2);
609          type=gdcmDicomDir::GDCM_DICOMDIR_IMAGE;
610          begin=end;
611       }
612    }
613
614    end=end2=listEntries.end();
615    if(begin!=end)
616       AddObjectToEnd(type,begin,--end2);
617 }
618 /**
619  * \ingroup gdcmDicomDir
620  * \brief   AddObjectToEnd
621  * @param   type
622  * @param   begin iterator on the first HeaderEntry within the chained List
623  * @param   end iterator on the last HeaderEntry within the chained List
624  */
625 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
626 {
627    if(begin==end)
628       return;
629
630    switch(type)
631    {
632       case gdcmDicomDir::GDCM_DICOMDIR_META:
633          AddDicomDirMetaToEnd(begin,end);
634          break;      
635       case gdcmDicomDir::GDCM_DICOMDIR_PATIENT:
636          AddDicomDirPatientToEnd(begin,end);
637          break;
638       case gdcmDicomDir::GDCM_DICOMDIR_STUDY:
639          AddDicomDirStudyToEnd(begin,end);
640          break;
641       case gdcmDicomDir::GDCM_DICOMDIR_SERIE:
642          AddDicomDirSerieToEnd(begin,end);
643          break;
644       case gdcmDicomDir::GDCM_DICOMDIR_IMAGE:
645          AddDicomDirImageToEnd(begin,end);
646          break;
647    }
648 }
649
650 /**
651  * \ingroup gdcmDicomDir
652  * \brief Well ... Not realy to end, there is only one occurence  
653  * @param   begin iterator on the first HeaderEntry within the chained List
654  * @param   end iterator on the last HeaderEntry within the chained List
655 */
656 void gdcmDicomDir::AddDicomDirMetaToEnd(ListTag::iterator begin,ListTag::iterator end)
657 {
658    if(metaElems)
659       delete metaElems;
660    metaElems = new gdcmDicomDirMeta(begin,end,&tagHT,&listEntries);
661 }
662
663 /**
664  * \ingroup gdcmDicomDir
665  * \brief  AddDicomDirPatientToEnd 
666  * @param   begin iterator on the first HeaderEntry within the chained List
667  * @param   end iterator on the last HeaderEntry within the chained List
668 */
669 void gdcmDicomDir::AddDicomDirPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
670 {
671    patients.push_back(new gdcmDicomDirPatient(begin,end,&tagHT, &listEntries));
672 }
673
674 /**
675  * \ingroup gdcmDicomDir
676  * \brief  AddDicomDirStudyToEnd 
677  * @param   begin iterator on the first HeaderEntry within the chained List
678  * @param   end iterator on the last HeaderEntry within the chained List
679  */
680  void gdcmDicomDir::AddDicomDirStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
681 {
682    if(patients.size()>0)
683    {
684       ListDicomDirPatient::iterator itp=patients.end();
685       itp--;
686      (*itp)->AddDicomDirStudy(new gdcmDicomDirStudy(begin,end,&tagHT, &listEntries));
687    }
688 }
689 /**
690  * \ingroup gdcmDicomDir
691  * \brief  AddDicomDirSerieToEnd 
692  * @param   begin iterator on the first HeaderEntry within the chained List
693  * @param   end iterator on the last HeaderEntry within the chained List
694  */
695 void gdcmDicomDir::AddDicomDirSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
696 {
697    if(patients.size()>0)
698    {
699       ListDicomDirPatient::iterator itp=patients.end();
700       itp--;
701
702       if((*itp)->GetDicomDirStudies().size()>0)
703       {
704          ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
705          itst--;
706         (*itst)->AddDicomDirSerie(new gdcmDicomDirSerie(begin,end,&tagHT, &listEntries));
707       }
708    }
709 }
710
711 /**
712  * \ingroup gdcmDicomDir
713  * \brief   AddDicomDirImageToEnd
714  * @param   begin iterator on the first HeaderEntry within the chained List
715  * @param   end iterator on the last HeaderEntry within the chained List
716  */
717  void gdcmDicomDir::AddDicomDirImageToEnd(ListTag::iterator begin,ListTag::iterator end)
718 {
719    if(patients.size()>0)
720    {
721       ListDicomDirPatient::iterator itp=patients.end();
722       itp--;
723
724       if((*itp)->GetDicomDirStudies().size()>0)
725       {
726          ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
727          itst--;
728
729          if((*itst)->GetDicomDirSeries().size()>0)
730          {
731             ListDicomDirSerie::iterator its=(*itst)->GetDicomDirSeries().end();
732             its--;
733            (*its)->AddDicomDirImage(new gdcmDicomDirImage(begin,end,&tagHT, &listEntries));
734          }
735       }
736    }
737 }
738
739 /**
740  * \ingroup gdcmDicomDir
741  * \brief  for each Header of the chained list, add/update the Patient/Study/Serie/Image info 
742  * @param   path path of the root directory
743  * @param   list chained list of Headers
744  */
745 void gdcmDicomDir::SetElements(std::string &path, ListHeader &list)
746 {
747    std::string patPrevName="",         patPrevID="";
748    std::string studPrevInstanceUID="", studPrevID="";
749    std::string serPrevInstanceUID="",  serPrevID="";
750
751    std::string patCurName,         patCurID;
752    std::string studCurInstanceUID, studCurID;
753    std::string serCurInstanceUID,  serCurID;
754
755    SetElement(path,GDCM_DICOMDIR_META,NULL);
756
757    ListTag::iterator debPat=listEntries.begin();
758    for(ListHeader::iterator it=list.begin();it!=list.end();++it) 
759    {
760       // get the current file characteristics
761       patCurName=        (*it)->GetEntryByNumber(0x0010,0x0010); 
762       patCurID=          (*it)->GetEntryByNumber(0x0010,0x0011); 
763       studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);            
764       studCurID=         (*it)->GetEntryByNumber(0x0020,0x0010);            
765       serCurInstanceUID= (*it)->GetEntryByNumber(0x0020,0x000e);            
766       serCurID=          (*it)->GetEntryByNumber(0x0020,0x0011);
767
768       if(patCurName!=patPrevName || patCurID!=patPrevID) 
769          SetElement(path,GDCM_DICOMDIR_PATIENT,*it);
770
771       // if new Study Deal with 'STUDY' Elements   
772       if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID) 
773          SetElement(path,GDCM_DICOMDIR_STUDY,*it);
774
775       // if new Serie Deal with 'SERIE' Elements   
776       if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID) 
777          SetElement(path,GDCM_DICOMDIR_SERIE,*it);
778       
779       // Always Deal with 'IMAGE' Elements  
780       SetElement(path,GDCM_DICOMDIR_IMAGE,*it);
781
782       patPrevName=        patCurName;
783       patPrevID=          patCurID;
784       studPrevInstanceUID=studCurInstanceUID;
785       studPrevID=         studCurID;
786       serPrevInstanceUID= serCurInstanceUID;
787       serPrevID=          serCurID;
788    }
789 }
790
791 /**
792  * \ingroup gdcmDicomDir
793  * \brief   adds to the HTable and at the end of the Chained List
794  *          the gdcmEntries (Dicom Elements) corresponding to the given type
795  * @param   path full path file name(only used when type = GDCM_DICOMDIR_IMAGE
796  * @param   type gdcmObject type to create (GDCM_DICOMDIR_PATIENT, GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...)
797  * @param   header gdcmHeader of the current file
798  */
799 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
800 {
801    std::list<gdcmElement> elemList;
802    std::list<gdcmElement>::iterator it;
803    guint16 tmpGr, tmpEl;
804    gdcmDictEntry *dictEntry;
805    gdcmHeaderEntry *entry;
806    std::string val;
807
808    switch(type)
809    {
810       case GDCM_DICOMDIR_PATIENT:
811          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();
812          break;
813       case GDCM_DICOMDIR_STUDY:
814          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirStudyElements();
815          break;
816       case GDCM_DICOMDIR_SERIE:
817          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirSerieElements();
818          break;
819       case GDCM_DICOMDIR_IMAGE:
820          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirImageElements();
821          break;
822       case GDCM_DICOMDIR_META:
823          elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirMetaElements();
824          break;
825       default:
826          return;
827    }
828
829    for(it=elemList.begin();it!=elemList.end();++it)
830    {
831       tmpGr=it->group;
832       tmpEl=it->elem;
833       dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
834       entry=new gdcmHeaderEntry(dictEntry);
835       entry->SetOffset(0); // just to avoid missprinting
836
837       if(header)
838          val=header->GetEntryByNumber(tmpGr,tmpEl);
839       else
840          val=GDCM_UNFOUND;
841
842       if(val==GDCM_UNFOUND) 
843       {
844          if((tmpGr==0x0004) &&(tmpEl==0x1130) ) // File-set ID
845          {       
846            // force to the *end* File Name
847            val=GetName(path);               
848          }
849          else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
850          {
851             if(header->GetFileName().substr(0,path.length())!=path)
852             {
853                dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
854                val=header->GetFileName();
855             }
856             else {
857                val=&(header->GetFileName().c_str()[path.length()]);
858             }   
859          }
860          else
861          {
862             val=it->value;
863          }
864       } 
865       else
866       {
867          if (header->GetEntryLengthByNumber(tmpGr,tmpEl)== 0)
868             val=it->value;
869       }
870             
871       entry->SetValue(val);
872
873       if(dictEntry)
874       {
875          if(dictEntry->GetGroup()==0xfffe) 
876          {
877             entry->SetLength(entry->GetValue().length());        
878          }
879          else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") ) 
880          {
881             entry->SetLength(4);
882          } 
883          else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") ) 
884          {
885             entry->SetLength(2); 
886          } 
887          else if(dictEntry->GetVR()=="SQ") 
888          {
889             entry->SetLength(0xffffffff);
890          }
891          else
892          {
893             entry->SetLength(entry->GetValue().length());        
894          }
895       }
896       //AddHeaderEntry(entry); // both in H Table and in chained list
897       tagHT.insert( PairHT( entry->GetKey(),entry) );
898       listEntries.push_back(entry);  
899       //wasUpdated = 1; // is private
900    }     
901 }
902 /**
903  * \ingroup gdcmDicomDir
904  * \brief   compares two dgcmHeaders
905  */
906 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
907 {
908    return(*header1<*header2);
909 }
910
911 /**
912  * \ingroup gdcmDicomDir
913  * \brief   Sets the accurate value for the (0x0004,0x1220) element of a DICOMDIR
914  */
915
916 void gdcmDicomDir::UpdateDirectoryRecordSequenceLength() {
917    int offset = 0;
918    ListTag::iterator it;
919    guint16 gr, el;
920    std::string vr;
921    for(it=listEntries.begin();it!=listEntries.end();++it) {
922       gr = (*it)->GetGroup();
923       el = (*it)->GetElement();
924       vr = (*it)->GetVR();      
925       if (gr !=0xfffe) {
926          if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {    
927             offset +=  4; // explicit VR AND OB, OW, SQ : 4 more bytes
928          }         
929          offset += 2 + 2 + 4 + (*it)->GetLength(); 
930       } else {
931          offset +=  4; // delimiters don't have a value.     
932       }            
933    }   
934    bool res=SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
935    return;
936 }
937
938 //-----------------------------------------------------------------------------