gdcmDicomDir.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002   
00003   Program:   gdcm
00004   Module:    $RCSfile: gdcmDicomDir.cxx,v $
00005   Language:  C++
00006   Date:      $Date: 2007/07/26 08:36:49 $
00007   Version:   $Revision: 1.194 $
00008   
00009   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
00010   l'Image). All rights reserved. See Doc/License.txt or
00011   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
00012   
00013      This software is distributed WITHOUT ANY WARRANTY; without even
00014      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00015      PURPOSE.  See the above copyright notices for more information.
00016   
00017 =========================================================================*/
00018 
00019 //-----------------------------------------------------------------------------
00020 //  For full DICOMDIR description, see:
00021 //  PS 3.3-2003, pages 731-750
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 "gdcmDicomDirPrivate.h"
00030 #include "gdcmDicomDirPatient.h"
00031 #include "gdcmDicomDirMeta.h"
00032 #include "gdcmDicomDirElement.h"
00033 #include "gdcmDirList.h"
00034 #include "gdcmUtil.h"
00035 #include "gdcmDebug.h"
00036 #include "gdcmGlobal.h"
00037 #include "gdcmFile.h"
00038 #include "gdcmSeqEntry.h"
00039 #include "gdcmSQItem.h"
00040 #include "gdcmDataEntry.h"
00041 #include "gdcmCommandManager.h"
00042 
00043 #include <fstream>
00044 #include <string>
00045 #include <algorithm>
00046 #include <sys/types.h>
00047 
00048 #ifdef _MSC_VER
00049 #   define getcwd _getcwd
00050 #endif
00051 
00052 #if defined(_MSC_VER) || defined(__BORLANDC__)
00053 #   include <direct.h>
00054 #else
00055 #   include <unistd.h>
00056 #endif
00057 
00058 #if defined(__BORLANDC__)
00059    #include <mem.h> // for memset
00060 #endif
00061 
00062 // ----------------------------------------------------------------------------
00063 //         Note for future developpers
00064 // ----------------------------------------------------------------------------
00065 //
00066 //  Dicom PS 3.3 describes the relationship between Directory Records, as follow
00067 //    (see also PS 4.3, 2004, page 50 for Entity-Relationship model)
00068 //
00069 //  Directory Record Type      Directory Record Types which may be included
00070 //                                in the next lower-level directory Entity
00071 //
00072 // (Root directory Entity)     PATIENT, TOPIC, PRIVATE
00073 //
00074 // PATIENT                     STUDY, PRIVATE
00075 //
00076 // STUDY                       SERIES, VISIT, RESULTS, STUDY COMPONENT, PRIVATE
00077 //
00078 // SERIES                      IMAGE, OVERLAYS, MODALITY LUT, VOI LUT,
00079 //                             CURVE, STORED PRINT, RT DOSE, RT STRUCTURE SET
00080 //                             RT PLAN, RT TREAT RECORD, PRESENTATION, WAVEFORM,
00081 //                             SR DOCUMENT, KEY OBJECT DOC, SPECTROSCOPY,
00082 //                             RAW DATA, REGISTRATION, FIDUCIAL, PRIVATE,
00083 //                             ENCAP DOC
00084 // IMAGE
00085 // OVERLAY
00086 // MODALITY LUT
00087 // VOI LUT
00088 // CURVE
00089 // STORED PRINT
00090 // RT DOSE
00091 // RT STRUCTURE SET
00092 // RT PLAN
00093 // RT TREAT RECORD
00094 // PRESENTATION
00095 // WAVEFORM
00096 // SR DOCUMENT
00097 // KEY OBJECT DOC
00098 // SPECTROSCOPY
00099 // RAW DATA
00100 // REGISTRATION
00101 // FIDUCIAL
00102 // PRIVATE
00103 // ENCAP DOC
00104 // 
00105 
00106 /*
00107 
00108 // see also : ftp://medical.nema.org/medical/dicom/final/cp343_ft.doc
00109 
00110 RELATIONSHIP BETWEEN DIRECTORY RECORDS
00111 
00112 Directory Record Type      Directory Record Types which may be included 
00113                            in the next lower-level directory Entity
00114 
00115 (Root Directory Entity)    PATIENT, TOPIC, PRIVATE
00116 
00117 PATIENT                    STUDY, PRIVATE
00118 
00119 STUDY                      SERIES, VISIT, RESULTS, STUDY COMPONENT, PRIVATE
00120 
00121 SERIES                     IMAGE, OVERLAY, MODALITY LUT, VOI LUT, CURVE, 
00122                            STORED PRINT, RT DOSE, RT STRUCTURE SET, RT PLAN, 
00123                            RT TREAT RECORD, PRESENTATION, WAVEFORM, SR DOCUMENT,
00124                             KEY OBJECT DOC, SPECTROSCOPY, RAW DATA, PRIVATE
00125 
00126 IMAGE                      PRIVATE
00127 OVERLAY                    PRIVATE
00128 MODALITY LUT               PRIVATE
00129 VOI LUT                    PRIVATE
00130 CURVE                      PRIVATE
00131 STORED PRINT               PRIVATE
00132 RT DOSE                    PRIVATE
00133 RT STRUCTURE SET           PRIVATE
00134 RT PLAN                    PRIVATE
00135 RT TREAT RECORD            PRIVATE
00136 PRESENTATION               PRIVATE
00137 WAVEFORM                   PRIVATE
00138 SR DOCUMENT                PRIVATE
00139 KEY OBJECT DOC             PRIVATE
00140 SPECTROSCOPY               PRIVATE
00141 RAW DATA                   PRIVATE
00142 
00143 TOPIC                      STUDY, SERIES, IMAGE, OVERLAY, MODALITY LUT, VOI LUT,
00144                            CURVE, STORED PRINT, RT DOSE, RT STRUCTURE SET, 
00145                            RT PLAN, RT TREAT RECORD, PRESENTATION, WAVEFORM, 
00146                            SR DOCUMENT, KEY OBJECT DOC, SPECTROSCOPY, RAW DATA, 
00147                            PRIVATE
00148 
00149 VISIT                      PRIVATE
00150 
00151 RESULTS                    INTERPRETATION, PRIVATE
00152 
00153 INTERPRETATION             PRIVATE
00154 STUDY COMPONENT            PRIVATE
00155 PRIVATE                    PRIVATE, (any of the above as privately defined)
00156 MRDR                      (Not applicable)
00157 
00158 Note :   Directory Record Types PRINT QUEUE, FILM SESSION, FILM BOX, and 
00159          IMAGE BOX  were previously defined in DICOM.  They have been retired.  
00160          See PS 3.3-1998.
00161 */
00162 
00163 // ----------------------
00164 // The current gdcm version only deals with :
00165 //
00166 // (Root directory Entity)     PATIENT
00167 // PATIENT                     STUDY
00168 // STUDY                       SERIES
00169 // STUDY                       VISIT 
00170 // SERIES                      IMAGE
00171 // IMAGE                       /
00172 //
00173 // DicomDir::CreateDicomDir will have to be completed
00174 // Treelike structure management will have to be upgraded
00175 // ----------------------------------------------------------------------------
00176     
00177 namespace GDCM_NAME_SPACE 
00178 {
00179 //-----------------------------------------------------------------------------
00180 // Constructor / Destructor
00184 DicomDir::DicomDir()
00185 {
00186    Initialize();  // sets all private fields to NULL
00187    ParseDir = false;
00188    NewMeta();
00189 }
00190 
00191 //#ifndef GDCM_LEGACY_REMOVE
00206  /*
00207 DicomDir::DicomDir(std::string const &fileName, bool parseDir ):
00208    Document( )
00209 {
00210    // At this step, Document constructor is already executed,
00211    // whatever user passed (either a root directory or a DICOMDIR)
00212    // and whatever the value of parseDir was.
00213    // (nothing is checked in Document constructor, to avoid overhead)
00214 
00215    ParseDir = parseDir;
00216    SetLoadMode (LD_ALL); // concerns only dicom files
00217    SetFileName( fileName );
00218    Load( );
00219 }
00220 */
00221 //#endif
00222 
00226 DicomDir::~DicomDir() 
00227 {
00228    ClearPatient();
00229    if ( MetaElems )
00230    {
00231       MetaElems->Delete();
00232    }
00233 }
00234 
00235 //-----------------------------------------------------------------------------
00236 // Public
00237 
00244 bool DicomDir::Load( ) 
00245 {
00246    if (!ParseDir)
00247    {
00248       if ( ! this->Document::Load( ) )
00249          return false;
00250    }
00251    return DoTheLoadingJob( );   
00252 }
00253 //#ifndef GDCM_LEGACY_REMOVE
00261  /*
00262 bool DicomDir::Load(std::string const &fileName ) 
00263 {
00264    // We should clean out anything that already exists.
00265    Initialize();  // sets all private fields to NULL
00266 
00267    SetFileName( fileName );
00268    if (!ParseDir)
00269    {
00270       if ( ! this->Document::Load( ) )
00271          return false;
00272    }
00273    return DoTheLoadingJob( );
00274 }
00275 */
00276 //#endif
00277 
00283 bool DicomDir::DoTheLoadingJob( ) 
00284 {
00285    Progress = 0.0f;
00286    Abort = false;
00287 
00288    if (!ParseDir)
00289    {
00290    // Only if user passed a DICOMDIR
00291    // ------------------------------
00292       Fp = 0;
00293       if (!Document::Load() )
00294       {
00295          return false;
00296       }
00297 
00298       if ( GetFirstEntry() == 0 ) // when user passed a Directory to parse
00299       {
00300          gdcmWarningMacro( "Entry HT empty for file: "<< GetFileName());
00301          return false;
00302       }
00303       // Directory record sequence
00304       DocEntry *e = GetDocEntry(0x0004, 0x1220);
00305       if ( !e )
00306       {
00307          gdcmWarningMacro( "NO 'Directory record sequence' (0x0004,0x1220)"
00308                           << " in file " << GetFileName());
00309          return false;
00310       }
00311       else
00312       {
00313          CreateDicomDir();
00314       }
00315    }
00316    else
00317    {
00318    // Only if user passed a root directory
00319    // ------------------------------------
00320       if ( GetFileName() == "." )
00321       {
00322          // user passed '.' as Name
00323          // we get current directory name
00324          char buf[2048];
00325          const char *cwd = getcwd(buf, 2048);
00326          if( cwd )
00327          {
00328             SetFileName( buf ); // will be converted into a string
00329          }
00330          else
00331          {
00332             gdcmErrorMacro( "Path was too long to fit on 2048 bytes" );
00333          }
00334       }
00335       NewMeta();
00336       gdcmDebugMacro( "Parse directory and create the DicomDir : " 
00337                          << GetFileName() );
00338       ParseDirectory();
00339    }
00340    return true;
00341 }
00342 
00351 bool DicomDir::IsReadable()
00352 {
00353    if ( Filetype == Unknown )
00354    {
00355       gdcmErrorMacro( "Wrong filetype for " << GetFileName());
00356       return false;
00357    }
00358    if ( !MetaElems )
00359    {
00360       gdcmWarningMacro( "Meta Elements missing in DicomDir");
00361       return false;
00362    }
00363    if ( Patients.size() <= 0 )
00364    {
00365       gdcmWarningMacro( "NO Patient in DicomDir");
00366       return false;
00367    }
00368 
00369    return true;
00370 }
00371 
00375 DicomDirMeta *DicomDir::NewMeta()
00376 {
00377    if ( MetaElems )
00378    {
00379       MetaElems->Delete();
00380    }
00381    DocEntry *entry = GetFirstEntry();
00382    if ( entry )
00383    { 
00384       MetaElems = DicomDirMeta::New(true); // true = empty
00385 
00386       entry = GetFirstEntry();
00387       while( entry )
00388       {
00389          if ( dynamic_cast<SeqEntry *>(entry) )
00390             break;
00391 
00392          MetaElems->AddEntry(entry);
00393          RemoveEntry(entry);
00394 
00395          entry = GetFirstEntry();
00396       }
00397    }
00398    else  // after root directory parsing
00399    {
00400       MetaElems = DicomDirMeta::New(false); // false = not empty
00401    }
00402    MetaElems->SetSQItemNumber(0); // To avoid further missprinting
00403    return MetaElems;  
00404 }
00405 
00410 DicomDirPatient *DicomDir::NewPatient()
00411 {
00412    DicomDirPatient *dd = DicomDirPatient::New();
00413    AddPatientToEnd( dd );
00414    return dd;
00415 }
00416 
00420 void DicomDir::ClearPatient()
00421 {
00422    for(ListDicomDirPatient::iterator cc = Patients.begin();
00423                                      cc!= Patients.end();
00424                                    ++cc)
00425    {
00426       (*cc)->Unregister();
00427    }
00428    Patients.clear();
00429 }
00430 
00435 DicomDirPatient *DicomDir::GetFirstPatient()
00436 {
00437    ItPatient = Patients.begin();
00438    if ( ItPatient != Patients.end() )
00439       return *ItPatient;
00440    return NULL;
00441 }
00442 
00448 DicomDirPatient *DicomDir::GetNextPatient()
00449 {
00450    gdcmAssertMacro (ItPatient != Patients.end());
00451 
00452    ++ItPatient;
00453    if ( ItPatient != Patients.end() )
00454       return *ItPatient;
00455    return NULL;
00456 }
00457 
00461 void DicomDir::ParseDirectory()
00462 {
00463    CreateDicomDirChainedList( GetFileName() );
00464    CreateDicomDir();
00465 }
00466 
00475 bool DicomDir::Write(std::string const &fileName) 
00476 {  
00477    int i;
00478    uint16_t sq[6] = { 0x0004, 0x1220, 0x5153, 0x0000, 0xffff, 0xffff };
00479    uint16_t sqt[4]= { 0xfffe, 0xe0dd, 0x0000, 0x0000 };
00480 
00481    std::ofstream *fp = new std::ofstream(fileName.c_str(),  
00482                                          std::ios::out | std::ios::binary);
00483    if ( !fp ) 
00484    {
00485       gdcmWarningMacro("Failed to open(write) File: " << fileName.c_str());
00486       return false;
00487    }
00488 
00489    char filePreamble[128];
00490    memset(filePreamble, 0, 128);
00491    fp->write(filePreamble, 128);
00492    binary_write( *fp, "DICM");
00493  
00494    DicomDirMeta *ptrMeta = GetMeta();
00495    ptrMeta->WriteContent(fp, ExplicitVR, true);
00496    
00497    // force writing 0004|1220 [SQ ], that CANNOT exist within DicomDirMeta
00498    for(i=0;i<6;++i)
00499    {
00500       binary_write(*fp, sq[i]);
00501    }
00502         
00503    for(ListDicomDirPatient::iterator cc  = Patients.begin();
00504                                      cc != Patients.end();
00505                                    ++cc )
00506    {
00507       (*cc)->WriteContent( fp, ExplicitVR, false );
00508    }
00509    
00510    // force writing Sequence Delimitation Item
00511    for(i=0;i<4;++i)
00512    {
00513       binary_write(*fp, sqt[i]);  // fffe e0dd 0000 0000 
00514    }
00515 
00516    fp->close();
00517    delete fp;
00518 
00519    return true;
00520 }
00521 
00527 bool DicomDir::Anonymize() 
00528 {
00529    DataEntry *v;
00530    // Something clever to be found to forge the Patient names
00531    std::ostringstream s;
00532    int i = 1;
00533    for(ListDicomDirPatient::iterator cc = Patients.begin();
00534                                      cc!= Patients.end();
00535                                    ++cc)
00536    {
00537       s << i;
00538       v = (*cc)->GetDataEntry(0x0010, 0x0010) ; // Patient's Name
00539       if (v)
00540       {
00541          v->SetString(s.str());
00542       }
00543 
00544       v = (*cc)->GetDataEntry(0x0010, 0x0020) ; // Patient ID
00545       if (v)
00546       {
00547          v->SetString(" ");
00548       }
00549 
00550       v = (*cc)->GetDataEntry(0x0010, 0x0030) ; // Patient's BirthDate
00551       if (v)
00552       {
00553          v->SetString(" ");
00554       }
00555       s << "";
00556       i++;
00557    }
00558    return true;
00559 }
00560 
00566 void DicomDir::Copy(DocEntrySet *set)
00567 {
00568    // Remove all previous childs
00569    ClearPatient();
00570 
00571    Document::Copy(set);
00572 
00573    DicomDir *dd = dynamic_cast<DicomDir *>(set);
00574    if( dd )
00575    {
00576       if(MetaElems)
00577          MetaElems->Unregister();
00578       MetaElems = dd->MetaElems;
00579       if(MetaElems)
00580          MetaElems->Register();
00581 
00582       Patients = dd->Patients;
00583       for(ItPatient = Patients.begin();ItPatient != Patients.end();++ItPatient)
00584          (*ItPatient)->Register();
00585    }
00586 }
00587 
00588 //-----------------------------------------------------------------------------
00589 // Protected
00594 void DicomDir::CreateDicomDirChainedList(std::string const &path)
00595 {
00596    CallStartMethod();
00597    DirList dirList(path,1); // gets recursively the file list
00598    unsigned int count = 0;
00599    VectDocument list;
00600    File *f;
00601 
00602    DirListType fileList = dirList.GetFilenames();
00603    unsigned int nbFile = fileList.size();
00604    for( DirListType::iterator it  = fileList.begin();
00605                               it != fileList.end();
00606                               ++it )
00607    {
00608       Progress = (float)(count+1)/(float)nbFile;
00609       CallProgressMethod();
00610       if ( Abort )
00611       {
00612          break;
00613       }
00614 
00615       f = File::New( );
00616       f->SetLoadMode(LoadMode); // we allow user not to load Sequences, 
00617                                 //        or Shadow groups, or ......
00618       f->SetFileName( it->c_str() );
00619       f->Load( );
00620 
00621       if ( f->IsReadable() )
00622       {
00623          // Add the file to the chained list:
00624          list.push_back(f);
00625          gdcmDebugMacro( "Readable " << it->c_str() );
00626        }
00627        else
00628        {
00629           f->Delete();
00630        }
00631        count++;
00632    }
00633    // sorts Patient/Study/Serie/
00634    std::sort(list.begin(), list.end(), DicomDir::HeaderLessThan );
00635    
00636    std::string tmp = dirList.GetDirName();      
00637    //for each File of the chained list, add/update the Patient/Study/Serie/Image info
00638    SetElements(tmp, list);
00639    CallEndMethod();
00640 
00641    for(VectDocument::iterator itDoc=list.begin();
00642        itDoc!=list.end();
00643        ++itDoc)
00644    {
00645       dynamic_cast<File *>(*itDoc)->Delete();
00646    }
00647 }
00648 
00649 
00650 //-----------------------------------------------------------------------------
00651 // Private
00655 void DicomDir::Initialize()
00656 {
00657    Progress = 0.0;
00658    Abort = false;
00659 
00660    MetaElems = NULL;   
00661 }
00662 
00666 void DicomDir::CreateDicomDir()
00667 {
00668    // The SeqEntries of "Directory Record Sequence" are parsed. 
00669    //  When a DicomDir tag ("PATIENT", "STUDY", "SERIE", "IMAGE") is found :
00670    //                    N.B. :  VISIT, PRIVATE not fully dealt with
00671    //  1 - we save the beginning iterator
00672    //  2 - we continue to parse
00673    //  3 - we find an other tag
00674    //       + we create the object for the precedent tag
00675    //       + loop to 1 -
00676    gdcmDebugMacro("Create DicomDir");
00677 
00678    // Directory record sequence
00679    DocEntry *e = GetDocEntry(0x0004, 0x1220);
00680    if ( !e )
00681    {
00682       gdcmWarningMacro( "No Directory Record Sequence (0004,1220) found");
00683       return;         
00684    }
00685    
00686    SeqEntry *s = dynamic_cast<SeqEntry *>(e);
00687    if ( !s )
00688    {
00689       gdcmWarningMacro( "Element (0004,1220) is not a Sequence ?!?");
00690       return;
00691    }
00692 
00693    NewMeta();
00694    
00695    DocEntry *d;
00696    std::string v;
00697    SQItem *si;
00698 
00699    SQItem *tmpSI=s->GetFirstSQItem();
00700    while(tmpSI)
00701    {
00702       d = tmpSI->GetDocEntry(0x0004, 0x1430); // Directory Record Type
00703       if ( DataEntry *dataEntry = dynamic_cast<DataEntry *>(d) )
00704       {
00705          v = dataEntry->GetString();
00706       }
00707       else
00708       {
00709          gdcmWarningMacro( "(0004,1430) not a DataEntry ?!?");
00710          continue;
00711       }
00712 
00713       // A decent DICOMDIR has much more images than series,
00714       // more series than studies, and so on.
00715       // This is the right order to perform the tests
00716 
00717       if ( v == "IMAGE " ) 
00718       {
00719          si = DicomDirImage::New(true); // true = empty
00720          if ( !AddImageToEnd( static_cast<DicomDirImage *>(si)) )
00721          {
00722             si->Delete();
00723             si = NULL;
00724             gdcmErrorMacro( "Add AddImageToEnd failed");
00725          }
00726       }
00727       else if ( v == "SERIES" )
00728       {
00729          si = DicomDirSerie::New(true);  // true = empty
00730          if ( !AddSerieToEnd( static_cast<DicomDirSerie *>(si)) )
00731          {
00732             si->Delete();
00733             si = NULL;
00734             gdcmErrorMacro( "Add AddSerieToEnd failed");
00735          }
00736       }
00737       else if ( v == "VISIT " )
00738       {
00739          si = DicomDirVisit::New(true);  // true = empty
00740          if ( !AddVisitToEnd( static_cast<DicomDirVisit *>(si)) )
00741          {
00742             si->Delete();
00743             si = NULL;
00744             gdcmErrorMacro( "Add AddVisitToEnd failed");
00745          }
00746       }
00747       else if ( v == "STUDY " )
00748       {
00749          si = DicomDirStudy::New(true);  // true = empty
00750          if ( !AddStudyToEnd( static_cast<DicomDirStudy *>(si)) )
00751          {
00752             si->Delete();
00753             si = NULL;
00754             gdcmErrorMacro( "Add AddStudyToEnd failed");
00755          }
00756       }
00757       else if ( v == "PATIENT " )
00758       {
00759          si = DicomDirPatient::New(true);  // true = empty
00760          if ( !AddPatientToEnd( static_cast<DicomDirPatient *>(si)) )
00761          {
00762             si->Delete();
00763             si = NULL;
00764             gdcmErrorMacro( "Add PatientToEnd failed");
00765          }
00766       }
00769       
00770       else if ( v == "PRIVATE " ) // for SIEMENS 'CSA Non Image'      
00771       {
00772       
00773          gdcmWarningMacro( " -------------------------------------------"
00774               << "a PRIVATE SQItem was found : " << v);
00775          si = DicomDirPrivate::New(true);  // true = empty
00776          if ( !AddPrivateToEnd( static_cast<DicomDirPrivate *>(si)) )
00777          {
00778             si->Delete();
00779             si = NULL;
00780             gdcmErrorMacro( "Add PrivateToEnd failed");
00781          }
00782       }      
00783       else
00784       {
00785          // It was neither a 'PATIENT', nor a 'STUDY', nor a 'SERIE',
00786          // nor an 'IMAGE' SQItem. Skip to next item.
00787          gdcmWarningMacro( " -------------------------------------------"
00788          << "a non PATIENT/STUDY/SERIE/IMAGE /VISIT/PRIVATE SQItem was found : "
00789          << v);
00790 
00791         // FIXME : deal with other item types !
00792         tmpSI=s->GetNextSQItem(); // To avoid infinite loop
00793         continue;
00794       }
00795       if ( si )
00796          si->Copy(tmpSI);
00797 
00798       tmpSI=s->GetNextSQItem();
00799    }
00800    ClearEntry();
00801 }
00802 
00807 bool DicomDir::AddPatientToEnd(DicomDirPatient *dd)
00808 {
00809    Patients.push_back(dd);
00810    return true;
00811 }
00812 
00817 bool DicomDir::AddStudyToEnd(DicomDirStudy *dd)
00818 {
00819    if ( Patients.size() > 0 )
00820    {
00821       ListDicomDirPatient::iterator itp = Patients.end();
00822       itp--;
00823       (*itp)->AddStudy(dd);
00824       return true;
00825    }
00826    return false;
00827 }
00828 
00833 bool DicomDir::AddSerieToEnd(DicomDirSerie *dd)
00834 {
00835    if ( Patients.size() > 0 )
00836    {
00837       ListDicomDirPatient::iterator itp = Patients.end();
00838       itp--;
00839 
00840       DicomDirStudy *study = (*itp)->GetLastStudy();
00841       if ( study )
00842       {
00843          study->AddSerie(dd);
00844          return true;
00845       }
00846    }
00847    return false;
00848 }
00849 
00854 bool DicomDir::AddVisitToEnd(DicomDirVisit *dd)
00855 {
00856    if ( Patients.size() > 0 )
00857    {
00858       ListDicomDirPatient::iterator itp = Patients.end();
00859       itp--;
00860 
00861       DicomDirStudy *study = (*itp)->GetLastStudy();
00862       if ( study )
00863       {
00864          study->AddVisit(dd);
00865          return true;
00866       }
00867    }
00868    return false;
00869 }
00874 bool DicomDir::AddImageToEnd(DicomDirImage *dd)
00875 {
00876    if ( Patients.size() > 0 )
00877    {
00878       ListDicomDirPatient::iterator itp = Patients.end();
00879       itp--;
00880 
00881       DicomDirStudy *study = (*itp)->GetLastStudy();
00882       if ( study )
00883       {
00884          DicomDirSerie *serie = study->GetLastSerie();
00885          if ( serie )
00886          {
00887             serie->AddImage(dd);
00888             return true;
00889          }
00890       }
00891    }
00892    return false;
00893 }
00894 
00900 bool DicomDir::AddPrivateToEnd(DicomDirPrivate *dd)
00901 {
00902    if ( Patients.size() > 0 )
00903    {
00904       ListDicomDirPatient::iterator itp = Patients.end();
00905       itp--;
00906 
00907       DicomDirStudy *study = (*itp)->GetLastStudy();
00908       if ( study )
00909       {
00910          DicomDirSerie *serie = study->GetLastSerie();
00911          if ( serie )
00912          {
00913             serie->AddPrivate(dd);
00914             return true;
00915          }
00916       }
00917    }
00918    return false;
00919 }
00920 
00927 void DicomDir::SetElements(std::string const &path, VectDocument const &list)
00928 {
00929    ClearEntry();
00930    ClearPatient();
00931 
00932    std::string patPrevName         = "", patPrevID  = "";
00933    std::string studPrevInstanceUID = "", studPrevID = "";
00934    std::string serPrevInstanceUID  = "", serPrevID  = "";
00935 
00936    std::string patCurName,         patCurID;
00937    std::string studCurInstanceUID, studCurID;
00938    std::string serCurInstanceUID,  serCurID;
00939 
00940    bool first = true;
00941    for( VectDocument::const_iterator it = list.begin();
00942                                      it != list.end(); 
00943                                    ++it )
00944    {
00945       // get the current file characteristics
00946       patCurName         = (*it)->GetEntryString(0x0010,0x0010);
00947       patCurID           = (*it)->GetEntryString(0x0010,0x0011);
00948       studCurInstanceUID = (*it)->GetEntryString(0x0020,0x000d);
00949       studCurID          = (*it)->GetEntryString(0x0020,0x0010);
00950       serCurInstanceUID  = (*it)->GetEntryString(0x0020,0x000e);
00951       serCurID           = (*it)->GetEntryString(0x0020,0x0011);
00952 
00953       if ( patCurName != patPrevName || patCurID != patPrevID || first )
00954       {
00955          SetElement(path, GDCM_DICOMDIR_PATIENT, *it);
00956          first = true;
00957       }
00958 
00959       // if new Study, deal with 'STUDY' Elements   
00960       if ( studCurInstanceUID != studPrevInstanceUID || studCurID != studPrevID 
00961          || first )
00962       {
00963          SetElement(path, GDCM_DICOMDIR_STUDY, *it);
00964          first = true;
00965       }
00966 
00967       // if new Serie, deal with 'SERIE' Elements   
00968       if ( serCurInstanceUID != serPrevInstanceUID || serCurID != serPrevID
00969          || first )
00970       {
00971          SetElement(path, GDCM_DICOMDIR_SERIE, *it);
00972       }
00973       
00974       // Always Deal with 'IMAGE' Elements  
00975       SetElement(path, GDCM_DICOMDIR_IMAGE, *it);
00976 
00977       patPrevName         = patCurName;
00978       patPrevID           = patCurID;
00979       studPrevInstanceUID = studCurInstanceUID;
00980       studPrevID          = studCurID;
00981       serPrevInstanceUID  = serCurInstanceUID;
00982       serPrevID           = serCurID;
00983       first = false;
00984    }
00985 }
00986 
00995 void DicomDir::SetElement(std::string const &path, DicomDirType type,
00996                           Document *header)
00997 {
00998    ListDicomDirElem elemList;
00999    ListDicomDirElem::const_iterator it;
01000    uint16_t tmpGr, tmpEl;
01001    //DictEntry *dictEntry;
01002    DataEntry *entry;
01003    std::string val;
01004    SQItem *si;
01005    switch( type )
01006    {
01007       case GDCM_DICOMDIR_IMAGE:
01008          elemList = Global::GetDicomDirElements()->GetDicomDirImageElements();
01009          si = DicomDirImage::New(true);
01010          if ( !AddImageToEnd(static_cast<DicomDirImage *>(si)) )
01011          {
01012             si->Delete();
01013             gdcmErrorMacro( "Add ImageToEnd failed");
01014          }
01015          break;
01016       case GDCM_DICOMDIR_SERIE:
01017          elemList = Global::GetDicomDirElements()->GetDicomDirSerieElements();
01018          si = DicomDirSerie::New(true);
01019          if ( !AddSerieToEnd(static_cast<DicomDirSerie *>(si)) )
01020          {
01021             si->Delete();
01022             gdcmErrorMacro( "Add SerieToEnd failed");
01023          }
01024          break;
01025       case GDCM_DICOMDIR_STUDY:
01026          elemList = Global::GetDicomDirElements()->GetDicomDirStudyElements();
01027          si = DicomDirStudy::New(true);
01028          if ( !AddStudyToEnd(static_cast<DicomDirStudy *>(si)) )
01029          {
01030             si->Delete();
01031             gdcmErrorMacro( "Add StudyToEnd failed");
01032          }
01033          break;
01034       case GDCM_DICOMDIR_PATIENT:
01035          elemList = Global::GetDicomDirElements()->GetDicomDirPatientElements();
01036          si = DicomDirPatient::New(true);
01037          if ( !AddPatientToEnd(static_cast<DicomDirPatient *>(si)) )
01038          {
01039             si->Delete();
01040             gdcmErrorMacro( "Add PatientToEnd failed");
01041          }
01042          break;
01043       case GDCM_DICOMDIR_META:  // never used ?!? --> Done within DoTheLoadingJob
01044          if ( MetaElems )
01045          {
01046             MetaElems->Delete();
01047             gdcmErrorMacro( "MetaElements already exist, they will be destroyed");
01048          }
01049          elemList = Global::GetDicomDirElements()->GetDicomDirMetaElements();
01050          MetaElems = DicomDirMeta::New(true);
01051          si = MetaElems;
01052          break;
01053       default:
01054          return;
01055    }
01056 
01057    // FIXME : troubles found when it's a SeqEntry
01058 
01059    // removed all the seems-to-be-useless stuff about Referenced Image Sequence
01060    // to avoid further troubles
01061    // imageElem 0008 1140 "" // Referenced Image Sequence
01062    // imageElem fffe e000 "" // 'no length' item : length to be set to 0xffffffff later
01063    // imageElem 0008 1150 "" // Referenced SOP Class UID    : to be set/forged later
01064    // imageElem 0008 1155 "" // Referenced SOP Instance UID : to be set/forged later
01065    // imageElem fffe e00d "" // Item delimitation : length to be set to ZERO later
01066  
01067    std::string referencedVal;
01068    // for all the relevant elements found in their own spot of the DicomDir.dic
01069    for( it = elemList.begin(); it != elemList.end(); ++it)
01070    {
01071       tmpGr     = it->Group;
01072       tmpEl     = it->Elem;
01073        
01074       entry     = DataEntry::New(tmpGr, tmpEl, it->VR); // dicomelements file was modified, to store VR
01075       entry->SetOffset(0); // just to avoid further missprinting
01076 
01077       if ( header )
01078       {
01079          // NULL when we Build Up (ex nihilo) a DICOMDIR
01080          //   or when we add the META elems
01081          val = header->GetEntryString(tmpGr, tmpEl); 
01082       }
01083       else
01084       {
01085          val = GDCM_UNFOUND;
01086       }
01087 
01088       if ( val == GDCM_UNFOUND) 
01089       {
01090          if ( tmpGr == 0x0004 ) // never present in File !     
01091          {
01092             switch (tmpEl)
01093             {
01094             case 0x1130: // File-set ID
01095                // force to the *end* File Name
01096                val = Util::GetName( path );
01097                break;
01098       
01099             case 0x1500: // Only used for image    
01100                if ( header->GetFileName().substr(0, path.length()) != path )
01101                { 
01102                  gdcmWarningMacro( "The base path of file name is incorrect");
01103                  val = header->GetFileName();
01104                }
01105                else
01106                { 
01107                  // avoid the first '/' in File name !
01108                  if ( header->GetFileName().c_str()[path.length()] 
01109                                                       == GDCM_FILESEPARATOR )
01110                     val = &(header->GetFileName().c_str()[path.length()+1]);
01111                  else  
01112                     val = &(header->GetFileName().c_str()[path.length()]);   
01113                }
01114                break;
01115     
01116              case 0x1510:  // Referenced SOP Class UID in File
01117                referencedVal = header->GetEntryString(0x0008, 0x0016);
01118                // FIXME : probabely something to check
01119                val = referencedVal;
01120                break;
01121        
01122              case 0x1511: // Referenced SOP Instance UID in File
01123                referencedVal = header->GetEntryString(0x0008, 0x0018);
01124                // FIXME : probabely something to check
01125                val = referencedVal;
01126                break;
01127     
01128             case 0x1512: // Referenced Transfer Syntax UID in File
01129                referencedVal = header->GetEntryString(0x0002, 0x0010);
01130                // FIXME : probabely something to check
01131                val = referencedVal;
01132                break;
01133     
01134             default :
01135                val = it->Value;   
01136             } 
01137          }
01138          else
01139          {
01140             // If the entry is not found in the Header, don't write its 'value' in the DICOMDIR !
01141             entry->Delete();
01142             continue;
01143           }
01144       }
01145       else
01146       {
01147          if ( header->GetEntryLength(tmpGr,tmpEl) == 0 )
01148          {
01149             val = it->Value;
01150             // Don't polute the DICOMDIR with empty fields
01151             if (val == "")
01152             {
01153                entry->Delete();
01154                continue;
01155             }  
01156          }    
01157       }
01158 
01159 /* FIX later the pb of creating the 'Implementation Version Name'!
01160 
01161       if (val == GDCM_UNFOUND)
01162          val = "";
01163 
01164       if ( tmpGr == 0x0002 && tmpEl == 0x0013)
01165       { 
01166          // 'Implementation Version Name'
01167          std::string val = "GDCM ";
01168          val += Util::GetVersion();
01169       }
01170 */ 
01171 
01172       entry->SetString( val ); // troubles expected when vr=SQ ...
01173 
01174       if ( type == GDCM_DICOMDIR_META ) // fusible : should never print !
01175       {
01176          gdcmDebugMacro("GDCM_DICOMDIR_META ?!? should never print that");
01177       }
01178       
01179       si->AddEntry(entry);
01180       entry->Delete();
01181    }
01182 }
01183 
01190 void DicomDir::MoveSQItem(DocEntrySet *dst, DocEntrySet *src)
01191 { 
01192    DocEntry *entry;
01193 // todo : rewrite the whole stuff, without using RemoveEntry an AddEntry,
01194 //        to save time
01195    entry = src->GetFirstEntry();
01196    while(entry)
01197    {
01198       dst->AddEntry(entry);  // use it, *before* removing it!
01199       src->RemoveEntry(entry);
01200       // we destroyed -> the current iterator is not longer valid
01201       entry = src->GetFirstEntry();
01202    }
01203 }
01204 
01208 bool DicomDir::HeaderLessThan(Document *header1, Document *header2)
01209 {
01210    return *header1 < *header2;
01211 }
01212 
01213 //-----------------------------------------------------------------------------
01214 // Print
01220 void DicomDir::Print(std::ostream &os, std::string const & )
01221 {
01222    if ( MetaElems )
01223    {
01224       MetaElems->SetPrintLevel(PrintLevel);
01225       MetaElems->Print(os);   
01226    }   
01227    for(ListDicomDirPatient::iterator cc  = Patients.begin();
01228                                      cc != Patients.end();
01229                                    ++cc)
01230    {
01231      (*cc)->SetPrintLevel(PrintLevel);
01232      (*cc)->Print(os);
01233    }
01234 }
01235 
01236 //-----------------------------------------------------------------------------
01237 } // end namespace gdcm

Generated on Fri Aug 24 12:59:29 2007 for gdcm by  doxygen 1.4.6