gdcmSequenceOfFragments.h
Go to the documentation of this file.
/*=========================================================================
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 GDCMSEQUENCEOFFRAGMENTS_H
#define GDCMSEQUENCEOFFRAGMENTS_H
#include "gdcmValue.h"
#include "gdcmVL.h"
#include "gdcmFragment.h"
#include "gdcmBasicOffsetTable.h"
namespace gdcm_ns
{
// FIXME gdcmSequenceOfItems and gdcmSequenceOfFragments
// should be rethink (duplicate code)
class GDCM_EXPORT SequenceOfFragments : public Value
{
public:
// Typdefs:
typedef std::vector<Fragment> FragmentVector;
typedef FragmentVector::size_type SizeType;
typedef FragmentVector::iterator Iterator;
typedef FragmentVector::const_iterator ConstIterator;
Iterator Begin() { return Fragments.begin(); }
Iterator End() { return Fragments.end(); }
ConstIterator Begin() const { return Fragments.begin(); }
ConstIterator End() const { return Fragments.end(); }
SequenceOfFragments():Table(),SequenceLengthField(0xFFFFFFFF) { }
VL GetLength() const override {
return SequenceLengthField;
}
void SetLength(VL length) override {
SequenceLengthField = length;
}
void Clear() override;
void AddFragment(Fragment const &item);
// Compute the length of all fragments (and fragments only!).
// Basically the size of the PixelData as stored (in bytes).
unsigned long ComputeByteLength() const;
// Compute the length of fragments (in bytes)+ length of tag...
// to be used for computation of Group Length
VL ComputeLength() const;
// Get the buffer
bool GetBuffer(char *buffer, unsigned long length) const;
bool GetFragBuffer(unsigned int fragNb, char *buffer, unsigned long &length) const;
SizeType GetNumberOfFragments() const;
const Fragment& GetFragment(SizeType num) const;
// Write the buffer of each fragment (call WriteBuffer on all Fragments, which are
// ByteValue). No Table information is written.
bool WriteBuffer(std::ostream &os) const;
const BasicOffsetTable &GetTable() const { return Table; }
BasicOffsetTable &GetTable() { return Table; }
template <typename TSwap>
std::istream& Read(std::istream &is, bool readvalues = true)
{
assert( SequenceLengthField.IsUndefined() );
ReadPreValue<TSwap>(is);
return ReadValue<TSwap>(is, readvalues);
}
template <typename TSwap>
std::istream& ReadPreValue(std::istream &is)
{
// First item is the basic offset table:
#if 0
try
{
Table.Read<TSwap>(is);
gdcmDebugMacro( "Table: " << Table );
}
catch(...)
{
// throw "SIEMENS Icon thingy";
// Bug_Siemens_PrivateIconNoItem.dcm
// First thing first let's rewind
is.seekg(-4, std::ios::cur);
// FF D8 <=> Start of Image (SOI) marker
// FF E0 <=> APP0 Reserved for Application Use
if ( Table.GetTag() == Tag(0xd8ff,0xe0ff) )
{
Table = BasicOffsetTable(); // clear up stuff
//Table.SetByteValue( "", 0 );
Fragment frag;
if( FillFragmentWithJPEG( frag, is ) )
{
Fragments.push_back( frag );
}
return is;
}
else
{
throw "Catch me if you can";
//assert(0);
}
}
#else
Table.Read<TSwap>(is);
gdcmDebugMacro( "Table: " << Table );
#endif
return is;
}
template <typename TSwap>
std::istream& ReadValue(std::istream &is, bool /*readvalues*/)
{
const Tag seqDelItem(0xfffe,0xe0dd);
// not used for now...
Fragment frag;
try
{
while( frag.Read<TSwap>(is) && frag.GetTag() != seqDelItem )
{
//gdcmDebugMacro( "Frag: " << frag );
Fragments.push_back( frag );
}
assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 );
}
catch(Exception &ex)
{
(void)ex;
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
// that's ok ! In all cases the whole file was read, because
// Fragment::Read only fail on eof() reached 1.
// SIEMENS-JPEG-CorruptFrag.dcm is more difficult to deal with, we have a
// partial fragment, read we decide to add it anyway to the stack of
// fragments (eof was reached so we need to clear error bit)
if( frag.GetTag() == Tag(0xfffe,0xe000) )
{
gdcmWarningMacro( "Pixel Data Fragment could be corrupted. Use file at own risk" );
Fragments.push_back( frag );
is.clear(); // clear the error bit
}
// 2. GENESIS_SIGNA-JPEG-CorruptFrag.dcm
else if ( frag.GetTag() == Tag(0xddff,0x00e0) )
{
assert( Fragments.size() == 1 );
const ByteValue *bv = Fragments[0].GetByteValue();
assert( bv->GetLength() >= 1 && (unsigned char)bv->GetPointer()[ bv->GetLength() - 1 ] == 0xfe );
// Yes this is an extra copy, this is a bug anyway, go fix YOUR code
Fragments[0].SetByteValue( bv->GetPointer(), bv->GetLength() - 1 );
gdcmWarningMacro( "JPEG Fragment length was declared with an extra byte"
" at the end: stripped !" );
is.clear(); // clear the error bit
}
// 3. LEICA/WSI
else if ( (frag.GetTag().GetGroup() == 0x00ff)
&& ((frag.GetTag().GetElement() & 0x00ff) == 0xe0) )
{
// Looks like there is a mess with offset and odd byte array
// We are going first to backtrack one byte back, and then use a
// ReadBacktrack function which in turn may backtrack up to 10 bytes
// backward. This appears to be working on a set of DICOM/WSI files from
// LEICA
gdcmWarningMacro( "Trying to fix the even-but-odd value length bug #1" );
assert( Fragments.size() );
const size_t lastf = Fragments.size() - 1;
const ByteValue *bv = Fragments[ lastf ].GetByteValue();
const char *a = bv->GetPointer();
gdcmAssertAlwaysMacro( bv->GetLength() >= 1 && (unsigned char)a[ bv->GetLength() - 1 ] == 0xfe );
Fragments[ lastf ].SetByteValue( bv->GetPointer(), bv->GetLength() - 1 );
is.seekg( -9, std::ios::cur );
assert( is.good() );
while( frag.ReadBacktrack<TSwap>(is) && frag.GetTag() != seqDelItem )
{
gdcmDebugMacro( "Frag: " << frag );
Fragments.push_back( frag );
}
assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 );
}
// 4. LEICA/WSI (bis)
else if ( frag.GetTag().GetGroup() == 0xe000 )
{
// Looks like there is a mess with offset and odd byte array
// We are going first to backtrack one byte back, and then use a
// ReadBacktrack function which in turn may backtrack up to 10 bytes
// backward. This appears to be working on a set of DICOM/WSI files from
// LEICA
gdcmWarningMacro( "Trying to fix the even-but-odd value length bug #2" );
assert( Fragments.size() );
const size_t lastf = Fragments.size() - 1;
const ByteValue *bv = Fragments[ lastf ].GetByteValue();
const char *a = bv->GetPointer();
gdcmAssertAlwaysMacro( bv->GetLength() >= 2 && (unsigned char)a[ bv->GetLength() - 2 ] == 0xfe );
Fragments[ lastf ].SetByteValue( bv->GetPointer(), bv->GetLength() - 2 );
is.seekg( -10, std::ios::cur );
assert( is.good() );
while( frag.ReadBacktrack<TSwap>(is) && frag.GetTag() != seqDelItem )
{
gdcmDebugMacro( "Frag: " << frag );
Fragments.push_back( frag );
}
assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 );
}
// 5. LEICA/WSI (ter)
else if ( (frag.GetTag().GetGroup() & 0x00ff) == 0x00e0
&& (frag.GetTag().GetElement() & 0xff00) == 0x0000 )
{
// Looks like there is a mess with offset and odd byte array
// We are going first to backtrack one byte back, and then use a
// ReadBacktrack function which in turn may backtrack up to 10 bytes
// backward. This appears to be working on a set of DICOM/WSI files from
// LEICA
gdcmWarningMacro( "Trying to fix the even-but-odd value length bug #3" );
assert( Fragments.size() );
const size_t lastf = Fragments.size() - 1;
const ByteValue *bv = Fragments[ lastf ].GetByteValue();
const char *a = bv->GetPointer();
gdcmAssertAlwaysMacro( bv->GetLength() >= 3 && (unsigned char)a[ bv->GetLength() - 3 ] == 0xfe );
Fragments[ lastf ].SetByteValue( bv->GetPointer(), bv->GetLength() - 3 );
is.seekg( -11, std::ios::cur );
assert( is.good() );
while( frag.ReadBacktrack<TSwap>(is) && frag.GetTag() != seqDelItem )
{
gdcmDebugMacro( "Frag: " << frag );
Fragments.push_back( frag );
}
assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 );
}
else
{
// 3. gdcm-JPEG-LossLess3a.dcm: easy case, an extra tag was found
// instead of terminator (eof is the next char)
gdcmWarningMacro( "Reading failed at Tag:" << frag.GetTag() << " Index #"
<< Fragments.size() << " Offset " << is.tellg() << ". Use file at own risk."
<< ex.what() );
}
#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */
}
return is;
}
template <typename TSwap>
std::ostream const &Write(std::ostream &os) const
{
if( !Table.Write<TSwap>(os) )
{
assert(0 && "Should not happen");
return os;
}
for(ConstIterator it = Begin();it != End(); ++it)
{
it->Write<TSwap>(os);
}
// seq del item is not stored, write it !
const Tag seqDelItem(0xfffe,0xe0dd);
seqDelItem.Write<TSwap>(os);
VL zero = 0;
zero.Write<TSwap>(os);
return os;
}
//#if defined(SWIGPYTHON) || defined(SWIGCSHARP) || defined(SWIGJAVA)
// For now leave it there, this does not make sense in the C++ layer
// Create a new object
static SmartPointer<SequenceOfFragments> New()
{
return new SequenceOfFragments();
}
//#endif
protected:
public:
void Print(std::ostream &os) const override {
os << "SQ L= " << SequenceLengthField << "\n";
os << "Table:" << Table << "\n";
for(ConstIterator it = Begin();it != End(); ++it)
{
os << " " << *it << "\n";
}
assert( SequenceLengthField.IsUndefined() );
{
const Tag seqDelItem(0xfffe,0xe0dd);
VL zero = 0;
os << seqDelItem;
os << "\t" << zero;
}
}
bool operator==(const Value &val) const override
{
const SequenceOfFragments &sqf = dynamic_cast<const SequenceOfFragments&>(val);
return Table == sqf.Table &&
SequenceLengthField == sqf.SequenceLengthField &&
Fragments == sqf.Fragments;
}
private:
BasicOffsetTable Table;
VL SequenceLengthField;
FragmentVector Fragments;
private:
bool FillFragmentWithJPEG( Fragment & frag, std::istream & is );
};
} // end namespace gdcm_ns
#endif //GDCMSEQUENCEOFFRAGMENTS_H
gdcm::BasicOffsetTable
Class to represent a BasicOffsetTable.
Definition gdcmBasicOffsetTable.h:27
gdcm::ByteValue
Class to represent binary value (array of bytes).
Definition gdcmByteValue.h:35
gdcm::ByteValue::GetPointer
const char * GetPointer() const
Definition gdcmByteValue.h:110
gdcm::ByteValue::GetLength
VL GetLength() const override
Definition gdcmByteValue.h:77
gdcm::DataElement::GetVL
const VL & GetVL() const
Get VL.
Definition gdcmDataElement.h:74
gdcm::DataElement::GetTag
const Tag & GetTag() const
Get Tag.
Definition gdcmDataElement.h:67
gdcm::Exception
Exception.
Definition gdcmException.h:44
gdcm::Exception::what
const char * what() const override
what implementation
Definition gdcmException.h:86
gdcm::Fragment
Class to represent a Fragment.
Definition gdcmFragment.h:44
gdcm::Fragment::ReadBacktrack
std::istream & ReadBacktrack(std::istream &is)
Definition gdcmFragment.h:122
gdcm::Fragment::Read
std::istream & Read(std::istream &is)
Definition gdcmFragment.h:56
gdcm::SequenceOfFragments::operator==
bool operator==(const Value &val) const override
Definition gdcmSequenceOfFragments.h:312
gdcm::SequenceOfFragments::Read
std::istream & Read(std::istream &is, bool readvalues=true)
Definition gdcmSequenceOfFragments.h:86
gdcm::SequenceOfFragments::SetLength
void SetLength(VL length) override
Sets the actual SQ length.
Definition gdcmSequenceOfFragments.h:53
gdcm::SequenceOfFragments::AddFragment
void AddFragment(Fragment const &item)
Appends a Fragment to the already added ones.
gdcm::SequenceOfFragments::WriteBuffer
bool WriteBuffer(std::ostream &os) const
gdcm::SequenceOfFragments::Iterator
FragmentVector::iterator Iterator
Definition gdcmSequenceOfFragments.h:37
gdcm::SequenceOfFragments::Begin
Iterator Begin()
Definition gdcmSequenceOfFragments.h:39
gdcm::SequenceOfFragments::GetTable
BasicOffsetTable & GetTable()
Definition gdcmSequenceOfFragments.h:83
gdcm::SequenceOfFragments::ReadPreValue
std::istream & ReadPreValue(std::istream &is)
Definition gdcmSequenceOfFragments.h:94
gdcm::SequenceOfFragments::GetFragBuffer
bool GetFragBuffer(unsigned int fragNb, char *buffer, unsigned long &length) const
gdcm::SequenceOfFragments::GetLength
VL GetLength() const override
Returns the SQ length, as read from disk.
Definition gdcmSequenceOfFragments.h:48
gdcm::SequenceOfFragments::GetFragment
const Fragment & GetFragment(SizeType num) const
gdcm::SequenceOfFragments::Begin
ConstIterator Begin() const
Definition gdcmSequenceOfFragments.h:41
gdcm::SequenceOfFragments::End
ConstIterator End() const
Definition gdcmSequenceOfFragments.h:42
gdcm::SequenceOfFragments::Print
void Print(std::ostream &os) const override
Definition gdcmSequenceOfFragments.h:297
gdcm::SequenceOfFragments::ComputeByteLength
unsigned long ComputeByteLength() const
gdcm::SequenceOfFragments::GetNumberOfFragments
SizeType GetNumberOfFragments() const
gdcm::SequenceOfFragments::Clear
void Clear() override
Clear.
gdcm::SequenceOfFragments::New
static SmartPointer< SequenceOfFragments > New()
Definition gdcmSequenceOfFragments.h:289
gdcm::SequenceOfFragments::End
Iterator End()
Definition gdcmSequenceOfFragments.h:40
gdcm::SequenceOfFragments::SizeType
FragmentVector::size_type SizeType
Definition gdcmSequenceOfFragments.h:36
gdcm::SequenceOfFragments::ReadValue
std::istream & ReadValue(std::istream &is, bool)
Definition gdcmSequenceOfFragments.h:136
gdcm::SequenceOfFragments::GetTable
const BasicOffsetTable & GetTable() const
Definition gdcmSequenceOfFragments.h:82
gdcm::SequenceOfFragments::ComputeLength
VL ComputeLength() const
gdcm::SequenceOfFragments::ConstIterator
FragmentVector::const_iterator ConstIterator
Definition gdcmSequenceOfFragments.h:38
gdcm::SequenceOfFragments::SequenceOfFragments
SequenceOfFragments()
constructor (UndefinedLength by default)
Definition gdcmSequenceOfFragments.h:45
gdcm::SequenceOfFragments::Write
std::ostream const & Write(std::ostream &os) const
Definition gdcmSequenceOfFragments.h:266
gdcm::SequenceOfFragments::FragmentVector
std::vector< Fragment > FragmentVector
Definition gdcmSequenceOfFragments.h:35
gdcm::SequenceOfFragments::GetBuffer
bool GetBuffer(char *buffer, unsigned long length) const
gdcm::SmartPointer
Class for Smart Pointer.
Definition gdcmSmartPointer.h:40
gdcm::Table
Table.
Definition gdcmTable.h:29
gdcm::Tag
Class to represent a DICOM Data Element (Attribute) Tag (Group, Element).
Definition gdcmTag.h:39
gdcm::Tag::GetGroup
uint16_t GetGroup() const
Returns the 'Group number' of the given Tag.
Definition gdcmTag.h:55
gdcm::Tag::Write
const std::ostream & Write(std::ostream &os) const
Write a tag in binary rep.
Definition gdcmTag.h:169
gdcm::Tag::GetElement
uint16_t GetElement() const
Returns the 'Element number' of the given Tag.
Definition gdcmTag.h:57
gdcm::VL
Value Length.
Definition gdcmVL.h:30
gdcm::VL::Write
const std::ostream & Write(std::ostream &os) const
Definition gdcmVL.h:99
gdcm::Value::Value
Value()=default
gdcmBasicOffsetTable.h
gdcmFragment.h
gdcmAssertAlwaysMacro
#define gdcmAssertAlwaysMacro(arg)
AssertAlways.
Definition gdcmTrace.h:228
gdcmWarningMacro
#define gdcmWarningMacro(msg)
Warning.
Definition gdcmTrace.h:142
gdcmDebugMacro
#define gdcmDebugMacro(msg)
Debug.
Definition gdcmTrace.h:119
gdcmVL.h
gdcmValue.h
GDCM_EXPORT
#define GDCM_EXPORT
Definition gdcmWin32.h:34