2 //-----------------------------------------------------------------------------
3 #include "gdcmDicomDir.h"
7 #include "gdcmDirList.h"
13 #include <sys/types.h>
16 //-----------------------------------------------------------------------------
17 // For full DICOMDIR description, see:
18 // PS 3.3-2003, pages 731-750
19 //-----------------------------------------------------------------------------
20 // Constructor / Destructor
22 * \ingroup gdcmDicomDir
25 * @param exception_on_error
27 gdcmDicomDir::gdcmDicomDir(const char *FileName, bool parseDir,
28 bool exception_on_error):
29 gdcmParser(FileName,exception_on_error,true)
34 startMethodArgDelete=NULL;
35 progressMethodArgDelete=NULL;
36 endMethodArgDelete=NULL;
46 if( GetListEntry().begin()==GetListEntry().end() )
48 dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry list empty");
52 dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : Parse directory and create the DicomDir");
61 * \ingroup gdcmDicomDir
62 * \brief Canonical destructor
64 gdcmDicomDir::~gdcmDicomDir()
67 SetProgressMethod(NULL);
73 for(ListPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
79 //-----------------------------------------------------------------------------
82 * \ingroup gdcmDicomDir
83 * \brief Canonical Printer
85 void gdcmDicomDir::Print(std::ostream &os)
89 metaElems->SetPrintLevel(printLevel);
93 for(ListPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
95 (*cc)->SetPrintLevel(printLevel);
100 //-----------------------------------------------------------------------------
103 * \ingroup gdcmDicomDir
104 * \brief This predicate, based on hopefully reasonable heuristics,
105 * decides whether or not the current gdcmParser was properly parsed
106 * and contains the mandatory information for being considered as
107 * a well formed and usable DicomDir.
108 * @return true when gdcmParser is the one of a reasonable DicomDir,
111 bool gdcmDicomDir::IsReadable(void)
113 if(!gdcmParser::IsReadable())
117 if(patients.size()<=0)
124 * \ingroup gdcmDicomDir
125 * \brief fills whole the structure
127 void gdcmDicomDir::ParseDirectory(void)
129 NewDicomDir(GetPath());
134 * \ingroup gdcmDicomDir
135 * \brief Set the start method to call when the parsing of the directory starts
136 * @param method Method to call
137 * @param arg Argument to pass to the method
138 * \warning In python : the arg parameter isn't considered
140 void gdcmDicomDir::SetStartMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
142 if((startArg)&&(startMethodArgDelete))
143 startMethodArgDelete(startArg);
147 startMethodArgDelete=argDelete;
151 * \ingroup gdcmDicomDir
152 * \brief Set the method to delete the argument
153 * The argument is destroyed when the method is changed or when the class
155 * @param method Method to call to delete the argument
157 void gdcmDicomDir::SetStartMethodArgDelete(gdcmMethod *method)
159 startMethodArgDelete=method;
163 * \ingroup gdcmDicomDir
164 * \brief Set the progress method to call when the parsing of the directory progress
165 * @param method Method to call
166 * @param arg Argument to pass to the method
167 * \warning In python : the arg parameter isn't considered
169 void gdcmDicomDir::SetProgressMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
171 if((progressArg)&&(progressMethodArgDelete))
172 progressMethodArgDelete(progressArg);
174 progressMethod=method;
176 progressMethodArgDelete=argDelete;
180 * \ingroup gdcmDicomDir
181 * \brief Set the method to delete the argument
182 * The argument is destroyed when the method is changed or when the class
184 * @param method Method to call to delete the argument
186 void gdcmDicomDir::SetProgressMethodArgDelete(gdcmMethod *method)
188 progressMethodArgDelete=method;
192 * \ingroup gdcmDicomDir
193 * \brief Set the end method to call when the parsing of the directory ends
194 * @param method Method to call
195 * @param arg Argument to pass to the method
196 * \warning In python : the arg parameter isn't considered
198 void gdcmDicomDir::SetEndMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
200 if((endArg)&&(endMethodArgDelete))
201 endMethodArgDelete(endArg);
205 endMethodArgDelete=argDelete;
209 * \ingroup gdcmDicomDir
210 * \brief Set the method to delete the argument
211 * The argument is destroyed when the method is changed or when the class
213 * @param method Method to call to delete the argument
215 void gdcmDicomDir::SetEndMethodArgDelete(gdcmMethod *method)
217 endMethodArgDelete=method;
221 * \ingroup gdcmDicomDir
222 * \brief writes on disc a DICOMDIR
223 * \ warning does NOT add the missing elements in the header :
224 * it's up to the user doing it !
225 * @param fileName file to be written to
226 * @return false only when fail to open
228 bool gdcmDicomDir::Write(std::string fileName)
232 fp1=fopen(fileName.c_str(),"wb");
235 printf("Failed to open(write) File [%s] \n",fileName.c_str());
240 filePreamble=(char*)calloc(128,1);
241 fwrite(filePreamble,128,1,fp1);
242 fwrite("DICM",4,1,fp1);
245 WriteEntries(fp1,DICOMDIR);
252 //-----------------------------------------------------------------------------
255 * \ingroup gdcmDicomDir
256 * \brief create a gdcmDicomDir from a root Directory
257 * @param path entry point of the stree-like structure
259 void gdcmDicomDir::NewDicomDir(std::string path)
263 gdcmDirList fileList(path,1);
264 unsigned int count=0;
271 for(gdcmDirList::iterator it=fileList.begin();
272 it!=fileList.end(); ++it)
274 progress=(float)(count+1)/(float)fileList.size();
275 CallProgressMethod();
279 header=new gdcmHeader(it->c_str());
280 if(header->IsReadable())
281 list.push_back(header);
288 std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan);
290 std::string tmp=fileList.GetDirName();
291 SetElements(tmp,list);
297 * \ingroup gdcmDicomDir
298 * \brief Get the DicomDir path
301 std::string gdcmDicomDir::GetPath(void)
303 std::string path=GetFileName();
305 int pos1=path.rfind("/");
306 int pos2=path.rfind("\\");
315 void gdcmDicomDir::CallStartMethod(void)
320 startMethod(startArg);
323 void gdcmDicomDir::CallProgressMethod(void)
326 progressMethod(progressArg);
329 void gdcmDicomDir::CallEndMethod(void)
336 //-----------------------------------------------------------------------------
339 * \ingroup gdcmDicomDir
340 * \brief create a 'gdcmDicomDir' from a DICOMDIR gdcmHeader
342 void gdcmDicomDir::CreateDicomDir()
344 // The list is parsed. When a tag is found :
345 // 1 - we save the beginning iterator
346 // 2 - we continue to parse
347 // 3 - we find an other tag
348 // + we create the object for the precedent tag
351 gdcmDicomDirType type=gdcmDicomDir::GDCM_META;
352 ListTag::iterator begin;
353 ListTag::iterator end;
355 begin=listEntries.begin();
357 for(ListTag::iterator i=end;i !=listEntries.end();++i)
359 std::string v=(*i)->GetValue();
363 AddObjectToEnd(type,begin,end);
365 type=gdcmDicomDir::GDCM_PATIENT;
372 AddObjectToEnd(type,begin,end);
374 type=gdcmDicomDir::GDCM_STUDY;
381 AddObjectToEnd(type,begin,end);
383 type=gdcmDicomDir::GDCM_SERIE;
390 AddObjectToEnd(type,begin,end);
392 type=gdcmDicomDir::GDCM_IMAGE;
397 end=GetListEntry().end();
399 AddObjectToEnd(type,begin,end);
402 * \ingroup gdcmDicomDir
408 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
415 case gdcmDicomDir::GDCM_META:
416 AddMetaToEnd(begin,end);
418 case gdcmDicomDir::GDCM_PATIENT:
419 AddPatientToEnd(begin,end);
421 case gdcmDicomDir::GDCM_STUDY:
422 AddStudyToEnd(begin,end);
424 case gdcmDicomDir::GDCM_SERIE:
425 AddSerieToEnd(begin,end);
427 case gdcmDicomDir::GDCM_IMAGE:
428 AddImageToEnd(begin,end);
434 * \ingroup gdcmDicomDir
435 * \brief Well ... Not realy to end, there is only one occurence
439 void gdcmDicomDir::AddMetaToEnd(ListTag::iterator begin,ListTag::iterator end)
443 metaElems = new gdcmMeta(begin,end);
447 * \ingroup gdcmDicomDir
452 void gdcmDicomDir::AddPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
454 patients.push_back(new gdcmPatient(begin,end));
458 * \ingroup gdcmDicomDir
463 void gdcmDicomDir::AddStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
465 if(patients.size()>0)
467 ListPatient::iterator itp=patients.end();
469 (*itp)->AddStudy(new gdcmStudy(begin,end));
473 * \ingroup gdcmDicomDir
478 void gdcmDicomDir::AddSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
480 if(patients.size()>0)
482 ListPatient::iterator itp=patients.end();
485 if((*itp)->GetStudies().size()>0)
487 ListStudy::iterator itst=(*itp)->GetStudies().end();
489 (*itst)->AddSerie(new gdcmSerie(begin,end));
495 * \ingroup gdcmDicomDir
500 void gdcmDicomDir::AddImageToEnd(ListTag::iterator begin,ListTag::iterator end)
502 if(patients.size()>0)
504 ListPatient::iterator itp=patients.end();
507 if((*itp)->GetStudies().size()>0)
509 ListStudy::iterator itst=(*itp)->GetStudies().end();
512 if((*itst)->GetSeries().size()>0)
514 ListSerie::iterator its=(*itst)->GetSeries().end();
516 (*its)->AddImage(new gdcmImage(begin,end));
523 * \ingroup gdcmDicomDir
528 void gdcmDicomDir::SetElements(std::string &path,ListHeader &list)
530 std::string patPrevName="", patPrevID="";
531 std::string studPrevInstanceUID="", studPrevID="";
532 std::string serPrevInstanceUID="", serPrevID="";
534 std::string patCurName, patCurID;
535 std::string studCurInstanceUID, studCurID;
536 std::string serCurInstanceUID, serCurID;
538 SetElement(path,GDCM_NONE,NULL);
540 ListTag::iterator debPat=listEntries.begin();
541 for(ListHeader::iterator it=list.begin();it!=list.end();++it)
543 // get the current file characteristics
544 patCurName=(*it)->GetEntryByNumber(0x0010,0x0010);
545 patCurID=(*it)->GetEntryByNumber(0x0010,0x0011);
546 studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);
547 studCurID=(*it)->GetEntryByNumber(0x0020,0x0010);
548 serCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000e);
549 serCurID=(*it)->GetEntryByNumber(0x0020,0x0011);
551 if(patCurName!=patPrevName || patCurID!=patPrevID)
552 SetElement(path,GDCM_PATIENT,*it);
554 // if new Study Deal with 'STUDY' Elements
555 if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID)
556 SetElement(path,GDCM_STUDY,*it);
558 // if new Serie Deal with 'SERIE' Elements
559 if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID)
560 SetElement(path,GDCM_SERIE,*it);
562 // Always Deal with 'IMAGE' Elements
563 SetElement(path,GDCM_IMAGE,*it);
565 patPrevName=patCurName;
567 studPrevInstanceUID=studCurInstanceUID;
568 studPrevID=studCurID;
569 serPrevInstanceUID=serCurInstanceUID;
575 * \ingroup gdcmDicomDir
581 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
583 std::list<gdcmElement> elemList;
584 std::list<gdcmElement>::iterator it;
585 guint16 tmpGr, tmpEl;
586 gdcmDictEntry *dictEntry;
587 gdcmHeaderEntry *entry;
593 elemList=gdcmGlobal::GetDicomDirElements()->GetPatientElements();
596 elemList=gdcmGlobal::GetDicomDirElements()->GetStudyElements();
599 elemList=gdcmGlobal::GetDicomDirElements()->GetSerieElements();
602 elemList=gdcmGlobal::GetDicomDirElements()->GetImageElements();
605 elemList=gdcmGlobal::GetDicomDirElements()->GetMetaElements();
611 for(it=elemList.begin();it!=elemList.end();++it)
616 dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
617 entry=new gdcmHeaderEntry(dictEntry);
618 entry->SetOffset(0); // just to avoid missprinting
621 val=header->GetEntryByNumber(tmpGr,tmpEl);
625 if(val==GDCM_UNFOUND)
627 if((tmpGr==0x0004) &&(tmpEl==0x1130) )
629 // TODO force the *end* File Name(remove path)
632 else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
634 if(header->GetFileName().substr(0,path.length())!=path)
636 dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
637 val=header->GetFileName();
640 val=&(header->GetFileName()[path.length()]);
647 entry->SetValue(val);
651 if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") )
655 else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") )
659 else if(dictEntry->GetVR()=="SQ")
661 entry->SetLength(0xffffffff);
665 entry->SetLength(entry->GetValue().length());
669 listEntries.push_back(entry);
673 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
675 return(*header1<*header2);
678 //-----------------------------------------------------------------------------