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