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 "gdcmDicomDirObject.h"
00025 #include "gdcmDicomDirStudy.h"
00026 #include "gdcmDicomDirSerie.h"
00027 #include "gdcmDicomDirVisit.h"
00028 #include "gdcmDicomDirImage.h"
00029 #include "gdcmDicomDirPatient.h"
00030 #include "gdcmDicomDirMeta.h"
00031 #include "gdcmDicomDirElement.h"
00032 #include "gdcmDirList.h"
00033 #include "gdcmUtil.h"
00034 #include "gdcmDebug.h"
00035 #include "gdcmGlobal.h"
00036 #include "gdcmFile.h"
00037 #include "gdcmSeqEntry.h"
00038 #include "gdcmSQItem.h"
00039 #include "gdcmDataEntry.h"
00040 #include "gdcmCommandManager.h"
00041
00042 #include <fstream>
00043 #include <string>
00044 #include <algorithm>
00045 #include <sys/types.h>
00046
00047 #ifdef _MSC_VER
00048 # define getcwd _getcwd
00049 #endif
00050
00051 #if defined(_MSC_VER) || defined(__BORLANDC__)
00052 # include <direct.h>
00053 #else
00054 # include <unistd.h>
00055 #endif
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
00106
00107
00108
00109
00110
00111
00112
00113 namespace gdcm
00114 {
00115
00116
00120 DicomDir::DicomDir()
00121 {
00122 Initialize();
00123 ParseDir = false;
00124 NewMeta();
00125 }
00126
00130 DicomDir::~DicomDir()
00131 {
00132 ClearPatient();
00133 if ( MetaElems )
00134 {
00135 MetaElems->Delete();
00136 }
00137 }
00138
00139
00140
00141
00148 bool DicomDir::Load( )
00149 {
00150 if (!ParseDir)
00151 {
00152 if ( ! this->Document::Load( ) )
00153 return false;
00154 }
00155 return DoTheLoadingJob( );
00156 }
00157
00163 bool DicomDir::DoTheLoadingJob( )
00164 {
00165 Progress = 0.0f;
00166 Abort = false;
00167
00168 if (!ParseDir)
00169 {
00170
00171
00172 Fp = 0;
00173 if (!Document::Load() )
00174 {
00175 return false;
00176 }
00177
00178 if ( GetFirstEntry() == 0 )
00179 {
00180 gdcmWarningMacro( "Entry HT empty for file: "<< GetFileName());
00181 return false;
00182 }
00183
00184 DocEntry *e = GetDocEntry(0x0004, 0x1220);
00185 if ( !e )
00186 {
00187 gdcmWarningMacro( "NO 'Directory record sequence' (0x0004,0x1220)"
00188 << " in file " << GetFileName());
00189 return false;
00190 }
00191 else
00192 CreateDicomDir();
00193 }
00194 else
00195 {
00196
00197
00198 if ( GetFileName() == "." )
00199 {
00200
00201
00202 char buf[2048];
00203 const char *cwd = getcwd(buf, 2048);
00204 if( cwd )
00205 {
00206 SetFileName( buf );
00207 }
00208 else
00209 {
00210 gdcmErrorMacro( "Path was too long to fit on 2048 bytes" );
00211 }
00212 }
00213 NewMeta();
00214 gdcmDebugMacro( "Parse directory and create the DicomDir : "
00215 << GetFileName() );
00216 ParseDirectory();
00217 }
00218 return true;
00219 }
00220
00229 bool DicomDir::IsReadable()
00230 {
00231 if ( Filetype == Unknown )
00232 {
00233 gdcmErrorMacro( "Wrong filetype for " << GetFileName());
00234 return false;
00235 }
00236 if ( !MetaElems )
00237 {
00238 gdcmWarningMacro( "Meta Elements missing in DicomDir");
00239 return false;
00240 }
00241 if ( Patients.size() <= 0 )
00242 {
00243 gdcmWarningMacro( "NO Patient in DicomDir");
00244 return false;
00245 }
00246
00247 return true;
00248 }
00249
00253 DicomDirMeta *DicomDir::NewMeta()
00254 {
00255 if ( MetaElems )
00256 MetaElems->Delete();
00257
00258 DocEntry *entry = GetFirstEntry();
00259 if ( entry )
00260 {
00261 MetaElems = DicomDirMeta::New(true);
00262
00263 entry = GetFirstEntry();
00264 while( entry )
00265 {
00266 if ( dynamic_cast<SeqEntry *>(entry) )
00267 break;
00268
00269 MetaElems->AddEntry(entry);
00270 RemoveEntry(entry);
00271
00272 entry = GetFirstEntry();
00273 }
00274 }
00275 else
00276 {
00277 MetaElems = DicomDirMeta::New(false);
00278 }
00279 MetaElems->SetSQItemNumber(0);
00280 return MetaElems;
00281 }
00282
00287 DicomDirPatient *DicomDir::NewPatient()
00288 {
00289 DicomDirPatient *dd = DicomDirPatient::New();
00290 AddPatientToEnd( dd );
00291 return dd;
00292 }
00293
00297 void DicomDir::ClearPatient()
00298 {
00299 for(ListDicomDirPatient::iterator cc = Patients.begin();
00300 cc!= Patients.end();
00301 ++cc)
00302 {
00303 (*cc)->Unregister();
00304 }
00305 Patients.clear();
00306 }
00307
00312 DicomDirPatient *DicomDir::GetFirstPatient()
00313 {
00314 ItPatient = Patients.begin();
00315 if ( ItPatient != Patients.end() )
00316 return *ItPatient;
00317 return NULL;
00318 }
00319
00325 DicomDirPatient *DicomDir::GetNextPatient()
00326 {
00327 gdcmAssertMacro (ItPatient != Patients.end());
00328
00329 ++ItPatient;
00330 if ( ItPatient != Patients.end() )
00331 return *ItPatient;
00332 return NULL;
00333 }
00334
00338 void DicomDir::ParseDirectory()
00339 {
00340 CreateDicomDirChainedList( GetFileName() );
00341 CreateDicomDir();
00342 }
00343
00352 bool DicomDir::Write(std::string const &fileName)
00353 {
00354 int i;
00355 uint16_t sq[6] = { 0x0004, 0x1220, 0x5153, 0x0000, 0xffff, 0xffff };
00356 uint16_t sqt[4]= { 0xfffe, 0xe0dd, 0x0000, 0x0000 };
00357
00358 std::ofstream *fp = new std::ofstream(fileName.c_str(),
00359 std::ios::out | std::ios::binary);
00360 if ( !fp )
00361 {
00362 gdcmWarningMacro("Failed to open(write) File: " << fileName.c_str());
00363 return false;
00364 }
00365
00366 char filePreamble[128];
00367 memset(filePreamble, 0, 128);
00368 fp->write(filePreamble, 128);
00369 binary_write( *fp, "DICM");
00370
00371 DicomDirMeta *ptrMeta = GetMeta();
00372 ptrMeta->WriteContent(fp, ExplicitVR);
00373
00374
00375 for(i=0;i<6;++i)
00376 {
00377 binary_write(*fp, sq[i]);
00378 }
00379
00380 for(ListDicomDirPatient::iterator cc = Patients.begin();
00381 cc != Patients.end();
00382 ++cc )
00383 {
00384 (*cc)->WriteContent( fp, ExplicitVR );
00385 }
00386
00387
00388 for(i=0;i<4;++i)
00389 {
00390 binary_write(*fp, sqt[i]);
00391 }
00392
00393 fp->close();
00394 delete fp;
00395
00396 return true;
00397 }
00398
00404 bool DicomDir::Anonymize()
00405 {
00406 DataEntry *v;
00407
00408 std::ostringstream s;
00409 int i = 1;
00410 for(ListDicomDirPatient::iterator cc = Patients.begin();
00411 cc!= Patients.end();
00412 ++cc)
00413 {
00414 s << i;
00415 v = (*cc)->GetDataEntry(0x0010, 0x0010) ;
00416 if (v)
00417 {
00418 v->SetString(s.str());
00419 }
00420
00421 v = (*cc)->GetDataEntry(0x0010, 0x0020) ;
00422 if (v)
00423 {
00424 v->SetString(" ");
00425 }
00426
00427 v = (*cc)->GetDataEntry(0x0010, 0x0030) ;
00428 if (v)
00429 {
00430 v->SetString(" ");
00431 }
00432 s << "";
00433 i++;
00434 }
00435 return true;
00436 }
00437
00443 void DicomDir::Copy(DocEntrySet *set)
00444 {
00445
00446 ClearPatient();
00447
00448 Document::Copy(set);
00449
00450 DicomDir *dd = dynamic_cast<DicomDir *>(set);
00451 if( dd )
00452 {
00453 if(MetaElems)
00454 MetaElems->Unregister();
00455 MetaElems = dd->MetaElems;
00456 if(MetaElems)
00457 MetaElems->Register();
00458
00459 Patients = dd->Patients;
00460 for(ItPatient = Patients.begin();ItPatient != Patients.end();++ItPatient)
00461 (*ItPatient)->Register();
00462 }
00463 }
00464
00465
00466
00471 void DicomDir::CreateDicomDirChainedList(std::string const &path)
00472 {
00473 CallStartMethod();
00474 DirList dirList(path,1);
00475 unsigned int count = 0;
00476 VectDocument list;
00477 File *f;
00478
00479 DirListType fileList = dirList.GetFilenames();
00480 unsigned int nbFile = fileList.size();
00481 for( DirListType::iterator it = fileList.begin();
00482 it != fileList.end();
00483 ++it )
00484 {
00485 Progress = (float)(count+1)/(float)nbFile;
00486 CallProgressMethod();
00487 if ( Abort )
00488 {
00489 break;
00490 }
00491
00492 f = File::New( );
00493 f->SetLoadMode(LoadMode);
00494
00495 f->SetFileName( it->c_str() );
00496 f->Load( );
00497
00498 if ( f->IsReadable() )
00499 {
00500
00501 list.push_back(f);
00502 gdcmDebugMacro( "Readable " << it->c_str() );
00503 }
00504 else
00505 {
00506 f->Delete();
00507 }
00508 count++;
00509 }
00510
00511 std::sort(list.begin(), list.end(), DicomDir::HeaderLessThan );
00512
00513 std::string tmp = dirList.GetDirName();
00514
00515 SetElements(tmp, list);
00516 CallEndMethod();
00517
00518 for(VectDocument::iterator itDoc=list.begin();
00519 itDoc!=list.end();
00520 ++itDoc)
00521 {
00522 dynamic_cast<File *>(*itDoc)->Delete();
00523 }
00524 }
00525
00526
00527
00528
00532 void DicomDir::Initialize()
00533 {
00534 Progress = 0.0;
00535 Abort = false;
00536
00537 MetaElems = NULL;
00538 }
00539
00543 void DicomDir::CreateDicomDir()
00544 {
00545
00546
00547
00548
00549
00550
00551
00552 gdcmDebugMacro("Create DicomDir");
00553
00554
00555 DocEntry *e = GetDocEntry(0x0004, 0x1220);
00556 if ( !e )
00557 {
00558 gdcmWarningMacro( "No Directory Record Sequence (0004,1220) found");
00559 return;
00560 }
00561
00562 SeqEntry *s = dynamic_cast<SeqEntry *>(e);
00563 if ( !s )
00564 {
00565 gdcmWarningMacro( "Element (0004,1220) is not a Sequence ?!?");
00566 return;
00567 }
00568
00569 NewMeta();
00570
00571 DocEntry *d;
00572 std::string v;
00573 SQItem *si;
00574
00575 SQItem *tmpSI=s->GetFirstSQItem();
00576 while(tmpSI)
00577 {
00578 d = tmpSI->GetDocEntry(0x0004, 0x1430);
00579 if ( DataEntry *dataEntry = dynamic_cast<DataEntry *>(d) )
00580 {
00581 v = dataEntry->GetString();
00582 }
00583 else
00584 {
00585 gdcmWarningMacro( "(0004,1430) not a DataEntry ?!?");
00586 continue;
00587 }
00588
00589
00590
00591
00592
00593 if ( v == "IMAGE " )
00594 {
00595 si = DicomDirImage::New(true);
00596 if ( !AddImageToEnd( static_cast<DicomDirImage *>(si)) )
00597 {
00598 si->Delete();
00599 si = NULL;
00600 gdcmErrorMacro( "Add AddImageToEnd failed");
00601 }
00602 }
00603 else if ( v == "SERIES" )
00604 {
00605 si = DicomDirSerie::New(true);
00606 if ( !AddSerieToEnd( static_cast<DicomDirSerie *>(si)) )
00607 {
00608 si->Delete();
00609 si = NULL;
00610 gdcmErrorMacro( "Add AddSerieToEnd failed");
00611 }
00612 }
00613 else if ( v == "VISIT " )
00614 {
00615 si = DicomDirVisit::New(true);
00616 if ( !AddVisitToEnd( static_cast<DicomDirVisit *>(si)) )
00617 {
00618 si->Delete();
00619 si = NULL;
00620 gdcmErrorMacro( "Add AddVisitToEnd failed");
00621 }
00622 }
00623 else if ( v == "STUDY " )
00624 {
00625 si = DicomDirStudy::New(true);
00626 if ( !AddStudyToEnd( static_cast<DicomDirStudy *>(si)) )
00627 {
00628 si->Delete();
00629 si = NULL;
00630 gdcmErrorMacro( "Add AddStudyToEnd failed");
00631 }
00632 }
00633 else if ( v == "PATIENT " )
00634 {
00635 si = DicomDirPatient::New(true);
00636 if ( !AddPatientToEnd( static_cast<DicomDirPatient *>(si)) )
00637 {
00638 si->Delete();
00639 si = NULL;
00640 gdcmErrorMacro( "Add PatientToEnd failed");
00641 }
00642 }
00643 else
00644 {
00645
00646
00647 gdcmDebugMacro( " -------------------------------------------"
00648 << "a non PATIENT/STUDY/SERIE/IMAGE SQItem was found : "
00649 << v);
00650
00651
00652 tmpSI=s->GetNextSQItem();
00653 continue;
00654 }
00655 if ( si )
00656 si->Copy(tmpSI);
00657
00658 tmpSI=s->GetNextSQItem();
00659 }
00660 ClearEntry();
00661 }
00662
00667 bool DicomDir::AddPatientToEnd(DicomDirPatient *dd)
00668 {
00669 Patients.push_back(dd);
00670 return true;
00671 }
00672
00677 bool DicomDir::AddStudyToEnd(DicomDirStudy *dd)
00678 {
00679 if ( Patients.size() > 0 )
00680 {
00681 ListDicomDirPatient::iterator itp = Patients.end();
00682 itp--;
00683 (*itp)->AddStudy(dd);
00684 return true;
00685 }
00686 return false;
00687 }
00688
00693 bool DicomDir::AddSerieToEnd(DicomDirSerie *dd)
00694 {
00695 if ( Patients.size() > 0 )
00696 {
00697 ListDicomDirPatient::iterator itp = Patients.end();
00698 itp--;
00699
00700 DicomDirStudy *study = (*itp)->GetLastStudy();
00701 if ( study )
00702 {
00703 study->AddSerie(dd);
00704 return true;
00705 }
00706 }
00707 return false;
00708 }
00709
00714 bool DicomDir::AddVisitToEnd(DicomDirVisit *dd)
00715 {
00716 if ( Patients.size() > 0 )
00717 {
00718 ListDicomDirPatient::iterator itp = Patients.end();
00719 itp--;
00720
00721 DicomDirStudy *study = (*itp)->GetLastStudy();
00722 if ( study )
00723 {
00724 study->AddVisit(dd);
00725 return true;
00726 }
00727 }
00728 return false;
00729 }
00734 bool DicomDir::AddImageToEnd(DicomDirImage *dd)
00735 {
00736 if ( Patients.size() > 0 )
00737 {
00738 ListDicomDirPatient::iterator itp = Patients.end();
00739 itp--;
00740
00741 DicomDirStudy *study = (*itp)->GetLastStudy();
00742 if ( study )
00743 {
00744 DicomDirSerie *serie = study->GetLastSerie();
00745 if ( serie )
00746 {
00747 serie->AddImage(dd);
00748 return true;
00749 }
00750 }
00751 }
00752 return false;
00753 }
00754
00761 void DicomDir::SetElements(std::string const &path, VectDocument const &list)
00762 {
00763 ClearEntry();
00764 ClearPatient();
00765
00766 std::string patPrevName = "", patPrevID = "";
00767 std::string studPrevInstanceUID = "", studPrevID = "";
00768 std::string serPrevInstanceUID = "", serPrevID = "";
00769
00770 std::string patCurName, patCurID;
00771 std::string studCurInstanceUID, studCurID;
00772 std::string serCurInstanceUID, serCurID;
00773
00774 bool first = true;
00775 for( VectDocument::const_iterator it = list.begin();
00776 it != list.end();
00777 ++it )
00778 {
00779
00780 patCurName = (*it)->GetEntryString(0x0010,0x0010);
00781 patCurID = (*it)->GetEntryString(0x0010,0x0011);
00782 studCurInstanceUID = (*it)->GetEntryString(0x0020,0x000d);
00783 studCurID = (*it)->GetEntryString(0x0020,0x0010);
00784 serCurInstanceUID = (*it)->GetEntryString(0x0020,0x000e);
00785 serCurID = (*it)->GetEntryString(0x0020,0x0011);
00786
00787 if ( patCurName != patPrevName || patCurID != patPrevID || first )
00788 {
00789 SetElement(path, GDCM_DICOMDIR_PATIENT, *it);
00790 first = true;
00791 }
00792
00793
00794 if ( studCurInstanceUID != studPrevInstanceUID || studCurID != studPrevID
00795 || first )
00796 {
00797 SetElement(path, GDCM_DICOMDIR_STUDY, *it);
00798 first = true;
00799 }
00800
00801
00802 if ( serCurInstanceUID != serPrevInstanceUID || serCurID != serPrevID
00803 || first )
00804 {
00805 SetElement(path, GDCM_DICOMDIR_SERIE, *it);
00806 }
00807
00808
00809 SetElement(path, GDCM_DICOMDIR_IMAGE, *it);
00810
00811 patPrevName = patCurName;
00812 patPrevID = patCurID;
00813 studPrevInstanceUID = studCurInstanceUID;
00814 studPrevID = studCurID;
00815 serPrevInstanceUID = serCurInstanceUID;
00816 serPrevID = serCurID;
00817 first = false;
00818 }
00819 }
00820
00829 void DicomDir::SetElement(std::string const &path, DicomDirType type,
00830 Document *header)
00831 {
00832 ListDicomDirElem elemList;
00833 ListDicomDirElem::const_iterator it;
00834 uint16_t tmpGr, tmpEl;
00835 DictEntry *dictEntry;
00836 DataEntry *entry;
00837 std::string val;
00838 SQItem *si;
00839
00840 switch( type )
00841 {
00842 case GDCM_DICOMDIR_IMAGE:
00843 elemList = Global::GetDicomDirElements()->GetDicomDirImageElements();
00844 si = DicomDirImage::New(true);
00845 if ( !AddImageToEnd(static_cast<DicomDirImage *>(si)) )
00846 {
00847 si->Delete();
00848 gdcmErrorMacro( "Add ImageToEnd failed");
00849 }
00850 break;
00851 case GDCM_DICOMDIR_SERIE:
00852 elemList = Global::GetDicomDirElements()->GetDicomDirSerieElements();
00853 si = DicomDirSerie::New(true);
00854 if ( !AddSerieToEnd(static_cast<DicomDirSerie *>(si)) )
00855 {
00856 si->Delete();
00857 gdcmErrorMacro( "Add SerieToEnd failed");
00858 }
00859 break;
00860 case GDCM_DICOMDIR_STUDY:
00861 elemList = Global::GetDicomDirElements()->GetDicomDirStudyElements();
00862 si = DicomDirStudy::New(true);
00863 if ( !AddStudyToEnd(static_cast<DicomDirStudy *>(si)) )
00864 {
00865 si->Delete();
00866 gdcmErrorMacro( "Add StudyToEnd failed");
00867 }
00868 break;
00869 case GDCM_DICOMDIR_PATIENT:
00870 elemList = Global::GetDicomDirElements()->GetDicomDirPatientElements();
00871 si = DicomDirPatient::New(true);
00872 if ( !AddPatientToEnd(static_cast<DicomDirPatient *>(si)) )
00873 {
00874 si->Delete();
00875 gdcmErrorMacro( "Add PatientToEnd failed");
00876 }
00877 break;
00878 case GDCM_DICOMDIR_META:
00879 if ( MetaElems )
00880 {
00881 MetaElems->Delete();
00882 gdcmErrorMacro( "MetaElements already exist, they will be destroyed");
00883 }
00884 elemList = Global::GetDicomDirElements()->GetDicomDirMetaElements();
00885 MetaElems = DicomDirMeta::New(true);
00886 si = MetaElems;
00887 break;
00888 default:
00889 return;
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902 std::string referencedVal;
00903
00904 for( it = elemList.begin(); it != elemList.end(); ++it)
00905 {
00906 tmpGr = it->Group;
00907 tmpEl = it->Elem;
00908 dictEntry = GetPubDict()->GetEntry(tmpGr, tmpEl);
00909
00910 entry = DataEntry::New( dictEntry );
00911 entry->SetOffset(0);
00912
00913 if ( header )
00914 {
00915
00916
00917
00918 val = header->GetEntryString(tmpGr, tmpEl);
00919 }
00920 else
00921 {
00922 val = GDCM_UNFOUND;
00923 }
00924
00925 if ( val == GDCM_UNFOUND)
00926 {
00927 if ( tmpGr == 0x0004 )
00928 {
00929 switch (tmpEl)
00930 {
00931 case 0x1130:
00932
00933 val = Util::GetName( path );
00934 break;
00935
00936 case 0x1500:
00937 if ( header->GetFileName().substr(0, path.length()) != path )
00938 {
00939 gdcmWarningMacro( "The base path of file name is incorrect");
00940 val = header->GetFileName();
00941 }
00942 else
00943 {
00944
00945 if ( header->GetFileName().c_str()[path.length()]
00946 == GDCM_FILESEPARATOR )
00947 val = &(header->GetFileName().c_str()[path.length()+1]);
00948 else
00949 val = &(header->GetFileName().c_str()[path.length()]);
00950 }
00951 break;
00952
00953 case 0x1510:
00954 referencedVal = header->GetEntryString(0x0008, 0x0016);
00955
00956 val = referencedVal;
00957 break;
00958
00959 case 0x1511:
00960 referencedVal = header->GetEntryString(0x0008, 0x0018);
00961
00962 val = referencedVal;
00963 break;
00964
00965 case 0x1512:
00966 referencedVal = header->GetEntryString(0x0002, 0x0010);
00967
00968 val = referencedVal;
00969 break;
00970
00971 default :
00972 val = it->Value;
00973 }
00974 }
00975 else
00976 {
00977
00978 entry->Delete();
00979 continue;
00980 }
00981 }
00982 else
00983 {
00984 if ( header->GetEntryLength(tmpGr,tmpEl) == 0 )
00985 {
00986 val = it->Value;
00987
00988 if (val == "")
00989 {
00990 entry->Delete();
00991 continue;
00992 }
00993 }
00994 }
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009 entry->SetString( val );
01010
01011 if ( type == GDCM_DICOMDIR_META )
01012 {
01013 gdcmDebugMacro("GDCM_DICOMDIR_META ?!? should never print that");
01014 }
01015
01016 si->AddEntry(entry);
01017 entry->Delete();
01018 }
01019 }
01020
01027 void DicomDir::MoveSQItem(DocEntrySet *dst, DocEntrySet *src)
01028 {
01029 DocEntry *entry;
01030
01031
01032 entry = src->GetFirstEntry();
01033 while(entry)
01034 {
01035 dst->AddEntry(entry);
01036 src->RemoveEntry(entry);
01037
01038 entry = src->GetFirstEntry();
01039 }
01040 }
01041
01045 bool DicomDir::HeaderLessThan(Document *header1, Document *header2)
01046 {
01047 return *header1 < *header2;
01048 }
01049
01050
01051
01057 void DicomDir::Print(std::ostream &os, std::string const & )
01058 {
01059 if ( MetaElems )
01060 {
01061 MetaElems->SetPrintLevel(PrintLevel);
01062 MetaElems->Print(os);
01063 }
01064 for(ListDicomDirPatient::iterator cc = Patients.begin();
01065 cc != Patients.end();
01066 ++cc)
01067 {
01068 (*cc)->SetPrintLevel(PrintLevel);
01069 (*cc)->Print(os);
01070 }
01071 }
01072
01073
01074 }