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)
43 if( GetListEntry().begin()==GetListEntry().end() )
45 dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry list empty");
49 dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : Parse directory and create the DicomDir");
58 * \ingroup gdcmDicomDir
59 * \brief Canonical destructor
61 gdcmDicomDir::~gdcmDicomDir()
66 for(ListPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
72 //-----------------------------------------------------------------------------
75 * \ingroup gdcmDicomDir
76 * \brief Canonical Printer
78 void gdcmDicomDir::Print(std::ostream &os)
82 metaElems->SetPrintLevel(printLevel);
86 for(ListPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
88 (*cc)->SetPrintLevel(printLevel);
93 //-----------------------------------------------------------------------------
96 * \ingroup gdcmDicomDir
97 * \brief This predicate, based on hopefully reasonable heuristics,
98 * decides whether or not the current gdcmParser was properly parsed
99 * and contains the mandatory information for being considered as
100 * a well formed and usable DicomDir.
101 * @return true when gdcmParser is the one of a reasonable DicomDir,
104 bool gdcmDicomDir::IsReadable(void)
106 if(!gdcmParser::IsReadable())
110 if(patients.size()<=0)
117 * \ingroup gdcmDicomDir
118 * \brief fills whole the structure
120 void gdcmDicomDir::ParseDirectory(void)
122 NewDicomDir(GetPath());
127 * \ingroup gdcmDicomDir
128 * \brief writes on disc a DICOMDIR
129 * \ warning does NOT add the missing elements in the header :
130 * it's up to the user doing it !
131 * @param fileName file to be written to
132 * @return false only when fail to open
134 bool gdcmDicomDir::Write(std::string fileName)
138 fp1=fopen(fileName.c_str(),"wb");
141 printf("Failed to open(write) File [%s] \n",fileName.c_str());
146 filePreamble=(char*)calloc(128,1);
147 fwrite(filePreamble,128,1,fp1);
148 fwrite("DICM",4,1,fp1);
151 WriteEntries(fp1,DICOMDIR);
158 //-----------------------------------------------------------------------------
161 * \ingroup gdcmDicomDir
162 * \brief create a gdcmDicomDir from a root Directory
163 * @param path entry point of the stree-like structure
165 void gdcmDicomDir::NewDicomDir(std::string path)
169 gdcmDirList fileList(path,1);
170 unsigned int count=0;
177 for(gdcmDirList::iterator it=fileList.begin();
178 it!=fileList.end(); ++it)
180 progress=(float)(count+1)/(float)fileList.size();
181 CallProgressMethod();
185 header=new gdcmHeader(it->c_str());
186 if(header->IsReadable())
187 list.push_back(header);
194 std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan);
196 std::string tmp=fileList.GetDirName();
197 SetElements(tmp,list);
203 * \ingroup gdcmDicomDir
204 * \brief Get the DicomDir path
207 std::string gdcmDicomDir::GetPath(void)
209 std::string path=GetFileName();
211 int pos1=path.rfind("/");
212 int pos2=path.rfind("\\");
221 void gdcmDicomDir::CallStartMethod(void)
226 startMethod(startArg);
229 void gdcmDicomDir::CallProgressMethod(void)
232 progressMethod(progressArg);
235 void gdcmDicomDir::CallEndMethod(void)
242 //-----------------------------------------------------------------------------
245 * \ingroup gdcmDicomDir
246 * \brief create a 'gdcmDicomDir' from a DICOMDIR gdcmHeader
248 void gdcmDicomDir::CreateDicomDir()
250 // The list is parsed. When a tag is found :
251 // 1 - we save the beginning iterator
252 // 2 - we continue to parse
253 // 3 - we find an other tag
254 // + we create the object for the precedent tag
257 gdcmDicomDirType type=gdcmDicomDir::GDCM_META;
258 ListTag::iterator begin;
259 ListTag::iterator end;
261 begin=listEntries.begin();
263 for(ListTag::iterator i=end;i !=listEntries.end();++i)
265 std::string v=(*i)->GetValue();
269 AddObjectToEnd(type,begin,end);
271 type=gdcmDicomDir::GDCM_PATIENT;
278 AddObjectToEnd(type,begin,end);
280 type=gdcmDicomDir::GDCM_STUDY;
287 AddObjectToEnd(type,begin,end);
289 type=gdcmDicomDir::GDCM_SERIE;
296 AddObjectToEnd(type,begin,end);
298 type=gdcmDicomDir::GDCM_IMAGE;
303 end=GetListEntry().end();
305 AddObjectToEnd(type,begin,end);
308 * \ingroup gdcmDicomDir
314 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
321 case gdcmDicomDir::GDCM_META:
322 AddMetaToEnd(begin,end);
324 case gdcmDicomDir::GDCM_PATIENT:
325 AddPatientToEnd(begin,end);
327 case gdcmDicomDir::GDCM_STUDY:
328 AddStudyToEnd(begin,end);
330 case gdcmDicomDir::GDCM_SERIE:
331 AddSerieToEnd(begin,end);
333 case gdcmDicomDir::GDCM_IMAGE:
334 AddImageToEnd(begin,end);
340 * \ingroup gdcmDicomDir
341 * \brief Well ... Not realy to end, there is only one occurence
345 void gdcmDicomDir::AddMetaToEnd(ListTag::iterator begin,ListTag::iterator end)
349 metaElems = new gdcmMeta(begin,end);
353 * \ingroup gdcmDicomDir
358 void gdcmDicomDir::AddPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
360 patients.push_back(new gdcmPatient(begin,end));
364 * \ingroup gdcmDicomDir
369 void gdcmDicomDir::AddStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
371 if(patients.size()>0)
373 ListPatient::iterator itp=patients.end();
375 (*itp)->AddStudy(new gdcmStudy(begin,end));
379 * \ingroup gdcmDicomDir
384 void gdcmDicomDir::AddSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
386 if(patients.size()>0)
388 ListPatient::iterator itp=patients.end();
391 if((*itp)->GetStudies().size()>0)
393 ListStudy::iterator itst=(*itp)->GetStudies().end();
395 (*itst)->AddSerie(new gdcmSerie(begin,end));
401 * \ingroup gdcmDicomDir
406 void gdcmDicomDir::AddImageToEnd(ListTag::iterator begin,ListTag::iterator end)
408 if(patients.size()>0)
410 ListPatient::iterator itp=patients.end();
413 if((*itp)->GetStudies().size()>0)
415 ListStudy::iterator itst=(*itp)->GetStudies().end();
418 if((*itst)->GetSeries().size()>0)
420 ListSerie::iterator its=(*itst)->GetSeries().end();
422 (*its)->AddImage(new gdcmImage(begin,end));
429 * \ingroup gdcmDicomDir
434 void gdcmDicomDir::SetElements(std::string &path,ListHeader &list)
436 std::string patPrevName="", patPrevID="";
437 std::string studPrevInstanceUID="", studPrevID="";
438 std::string serPrevInstanceUID="", serPrevID="";
440 std::string patCurName, patCurID;
441 std::string studCurInstanceUID, studCurID;
442 std::string serCurInstanceUID, serCurID;
444 SetElement(path,GDCM_NONE,NULL);
446 ListTag::iterator debPat=listEntries.begin();
447 for(ListHeader::iterator it=list.begin();it!=list.end();++it)
449 // get the current file characteristics
450 patCurName=(*it)->GetEntryByNumber(0x0010,0x0010);
451 patCurID=(*it)->GetEntryByNumber(0x0010,0x0011);
452 studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);
453 studCurID=(*it)->GetEntryByNumber(0x0020,0x0010);
454 serCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000e);
455 serCurID=(*it)->GetEntryByNumber(0x0020,0x0011);
457 if(patCurName!=patPrevName || patCurID!=patPrevID)
458 SetElement(path,GDCM_PATIENT,*it);
460 // if new Study Deal with 'STUDY' Elements
461 if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID)
462 SetElement(path,GDCM_STUDY,*it);
464 // if new Serie Deal with 'SERIE' Elements
465 if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID)
466 SetElement(path,GDCM_SERIE,*it);
468 // Always Deal with 'IMAGE' Elements
469 SetElement(path,GDCM_IMAGE,*it);
471 patPrevName=patCurName;
473 studPrevInstanceUID=studCurInstanceUID;
474 studPrevID=studCurID;
475 serPrevInstanceUID=serCurInstanceUID;
481 * \ingroup gdcmDicomDir
487 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
489 std::list<gdcmElement> elemList;
490 std::list<gdcmElement>::iterator it;
491 guint16 tmpGr, tmpEl;
492 gdcmDictEntry *dictEntry;
493 gdcmHeaderEntry *entry;
499 elemList=gdcmGlobal::GetDicomDirElements()->GetPatientElements();
502 elemList=gdcmGlobal::GetDicomDirElements()->GetStudyElements();
505 elemList=gdcmGlobal::GetDicomDirElements()->GetSerieElements();
508 elemList=gdcmGlobal::GetDicomDirElements()->GetImageElements();
511 elemList=gdcmGlobal::GetDicomDirElements()->GetMetaElements();
517 for(it=elemList.begin();it!=elemList.end();++it)
522 dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
523 entry=new gdcmHeaderEntry(dictEntry);
524 entry->SetOffset(0); // just to avoid missprinting
527 val=header->GetEntryByNumber(tmpGr,tmpEl);
531 if(val==GDCM_UNFOUND)
533 if((tmpGr==0x0004) &&(tmpEl==0x1130) )
535 // TODO force the *end* File Name(remove path)
538 else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
540 if(header->GetFileName().substr(0,path.length())!=path)
542 dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
543 val=header->GetFileName();
546 val=&(header->GetFileName()[path.length()]);
553 entry->SetValue(val);
557 if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") )
561 else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") )
565 else if(dictEntry->GetVR()=="SQ")
567 entry->SetLength(0xffffffff);
571 entry->SetLength(entry->GetValue().length());
575 listEntries.push_back(entry);
579 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
581 return(*header1<*header2);
584 //-----------------------------------------------------------------------------