📄 gdcmdocument.cxx
字号:
}
else if ( s1 > s2 )
{
return false;
}
else
{
// Patient ID
s1 = GetEntryValue(0x0010,0x0020);
s2 = document.GetEntryValue(0x0010,0x0020);
if ( s1 < s2 )
{
return true;
}
else if ( s1 > s2 )
{
return false;
}
else
{
// Study Instance UID
s1 = GetEntryValue(0x0020,0x000d);
s2 = document.GetEntryValue(0x0020,0x000d);
if ( s1 < s2 )
{
return true;
}
else if ( s1 > s2 )
{
return false;
}
else
{
// Serie Instance UID
s1 = GetEntryValue(0x0020,0x000e);
s2 = document.GetEntryValue(0x0020,0x000e);
if ( s1 < s2 )
{
return true;
}
else if ( s1 > s2 )
{
return false;
}
}
}
}
return false;
}
//-----------------------------------------------------------------------------
// Protected
/**
* \brief Reads a supposed to be 16 Bits integer
* (swaps it depending on processor endianness)
* @return read value
*/
uint16_t Document::ReadInt16()
throw( FormatError )
{
uint16_t g;
Fp->read ((char*)&g, (size_t)2);
if ( Fp->fail() )
{
throw FormatError( "Document::ReadInt16()", " file error." );
}
if ( Fp->eof() )
{
throw FormatError( "Document::ReadInt16()", "EOF." );
}
g = SwapShort(g);
return g;
}
/**
* \brief Reads a supposed to be 32 Bits integer
* (swaps it depending on processor endianness)
* @return read value
*/
uint32_t Document::ReadInt32()
throw( FormatError )
{
uint32_t g;
Fp->read ((char*)&g, (size_t)4);
if ( Fp->fail() )
{
throw FormatError( "Document::ReadInt32()", " file error." );
}
if ( Fp->eof() )
{
throw FormatError( "Document::ReadInt32()", "EOF." );
}
g = SwapLong(g);
return g;
}
/**
* \brief skips bytes inside the source file
* \warning NOT end user intended method !
* @return
*/
void Document::SkipBytes(uint32_t nBytes)
{
//FIXME don't dump the returned value
Fp->seekg((long)nBytes, std::ios::cur);
}
/**
* \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
*/
int Document::ComputeGroup0002Length( /*FileType filetype*/ )
{
uint16_t gr;
std::string vr;
int groupLength = 0;
bool found0002 = false;
// for each zero-level Tag in the DCM Header
DocEntry *entry = GetFirstEntry();
while( entry )
{
gr = entry->GetGroup();
if ( gr == 0x0002 )
{
found0002 = true;
if ( entry->GetElement() != 0x0000 )
{
vr = entry->GetVR();
//if ( (vr == "OB")||(vr == "OW")||(vr == "UT")||(vr == "SQ"))
// (no SQ, OW, UT in group 0x0002;)
if ( vr == "OB" )
{
// explicit VR AND (OB, OW, SQ, UT) : 4 more bytes
groupLength += 4;
}
groupLength += 2 + 2 + 4 + entry->GetLength();
}
}
else if (found0002 )
break;
entry = GetNextEntry();
}
return groupLength;
}
//-----------------------------------------------------------------------------
// Private
/**
* \brief Loads all the needed Dictionaries
* \warning NOT end user intended method !
*/
void Document::Initialize()
{
RefPubDict = Global::GetDicts()->GetDefaultPubDict();
RefShaDict = NULL;
Filetype = Unknown;
}
/**
* \brief Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries)
* @param set DocEntrySet we are going to parse ('zero level' or a SQItem)
* @param offset start of parsing
* @param l_max length to parse (meaningless when we are in 'delimitor mode')
* @param delim_mode : whether we are in 'delimitor mode' (l=0xffffff) or not
*/
void Document::ParseDES(DocEntrySet *set, long offset,
long l_max, bool delim_mode)
{
DocEntry *newDocEntry;
ValEntry *newValEntry;
BinEntry *newBinEntry;
SeqEntry *newSeqEntry;
VRKey vr;
bool used; // will be set to false when something wrong happens to an Entry.
// (Entry will then be deleted)
bool delim_mode_intern = delim_mode;
bool first = true;
gdcmDebugMacro( "Enter in ParseDES, delim-mode " << delim_mode
<< " at offset " << std::hex << "0x(" << offset << ")" );
while (true)
{
if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max)
{
break;
}
newDocEntry = ReadNextDocEntry( );
// FIXME :
// Private tag, in IMplicit VR are defaulted as a BinEntry,
// Very often they are only composed of Printable characters,
// and could be defaulted as a ValEntry.
// It's too late to do the Job
// (we should check the value, but we know it after LoadDocEntry ...)
// --> in next gdcm major release let's unify ValEntry and BinEntry !
// Uncoment this printf line to be able to 'follow' the DocEntries
// when something *very* strange happens
if ( !newDocEntry )
{
break;
}
// an Item Starter found elsewhere but the first position
// of a SeqEntry means previous entry was a Sequence
// but we didn't get it (private Sequence + Implicit VR)
// we have to backtrack.
if ( !first && newDocEntry->IsItemStarter() )
{
// Debug message within the method !
newDocEntry = Backtrack(newDocEntry);
}
else
{
PreviousDocEntry = newDocEntry;
}
used = true;
newValEntry = dynamic_cast<ValEntry*>(newDocEntry);
newBinEntry = dynamic_cast<BinEntry*>(newDocEntry);
if ( newValEntry || newBinEntry )
{
//////////////////////////// ContentEntry
if ( newBinEntry )
{
vr = newDocEntry->GetVR();
if ( Filetype == ExplicitVR &&
!Global::GetVR()->IsVROfBinaryRepresentable(vr) )
{
////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
gdcmWarningMacro( std::hex << newDocEntry->GetGroup()
<< "|" << newDocEntry->GetElement()
<< " : Neither Valentry, nor BinEntry."
"Probably unknown VR.");
}
//////////////////// BinEntry or UNKOWN VR:
// When "this" is a Document the Key is simply of the
// form ( group, elem )...
//if ( set == this ) // ( dynamic_cast< Document* > ( set ) )
//{
// newBinEntry->SetKey( newBinEntry->GetKey() );
//}
// but when "this" is a SQItem, we are inserting this new
// valEntry in a sequence item, and the key has the
// generalized form (refer to \ref BaseTagKey):
// time waste hunting
//if (SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ) )
//{
// newBinEntry->SetKey( parentSQItem->GetBaseTagKey()
// + newBinEntry->GetKey() );
//}
if ( !set->AddEntry( newBinEntry ) )
{
gdcmWarningMacro( "in ParseDES : cannot add a BinEntry "
<< newBinEntry->GetKey()
<< " (at offset : "
<< newBinEntry->GetOffset() << " )" );
used=false;
}
else
{
// Load only if we can add (not a duplicate key)
LoadDocEntry( newBinEntry );
}
} // end BinEntry
else
{
/////////////////////// ValEntry
// When "set" is a Document, then we are at the top of the
// hierarchy and the Key is simply of the form ( group, elem )...
//if ( set == this ) // ( dynamic_cast< Document* > ( set ) )
//{
// newValEntry->SetKey( newValEntry->GetKey() );
//}
// ...but when "set" is a SQItem, we are inserting this new
// valEntry in a sequence item. Hence the key has the
// generalized form (refer to \ref BaseTagKey):
// time waste hunting
//if (SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ) )
//{
// newValEntry->SetKey( parentSQItem->GetBaseTagKey()
// + newValEntry->GetKey() );
//}
if ( !set->AddEntry( newValEntry ) )
{
gdcmWarningMacro( "in ParseDES : cannot add a ValEntry "
<< newValEntry->GetKey()
<< " (at offset : "
<< newValEntry->GetOffset() << " )" );
used=false;
}
else
{
// Load only if we can add (not a duplicate key)
LoadDocEntry( newValEntry );
}
if ( newValEntry->GetElement() == 0x0000 ) // if on group length
{
if ( newValEntry->GetGroup()%2 != 0 ) // if Shadow Group
{
if ( LoadMode & LD_NOSHADOW ) // if user asked to skip shad.gr
{
std::string strLgrGroup = newValEntry->GetValue();
int lgrGroup;
if ( strLgrGroup != GDCM_UNFOUND)
{
lgrGroup = atoi(strLgrGroup.c_str());
Fp->seekg(lgrGroup, std::ios::cur);
//used = false; // never used
RemoveEntry( newDocEntry ); // Remove and delete
// bcc 5.5 is right "assigned a value that's never used"
// newDocEntry = 0;
continue;
}
}
}
}
bool delimitor = newValEntry->IsItemDelimitor();
if ( (delimitor) ||
(!delim_mode && ((long)(Fp->tellg())-offset) >= l_max) )
{
if ( !used )
delete newDocEntry;
break;
}
}
// Just to make sure we are at the beginning of next entry.
SkipToNextDocEntry(newDocEntry);
}
else
{
/////////////////////// SeqEntry : VR = "SQ"
unsigned long l = newDocEntry->GetReadLength();
if ( l != 0 ) // don't mess the delim_mode for 'zero-length sequence'
{
if ( l == 0xffffffff )
{
delim_mode_intern = true;
}
else
{
delim_mode_intern = false;
}
}
if ( (LoadMode & LD_NOSHADOWSEQ) && ! delim_mode_intern )
{
// User asked to skip SeQuences *only* if they belong to Shadow Group
if ( newDocEntry->GetGroup()%2 != 0 )
{
Fp->seekg( l, std::ios::cur);
RemoveEntry( newDocEntry ); // Remove and delete
continue;
}
}
if ( (LoadMode & LD_NOSEQ) && ! delim_mode_intern )
{
// User asked to skip *any* SeQuence
Fp->seekg( l, std::ios::cur);
RemoveEntry( newDocEntry ); // Remove and delete
continue;
}
// delay the dynamic cast as late as possible
newSeqEntry = dynamic_cast<SeqEntry*>(newDocEntry);
// no other way to create the Delimitor ...
newSeqEntry->SetDelimitorMode( delim_mode_intern );
// At the top of the hierarchy, stands a Document. When "set"
// is a Document, then we are building the first depth level.
// Hence the SeqEntry we are building simply has a depth
// level of one:
if ( set == this ) // ( dynamic_cast< Document* > ( set ) )
{
newSeqEntry->SetDepthLevel( 1 );
}
// But when "set" is already a SQItem, we are building a nested
// sequence, and hence the depth level of the new SeqEntry
// we are building, is one level deeper:
// time waste hunting
else if (SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ) )
{
newSeqEntry->SetDepthLevel( parentSQItem->GetDepthLevel() + 1 );
}
if ( l != 0 )
{ // Don't try to parse zero-length sequences
gdcmDebugMacro( "Entry in ParseSQ, delim " << delim_mode_intern
<< " at offset 0x(" << std::hex
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -