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