/*========================================================================= 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 GDCMEXPLICITDATAELEMENT_TXX #define GDCMEXPLICITDATAELEMENT_TXX #include "gdcmSequenceOfItems.h" #include "gdcmSequenceOfFragments.h" #include "gdcmVL.h" #include "gdcmParseException.h" #include "gdcmImplicitDataElement.h" #include "gdcmValueIO.h" #include "gdcmSwapper.h" namespace gdcm_ns { //----------------------------------------------------------------------------- template std::istream &ExplicitDataElement::Read(std::istream &is) { ReadPreValue(is); return ReadValue(is); } template std::istream &ExplicitDataElement::ReadPreValue(std::istream &is) { TagField.Read(is); // See PS 3.5, Data Element Structure With Explicit VR // Read Tag if( !is ) { if( !is.eof() ) // FIXME This should not be needed { assert(0 && "Should not happen" ); } return is; } if( TagField == Tag(0xfffe,0xe0dd) ) { ParseException pe; pe.SetLastElement( *this ); throw pe; } //assert( TagField != Tag(0xfeff,0xdde0) ); const Tag itemDelItem(0xfffe,0xe00d); if( TagField == itemDelItem ) { if( !ValueLengthField.Read(is) ) { assert(0 && "Should not happen"); return is; } if( ValueLengthField ) { gdcmDebugMacro( "Item Delimitation Item has a length different from 0 and is: " << ValueLengthField ); } // Reset ValueLengthField to avoid user error ValueLengthField = 0; // Set pointer to NULL to avoid user error ValueField = nullptr; VRField = VR::INVALID; return is; } #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION if( TagField == Tag(0x00ff, 0x4aa5) ) { //assert(0 && "Should not happen" ); // gdcmDataExtra/gdcmBreakers/DigitexAlpha_no_7FE0.dcm is.seekg( -4, std::ios::cur ); TagField = Tag(0x7fe0,0x0010); VRField = VR::OW; ValueField = new ByteValue; std::streampos s = is.tellg(); is.seekg( 0, std::ios::end); std::streampos e = is.tellg(); is.seekg( s, std::ios::beg ); ValueField->SetLength( (int32_t)(e - s) ); ValueLengthField = ValueField->GetLength(); bool failed = !ValueIO::Read(is,*ValueField,true); gdcmAssertAlwaysMacro( !failed ); return is; //throw Exception( "Unhandled" ); } #endif // Read VR try { if( !VRField.Read(is) ) { assert(0 && "Should not happen" ); return is; } } catch( Exception &ex ) { #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION // gdcm-MR-PHILIPS-16-Multi-Seq.dcm // assert( TagField == Tag(0xfffe, 0xe000) ); // -> For some reason VR is written as {44,0} well I guess this is a VR... // Technically there is a second bug, dcmtk assume other things when reading this tag, // so I need to change this tag too, if I ever want dcmtk to read this file. oh well // 0019004_Baseline_IMG1.dcm // -> VR is garbage also... // assert( TagField == Tag(8348,0339) || TagField == Tag(b5e8,0338)) //gdcmWarningMacro( "Assuming 16 bits VR for Tag=" << // TagField << " in order to read a buggy DICOM file." ); //VRField = VR::INVALID; (void)ex; //compiler warning ParseException pe; pe.SetLastElement( *this ); throw pe; #else throw ex; #endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ } // Read Value Length if( VR::GetLength(VRField) == 4 ) { if( !ValueLengthField.Read(is) ) { assert(0 && "Should not happen"); return is; } } else { // 16bits only if( !ValueLengthField.template Read16(is) ) { assert(0 && "Should not happen"); return is; } #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION // HACK for SIEMENS Leonardo if( ValueLengthField == 0x0006 && VRField == VR::UL && TagField.GetGroup() == 0x0009 ) { gdcmWarningMacro( "Replacing VL=0x0006 with VL=0x0004, for Tag=" << TagField << " in order to read a buggy DICOM file." ); ValueLengthField = 0x0004; } #endif } //std::cerr << "exp cur tag=" << TagField << " VR=" << VRField << " VL=" << ValueLengthField << std::endl; // // I don't like the following 3 lines, what if 0000,0000 was indeed -wrongly- sent, we should be able to continue // chances is that 99% of times there is now way we can reach here, so safely throw an exception if( TagField == Tag(0x0000,0x0000) && ValueLengthField == 0 && VRField == VR::INVALID ) { ParseException pe; pe.SetLastElement( *this ); throw pe; } #ifdef ELSCINT1_01F7_1070 if( TagField == Tag(0x01f7,0x1070) ) { ValueLengthField = ValueLengthField - 7; } #endif return is; } template std::istream &ExplicitDataElement::ReadValue(std::istream &is, bool readvalues) { if( is.eof() ) return is; if( ValueLengthField == 0 ) { // Simple fast path ValueField = nullptr; return is; } // Read the Value //assert( ValueField == 0 ); if( VRField == VR::SQ ) { // Check whether or not this is an undefined length sequence assert( TagField != Tag(0x7fe0,0x0010) ); ValueField = new SequenceOfItems; } else if( ValueLengthField.IsUndefined() ) { if( TagField == Tag(0x7fe0,0x0010) ) { // Ok this is Pixel Data fragmented... assert( VRField & VR::OB_OW || VRField == VR::UN ); ValueField = new SequenceOfFragments; } else { // Support cp246 conforming file: // Enhanced_MR_Image_Storage_PixelSpacingNotIn_0028_0030.dcm (illegal) // vs // undefined_length_un_vr.dcm assert( TagField != Tag(0x7fe0,0x0010) ); assert( VRField == VR::UN ); ValueField = new SequenceOfItems; ValueField->SetLength(ValueLengthField); // perform realloc try { //if( !ValueIO::Read(is,*ValueField) ) // non cp246 if( !ValueIO::Read(is,*ValueField,readvalues) ) // cp246 compliant { assert(0); } } catch( std::exception &) { // Must be one of those non-cp246 file... // but for some reason seekg back to previous offset + Read // as Explicit does not work... ParseException pe; pe.SetLastElement(*this); throw pe; } return is; } } else { //assert( TagField != Tag(0x7fe0,0x0010) ); ValueField = new ByteValue; } // We have the length we should be able to read the value this->SetValueFieldLength( ValueLengthField, readvalues ); #if defined(GDCM_SUPPORT_BROKEN_IMPLEMENTATION) && 0 // PHILIPS_Intera-16-MONO2-Uncompress.dcm if( TagField == Tag(0x2001,0xe05f) || TagField == Tag(0x2001,0xe100) || TagField == Tag(0x2005,0xe080) || TagField == Tag(0x2005,0xe083) || TagField == Tag(0x2005,0xe084) || TagField == Tag(0x2005,0xe402) //TagField.IsPrivate() && VRField == VR::SQ //-> Does not work for 0029 //we really need to read item marker ) { gdcmWarningMacro( "ByteSwaping Private SQ: " << TagField ); assert( VRField == VR::SQ ); assert( TagField.IsPrivate() ); try { if( !ValueIO::Read(is,*ValueField,readvalues) ) { assert(0 && "Should not happen"); } Value* v = &*ValueField; SequenceOfItems *sq = dynamic_cast(v); assert( sq ); SequenceOfItems::Iterator it = sq->Begin(); for( ; it != sq->End(); ++it) { Item &item = *it; DataSet &ds = item.GetNestedDataSet(); ByteSwapFilter bsf(ds); bsf.ByteSwap(); } } catch( std::exception &ex ) { ValueLengthField = ValueField->GetLength(); } return is; } #endif bool failed; //assert( VRField != VR::UN ); if( VRField & VR::VRASCII ) { //assert( VRField.GetSize() == 1 ); failed = !ValueIO::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::Read(is,*ValueField,readvalues); break; case 2: failed = !ValueIO::Read(is,*ValueField,readvalues); break; case 4: failed = !ValueIO::Read(is,*ValueField,readvalues); break; case 8: failed = !ValueIO::Read(is,*ValueField,readvalues); break; default: failed = true; assert(0); } } if( failed ) { #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION if( TagField == Tag(0x7fe0,0x0010) ) { // BUG this should be moved to the ImageReader class, only this class // knows what 7fe0 actually is, and should tolerate partial Pixel Data // element... PMS-IncompletePixelData.dcm gdcmWarningMacro( "Incomplete Pixel Data found, use file at own risk" ); is.clear(); } else #endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ { // Might be the famous UN 16bits ParseException pe; pe.SetLastElement( *this ); throw pe; } return is; } #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION if( SequenceOfItems *sqi = dynamic_cast(&GetValue()) ) { assert( ValueField->GetLength() == ValueLengthField ); // Recompute the total length: if( !ValueLengthField.IsUndefined() ) { // PhilipsInteraSeqTermInvLen.dcm // contains an extra seq del item marker, which we are not loading. Therefore the // total length needs to be recomputed when sqi is expressed in defined length VL dummy = sqi->template ComputeLength(); ValueLengthField = dummy; sqi->SetLength( dummy ); gdcmAssertAlwaysMacro( dummy == ValueLengthField ); } } else if( SequenceOfFragments *sqf = dynamic_cast(&GetValue()) ) { assert( ValueField->GetLength() == ValueLengthField ); assert( sqf->GetLength() == ValueLengthField ); (void)sqf; assert( ValueLengthField.IsUndefined() ); } #endif return is; } template std::istream &ExplicitDataElement::ReadWithLength(std::istream &is, VL & length) { (void)length; return Read(is); } //----------------------------------------------------------------------------- template const std::ostream &ExplicitDataElement::Write(std::ostream &os) const { if( TagField == Tag(0xfffe,0xe0dd) ) throw Exception( "Impossible" ); //if( TagField == Tag(0xfffe,0xe0dd) ) return os; if( !TagField.Write(os) ) { assert( 0 && "Should not happen" ); return os; } const Tag itemDelItem(0xfffe,0xe00d); if( TagField == itemDelItem ) { assert(0); assert( ValueField == nullptr ); #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION if( ValueLengthField != 0 ) { gdcmWarningMacro( "Item Delimitation Item had a length different from 0." ); VL zero = 0; zero.Write(os); return os; } #endif // else assert( ValueLengthField == 0 ); if( !ValueLengthField.Write(os) ) { assert( 0 && "Should not happen" ); return os; } return os; } bool vr16bitsimpossible = (VRField & VR::VL16) && (ValueLengthField > (uint32_t)VL::GetVL16Max()); if( VRField == VR::INVALID || vr16bitsimpossible ) { if ( TagField.IsPrivateCreator() ) { gdcmAssertAlwaysMacro( !vr16bitsimpossible ); VR lo = VR::LO; if( TagField.IsGroupLength() ) { lo = VR::UL; } lo.Write(os); ValueLengthField.Write16(os); } else { const VR un = VR::UN; un.Write(os); if( ValueField && dynamic_cast(&*ValueField) ) { VL vl = 0xFFFFFFFF; assert( vl.IsUndefined() ); vl.Write(os); } else ValueLengthField.Write(os); } } else { assert( VRField.IsVRFile() && VRField != VR::INVALID ); if( !VRField.Write(os) ) { assert( 0 && "Should not happen" ); return os; } if( VRField & VR::VL32 ) { if( !ValueLengthField.Write(os) ) { assert( 0 && "Should not happen" ); return os; } } else { // 16bits only if( !ValueLengthField.template Write16(os) ) { assert( 0 && "Should not happen" ); return os; } } } if( ValueLengthField ) { // Special case, check SQ if ( GetVR() == VR::SQ ) { gdcmAssertAlwaysMacro( dynamic_cast(&GetValue()) ); } //#ifndef NDEBUG // check consistency in Length: if( GetByteValue() ) { assert( ValueField->GetLength() == ValueLengthField ); } //else if( GetSequenceOfItems() ) else if( const SequenceOfItems *sqi = dynamic_cast(&GetValue()) ) { assert( ValueField->GetLength() == ValueLengthField ); // Recompute the total length: if( !ValueLengthField.IsUndefined() ) { VL dummy = sqi->template ComputeLength(); gdcmAssertAlwaysMacro( dummy == ValueLengthField ); } } else if( GetSequenceOfFragments() ) { assert( ValueField->GetLength() == ValueLengthField ); } //#endif // We have the length we should be able to write the value if( VRField == VR::UN && ValueLengthField.IsUndefined() ) { assert( TagField == Tag(0x7fe0,0x0010) || GetValueAsSQ() ); ValueIO::Write(os,*ValueField); } #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION else if( VRField == VR::INVALID && dynamic_cast(&*ValueField) ) { // We have pretended so far that the Sequence was encoded as UN. Well the real // troubles is that we cannot store the length as explicit length, otherwise // we will loose the SQ, therefore change the length into undefined length // and add a seq del item: ValueIO::Write(os,*ValueField); if( !ValueLengthField.IsUndefined() ) { // eg. TestWriter with ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm // seq del item is not stored, write it ! const Tag seqDelItem(0xfffe,0xe0dd); seqDelItem.Write(os); VL zero = 0; zero.Write(os); } } #endif else { bool failed; if( VRField & VR::VRASCII || VRField == VR::INVALID ) { failed = !ValueIO::Write(os,*ValueField); } 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::Write(os,*ValueField); break; case 2: failed = !ValueIO::Write(os,*ValueField); break; case 4: failed = !ValueIO::Write(os,*ValueField); break; case 8: failed = !ValueIO::Write(os,*ValueField); break; default: failed = true; assert(0); } } if( failed ) { assert( 0 && "Should not happen" ); } } } return os; } } // end namespace gdcm_ns #endif // GDCMEXPLICITDATAELEMENT_TXX