
| Current Path : /usr/include/gdcm-3.0/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //usr/include/gdcm-3.0/gdcmImplicitDataElement.txx |
/*=========================================================================
Program: GDCM (Grassroots DICOM). A DICOM library
Copyright (c) 2006-2011 Mathieu Malaterre
All rights reserved.
See Copyright.txt or http://gdcm.sourceforge.net/Copyright.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 notice for more information.
=========================================================================*/
#ifndef GDCMIMPLICITDATAELEMENT_TXX
#define GDCMIMPLICITDATAELEMENT_TXX
#include "gdcmSequenceOfItems.h"
#include "gdcmValueIO.h"
#include "gdcmSwapper.h"
#ifdef GDCM_WORDS_BIGENDIAN
#include "gdcmTagToVR.h"
#endif
namespace gdcm_ns
{
//-----------------------------------------------------------------------------
template <typename TSwap>
std::istream &ImplicitDataElement::Read(std::istream &is)
{
ReadPreValue<TSwap>(is);
return ReadValue<TSwap>(is);
}
template <typename TSwap>
std::istream &ImplicitDataElement::ReadPreValue(std::istream& is)
{
TagField.Read<TSwap>(is);
// See PS 3.5, 7.1.3 Data Element Structure With Implicit VR
// Read Tag
if( !is )
{
if( !is.eof() ) // FIXME This should not be needed
assert(0 && "Should not happen");
return is;
}
const Tag itemStartItem(0xfffe,0xe000);
if( TagField == itemStartItem ) return is;
//assert( TagField != Tag(0xfffe,0xe0dd) );
// Read Value Length
if( !ValueLengthField.Read<TSwap>(is) )
{
//assert(0 && "Should not happen");
throw Exception("Impossible ValueLengthField");
return is;
}
return is;
}
template <typename TSwap>
std::istream &ImplicitDataElement::ReadValue(std::istream &is, bool readvalues)
{
if( is.eof() ) return is;
const Tag itemStartItem(0xfffe,0xe000);
assert( TagField != itemStartItem );
/*
* technically this should not be needed, but what if an implementor, forgot
* to set VL = 0, then we should make sure to exit early
*/
const Tag itemDelItem(0xfffe,0xe00d);
if( TagField == itemDelItem )
{
if( ValueLengthField != 0 )
{
gdcmWarningMacro( "VL should be set to 0" );
}
ValueField = nullptr;
return is;
}
//std::cerr << "imp cur tag=" << TagField << " VL=" << ValueLengthField << std::endl;
//if( ValueLengthField > length && !ValueLengthField.IsUndefined() )
// {
// gdcmWarningMacro( "Cannot read more length than what is remaining in the file" );
// throw Exception( "Impossible" );
// }
if( ValueLengthField == 0 )
{
// Simple fast path
ValueField = nullptr;
return is;
}
else if( ValueLengthField.IsUndefined() )
{
//assert( de.GetVR() == VR::SQ );
// FIXME what if I am reading the pixel data...
//assert( TagField != Tag(0x7fe0,0x0010) );
if( TagField != Tag(0x7fe0,0x0010) )
{
ValueField = new SequenceOfItems;
}
else
{
gdcmErrorMacro( "Undefined value length is impossible in non-encapsulated Transfer Syntax. Proceeding with caution" );
ValueField = new SequenceOfFragments;
}
//VRField = VR::SQ;
}
else
{
if( true /*ValueLengthField < 8 */ )
{
ValueField = new ByteValue;
}
else
{
// In the following we read 4 more bytes in the Value field
// to find out if this is a SQ or not
// there is still work to do to handle the PMS featured SQ
// where item Start is in fact 0xfeff, 0x00e0 ... sigh
const Tag itemStart(0xfffe, 0xe000);
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
const Tag itemPMSStart(0xfeff, 0x00e0);
const Tag itemPMSStart2(0x3f3f, 0x3f00);
#endif
Tag item;
// TODO FIXME
// This is pretty dumb to actually read to later on seekg back, why not `peek` directly ?
item.Read<TSwap>(is);
// Maybe this code can later be rewritten as I believe that seek back
// is very slow...
is.seekg(-4, std::ios::cur );
if( item == itemStart )
{
assert( TagField != Tag(0x7fe0,0x0010) );
ValueField = new SequenceOfItems;
}
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
else if ( item == itemPMSStart )
{
// MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm
gdcmWarningMacro( "Illegal Tag for Item starter: " << TagField << " should be: " << itemStart );
// TODO: We READ Explicit ok...but we store Implicit !
// Indeed when copying the VR will be saved... pretty cool eh ?
ValueField = new SequenceOfItems;
ValueField->SetLength(ValueLengthField); // perform realloc
std::streampos start = is.tellg();
try
{
if( !ValueIO<ExplicitDataElement,SwapperDoOp>::Read(is,*ValueField,readvalues) )
{
assert(0 && "Should not happen");
}
gdcmWarningMacro( "Illegal: Explicit SQ found in a file with "
"TransferSyntax=Implicit for tag: " << TagField );
}
catch( Exception & )
{
// MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm
std::streampos current = is.tellg();
std::streamoff diff = start - current;
is.seekg( diff, std::ios::cur );
assert( diff == -14 );
ValueIO<ImplicitDataElement,SwapperDoOp>::Read(is,*ValueField,readvalues);
}
catch( std::exception & )
{
ValueLengthField = ValueField->GetLength();
}
return is;
}
else if ( item == itemPMSStart2 && false )
{
gdcmWarningMacro( "Illegal: SQ start with " << itemPMSStart2
<< " instead of " << itemStart << " for tag: " << TagField );
ValueField = new SequenceOfItems;
ValueField->SetLength(ValueLengthField); // perform realloc
if( !ValueIO<ImplicitDataElement,TSwap>::Read(is,*ValueField,readvalues) )
{
assert(0 && "Should not happen");
}
return is;
}
#endif
else
{
ValueField = new ByteValue;
}
}
}
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
// THE WORST BUG EVER. From GE Workstation
if( ValueLengthField == 13 )
{
// Historically gdcm did not enforce proper length
// thus Theralys started writing illegal DICOM images:
const Tag theralys1(0x0008,0x0070);
const Tag theralys2(0x0008,0x0080);
if( TagField != theralys1
&& TagField != theralys2 )
{
gdcmWarningMacro( "GE,13: Replacing VL=0x000d with VL=0x000a, for Tag="
<< TagField << " in order to read a buggy DICOM file." );
ValueLengthField = 10;
}
}
#endif
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
if( ValueLengthField == 0x31f031c && TagField == Tag(0x031e,0x0324) )
{
// TestImages/elbow.pap
gdcmWarningMacro( "Replacing a VL. To be able to read a supposively "
"broken Payrus file." );
ValueLengthField = 202; // 0xca
}
#endif
// We have the length we should be able to read the value
this->SetValueFieldLength( ValueLengthField, readvalues );
bool failed;
#ifdef GDCM_WORDS_BIGENDIAN
VR vrfield = GetVRFromTag( TagField );
if( vrfield & VR::VRASCII || vrfield == VR::INVALID )
{
//assert( VRField.GetSize() == 1 );
failed = !ValueIO<ImplicitDataElement,TSwap>::Read(is,*ValueField,readvalues);
}
else
{
assert( vrfield & VR::VRBINARY );
unsigned int vrsize = vrfield.GetSize();
assert( vrsize == 1 || vrsize == 2 || vrsize == 4 || vrsize == 8 );
if(vrfield==VR::AT) vrsize = 2;
switch(vrsize)
{
case 1:
failed = !ValueIO<ImplicitDataElement,TSwap,uint8_t>::Read(is,*ValueField,readvalues);
break;
case 2:
failed = !ValueIO<ImplicitDataElement,TSwap,uint16_t>::Read(is,*ValueField,readvalues);
break;
case 4:
failed = !ValueIO<ImplicitDataElement,TSwap,uint32_t>::Read(is,*ValueField,readvalues);
break;
case 8:
failed = !ValueIO<ImplicitDataElement,TSwap,uint64_t>::Read(is,*ValueField,readvalues);
break;
default:
failed = true;
assert(0);
}
}
#else
failed = !ValueIO<ImplicitDataElement,TSwap>::Read(is,*ValueField,readvalues);
#endif
if( failed )
{
// Special handling for PixelData tag:
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
if( TagField == Tag(0x7fe0,0x0010) )
{
gdcmWarningMacro( "Incomplete Pixel Data found, use file at own risk" );
is.clear();
}
else
#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */
{
throw Exception("Should not happen (imp)");
}
return is;
}
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
// dcmtk 3.5.4 is resilient to broken explicit SQ length and will properly
// recompute it as long as each of the Item lengths are correct
VL dummy = ValueField->GetLength();
if( ValueLengthField != dummy )
{
gdcmWarningMacro( "ValueLengthField was bogus" ); assert(0);
ValueLengthField = dummy;
}
#else
assert( ValueLengthField == ValueField->GetLength() );
assert( VRField == VR::INVALID );
#endif
return is;
}
//-----------------------------------------------------------------------------
template <typename TSwap>
std::istream &ImplicitDataElement::ReadWithLength(std::istream &is, VL & length, bool readvalues)
{
ReadPreValue<TSwap>(is);
return ReadValueWithLength<TSwap>(is, length, readvalues);
}
template <typename TSwap>
std::istream &ImplicitDataElement::ReadValueWithLength(std::istream& is, VL & length, bool readvalues)
{
if( is.eof() ) return is;
const Tag itemStartItem(0xfffe,0xe000);
if( TagField == itemStartItem ) return is;
/*
* technically this should not be needed, but what if an implementor, forgot
* to set VL = 0, then we should make sure to exit early
*/
const Tag itemDelItem(0xfffe,0xe00d);
if( TagField == itemDelItem )
{
if( ValueLengthField != 0 )
{
gdcmWarningMacro( "VL should be set to 0" );
}
ValueField = nullptr;
return is;
}
//std::cerr << "imp cur tag=" << TagField << " VL=" << ValueLengthField << std::endl;
if( ValueLengthField > length && !ValueLengthField.IsUndefined() )
{
gdcmWarningMacro( "Cannot read more length than what is remaining in the file" );
throw Exception( "Impossible (more)" );
}
if( ValueLengthField == 0 )
{
// Simple fast path
ValueField = nullptr;
return is;
}
else if( ValueLengthField.IsUndefined() )
{
//assert( de.GetVR() == VR::SQ );
// FIXME what if I am reading the pixel data...
//assert( TagField != Tag(0x7fe0,0x0010) );
if( TagField != Tag(0x7fe0,0x0010) )
{
ValueField = new SequenceOfItems;
}
else
{
gdcmErrorMacro( "Undefined value length is impossible in non-encapsulated Transfer Syntax. Proceeding with caution" );
ValueField = new SequenceOfFragments;
}
//VRField = VR::SQ;
}
else
{
if( true /*ValueLengthField < 8*/ )
{
ValueField = new ByteValue;
}
else
{
// In the following we read 4 more bytes in the Value field
// to find out if this is a SQ or not
// there is still work to do to handle the PMS featured SQ
// where item Start is in fact 0xfeff, 0x00e0 ... sigh
const Tag itemStart(0xfffe, 0xe000);
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
const Tag itemPMSStart(0xfeff, 0x00e0);
const Tag itemPMSStart2(0x3f3f, 0x3f00);
#endif
Tag item;
// TODO FIXME
// This is pretty dumb to actually read to later on seekg back, why not `peek` directly ?
item.Read<TSwap>(is);
// Maybe this code can later be rewritten as I believe that seek back
// is very slow...
is.seekg(-4, std::ios::cur );
if( item == itemStart )
{
assert( TagField != Tag(0x7fe0,0x0010) );
ValueField = new SequenceOfItems;
}
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
else if ( item == itemPMSStart )
{
// MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm
gdcmWarningMacro( "Illegal Tag for Item starter: " << TagField << " should be: " << itemStart );
// TODO: We READ Explicit ok...but we store Implicit !
// Indeed when copying the VR will be saved... pretty cool eh ?
ValueField = new SequenceOfItems;
ValueField->SetLength(ValueLengthField); // perform realloc
std::streampos start = is.tellg();
try
{
if( !ValueIO<ExplicitDataElement,SwapperDoOp>::Read(is,*ValueField,readvalues) )
{
assert(0 && "Should not happen");
}
gdcmWarningMacro( "Illegal: Explicit SQ found in a file with "
"TransferSyntax=Implicit for tag: " << TagField );
}
catch( Exception &)
{
// MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm
std::streampos current = is.tellg();
std::streamoff diff = start - current;//could be bad, if the specific implementation does not support negative streamoff values.
is.seekg( diff, std::ios::cur );
assert( diff == -14 );
ValueIO<ImplicitDataElement,SwapperDoOp>::Read(is,*ValueField,readvalues);
}
catch( std::exception & )
{
ValueLengthField = ValueField->GetLength();
}
return is;
}
else if ( item == itemPMSStart2 )
{
assert( 0 ); // FIXME: Sync Read/ReadWithLength
gdcmWarningMacro( "Illegal: SQ start with " << itemPMSStart2
<< " instead of " << itemStart << " for tag: " << TagField );
ValueField = new SequenceOfItems;
ValueField->SetLength(ValueLengthField); // perform realloc
if( !ValueIO<ImplicitDataElement,TSwap>::Read(is,*ValueField,readvalues) )
{
assert(0 && "Should not happen");
}
return is;
}
#endif
else
{
ValueField = new ByteValue;
}
}
}
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
// THE WORST BUG EVER. From GE Workstation
if( ValueLengthField == 13 )
{
// Historically gdcm did not enforce proper length
// thus Theralys started writing illegal DICOM images:
const Tag theralys1(0x0008,0x0070);
const Tag theralys2(0x0008,0x0080);
if( TagField != theralys1
&& TagField != theralys2 )
{
gdcmWarningMacro( "GE,13: Replacing VL=0x000d with VL=0x000a, for Tag="
<< TagField << " in order to read a buggy DICOM file." );
ValueLengthField = 10;
}
}
#endif
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
if( ValueLengthField == 0x31f031c && TagField == Tag(0x031e,0x0324) )
{
// TestImages/elbow.pap
gdcmWarningMacro( "Replacing a VL. To be able to read a supposively"
"broken Payrus file." );
ValueLengthField = 202; // 0xca
}
#endif
// We have the length we should be able to read the value
ValueField->SetLength(ValueLengthField); // perform realloc
bool failed;
#ifdef GDCM_WORDS_BIGENDIAN
VR vrfield = GetVRFromTag( TagField );
if( vrfield & VR::VRASCII || vrfield == VR::INVALID )
{
//assert( VRField.GetSize() == 1 );
failed = !ValueIO<ImplicitDataElement,TSwap>::Read(is,*ValueField,readvalues);
}
else
{
assert( vrfield & VR::VRBINARY );
unsigned int vrsize = vrfield.GetSize();
assert( vrsize == 1 || vrsize == 2 || vrsize == 4 || vrsize == 8 );
if(vrfield==VR::AT) vrsize = 2;
switch(vrsize)
{
case 1:
failed = !ValueIO<ImplicitDataElement,TSwap,uint8_t>::Read(is,*ValueField,readvalues);
break;
case 2:
failed = !ValueIO<ImplicitDataElement,TSwap,uint16_t>::Read(is,*ValueField,readvalues);
break;
case 4:
failed = !ValueIO<ImplicitDataElement,TSwap,uint32_t>::Read(is,*ValueField,readvalues);
break;
case 8:
failed = !ValueIO<ImplicitDataElement,TSwap,uint64_t>::Read(is,*ValueField,readvalues);
break;
default:
failed = true;
assert(0);
}
}
#else
failed = !ValueIO<ImplicitDataElement,TSwap>::Read(is,*ValueField,readvalues);
#endif
if( failed )
//if( !ValueIO<ImplicitDataElement,TSwap>::Read(is,*ValueField) )
{
// Special handling for PixelData tag:
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
if( TagField == Tag(0x7fe0,0x0010) )
{
gdcmWarningMacro( "Incomplete Pixel Data found, use file at own risk" );
is.clear();
}
else
#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */
{
throw Exception("Should not happen (imp)");
}
return is;
}
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
// dcmtk 3.5.4 is resilient to broken explicit SQ length and will properly recompute it
// as long as each of the Item lengths are correct
VL dummy = ValueField->GetLength();
if( ValueLengthField != dummy )
{
gdcmWarningMacro( "ValueLengthField was bogus" );
ValueLengthField = dummy;
}
#else
assert( ValueLengthField == ValueField->GetLength() );
assert( VRField == VR::INVALID );
#endif
return is;
}
//-----------------------------------------------------------------------------
template <typename TSwap>
const std::ostream &ImplicitDataElement::Write(std::ostream &os) const
{
// See PS 3.5, 7.1.3 Data Element Structure With Implicit VR
// Write Tag
if( !TagField.Write<TSwap>(os) )
{
assert(0 && "Should not happen");
return os;
}
// Write Value Length
const SequenceOfItems *sqi = dynamic_cast<const SequenceOfItems*>( ValueField.GetPointer() ); //GetSequenceOfItems();
if( sqi && !ValueLengthField.IsUndefined() )
{
// Hum, we might have to recompute the length:
// See TestWriter2, where an explicit SQ is converted to implicit SQ
VL len = sqi->template ComputeLength<ImplicitDataElement>();
//assert( len == ValueLengthField );
if( !len.Write<TSwap>(os) )
{
assert(0 && "Should not happen");
return os;
}
}
else // It should be safe to simply use the ValueLengthField as stored:
{
// Do not allow writing file such as: dcm4che_UndefinedValueLengthInImplicitTS.dcm
if( TagField == Tag(0x7fe0,0x0010) && ValueLengthField.IsUndefined() ) throw Exception( "VL u/f Impossible" );
if( !ValueLengthField.Write<TSwap>(os) )
{
assert(0 && "Should not happen");
return os;
}
}
// Write Value
if( ValueLengthField )
{
assert( ValueField );
gdcmAssertAlwaysMacro( ValueLengthField == ValueField->GetLength() );
assert( TagField != Tag(0xfffe, 0xe00d)
&& TagField != Tag(0xfffe, 0xe0dd) );
if( !ValueIO<ImplicitDataElement,TSwap>::Write(os,*ValueField) )
{
assert(0 && "Should not happen");
return os;
}
}
return os;
}
} // end namespace gdcm_ns
#endif // GDCMIMPLICITDATAELEMENT_TXX