📄 gdcmdicomdir.cxx
字号:
/*=========================================================================
Program: gdcm
Module: $RCSfile: gdcmDicomDir.cxx,v $
Language: C++
Date: $Date: 2008-05-26 00:47:50 $
Version: $Revision: 1.13 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
//-----------------------------------------------------------------------------
// For full DICOMDIR description, see:
// PS 3.3-2003, pages 731-750
//-----------------------------------------------------------------------------
#include "gdcmDicomDir.h"
#include "gdcmDicomDirObject.h"
#include "gdcmDicomDirStudy.h"
#include "gdcmDicomDirSerie.h"
#include "gdcmDicomDirVisit.h"
#include "gdcmDicomDirImage.h"
#include "gdcmDicomDirPatient.h"
#include "gdcmDicomDirMeta.h"
#include "gdcmDicomDirElement.h"
#include "gdcmDirList.h"
#include "gdcmUtil.h"
#include "gdcmDebug.h"
#include "gdcmGlobal.h"
#include "gdcmFile.h"
#include "gdcmSeqEntry.h"
#include "gdcmSQItem.h"
#include "gdcmValEntry.h"
#include <fstream>
#include <string>
#include <algorithm>
#include <sys/types.h>
#ifdef _MSC_VER
# define getcwd _getcwd
#endif
#if defined(_MSC_VER) || defined(__BORLANDC__)
# include <direct.h>
#else
# include <unistd.h>
#endif
#if defined(__BORLANDC__)
#include <mem.h> // for memset
#endif
// ----------------------------------------------------------------------------
// Note for future developpers
// ----------------------------------------------------------------------------
//
// Dicom PS 3.3 describes the relationship between Directory Records, as follow
// (see also PS 4.3, 2004, page 50 for Entity-Relationship model)
//
// Directory Record Type Directory Record Types which may be included
// in the next lower-level directory Entity
//
// (Root directory Entity) PATIENT, TOPIC, PRIVATE
//
// PATIENT STUDY, PRIVATE
//
// STUDY SERIES, VISIT, RESULTS, STUDY COMPONENT, PRIVATE
//
// SERIES IMAGE, OVERLAYS, MODALITY LUT, VOI LUT,
// CURVE, STORED PRINT, RT DOSE, RT STRUCTURE SET
// RT PLAN, RT TREAT RECORD, PRESENTATION, WAVEFORM,
// SR DOCUMENT, KEY OBJECT DOC, SPECTROSCOPY,
// RAW DATA, REGISTRATION, FIDUCIAL, PRIVATE,
// ENCAP DOC
// IMAGE
// OVERLAY
// MODALITY LUT
// VOI LUT
// CURVE
// STORED PRINT
// RT DOSE
// RT STRUCTURE SET
// RT PLAN
// RT TREAT RECORD
// PRESENTATION
// WAVEFORM
// SR DOCUMENT
// KEY OBJECT DOC
// SPECTROSCOPY
// RAW DATA
// REGISTRATION
// FIDUCIAL
// PRIVATE
// ENCAP DOC
//
// ----------------------
// The current gdcm version only deals with :
//
// (Root directory Entity) PATIENT
// PATIENT STUDY
// STUDY SERIES
// STUDY VISIT
// SERIES IMAGE
// IMAGE /
//
// DicomDir::CreateDicomDir will have to be completed
// Treelike structure management will have to be upgraded
// ----------------------------------------------------------------------------
namespace gdcm
{
//-----------------------------------------------------------------------------
// Constructor / Destructor
/**
* \brief Constructor : creates an empty DicomDir
*/
DicomDir::DicomDir()
:Document( )
{
Initialize(); // sets all private fields to NULL
ParseDir = false;
NewMeta();
}
#ifndef GDCM_LEGACY_REMOVE
/**
* \brief Constructor Parses recursively the directory and creates the DicomDir
* or uses an already built DICOMDIR, depending on 'parseDir' value.
* @param fileName name
* - of the root directory (parseDir = true)
* - of the DICOMDIR (parseDir = false)
* @param parseDir boolean
* - true if user passed an entry point
* and wants to explore recursively the directories
* - false if user passed an already built DICOMDIR file
* and wants to use it
* @deprecated use : new DicomDir() + [ SetLoadMode(lm) + ] SetDirectoryName(name)
* or : new DicomDir() + SetFileName(name)
*/
DicomDir::DicomDir(std::string const &fileName, bool parseDir )
{
// At this step, Document constructor is already executed,
// whatever user passed (either a root directory or a DICOMDIR)
// and whatever the value of parseDir was.
// (nothing is cheked in Document constructor, to avoid overhead)
ParseDir = parseDir;
SetLoadMode (LD_ALL); // concerns only dicom files
SetFileName( fileName );
Load( );
}
#endif
/**
* \brief Canonical destructor
*/
DicomDir::~DicomDir()
{
SetStartMethod(NULL,NULL,NULL);
SetProgressMethod(NULL,NULL,NULL);
SetEndMethod(NULL,NULL,NULL);
ClearPatient();
if ( MetaElems )
{
delete MetaElems;
}
}
//-----------------------------------------------------------------------------
// Public
/**
* \brief Loader. use SetFileName(fn)
* or SetLoadMode(lm) + SetDirectoryName(dn) before !
* @return false if file cannot be open or no swap info was found,
* or no tag was found.
*/
bool DicomDir::Load( )
{
// We should clean out anything that already exists.
Initialize(); // sets all private fields to NULL
if (!ParseDir)
{
if ( ! this->Document::Load( ) )
return false;
}
return DoTheLoadingJob( );
}
#ifndef GDCM_LEGACY_REMOVE
/**
* \brief Loader. (DEPRECATED : kept not to break the API)
* @param fileName file to be open for parsing
* @return false if file cannot be open or no swap info was found,
* or no tag was found.
* @deprecated use SetFileName(n) + Load() instead
*/
bool DicomDir::Load(std::string const &fileName )
{
// We should clean out anything that already exists.
Initialize(); // sets all private fields to NULL
SetFileName( fileName );
if (!ParseDir)
{
if ( ! this->Document::Load( ) )
return false;
}
return DoTheLoadingJob( );
}
/// DEPRECATED : use SetDirectoryName(dname) instead
/**
* \brief Loader. (DEPRECATED : kept not to break the API)
* @param paseDir Parse Dir
* @deprecated use SetDirectoryName(dname) instead
*/
void DicomDir::SetParseDir(bool parseDir)
{
ParseDir = parseDir;
}
#endif
/**
* \brief Does the Loading Job (internal use only)
* @return false if file cannot be open or no swap info was found,
* or no tag was found.
*/
bool DicomDir::DoTheLoadingJob( )
{
// We should clean out anything that already exists.
Initialize(); // sets all private fields to NULL
if (!ParseDir)
{
// Only if user passed a DICOMDIR
// ------------------------------
Fp = 0;
if ( !OpenFile() )
{
return false;
}
if (!Document::Load() )
{
return false;
}
if ( GetFirstEntry() == 0 ) // when user passed a Directory to parse
{
gdcmWarningMacro( "Entry HT empty for file: "<< GetFileName());
return false;
}
// Directory record sequence
DocEntry *e = GetDocEntry(0x0004, 0x1220);
if ( !e )
{
gdcmWarningMacro( "NO 'Directory record sequence' (0x0004,0x1220)"
<< " in file " << GetFileName());
return false;
}
else
CreateDicomDir();
}
else
{
// Only if user passed a root directory
// ------------------------------------
if ( GetFileName() == "." )
{
// user passed '.' as Name
// we get current directory name
char buf[2048];
const char *cwd = getcwd(buf, 2048);
if( cwd )
{
SetFileName( buf ); // will be converted into a string
}
else
{
gdcmErrorMacro( "Path was too long to fit on 2048 bytes" );
}
}
NewMeta();
gdcmDebugMacro( "Parse directory and create the DicomDir : "
<< GetFileName() );
ParseDirectory();
}
return true;
}
/**
* \brief This predicate, based on hopefully reasonable heuristics,
* decides whether or not the current document was properly parsed
* and contains the mandatory information for being considered as
* a well formed and usable DicomDir.
* @return true when Document is the one of a reasonable DicomDir,
* false otherwise.
*/
bool DicomDir::IsReadable()
{
if ( Filetype == Unknown )
{
gdcmErrorMacro( "Wrong filetype for " << GetFileName());
return false;
}
if ( !MetaElems )
{
gdcmWarningMacro( "Meta Elements missing in DicomDir");
return false;
}
if ( Patients.size() <= 0 )
{
gdcmWarningMacro( "NO Patient in DicomDir");
return false;
}
return true;
}
/**
* \brief adds *the* Meta to a partially created DICOMDIR
*/
DicomDirMeta *DicomDir::NewMeta()
{
if ( MetaElems )
delete MetaElems;
DocEntry *entry = GetFirstEntry();
if ( entry )
{
MetaElems = new DicomDirMeta(true); // true = empty
entry = GetFirstEntry();
while( entry )
{
if ( dynamic_cast<SeqEntry *>(entry) )
break;
RemoveEntryNoDestroy(entry);
MetaElems->AddEntry(entry);
entry = GetFirstEntry();
}
}
else // after root directory parsing
{
MetaElems = new DicomDirMeta(false); // false = not empty
}
MetaElems->SetSQItemNumber(0); // To avoid further missprinting
return MetaElems;
}
/**
* \brief adds a new Patient (with the basic elements) to a partially created
* DICOMDIR
*/
DicomDirPatient *DicomDir::NewPatient()
{
DicomDirPatient *p = new DicomDirPatient();
AddPatientToEnd( p );
return p;
}
/**
* \brief Remove all Patients
*/
void DicomDir::ClearPatient()
{
for(ListDicomDirPatient::iterator cc = Patients.begin();
cc!= Patients.end();
++cc)
{
delete *cc;
}
Patients.clear();
}
/**
* \brief Get the first entry while visiting the DicomDirPatients
* \return The first DicomDirPatient if found, otherwhise NULL
*/
DicomDirPatient *DicomDir::GetFirstPatient()
{
ItPatient = Patients.begin();
if ( ItPatient != Patients.end() )
return *ItPatient;
return NULL;
}
/**
* \brief Get the next entry while visiting the DicomDirPatients
* \note : meaningfull only if GetFirstEntry already called
* \return The next DicomDirPatient if found, otherwhise NULL
*/
DicomDirPatient *DicomDir::GetNextPatient()
{
gdcmAssertMacro (ItPatient != Patients.end());
++ItPatient;
if ( ItPatient != Patients.end() )
return *ItPatient;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -