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