📄 gdcmdocument.cxx
字号:
<< newDocEntry->GetOffset() << ")");
ParseSQ( newSeqEntry,
static_cast< long >( newDocEntry->GetOffset() ),
l, delim_mode_intern);
gdcmDebugMacro( "Exit from ParseSQ, delim " << delim_mode_intern);
}
if ( !set->AddEntry( newSeqEntry ) )
{
gdcmWarningMacro( "in ParseDES : cannot add a SeqEntry "
<< newSeqEntry->GetKey()
<< " (at offset : 0x("
<< newSeqEntry->GetOffset() << ") )" );
used = false;
}
if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max)
{
if ( !used )
delete newDocEntry;
break;
}
} // end SeqEntry : VR = "SQ"
if ( !used )
{
delete newDocEntry;
}
first = false;
} // end While
gdcmDebugMacro( "Exit from ParseDES, delim-mode " << delim_mode );
}
/**
* \brief Parses a Sequence ( SeqEntry after SeqEntry)
* @return parsed length for this level
*/
void Document::ParseSQ( SeqEntry *seqEntry,
long offset, long l_max, bool delim_mode)
{
int SQItemNumber = 0;
bool dlm_mod;
long offsetStartCurrentSQItem = offset;
while (true)
{
// the first time, we read the fff0,e000 of the first SQItem
DocEntry *newDocEntry = ReadNextDocEntry();
if ( !newDocEntry )
{
gdcmWarningMacro("in ParseSQ : should never get here!");
break;
}
if ( delim_mode )
{
if ( newDocEntry->IsSequenceDelimitor() )
{
seqEntry->SetDelimitationItem( newDocEntry );
break;
}
}
if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max)
{
delete newDocEntry;
break;
}
// create the current SQItem
SQItem *itemSQ = new SQItem( seqEntry->GetDepthLevel() );
unsigned int l = newDocEntry->GetReadLength();
if ( l == 0xffffffff )
{
dlm_mod = true;
}
else
{
dlm_mod = false;
}
// remove fff0,e000, created out of the SQItem
delete newDocEntry;
// fill up the current SQItem, starting at the beginning of fff0,e000
ParseDES(itemSQ, offsetStartCurrentSQItem, l+8, dlm_mod);
offsetStartCurrentSQItem = Fp->tellg();
seqEntry->AddSQItem( itemSQ, SQItemNumber );
SQItemNumber++;
if ( !delim_mode && ((long)(Fp->tellg())-offset ) >= l_max )
{
break;
}
}
}
/**
* \brief When a private Sequence + Implicit VR is encountered
* we cannot guess it's a Sequence till we find the first
* Item Starter. We then backtrack to do the job.
* @param docEntry Item Starter that warned us
*/
DocEntry *Document::Backtrack(DocEntry *docEntry)
{
// delete the Item Starter, built erroneously out of any Sequence
// it's not yet in the HTable/chained list
delete docEntry;
// Get all info we can from PreviousDocEntry
uint16_t group = PreviousDocEntry->GetGroup();
uint16_t elem = PreviousDocEntry->GetElement();
uint32_t lgt = PreviousDocEntry->GetLength();
long offset = static_cast< long >( PreviousDocEntry->GetOffset() );
gdcmDebugMacro( "Backtrack :" << std::hex << group
<< "|" << elem
<< " at offset 0x(" <<offset << ")" );
RemoveEntry( PreviousDocEntry );
// forge the Seq Entry
DocEntry *newEntry = NewSeqEntry(group, elem);
newEntry->SetLength(lgt);
newEntry->SetOffset(offset);
// Move back to the beginning of the Sequence
Fp->seekg(offset, std::ios::beg); // Only for Shadow Implicit VR SQ
return newEntry;
}
/**
* \brief Loads (or not) the element content depending if its length exceeds
* or not the value specified with Document::SetMaxSizeLoadEntry()
* @param entry Header Entry (Dicom Element) to be dealt with
* @param forceLoad whether you want to force loading of 'long' elements
*/
void Document::LoadDocEntry(DocEntry *entry, bool forceLoad)
{
uint16_t group = entry->GetGroup();
uint16_t elem = entry->GetElement();
std::string vr = entry->GetVR();
uint32_t length = entry->GetLength();
Fp->seekg((long)entry->GetOffset(), std::ios::beg);
// A SeQuence "contains" a set of Elements.
// (fffe e000) tells us an Element is beginning
// (fffe e00d) tells us an Element just ended
// (fffe e0dd) tells us the current SeQuence just ended
// (fffe 0000) is an 'impossible' tag value,
// found in MR-PHILIPS-16-Multi-Seq.dcm
if ( (group == 0xfffe && elem != 0x0000 ) || vr == "SQ" )
{
// NO more value field for SQ !
return;
}
// When the length is zero things are easy:
if ( length == 0 )
{
((ValEntry *)entry)->SetValue("");
return;
}
// The elements whose length is bigger than the specified upper bound
// are not loaded. Instead we leave a short notice on the offset of
// the element content and it's length.
itksys_ios::ostringstream s;
if (!forceLoad)
{
if (length > MaxSizeLoadEntry)
{
if (BinEntry *binEntryPtr = dynamic_cast< BinEntry* >(entry) )
{
s << GDCM_NOTLOADED;
s << " Ad.:" << (long)entry->GetOffset();
s << " x(" << std::hex << entry->GetOffset() << ")";
s << std::dec;
s << " Lgt:" << entry->GetLength();
s << " x(" << std::hex << entry->GetLength() << ")";
binEntryPtr->SetValue(s.str());
}
else if (ValEntry *valEntryPtr = dynamic_cast< ValEntry* >(entry) )
{
s << GDCM_NOTLOADED;
s << " Address:" << (long)entry->GetOffset();
s << " Length:" << entry->GetLength();
s << " x(" << std::hex << entry->GetLength() << ")";
valEntryPtr->SetValue(s.str());
}
else
{
// fusible
gdcmErrorMacro( "MaxSizeLoadEntry exceeded, neither a BinEntry "
<< "nor a ValEntry ?! Should never print that !" );
}
// to be sure we are at the end of the value ...
// Fp->seekg((long)entry->GetOffset()+(long)entry->GetLength(),
// std::ios::beg);
return;
}
}
// When we find a BinEntry not very much can be done :
if (BinEntry *binEntryPtr = dynamic_cast< BinEntry* >(entry) )
{
s << GDCM_BINLOADED;
binEntryPtr->SetValue(s.str());
LoadEntryBinArea(binEntryPtr); // last one, not to erase length !
return;
}
if ( IsDocEntryAnInteger(entry) )
{
int nbInt;
// When short integer(s) are expected, read and convert the following
// (n * 2) characters properly i.e. consider them as short integers as
// opposed to strings.
// Elements with Value Multiplicity > 1
// contain a set of integers (not a single one)
if (vr == "US")
{
nbInt = length / 2;
uint16_t NewInt = ReadInt16();
s << NewInt;
if (nbInt > 1)
{
for (int i=1; i < nbInt; i++)
{
s << '\\';
NewInt = ReadInt16();
s << NewInt;
}
}
}
else if (vr == "SS")
{
nbInt = length / 2;
int16_t NewInt = ReadInt16();
s << NewInt;
if (nbInt > 1)
{
for (int i=1; i < nbInt; i++)
{
s << '\\';
NewInt = ReadInt16();
s << NewInt;
}
}
}
// See above comment on multiple integers (mutatis mutandis).
else if (vr == "UL")
{
nbInt = length / 4;
uint32_t NewInt = ReadInt32();
s << NewInt;
if (nbInt > 1)
{
for (int i=1; i < nbInt; i++)
{
s << '\\';
NewInt = ReadInt32();
s << NewInt;
}
}
}
else if (vr == "SL")
{
nbInt = length / 4;
int32_t NewInt = ReadInt32();
s << NewInt;
if (nbInt > 1)
{
for (int i=1; i < nbInt; i++)
{
s << '\\';
NewInt = ReadInt32();
s << NewInt;
}
}
}
#ifdef GDCM_NO_ANSI_STRING_STREAM
s << std::ends; // to avoid oddities on Solaris
#endif //GDCM_NO_ANSI_STRING_STREAM
((ValEntry *)entry)->SetValue(s.str());
return;
}
// FIXME: We need an additional byte for storing \0 that is not on disk
char *str = new char[length+1];
Fp->read(str, (size_t)length);
str[length] = '\0'; //this is only useful when length is odd
// Special DicomString call to properly handle \0 and even length
std::string newValue;
if ( length % 2 )
{
newValue = Util::DicomString(str, length+1);
gdcmWarningMacro("Warning: bad length: " << length <<
" For string :" << newValue.c_str());
// Since we change the length of string update it length
//entry->SetReadLength(length+1);
}
else
{
newValue = Util::DicomString(str, length);
}
delete[] str;
if ( ValEntry *valEntry = dynamic_cast<ValEntry* >(entry) )
{
if ( Fp->fail() || Fp->eof())
{
if ( Fp->fail() )
gdcmWarningMacro("--> fail");
gdcmWarningMacro("Unread element value " << valEntry->GetKey()
<< " lgt : " << valEntry->GetReadLength()
<< " at " << std::hex << valEntry->GetOffset());
valEntry->SetValue(GDCM_UNREAD);
return;
}
// if ( vr == "UI" )
// {
// // Because of correspondance with the VR dic
// valEntry->SetValue(newValue);
// }
// else
// {
// valEntry->SetValue(newValue);
// }
// Anybody remembers the genesis of strange previous (commented out) code?
valEntry->SetValue(newValue);
}
else
{
gdcmWarningMacro("Should have a ValEntry, here ! " << valEntry->GetKey()
<< " lgt : " << valEntry->GetReadLength()
<< " at " << std::hex << valEntry->GetOffset());
}
}
/**
* \brief Find the value Length of the passed Doc Entry
* @param entry Header Entry whose length of the value shall be loaded.
*/
void Document::FindDocEntryLength( DocEntry *entry, std::string vr )
throw ( FormatError )
{
uint16_t length16;
if ( Filetype == ExplicitVR && !entry->IsImplicitVR() )
{
if ( vr == "OB" || vr == "OW" || vr == "SQ" || vr == "UT"
|| vr == "UN" )
{
// The following reserved two bytes (see PS 3.5-2003, section
// "7.1.2 Data element structure with explicit vr", p 27) must be
// skipped before proceeding on reading the length on 4 bytes.
Fp->seekg( 2L, std::ios::cur); // Once per OW,OB,SQ DocEntry
uint32_t length32 = ReadInt32();
if ( (vr == "OB" || vr == "OW") && length32 == 0xffffffff )
{
uint32_t lengthOB;
try
{
lengthOB = FindDocEntryLengthOBOrOW();// for encapsulation of encoded pixel
}
catch ( FormatUnexpected )
{
// Computing the length failed (this happens with broken
// files like gdcm-JPEG-LossLess3a.dcm). We still have a
// chance to get the pixels by deciding the element goes
// until the end of the file. Hence we artificially fix the
// the length and proceed.
gdcmWarningMacro( " Computing the length failed for " <<
entry->GetKey() <<" in " <<GetFileName());
long currentPosition = Fp->tellg(); // Only for gdcm-JPEG-LossLess3a.dcm-like
Fp->seekg(0L,std::ios::end); // Only for gdcm-JPEG-LossLess3a.dcm-like
long lengthUntilEOF = (long)(Fp->tellg())-currentPosition; // Only for gdcm-JPEG-LossLess3a.dcm-like
Fp->seekg(currentPosition, std::ios::beg); // Only for gdcm-JPEG-LossLess3a.dcm-like
entry->SetReadLength(lengthUntilEOF);
entry->SetLength(lengthUntilEOF);
return;
}
entry->SetReadLength(lengthOB);
entry->SetLength(lengthOB);
return;
}
FixDocEntryFoundLength(entry, length32);
return;
}
// Length is encoded on 2 bytes.
length16 = ReadInt16();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -