Program: gdcm
Module: $RCSfile: gdcmDocument.cxx,v $
Language: C++
- Date: $Date: 2004/12/02 15:14:17 $
- Version: $Revision: 1.145 $
+ Date: $Date: 2005/01/06 16:33:54 $
+ Version: $Revision: 1.159 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
#include "gdcmGlobal.h"
#include "gdcmUtil.h"
#include "gdcmDebug.h"
+#include "gdcmTS.h"
+#include "gdcmException.h"
+#include "gdcmDictSet.h"
+#include "gdcmRLEFramesInfo.h"
+#include "gdcmJPEGFragmentsInfo.h"
+#include "gdcmDocEntrySet.h"
+#include "gdcmSQItem.h"
#include <vector>
#include <iomanip>
static const char *TransferSyntaxStrings[] = {
// Implicit VR Little Endian
"1.2.840.10008.1.2",
- // Implicit VR Little Endian DLX G.E?
+ // Implicit VR Big Endian DLX G.E?
"1.2.840.113619.5.2",
// Explicit VR Little Endian
"1.2.840.10008.1.2.1",
SetEntryByNumber(rows , 0x0028, 0x0011);
}
// ----------------- End of ACR-LibIDO kludge ------------------
-
- PrintLevel = 1; // 'Medium' print level by default
}
/**
Initialise();
SwapCode = 0;
Filetype = ExplicitVR;
- PrintLevel = 1; // 'Medium' print level by default
}
/**
*/
void Document::PrintPubDict(std::ostream & os)
{
+ RefPubDict->SetPrintLevel(PrintLevel);
RefPubDict->Print(os);
}
*/
void Document::PrintShaDict(std::ostream & os)
{
+ RefShaDict->SetPrintLevel(PrintLevel);
RefShaDict->Print(os);
}
}
uint16_t zero;
- Fp->read((char*)&zero, (size_t)2 );
+ Fp->read((char*)&zero, (size_t)2);
+ if( Fp->eof() )
+ {
+ CloseFile();
+ return 0;
+ }
//ACR -- or DICOM with no Preamble; may start with a Shadow Group --
if(
Fp->seekg(126L, std::ios::cur);
char dicm[4];
Fp->read(dicm, (size_t)4);
+ if( Fp->eof() )
+ {
+ CloseFile();
+ return 0;
+ }
if( memcmp(dicm, "DICM", 4) == 0 )
{
return Fp;
}
/**
- * \brief Modifies the value of a given Header Entry (Dicom Element)
+ * \brief Modifies the value of a given Doc Entry (Dicom Element)
* when it exists. Create it with the given value when unexistant.
* @param value (string) Value to be set
* @param group Group number of the Entry
* \return pointer to the modified/created Header Entry (NULL when creation
* failed).
*/
-ValEntry* Document::ReplaceOrCreateByNumber(
- std::string const & value,
- uint16_t group,
- uint16_t elem,
- TagName const & vr )
+ValEntry* Document::ReplaceOrCreateByNumber(std::string const & value,
+ uint16_t group,
+ uint16_t elem,
+ TagName const & vr )
{
ValEntry* valEntry = 0;
DocEntry* currentEntry = GetDocEntryByNumber( group, elem);
- if (!currentEntry)
+ if (currentEntry)
{
- // check if (group,element) DictEntry exists
- // if it doesn't, create an entry in DictSet::VirtualEntry
- // and use it
+ valEntry = dynamic_cast< ValEntry* >(currentEntry);
- // Find out if the tag we received is in the dictionaries:
- Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
- DictEntry* dictEntry = pubDict->GetDictEntryByNumber(group, elem);
- if (!dictEntry)
- {
- currentEntry = NewDocEntryByNumber(group, elem, vr);
- }
- else
- {
- currentEntry = NewDocEntryByNumber(group, elem);
- }
+ // Verify the VR
+ if( valEntry )
+ if( valEntry->GetVR()!=vr )
+ valEntry=NULL;
- if (!currentEntry)
+ // if currentEntry doesn't correspond to the requested valEntry
+ if( !valEntry)
{
- dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: call to"
- " NewDocEntryByNumber failed.");
- return NULL;
+ if (!RemoveEntry(currentEntry))
+ {
+ dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: removal"
+ " of previous DocEntry failed.");
+
+ return NULL;
+ }
}
+ }
- valEntry = new ValEntry(currentEntry);
- delete currentEntry;
+ // Create a new valEntry if necessary
+ if (!valEntry)
+ {
+ valEntry = NewValEntryByNumber(group, elem, vr);
if ( !AddEntry(valEntry))
{
- delete valEntry;
dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: AddEntry"
" failed allthough this is a creation.");
+
+ delete valEntry;
return NULL;
}
}
- else
- {
- valEntry = dynamic_cast< ValEntry* >(currentEntry);
- if ( !valEntry ) // Euuuuh? It wasn't a ValEntry
- // then we change it to a ValEntry ?
- // Shouldn't it be considered as an error ?
- {
- // We need to promote the DocEntry to a ValEntry:
- valEntry = new ValEntry(currentEntry);
- if (!RemoveEntry(currentEntry))
- {
- delete valEntry;
- dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: removal"
- " of previous DocEntry failed.");
- return NULL;
- }
- if ( !AddEntry(valEntry))
- {
- delete valEntry;
- dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: adding"
- " promoted ValEntry failed.");
- return NULL;
- }
- }
- }
-
- SetEntryByNumber(value, group, elem);
+ // Set the binEntry value
+ SetEntry(value, valEntry);
return valEntry;
}
* @param binArea (binary) value to be set
* @param Group Group number of the Entry
* @param Elem Element number of the Entry
+ * @param vr V(alue) R(epresentation) of the Entry -if private Entry-
* \return pointer to the modified/created Header Entry (NULL when creation
* failed).
*/
-BinEntry* Document::ReplaceOrCreateByNumber(
- uint8_t* binArea,
- int lgth,
- uint16_t group,
- uint16_t elem,
- TagName const & vr )
+BinEntry* Document::ReplaceOrCreateByNumber(uint8_t* binArea,
+ int lgth,
+ uint16_t group,
+ uint16_t elem,
+ TagName const & vr )
{
BinEntry* binEntry = 0;
DocEntry* currentEntry = GetDocEntryByNumber( group, elem);
- if (!currentEntry)
- {
-
- // check if (group,element) DictEntry exists
- // if it doesn't, create an entry in DictSet::VirtualEntry
- // and use it
-
- // Find out if the tag we received is in the dictionaries:
- Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
- DictEntry *dictEntry = pubDict->GetDictEntryByNumber(group, elem);
- if (!dictEntry)
- {
- currentEntry = NewDocEntryByNumber(group, elem, vr);
- }
- else
- {
- currentEntry = NewDocEntryByNumber(group, elem);
- }
- if (!currentEntry)
- {
- dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: call to"
- " NewDocEntryByNumber failed.");
- return NULL;
- }
- binEntry = new BinEntry(currentEntry);
- if ( !AddEntry(binEntry))
- {
- dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: AddEntry"
- " failed allthough this is a creation.");
- }
- delete currentEntry;
- }
- else
+ // Verify the currentEntry
+ if (currentEntry)
{
binEntry = dynamic_cast< BinEntry* >(currentEntry);
- if ( !binEntry ) // Euuuuh? It wasn't a BinEntry
- // then we change it to a BinEntry ?
- // Shouldn't it be considered as an error ?
+
+ // Verify the VR
+ if( binEntry )
+ if( binEntry->GetVR()!=vr )
+ binEntry=NULL;
+
+ // if currentEntry doesn't correspond to the requested valEntry
+ if( !binEntry)
{
- // We need to promote the DocEntry to a BinEntry:
- binEntry = new BinEntry(currentEntry);
if (!RemoveEntry(currentEntry))
{
dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: removal"
" of previous DocEntry failed.");
+
return NULL;
}
- if ( !AddEntry(binEntry))
- {
- dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: adding"
- " promoted BinEntry failed.");
- return NULL;
- }
}
}
+ // Create a new binEntry if necessary
+ if (!binEntry)
+ {
+ binEntry = NewBinEntryByNumber(group, elem, vr);
+
+ if ( !AddEntry(binEntry))
+ {
+ dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: AddEntry"
+ " failed allthough this is a creation.");
+
+ delete binEntry;
+ return NULL;
+ }
+ }
+
+ // Set the binEntry value
uint8_t *tmpArea;
if (lgth>0 && binArea)
{
{
tmpArea = 0;
}
- if (!SetEntryByNumber(tmpArea, lgth, group, elem))
+ if (!SetEntry(tmpArea,lgth,binEntry))
{
if (tmpArea)
{
return binEntry;
}
-
/*
* \brief Modifies the value of a given Header Entry (Dicom Element)
* when it exists. Create it when unexistant.
*/
SeqEntry* Document::ReplaceOrCreateByNumber( uint16_t group, uint16_t elem)
{
- SeqEntry* b = 0;
- DocEntry* a = GetDocEntryByNumber( group, elem);
- if (!a)
+ SeqEntry* seqEntry = 0;
+ DocEntry* currentEntry = GetDocEntryByNumber( group, elem);
+
+ // Verify the currentEntry
+ if (currentEntry)
{
- a = NewSeqEntryByNumber(group, elem);
- if (!a)
+ seqEntry = dynamic_cast< SeqEntry* >(currentEntry);
+
+ // Verify the VR
+ if( seqEntry )
+ if( seqEntry->GetVR()!="SQ" )
+ seqEntry=NULL;
+
+ // if currentEntry doesn't correspond to the requested valEntry
+ if( !seqEntry)
{
- return 0;
+ if (!RemoveEntry(currentEntry))
+ {
+ dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: removal"
+ " of previous DocEntry failed.");
+
+ return NULL;
+ }
}
+ }
- b = new SeqEntry(a, 1); // FIXME : 1 (Depth)
- AddEntry(b);
- }
- return b;
+ // Create a new seqEntry if necessary
+ if (!seqEntry)
+ {
+ seqEntry = NewSeqEntryByNumber(group, elem);
+
+ if ( !AddEntry(seqEntry))
+ {
+ dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: AddEntry"
+ " failed allthough this is a creation.");
+
+ delete seqEntry;
+ return NULL;
+ }
+ }
+
+ return seqEntry;
}
/**
std::string Document::GetEntryByNumber(uint16_t group, uint16_t element)
{
TagKey key = DictEntry::TranslateToKey(group, element);
- /// \todo use map methods, instead of multimap JPR
if ( !TagHT.count(key))
{
return GDCM_UNFOUND;
bool Document::SetEntryByNumber(std::string const& content,
uint16_t group, uint16_t element)
{
- int c;
- int l;
-
- ValEntry* valEntry = GetValEntryByNumber(group, element);
- if (!valEntry )
+ ValEntry* entry = GetValEntryByNumber(group, element);
+ if (!entry )
{
dbg.Verbose(0, "Document::SetEntryByNumber: no corresponding",
" ValEntry (try promotion first).");
return false;
}
- // Non even content must be padded with a space (020H)...
- std::string finalContent = Util::DicomString( content.c_str() );
- assert( !(finalContent.size() % 2) );
- valEntry->SetValue(finalContent);
-
- // Integers have a special treatement for their length:
-
- l = finalContent.length();
- if ( l != 0) // To avoid to be cheated by 'zero length' integers
- {
- VRKey vr = valEntry->GetVR();
- if( vr == "US" || vr == "SS" )
- {
- // for multivaluated items
- c = Util::CountSubstring(content, "\\") + 1;
- l = c*2;
- }
- else if( vr == "UL" || vr == "SL" )
- {
- // for multivaluated items
- c = Util::CountSubstring(content, "\\") + 1;
- l = c*4;;
- }
- }
- valEntry->SetLength(l);
- return true;
+ return SetEntry(content,entry);
}
/**
bool Document::SetEntryByNumber(uint8_t*content, int lgth,
uint16_t group, uint16_t element)
{
- (void)lgth; //not used
- TagKey key = DictEntry::TranslateToKey(group, element);
- if ( !TagHT.count(key))
+ BinEntry* entry = GetBinEntryByNumber(group, element);
+ if (!entry )
{
+ dbg.Verbose(0, "Document::SetEntryByNumber: no corresponding",
+ " ValEntry (try promotion first).");
return false;
}
-/* Hope Binary field length is *never* wrong
- if(lgth%2) // Non even length are padded with a space (020H).
- {
- lgth++;
- //content = content + '\0'; // fing a trick to enlarge a binary field?
- }
-*/
- BinEntry* entry = (BinEntry *)TagHT[key];
- entry->SetBinArea(content);
- entry->SetLength(lgth);
- entry->SetValue(GDCM_BINLOADED);
-
- return true;
+ return SetEntry(content,lgth,entry);
}
/**
* \brief Accesses an existing DocEntry (i.e. a Dicom Element)
- * in the PubDocEntrySet of this instance
- * through it's (group, element) and modifies it's length with
- * the given value.
- * \warning Use with extreme caution.
- * @param l new length to substitute with
- * @param group group number of the Entry to modify
- * @param element element number of the Entry to modify
- * @return true on success, false otherwise.
+ * and modifies it's content with the given value.
+ * @param content new value (string) to substitute with
+ * @param entry Entry to be modified
*/
-/*bool Document::SetEntryLengthByNumber(uint32_t l,
- uint16_t group, uint16_t element)
+bool Document::SetEntry(std::string const & content,ValEntry* entry)
{
- /// \todo use map methods, instead of multimap JPR
- TagKey key = DictEntry::TranslateToKey(group, element);
- if ( !TagHT.count(key) )
- {
- return false;
- }
- if ( l % 2 )
+ if(entry)
{
- l++; // length must be even
+ entry->SetValue(content);
+ return true;
}
- ( ((TagHT.equal_range(key)).first)->second )->SetLength(l);
-
- return true ;
-}*/
+ return false;
+}
/**
- * \brief Gets (from Header) the offset of a 'non string' element value
- * (LoadElementValues has already be executed)
- * @param group group number of the Entry
- * @param elem element number of the Entry
- * @return File Offset of the Element Value
+ * \brief Accesses an existing BinEntry (i.e. a Dicom Element)
+ * and modifies it's content with the given value.
+ * @param content new value (void* -> uint8_t*) to substitute with
+ * @param entry Entry to be modified
+ * @param lgth new value length
*/
-/*size_t Document::GetEntryOffsetByNumber(uint16_t group, uint16_t elem)
+bool Document::SetEntry(uint8_t* content, int lgth, BinEntry* entry)
{
- DocEntry* entry = GetDocEntryByNumber(group, elem);
- if (!entry)
+ if(entry)
{
- dbg.Verbose(1, "Document::GetDocEntryByNumber: no entry present.");
- return 0;
+ // Hope Binary field length is *never* wrong
+ /*if(lgth%2) // Non even length are padded with a space (020H).
+ {
+ lgth++;
+ //content = content + '\0'; // fing a trick to enlarge a binary field?
+ }*/
+
+ entry->SetBinArea(content);
+ entry->SetLength(lgth);
+ entry->SetValue(GDCM_BINLOADED);
+ return true;
}
- return entry->GetOffset();
-}*/
+ return false;
+}
/**
* \brief Gets (from Header) a 'non string' element value
return false;
}*/
-/**
- * \brief Update the entries with the shadow dictionary.
- * Only non even entries are analyzed
- */
-void Document::UpdateShaEntries()
-{
- //DictEntry *entry;
- std::string vr;
-
- /// \todo TODO : still any use to explore recursively the whole structure?
-/*
- for(ListTag::iterator it=listEntries.begin();
- it!=listEntries.end();
- ++it)
- {
- // Odd group => from public dictionary
- if((*it)->GetGroup()%2==0)
- continue;
-
- // Peer group => search the corresponding dict entry
- if(RefShaDict)
- entry=RefShaDict->GetDictEntryByNumber((*it)->GetGroup(),(*it)->GetElement());
- else
- entry=NULL;
-
- if((*it)->IsImplicitVR())
- vr="Implicit";
- else
- vr=(*it)->GetVR();
-
- (*it)->SetValue(GetDocEntryUnvalue(*it)); // to go on compiling
- if(entry){
- // Set the new entry and the new value
- (*it)->SetDictEntry(entry);
- CheckDocEntryVR(*it,vr);
-
- (*it)->SetValue(GetDocEntryValue(*it)); // to go on compiling
-
- }
- else
- {
- // Remove precedent value transformation
- (*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr));
- }
- }
-*/
-}
-
/**
* \brief Searches within the Header Entries for a Dicom Element of
* a given tag.
{
return 0;
}
- if ( ValEntry* valEntry = dynamic_cast<ValEntry*>(currentEntry) )
+ if ( ValEntry* entry = dynamic_cast<ValEntry*>(currentEntry) )
{
- return valEntry;
+ return entry;
}
dbg.Verbose(0, "Document::GetValEntryByNumber: unfound ValEntry.");
return 0;
}
+/**
+ * \brief Same as \ref Document::GetDocEntryByNumber except it only
+ * returns a result when the corresponding entry is of type
+ * BinEntry.
+ * @return When present, the corresponding BinEntry.
+ */
+BinEntry* Document::GetBinEntryByNumber(uint16_t group, uint16_t element)
+{
+ DocEntry* currentEntry = GetDocEntryByNumber(group, element);
+ if ( !currentEntry )
+ {
+ return 0;
+ }
+ if ( BinEntry* entry = dynamic_cast<BinEntry*>(currentEntry) )
+ {
+ return entry;
+ }
+ dbg.Verbose(0, "Document::GetBinEntryByNumber: unfound BinEntry.");
+
+ return 0;
+}
+
/**
* \brief Loads the element while preserving the current
* underlying file position indicator as opposed to
/**
* \brief Find the Value Representation of the current Dicom Element.
- * @param entry
+ * @return Value Representation of the current Entry
*/
-void Document::FindDocEntryVR( DocEntry *entry )
+std::string Document::FindDocEntryVR()
{
if ( Filetype != ExplicitVR )
- {
- return;
- }
-
- char vr[3];
+ return(GDCM_UNKNOWN);
long positionOnEntry = Fp->tellg();
// Warning: we believe this is explicit VR (Value Representation) because
// 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.
- vr[0] = 0x00;
- vr[1] = 0x00;
+
+ char vr[3];
Fp->read (vr, (size_t)2);
vr[2] = 0;
- if( !CheckDocEntryVR(entry, vr) )
+ if( !CheckDocEntryVR(vr) )
{
Fp->seekg(positionOnEntry, std::ios::beg);
- // When this element is known in the dictionary we shall use, e.g. for
- // the semantics (see the usage of IsAnInteger), the VR proposed by the
- // dictionary entry. Still we have to flag the element as implicit since
- // we know now our assumption on expliciteness is not furfilled.
- // avoid .
- if ( entry->IsVRUnknown() )
- {
- entry->SetVR("Implicit");
- }
- entry->SetImplicitVR();
+ 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 entry Header Entry to check
* @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(DocEntry *entry, VRKey vr)
+bool Document::CheckDocEntryVR(VRKey vr)
{
- std::string msg;
- bool realExplicit = true;
-
- // Assume we are reading a falsely explicit VR file i.e. we reached
- // a tag where we expect reading a VR but are in fact we read the
- // first to bytes of the length. Then we will interogate (through find)
- // the dicom_vr dictionary with oddities like "\004\0" which crashes
- // both GCC and VC++ implementations of the STL map. Hence when the
- // expected VR read happens to be non-ascii characters we consider
- // we hit falsely explicit VR tag.
-
- if ( !isalpha((unsigned char)vr[0]) && !isalpha((unsigned char)vr[1]) )
- {
- realExplicit = false;
- }
-
// 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 ( realExplicit && !Global::GetVR()->Count(vr) )
- {
- realExplicit = false;
- }
-
- if ( !realExplicit )
- {
- // We thought this was explicit VR, but we end up with an
- // implicit VR tag. Let's backtrack.
- msg = Util::Format("Falsely explicit vr file (%04x,%04x)\n",
- entry->GetGroup(), entry->GetElement());
- dbg.Verbose(1, "Document::FindVR: ", msg.c_str());
-
- if( entry->GetGroup() % 2 && entry->GetElement() == 0x0000)
- {
- // Group length is UL !
- DictEntry* newEntry = NewVirtualDictEntry(
- entry->GetGroup(), entry->GetElement(),
- "UL", "FIXME", "Group Length");
- entry->SetDictEntry( newEntry );
- }
+ if ( !Global::GetVR()->IsValidVR(vr) )
return false;
- }
-
- if ( entry->IsVRUnknown() )
- {
- // When not a dictionary entry, we can safely overwrite the VR.
- if( entry->GetElement() == 0x0000 )
- {
- // Group length is UL !
- entry->SetVR("UL");
- }
- else
- {
- entry->SetVR(vr);
- }
- }
- else if ( entry->GetVR() != vr )
- {
- // The VR present in the file and the dictionary disagree. We assume
- // the file writer knew best and use the VR of the file. Since it would
- // be unwise to overwrite the VR of a dictionary (since it would
- // compromise it's next user), we need to clone the actual DictEntry
- // and change the VR for the read one.
- DictEntry* newEntry = NewVirtualDictEntry(
- entry->GetGroup(), entry->GetElement(),
- vr, "FIXME", entry->GetName());
- entry->SetDictEntry(newEntry);
- }
return true;
}
if ( vr == "UL" || vr == "US" || vr == "SL" || vr == "SS" )
{
return true;
- }
-
+ }
return false;
}
reversedEndian--;
SwitchSwapToBigEndian();
}
-
}
/**
}
HandleBrokenEndian(group, elem);
- DocEntry *newEntry = NewDocEntryByNumber(group, elem);
- FindDocEntryVR(newEntry);
+ std::string vr=FindDocEntryVR();
+
+ DocEntry *newEntry = NewDocEntryByNumber(group, elem, vr);
+ if( vr == GDCM_UNKNOWN )
+ {
+ if( Filetype == ExplicitVR )
+ {
+ // We thought this was explicit VR, but we end up with an
+ // implicit VR tag. Let's backtrack.
+ std::string msg;
+ msg = Util::Format("Falsely explicit vr file (%04x,%04x)\n",
+ newEntry->GetGroup(), newEntry->GetElement());
+ dbg.Verbose(1, "Document::FindVR: ", msg.c_str());
+ }
+ newEntry->SetImplicitVR();
+ }
try
{
return false;
}
+
+/**
+ * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
+ * @param filetype Type of the File to be written
+ */
+int Document::ComputeGroup0002Length( FileType filetype )
+{
+ uint16_t gr, el;
+ std::string vr;
+
+ int groupLength = 0;
+ bool found0002 = false;
+
+ // for each zero-level Tag in the DCM Header
+ DocEntry *entry;
+
+ Initialize();
+ entry = GetNextEntry();
+ while(entry)
+ {
+ gr = entry->GetGroup();
+
+ if (gr == 0x0002)
+ {
+ found0002 = true;
+
+ el = entry->GetElement();
+ vr = entry->GetVR();
+
+ if (filetype == ExplicitVR)
+ {
+ if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") )
+ {
+ groupLength += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
+ }
+ }
+ groupLength += 2 + 2 + 4 + entry->GetLength();
+ }
+ else if (found0002 )
+ break;
+
+ entry = GetNextEntry();
+ }
+ return groupLength;
+}
+
} // end namespace gdcm
//-----------------------------------------------------------------------------