#ifndef GDCMFRAGMENT_H
#define GDCMFRAGMENT_H
#include "gdcmDataElement.h"
#include "gdcmByteValue.h"
#include "gdcmSmartPointer.h"
#include "gdcmParseException.h"
namespace gdcm_ns
{
class GDCM_EXPORT Fragment : public DataElement
{
public:
Fragment() : DataElement(Tag(0xfffe, 0xe000), 0) {}
friend std::ostream &operator<<(std::ostream &os, const Fragment &val);
VL GetLength() const;
VL ComputeLength() const;
template <typename TSwap>
std::istream &Read(std::istream &is)
{
ReadPreValue<TSwap>(is);
return ReadValue<TSwap>(is);
}
template <typename TSwap>
std::istream &ReadPreValue(std::istream &is)
{
TagField.Read<TSwap>(is);
if( !is )
{
throw Exception( "Problem #1" );
}
if( !ValueLengthField.Read<TSwap>(is) )
{
throw Exception( "Problem #2" );
}
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
const Tag itemStart(0xfffe, 0xe000);
const Tag seqDelItem(0xfffe,0xe0dd);
if( TagField != itemStart && TagField != seqDelItem )
{
throw Exception( "Problem #3" );
}
#endif
return is;
}
template <typename TSwap>
std::istream &ReadValue(std::istream &is)
{
SmartPointer<ByteValue> bv = new ByteValue;
bv->SetLength(ValueLengthField);
if( !bv->Read<TSwap>(is) )
{
gdcmWarningMacro( "Fragment could not be read" );
ValueField = bv;
ParseException pe;
pe.SetLastElement( *this );
throw pe;
}
ValueField = bv;
return is;
}
template <typename TSwap>
std::istream &ReadBacktrack(std::istream &is)
{
const Tag itemStart(0xfffe, 0xe000);
const Tag seqDelItem(0xfffe,0xe0dd);
bool cont = true;
const std::streampos start = is.tellg();
const int max = 10;
int offset = 0;
while( cont )
{
TagField.Read<TSwap>(is);
gdcm_assert( is );
if( TagField != itemStart && TagField != seqDelItem )
{
++offset;
is.seekg( (std::streampos)((size_t)start - offset) );
gdcmWarningMacro( "Fuzzy Search, backtrack: " << (start - is.tellg()) << " Offset: " << is.tellg() );
if( offset > max )
{
gdcmErrorMacro( "Giving up" );
throw "Impossible to backtrack";
}
}
else
{
cont = false;
}
}
gdcm_assert( TagField == itemStart || TagField == seqDelItem );
if( !ValueLengthField.Read<TSwap>(is) )
{
return is;
}
SmartPointer<ByteValue> bv = new ByteValue;
bv->SetLength(ValueLengthField);
if( !bv->Read<TSwap>(is) )
{
gdcmWarningMacro( "Fragment could not be read" );
ValueField = bv;
ParseException pe;
pe.SetLastElement( *this );
throw pe;
}
ValueField = bv;
return is;
}
template <typename TSwap>
std::ostream &Write(std::ostream &os) const {
const Tag itemStart(0xfffe, 0xe000);
const Tag seqDelItem(0xfffe,0xe0dd);
if( !TagField.Write<TSwap>(os) )
{
gdcm_assert(0 && "Should not happen");
return os;
}
gdcm_assert( TagField == itemStart
|| TagField == seqDelItem );
const ByteValue *bv = GetByteValue();
if( IsEmpty() )
{
VL zero = 0;
if( !zero.Write<TSwap>(os) )
{
gdcm_assert(0 && "Should not happen");
return os;
}
}
else
{
gdcm_assert( ValueLengthField );
gdcm_assert( !ValueLengthField.IsUndefined() );
const VL actuallen = bv->ComputeLength();
gdcm_assert( actuallen == ValueLengthField || actuallen == ValueLengthField + 1 );
if( !actuallen.Write<TSwap>(os) )
{
gdcm_assert(0 && "Should not happen");
return os;
}
}
if( ValueLengthField && bv )
{
gdcm_assert( bv );
gdcm_assert( bv->GetLength() == ValueLengthField );
if( !bv->Write<TSwap>(os) )
{
gdcm_assert(0 && "Should not happen");
return os;
}
}
return os;
}
};
inline std::ostream &operator<<(std::ostream &os, const Fragment &val)
{
os << "Tag: " << val.TagField;
os << "\tVL: " << val.ValueLengthField;
if( val.ValueField )
{
os << "\t" << *(val.ValueField);
}
return os;
}
}
#endif