- std::ostringstream s;
- if (length > MaxSizeLoadEntry)
- {
- if (BinEntry *binEntryPtr = dynamic_cast< BinEntry* >(entry) )
- {
- //s << "gdcm::NotLoaded (BinEntry)";
- s << GDCM_NOTLOADED;
- s << " Address:" << (long)entry->GetOffset();
- s << " Length:" << entry->GetLength();
- s << " x(" << std::hex << entry->GetLength() << ")";
- binEntryPtr->SetValue(s.str());
- }
- // Be carefull : a BinEntry IS_A ValEntry ...
- else if (ValEntry *valEntryPtr = dynamic_cast< ValEntry* >(entry) )
- {
- // s << "gdcm::NotLoaded. (ValEntry)";
- 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;
- }
-
- /// \todo Any compacter code suggested (?)
- if ( IsDocEntryAnInteger(entry) )
- {
- uint32_t NewInt;
- int nbInt;
- // When short integer(s) are expected, read and convert the following
- // n *two 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" || vr == "SS")
- {
- nbInt = length / 2;
- 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" || vr == "SL")
- {
- nbInt = length / 4;
- 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);
- gdcmVerboseMacro("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())
- {
- gdcmVerboseMacro("Unread element value");
- valEntry->SetValue(GDCM_UNREAD);
- return;
- }
-
- if( vr == "UI" )
- {
- // Because of correspondance with the VR dic
- valEntry->SetValue(newValue);
- }
- else
- {
- valEntry->SetValue(newValue);
- }
- }
- else
- {
- gdcmErrorMacro( "Should have a ValEntry, here !");
- }
-}
-
-
-/**
- * \brief Find the value Length of the passed Header Entry
- * @param entry Header Entry whose length of the value shall be loaded.
- */
-void Document::FindDocEntryLength( DocEntry *entry )
- throw ( FormatError )
-{
- std::string vr = entry->GetVR();
- uint16_t length16;
-
- if ( Filetype == ExplicitVR && !entry->IsImplicitVR() )
- {
- if ( vr == "OB" || vr == "OW" || vr == "SQ" || 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);
- uint32_t length32 = ReadInt32();
-
- if ( (vr == "OB" || vr == "OW") && length32 == 0xffffffff )
- {
- uint32_t lengthOB;
- try
- {
- lengthOB = FindDocEntryLengthOBOrOW();
- }
- 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.
- long currentPosition = Fp->tellg();
- Fp->seekg(0L,std::ios::end);
-
- long lengthUntilEOF = (long)(Fp->tellg())-currentPosition;
- Fp->seekg(currentPosition, std::ios::beg);
-
- 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();
-
- // FIXME : This heuristic supposes that the first group following
- // group 0002 *has* and element 0000.
- // BUT ... Element 0000 is optionnal :-(
-
-
- // Fixed using : HandleOutOfGroup0002()
- // (first hereafter strategy ...)
-
- // We can tell the current file is encoded in big endian (like
- // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
- // and it's value is the one of the encoding of a big endian file.
- // In order to deal with such big endian encoded files, we have
- // (at least) two strategies:
- // * when we load the "Transfer Syntax" tag with value of big endian
- // encoding, we raise the proper flags. Then we wait for the end
- // of the META group (0x0002) among which is "Transfer Syntax",
- // before switching the swap code to big endian. We have to postpone
- // the switching of the swap code since the META group is fully encoded
- // in little endian, and big endian coding only starts at the next
- // group. The corresponding code can be hard to analyse and adds
- // many additional unnecessary tests for regular tags.
- // * the second strategy consists in waiting for trouble, that shall
- // appear when we find the first group with big endian encoding. This
- // is easy to detect since the length of a "Group Length" tag (the
- // ones with zero as element number) has to be of 4 (0x0004). When we
- // encounter 1024 (0x0400) chances are the encoding changed and we
- // found a group with big endian encoding.
- //---> Unfortunately, element 0000 is optional.
- //---> This will not work when missing!
- // We shall use this second strategy. In order to make sure that we
- // can interpret the presence of an apparently big endian encoded
- // length of a "Group Length" without committing a big mistake, we
- // add an additional check: we look in the already parsed elements
- // for the presence of a "Transfer Syntax" whose value has to be "big
- // endian encoding". When this is the case, chances are we have got our
- // hands on a big endian encoded file: we switch the swap code to
- // big endian and proceed...
-
- //
- // if ( element == 0x0000 && length16 == 0x0400 )
- // {
- // std::string ts = GetTransferSyntax();
- // if ( Global::GetTS()->GetSpecialTransferSyntax(ts)
- // != TS::ExplicitVRBigEndian )
- // {
- // throw FormatError( "Document::FindDocEntryLength()",
- // " not explicit VR." );
- // return;
- // }
- // length16 = 4;
- // SwitchByteSwapCode();
-
- // Restore the unproperly loaded values i.e. the group, the element
- // and the dictionary entry depending on them.
-// uint16_t correctGroup = SwapShort( entry->GetGroup() );
-// uint16_t correctElem = SwapShort( entry->GetElement() );
-// DictEntry *newTag = GetDictEntry( correctGroup, correctElem ); if ( !newTag )
-// {
- // This correct tag is not in the dictionary. Create a new one.
-// newTag = NewVirtualDictEntry(correctGroup, correctElem);
-// }
- // FIXME this can create a memory leaks on the old entry that be
- // left unreferenced.
-// entry->SetDictEntry( newTag );
-// }
-
-
- // 0xffff means that we deal with 'No Length' Sequence
- // or 'No Length' SQItem
- if ( length16 == 0xffff)
- {
- length16 = 0;
- }
- FixDocEntryFoundLength( entry, (uint32_t)length16 );
- return;
- }
- else
- {
- // Either implicit VR or a non DICOM conformal (see note below) explicit
- // VR that ommited the VR of (at least) this element. Farts happen.
- // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
- // on Data elements "Implicit and Explicit VR Data Elements shall
- // not coexist in a Data Set and Data Sets nested within it".]
- // Length is on 4 bytes.
-
- FixDocEntryFoundLength( entry, ReadInt32() );
- return;
- }
-}
-
-/**
- * \brief Find the Value Representation of the current Dicom Element.
- * @return Value Representation of the current Entry
- */
-std::string Document::FindDocEntryVR()
-{
- if ( Filetype != ExplicitVR )
- return GDCM_UNKNOWN;
-
- long positionOnEntry = Fp->tellg();
- // Warning: we believe this is explicit VR (Value Representation) because
- // we used a heuristic that found "UL" in the first tag. Alas this
- // doesn't guarantee that all the tags will be in explicit VR. In some
- // cases (see e-film filtered files) one finds implicit VR tags mixed
- // within an explicit VR file. Hence we make sure the present tag
- // is in explicit VR and try to fix things if it happens not to be
- // the case.
-
- char vr[3];
- Fp->read (vr, (size_t)2);
- vr[2] = 0;
-
- if( !CheckDocEntryVR(vr) )
- {
- Fp->seekg(positionOnEntry, std::ios::beg);
- return GDCM_UNKNOWN;
- }
- return vr;
-}
-
-/**
- * \brief Check the correspondance between the VR of the header entry
- * and the taken VR. If they are different, the header entry is
- * updated with the new VR.
- * @param vr Dicom Value Representation
- * @return false if the VR is incorrect of if the VR isn't referenced
- * otherwise, it returns true
-*/
-bool Document::CheckDocEntryVR(VRKey vr)
-{
- // CLEANME searching the dicom_vr at each occurence is expensive.
- // PostPone this test in an optional integrity check at the end
- // of parsing or only in debug mode.
- if ( !Global::GetVR()->IsValidVR(vr) )
- return false;
-
- return true;
-}
-
-/**
- * \brief Get the transformed value of the header entry. The VR value
- * is used to define the transformation to operate on the value
- * \warning NOT end user intended method !
- * @param entry entry to tranform
- * @return Transformed entry value
- */
-std::string Document::GetDocEntryValue(DocEntry *entry)
-{
- if ( IsDocEntryAnInteger(entry) && entry->IsImplicitVR() )
- {
- std::string val = ((ValEntry *)entry)->GetValue();
- std::string vr = entry->GetVR();
- uint32_t length = entry->GetLength();
- std::ostringstream s;
- int nbInt;
-
- // When short integer(s) are expected, read and convert the following
- // n * 2 bytes properly i.e. as a multivaluated strings
- // (each single value is separated fromthe next one by '\'
- // as usual for standard multivaluated filels
- // Elements with Value Multiplicity > 1
- // contain a set of short integers (not a single one)
-
- if( vr == "US" || vr == "SS" )
- {
- uint16_t newInt16;
-
- nbInt = length / 2;
- for (int i=0; i < nbInt; i++)
- {
- if( i != 0 )
- {
- s << '\\';
- }
- newInt16 = ( val[2*i+0] & 0xFF ) + ( ( val[2*i+1] & 0xFF ) << 8);
- newInt16 = SwapShort( newInt16 );
- s << newInt16;
- }
- }
-
- // When integer(s) are expected, read and convert the following
- // n * 4 bytes properly i.e. as a multivaluated strings
- // (each single value is separated fromthe next one by '\'
- // as usual for standard multivaluated filels
- // Elements with Value Multiplicity > 1
- // contain a set of integers (not a single one)
- else if( vr == "UL" || vr == "SL" )
- {
- uint32_t newInt32;
-
- nbInt = length / 4;
- for (int i=0; i < nbInt; i++)
- {
- if( i != 0)
- {
- s << '\\';
- }
- newInt32 = ( val[4*i+0] & 0xFF )
- + (( val[4*i+1] & 0xFF ) << 8 )
- + (( val[4*i+2] & 0xFF ) << 16 )
- + (( val[4*i+3] & 0xFF ) << 24 );
- newInt32 = SwapLong( newInt32 );
- s << newInt32;
- }
- }
-#ifdef GDCM_NO_ANSI_STRING_STREAM
- s << std::ends; // to avoid oddities on Solaris
-#endif //GDCM_NO_ANSI_STRING_STREAM
- return s.str();
- }
-
- return ((ValEntry *)entry)->GetValue();