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