00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "gdcmDicomDir.h"
00024 #include "gdcmDicomDirStudy.h"
00025 #include "gdcmDicomDirSerie.h"
00026 #include "gdcmDicomDirImage.h"
00027 #include "gdcmDicomDirPatient.h"
00028 #include "gdcmDicomDirMeta.h"
00029 #include "gdcmDicomDirElement.h"
00030 #include "gdcmDirList.h"
00031 #include "gdcmUtil.h"
00032 #include "gdcmDebug.h"
00033 #include "gdcmGlobal.h"
00034 #include "gdcmFile.h"
00035 #include "gdcmSeqEntry.h"
00036 #include "gdcmSQItem.h"
00037 #include "gdcmValEntry.h"
00038
00039 #include <fstream>
00040 #include <string>
00041 #include <algorithm>
00042 #include <sys/types.h>
00043
00044 #ifdef _MSC_VER
00045 # define getcwd _getcwd
00046 #endif
00047
00048 #if defined(_MSC_VER) || defined(__BORLANDC__)
00049 # include <direct.h>
00050 #else
00051 # include <unistd.h>
00052 #endif
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 namespace gdcm
00106 {
00107
00108
00112 DicomDir::DicomDir()
00113 :Document( )
00114 {
00115 Initialize();
00116 NewMeta();
00117 }
00118
00131 DicomDir::DicomDir(std::string const &fileName, bool parseDir ):
00132 Document( fileName )
00133 {
00134
00135
00136
00137
00138
00139 Initialize();
00140
00141
00142
00143 if ( GetFirstEntry() == 0 )
00144 {
00145 if (!parseDir)
00146 gdcmWarningMacro( "Entry HT empty for file: "<<fileName);
00147
00148
00149
00150 if ( fileName == "." )
00151 {
00152
00153
00154 char dummy[1000];
00155 getcwd(dummy, (size_t)1000);
00156 SetFileName( dummy );
00157 }
00158
00159 if ( parseDir )
00160 {
00161 NewMeta();
00162
00163 gdcmWarningMacro( "Parse directory and create the DicomDir");
00164 ParseDirectory();
00165 }
00166 else
00167 {
00169
00170 }
00171 }
00172
00173
00174 else
00175 {
00176
00177 DocEntry *e = GetDocEntry(0x0004, 0x1220);
00178 if ( !e )
00179 {
00180 gdcmWarningMacro( "NO 'Directory record sequence' (0x0004,0x1220)"
00181 << " in file " << fileName);
00184 }
00185 else
00186 CreateDicomDir();
00187 }
00188 }
00189
00193 DicomDir::~DicomDir()
00194 {
00195 SetStartMethod(NULL);
00196 SetProgressMethod(NULL);
00197 SetEndMethod(NULL);
00198
00199 ClearPatient();
00200 if ( MetaElems )
00201 {
00202 delete MetaElems;
00203 }
00204 }
00205
00206
00207
00216 bool DicomDir::IsReadable()
00217 {
00218 if( Filetype == Unknown)
00219 {
00220 gdcmWarningMacro( "Wrong filetype");
00221 return false;
00222 }
00223 if( !MetaElems )
00224 {
00225 gdcmWarningMacro( "Meta Elements missing in DicomDir");
00226 return false;
00227 }
00228 if( Patients.size() <= 0 )
00229 {
00230 gdcmWarningMacro( "NO Patient in DicomDir");
00231 return false;
00232 }
00233
00234 return true;
00235 }
00236
00240 DicomDirMeta *DicomDir::NewMeta()
00241 {
00242 if( MetaElems )
00243 delete MetaElems;
00244
00245 DocEntry *entry = GetFirstEntry();
00246 if( entry )
00247 {
00248 MetaElems = new DicomDirMeta(true);
00249
00250 entry = GetFirstEntry();
00251 while( entry )
00252 {
00253 if( dynamic_cast<SeqEntry *>(entry) )
00254 break;
00255
00256 RemoveEntryNoDestroy(entry);
00257 MetaElems->AddEntry(entry);
00258
00259 entry = GetFirstEntry();
00260 }
00261 }
00262 else
00263 {
00264 MetaElems = new DicomDirMeta(false);
00265 }
00266 MetaElems->SetSQItemNumber(0);
00267 return MetaElems;
00268 }
00269
00274 DicomDirPatient *DicomDir::NewPatient()
00275 {
00276 DicomDirPatient *p = new DicomDirPatient();
00277 AddPatientToEnd( p );
00278 return p;
00279 }
00280
00284 void DicomDir::ClearPatient()
00285 {
00286 for(ListDicomDirPatient::iterator cc = Patients.begin();
00287 cc!= Patients.end();
00288 ++cc)
00289 {
00290 delete *cc;
00291 }
00292 Patients.clear();
00293 }
00294
00299 DicomDirPatient *DicomDir::GetFirstPatient()
00300 {
00301 ItPatient = Patients.begin();
00302 if ( ItPatient != Patients.end() )
00303 return *ItPatient;
00304 return NULL;
00305 }
00306
00312 DicomDirPatient *DicomDir::GetNextPatient()
00313 {
00314 gdcmAssertMacro (ItPatient != Patients.end());
00315
00316 ++ItPatient;
00317 if ( ItPatient != Patients.end() )
00318 return *ItPatient;
00319 return NULL;
00320 }
00321
00325 void DicomDir::ParseDirectory()
00326 {
00327 CreateDicomDirChainedList( GetFileName() );
00328 CreateDicomDir();
00329 }
00330
00339 void DicomDir::SetStartMethod( DicomDir::Method *method, void *arg,
00340 DicomDir::Method *argDelete )
00341 {
00342 if( StartArg && StartMethodArgDelete )
00343 {
00344 StartMethodArgDelete( StartArg );
00345 }
00346
00347 StartMethod = method;
00348 StartArg = arg;
00349 StartMethodArgDelete = argDelete;
00350 }
00351
00360 void DicomDir::SetProgressMethod( DicomDir::Method *method, void *arg,
00361 DicomDir::Method *argDelete )
00362 {
00363 if( ProgressArg && ProgressMethodArgDelete )
00364 {
00365 ProgressMethodArgDelete( ProgressArg );
00366 }
00367
00368 ProgressMethod = method;
00369 ProgressArg = arg;
00370 ProgressMethodArgDelete = argDelete;
00371 }
00372
00380 void DicomDir::SetEndMethod( DicomDir::Method *method, void *arg,
00381 DicomDir::Method *argDelete )
00382 {
00383 if( EndArg && EndMethodArgDelete )
00384 {
00385 EndMethodArgDelete( EndArg );
00386 }
00387
00388 EndMethod = method;
00389 EndArg = arg;
00390 EndMethodArgDelete = argDelete;
00391 }
00392
00399 void DicomDir::SetStartMethodArgDelete( DicomDir::Method *method )
00400 {
00401 StartMethodArgDelete = method;
00402 }
00403
00410 void DicomDir::SetProgressMethodArgDelete( DicomDir::Method *method )
00411 {
00412 ProgressMethodArgDelete = method;
00413 }
00414
00421 void DicomDir::SetEndMethodArgDelete( DicomDir::Method *method )
00422 {
00423 EndMethodArgDelete = method;
00424 }
00425
00437 bool DicomDir::WriteDicomDir(std::string const &fileName)
00438 {
00439 int i;
00440 uint16_t sq[4] = { 0x0004, 0x1220, 0xffff, 0xffff };
00441 uint16_t sqt[4]= { 0xfffe, 0xe0dd, 0xffff, 0xffff };
00442
00443 std::ofstream *fp = new std::ofstream(fileName.c_str(),
00444 std::ios::out | std::ios::binary);
00445 if( !fp )
00446 {
00447 gdcmWarningMacro("Failed to open(write) File: " << fileName.c_str());
00448 return false;
00449 }
00450
00451 char filePreamble[128];
00452 memset(filePreamble, 0, 128);
00453 fp->write(filePreamble, 128);
00454 binary_write( *fp, "DICM");
00455
00456 DicomDirMeta *ptrMeta = GetMeta();
00457 ptrMeta->WriteContent(fp, ExplicitVR);
00458
00459
00460 for(i=0;i<4;++i)
00461 {
00462 binary_write(*fp, sq[i]);
00463 }
00464
00465 for(ListDicomDirPatient::iterator cc = Patients.begin();
00466 cc != Patients.end();
00467 ++cc )
00468 {
00469 (*cc)->WriteContent( fp, ExplicitVR );
00470 }
00471
00472
00473 for(i=0;i<4;++i)
00474 {
00475 binary_write(*fp, sqt[i]);
00476 }
00477
00478 fp->close();
00479 delete fp;
00480
00481 return true;
00482 }
00483
00484
00485
00490 void DicomDir::CreateDicomDirChainedList(std::string const &path)
00491 {
00492 CallStartMethod();
00493 DirList dirList(path,1);
00494 unsigned int count = 0;
00495 VectDocument list;
00496 File *header;
00497
00498 DirListType fileList = dirList.GetFilenames();
00499
00500 for( DirListType::iterator it = fileList.begin();
00501 it != fileList.end();
00502 ++it )
00503 {
00504 Progress = (float)(count+1)/(float)fileList.size();
00505 CallProgressMethod();
00506 if( Abort )
00507 {
00508 break;
00509 }
00510
00511 header = new File( it->c_str() );
00512 if( !header )
00513 {
00514 gdcmWarningMacro( "Failure in new gdcm::File " << it->c_str() );
00515 continue;
00516 }
00517
00518 if( header->IsReadable() )
00519 {
00520
00521 list.push_back(header);
00522 gdcmWarningMacro( "Readable " << it->c_str() );
00523 }
00524 else
00525 {
00526 delete header;
00527 }
00528 count++;
00529 }
00530
00531 std::sort(list.begin(), list.end(), DicomDir::HeaderLessThan );
00532
00533 std::string tmp = dirList.GetDirName();
00534
00535 SetElements(tmp, list);
00536 CallEndMethod();
00537
00538 for(VectDocument::iterator itDoc=list.begin();
00539 itDoc!=list.end();
00540 ++itDoc)
00541 {
00542 delete dynamic_cast<File *>(*itDoc);
00543 }
00544 }
00545
00549 void DicomDir::CallStartMethod()
00550 {
00551 Progress = 0.0f;
00552 Abort = false;
00553 if( StartMethod )
00554 {
00555 StartMethod( StartArg );
00556 }
00557 }
00558
00562 void DicomDir::CallProgressMethod()
00563 {
00564 if( ProgressMethod )
00565 {
00566 ProgressMethod( ProgressArg );
00567 }
00568 }
00569
00573 void DicomDir::CallEndMethod()
00574 {
00575 Progress = 1.0f;
00576 if( EndMethod )
00577 {
00578 EndMethod( EndArg );
00579 }
00580 }
00581
00582
00583
00587 void DicomDir::Initialize()
00588 {
00589 StartMethod = NULL;
00590 ProgressMethod = NULL;
00591 EndMethod = NULL;
00592 StartMethodArgDelete = NULL;
00593 ProgressMethodArgDelete = NULL;
00594 EndMethodArgDelete = NULL;
00595 StartArg = NULL;
00596 ProgressArg = NULL;
00597 EndArg = NULL;
00598
00599 Progress = 0.0;
00600 Abort = false;
00601
00602 MetaElems = NULL;
00603 }
00604
00608 void DicomDir::CreateDicomDir()
00609 {
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619 DocEntry *e = GetDocEntry(0x0004, 0x1220);
00620 if ( !e )
00621 {
00622 gdcmWarningMacro( "No Directory Record Sequence (0004,1220) found");
00624 return;
00625 }
00626
00627 SeqEntry *s = dynamic_cast<SeqEntry *>(e);
00628 if ( !s )
00629 {
00630 gdcmWarningMacro( "Element (0004,1220) is not a Sequence ?!?");
00631 return;
00632 }
00633
00634 NewMeta();
00635
00636 DocEntry *d;
00637 std::string v;
00638 SQItem *si;
00639
00640 SQItem *tmpSI=s->GetFirstSQItem();
00641 while(tmpSI)
00642 {
00643 d = tmpSI->GetDocEntry(0x0004, 0x1430);
00644 if ( ValEntry* valEntry = dynamic_cast<ValEntry *>(d) )
00645 {
00646 v = valEntry->GetValue();
00647 }
00648 else
00649 {
00650 gdcmWarningMacro( "Not a ValEntry.");
00651 continue;
00652 }
00653
00654 if( v == "PATIENT " )
00655 {
00656 si = new DicomDirPatient(true);
00657 if( !AddPatientToEnd( static_cast<DicomDirPatient *>(si)) )
00658 {
00659 delete si;
00660 si = NULL;
00661 gdcmErrorMacro( "Add PatientToEnd failed");
00662 }
00663 }
00664 else if( v == "STUDY " )
00665 {
00666 si = new DicomDirStudy(true);
00667 if( !AddStudyToEnd( static_cast<DicomDirStudy *>(si)) )
00668 {
00669 delete si;
00670 si = NULL;
00671 gdcmErrorMacro( "Add AddStudyToEnd failed");
00672 }
00673 }
00674 else if( v == "SERIES" )
00675 {
00676 si = new DicomDirSerie(true);
00677 if( !AddSerieToEnd( static_cast<DicomDirSerie *>(si)) )
00678 {
00679 delete si;
00680 si = NULL;
00681 gdcmErrorMacro( "Add AddSerieToEnd failed");
00682 }
00683 }
00684 else if( v == "IMAGE " )
00685 {
00686 si = new DicomDirImage(true);
00687 if( !AddImageToEnd( static_cast<DicomDirImage *>(si)) )
00688 {
00689 delete si;
00690 si = NULL;
00691 gdcmErrorMacro( "Add AddImageToEnd failed");
00692 }
00693 }
00694 else
00695 {
00696
00697
00698 continue;
00699 }
00700 if( si )
00701 MoveSQItem(si,tmpSI);
00702
00703 tmpSI=s->GetNextSQItem();
00704 }
00705 ClearEntry();
00706 }
00707
00712 bool DicomDir::AddPatientToEnd(DicomDirPatient *dd)
00713 {
00714 Patients.push_back(dd);
00715 return true;
00716 }
00717
00722 bool DicomDir::AddStudyToEnd(DicomDirStudy *dd)
00723 {
00724 if( Patients.size() > 0 )
00725 {
00726 ListDicomDirPatient::iterator itp = Patients.end();
00727 itp--;
00728 (*itp)->AddStudy(dd);
00729 return true;
00730 }
00731 return false;
00732 }
00733
00738 bool DicomDir::AddSerieToEnd(DicomDirSerie *dd)
00739 {
00740 if( Patients.size() > 0 )
00741 {
00742 ListDicomDirPatient::iterator itp = Patients.end();
00743 itp--;
00744
00745 DicomDirStudy *study = (*itp)->GetLastStudy();
00746 if( study )
00747 {
00748 study->AddSerie(dd);
00749 return true;
00750 }
00751 }
00752 return false;
00753 }
00754
00759 bool DicomDir::AddImageToEnd(DicomDirImage *dd)
00760 {
00761 if( Patients.size() > 0 )
00762 {
00763 ListDicomDirPatient::iterator itp = Patients.end();
00764 itp--;
00765
00766 DicomDirStudy *study = (*itp)->GetLastStudy();
00767 if( study )
00768 {
00769 DicomDirSerie *serie = study->GetLastSerie();
00770 if( serie )
00771 {
00772 serie->AddImage(dd);
00773 return true;
00774 }
00775 }
00776 }
00777 return false;
00778 }
00779
00786 void DicomDir::SetElements(std::string const &path, VectDocument const &list)
00787 {
00788 ClearEntry();
00789 ClearPatient();
00790
00791 std::string patPrevName = "", patPrevID = "";
00792 std::string studPrevInstanceUID = "", studPrevID = "";
00793 std::string serPrevInstanceUID = "", serPrevID = "";
00794
00795 std::string patCurName, patCurID;
00796 std::string studCurInstanceUID, studCurID;
00797 std::string serCurInstanceUID, serCurID;
00798
00799 bool first = true;
00800 for( VectDocument::const_iterator it = list.begin();
00801 it != list.end();
00802 ++it )
00803 {
00804
00805 patCurName = (*it)->GetEntryValue(0x0010,0x0010);
00806 patCurID = (*it)->GetEntryValue(0x0010,0x0011);
00807 studCurInstanceUID = (*it)->GetEntryValue(0x0020,0x000d);
00808 studCurID = (*it)->GetEntryValue(0x0020,0x0010);
00809 serCurInstanceUID = (*it)->GetEntryValue(0x0020,0x000e);
00810 serCurID = (*it)->GetEntryValue(0x0020,0x0011);
00811
00812 if( patCurName != patPrevName || patCurID != patPrevID || first )
00813 {
00814 SetElement(path, GDCM_DICOMDIR_PATIENT, *it);
00815 first = true;
00816 }
00817
00818
00819 if( studCurInstanceUID != studPrevInstanceUID || studCurID != studPrevID
00820 || first )
00821 {
00822 SetElement(path, GDCM_DICOMDIR_STUDY, *it);
00823 first = true;
00824 }
00825
00826
00827 if( serCurInstanceUID != serPrevInstanceUID || serCurID != serPrevID
00828 || first )
00829 {
00830 SetElement(path, GDCM_DICOMDIR_SERIE, *it);
00831 first = true;
00832 }
00833
00834
00835 SetElement(path, GDCM_DICOMDIR_IMAGE, *it);
00836
00837 patPrevName = patCurName;
00838 patPrevID = patCurID;
00839 studPrevInstanceUID = studCurInstanceUID;
00840 studPrevID = studCurID;
00841 serPrevInstanceUID = serCurInstanceUID;
00842 serPrevID = serCurID;
00843 first = false;
00844 }
00845 }
00846
00855 void DicomDir::SetElement(std::string const &path, DicomDirType type,
00856 Document *header)
00857 {
00858 ListDicomDirElem elemList;
00859 ListDicomDirElem::const_iterator it;
00860 uint16_t tmpGr, tmpEl;
00861 DictEntry *dictEntry;
00862 ValEntry *entry;
00863 std::string val;
00864 SQItem *si;
00865
00866 switch( type )
00867 {
00868 case GDCM_DICOMDIR_IMAGE:
00869 elemList = Global::GetDicomDirElements()->GetDicomDirImageElements();
00870 si = new DicomDirImage(true);
00871 if( !AddImageToEnd(static_cast<DicomDirImage *>(si)) )
00872 {
00873 delete si;
00874 gdcmErrorMacro( "Add ImageToEnd failed");
00875 }
00876 break;
00877 case GDCM_DICOMDIR_SERIE:
00878 elemList = Global::GetDicomDirElements()->GetDicomDirSerieElements();
00879 si = new DicomDirSerie(true);
00880 if( !AddSerieToEnd(static_cast<DicomDirSerie *>(si)) )
00881 {
00882 delete si;
00883 gdcmErrorMacro( "Add SerieToEnd failed");
00884 }
00885 break;
00886 case GDCM_DICOMDIR_STUDY:
00887 elemList = Global::GetDicomDirElements()->GetDicomDirStudyElements();
00888 si = new DicomDirStudy(true);
00889 if( !AddStudyToEnd(static_cast<DicomDirStudy *>(si)) )
00890 {
00891 delete si;
00892 gdcmErrorMacro( "Add StudyToEnd failed");
00893 }
00894 break;
00895 case GDCM_DICOMDIR_PATIENT:
00896 elemList = Global::GetDicomDirElements()->GetDicomDirPatientElements();
00897 si = new DicomDirPatient(true);
00898 if( !AddPatientToEnd(static_cast<DicomDirPatient *>(si)) )
00899 {
00900 delete si;
00901 gdcmErrorMacro( "Add PatientToEnd failed");
00902 }
00903 break;
00904 case GDCM_DICOMDIR_META:
00905 elemList = Global::GetDicomDirElements()->GetDicomDirMetaElements();
00906 si = new DicomDirMeta(true);
00907 if( MetaElems )
00908 {
00909 delete MetaElems;
00910 gdcmErrorMacro( "MetaElements already exist, they will be destroyed");
00911 }
00912 MetaElems = static_cast<DicomDirMeta *>(si);
00913 break;
00914 default:
00915 return;
00916 }
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 for( it = elemList.begin(); it != elemList.end(); ++it)
00929 {
00930 tmpGr = it->Group;
00931 tmpEl = it->Elem;
00932 dictEntry = GetPubDict()->GetEntry(tmpGr, tmpEl);
00933
00934 entry = new ValEntry( dictEntry );
00935
00936 entry->SetOffset(0);
00937
00938 if( header )
00939 {
00940
00941
00942 val = header->GetEntryValue(tmpGr, tmpEl);
00943 }
00944 else
00945 {
00946 val = GDCM_UNFOUND;
00947 }
00948
00949 if( val == GDCM_UNFOUND)
00950 {
00951 if( tmpGr == 0x0004 && tmpEl == 0x1130 )
00952 {
00953
00954 val = Util::GetName( path );
00955 }
00956 else if( tmpGr == 0x0004 && tmpEl == 0x1500 )
00957 {
00958 if( header->GetFileName().substr(0, path.length()) != path )
00959 {
00960 gdcmWarningMacro( "The base path of file name is incorrect");
00961 val = header->GetFileName();
00962 }
00963 else
00964 {
00965 val = &(header->GetFileName().c_str()[path.length()]);
00966 }
00967 }
00968 else
00969 {
00970 val = it->Value;
00971 }
00972 }
00973 else
00974 {
00975 if ( header->GetEntryLength(tmpGr,tmpEl) == 0 )
00976 val = it->Value;
00977 }
00978
00979 entry->SetValue( val );
00980
00981 if ( type == GDCM_DICOMDIR_META )
00982 {
00983 gdcmWarningMacro("GDCM_DICOMDIR_META ?!? should never print that");
00984 }
00985 si->AddEntry(entry);
00986 }
00987 }
00988
00995 void DicomDir::MoveSQItem(DocEntrySet *dst,DocEntrySet *src)
00996 {
00997 DocEntry *entry;
00998
00999 entry = src->GetFirstEntry();
01000 while(entry)
01001 {
01002 src->RemoveEntryNoDestroy(entry);
01003 dst->AddEntry(entry);
01004
01005 entry = src->GetFirstEntry();
01006 }
01007 }
01008
01012 bool DicomDir::HeaderLessThan(Document *header1, Document *header2)
01013 {
01014 return *header1 < *header2;
01015 }
01016
01017
01018
01024 void DicomDir::Print(std::ostream &os, std::string const & )
01025 {
01026 if( MetaElems )
01027 {
01028 MetaElems->SetPrintLevel(PrintLevel);
01029 MetaElems->Print(os);
01030 }
01031 for(ListDicomDirPatient::iterator cc = Patients.begin();
01032 cc != Patients.end();
01033 ++cc)
01034 {
01035 (*cc)->SetPrintLevel(PrintLevel);
01036 (*cc)->Print(os);
01037 }
01038 }
01039
01040
01041 }