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