Program: gdcm
Module: $RCSfile: gdcmDocument.cxx,v $
Language: C++
- Date: $Date: 2005/01/06 13:35:38 $
- Version: $Revision: 1.155 $
+ Date: $Date: 2005/01/06 17:16:15 $
+ Version: $Revision: 1.160 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
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",
// Unknown
"Unknown Transfer Syntax"
};
-
+
//-----------------------------------------------------------------------------
// Refer to Document::CheckSwap()
//const unsigned int Document::HEADER_LENGTH_TO_READ = 256;
}
/**
- * \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;
}
/**
bool Document::SetEntryByNumber(std::string const& content,
uint16_t group, uint16_t element)
{
- 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)...
- valEntry->SetValue(content);
- 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?
+ return SetEntry(content,lgth,entry);
+}
+
+/**
+ * \brief Accesses an existing DocEntry (i.e. a Dicom Element)
+ * 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::SetEntry(std::string const & content,ValEntry* entry)
+{
+ if(entry)
+ {
+ entry->SetValue(content);
+ return true;
}
-*/
- BinEntry* entry = (BinEntry *)TagHT[key];
- entry->SetBinArea(content);
- entry->SetLength(lgth);
- entry->SetValue(GDCM_BINLOADED);
+ return false;
+}
- return true;
-}
+/**
+ * \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
+ */
+bool Document::SetEntry(uint8_t* content, int lgth, BinEntry* entry)
+{
+ if(entry)
+ {
+ // 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 false;
+}
/**
* \brief Gets (from Header) a 'non string' element value
{
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
long l_max, bool delim_mode)
{
DocEntry *newDocEntry = 0;
+ ValEntry* newValEntry;
+ BinEntry* newBinEntry;
+ SeqEntry* newSeqEntry;
+ VRKey vr;
+ bool used=false;
+ long offsetEntry,readEntry;
while (true)
{
{
break;
}
+
+ used=true;
newDocEntry = ReadNextDocEntry( );
if ( !newDocEntry )
{
break;
}
- VRKey vr = newDocEntry->GetVR();
- if ( vr != "SQ" )
+ vr = newDocEntry->GetVR();
+ newValEntry = dynamic_cast<ValEntry*>(newDocEntry);
+ newBinEntry = dynamic_cast<BinEntry*>(newDocEntry);
+ newSeqEntry = dynamic_cast<SeqEntry*>(newDocEntry);
+
+ if ( newValEntry || newBinEntry )
{
+ offsetEntry=newDocEntry->GetOffset();
+ readEntry=newDocEntry->GetReadLength();
- if ( Global::GetVR()->IsVROfGdcmStringRepresentable(vr) )
+ if ( newBinEntry )
+ {
+ if ( ! Global::GetVR()->IsVROfBinaryRepresentable(vr) )
+ {
+ ////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
+ dbg.Verbose(0, "Document::ParseDES: neither Valentry, "
+ "nor BinEntry. Probably unknown VR.");
+ }
+
+ //////////////////// BinEntry or UNKOWN VR:
+ // When "this" is a Document the Key is simply of the
+ // form ( group, elem )...
+ if (Document* dummy = dynamic_cast< Document* > ( set ) )
+ {
+ (void)dummy;
+ newBinEntry->SetKey( newBinEntry->GetKey() );
+ }
+ // but when "this" is a SQItem, we are inserting this new
+ // valEntry in a sequence item, and the kay has the
+ // generalized form (refer to \ref BaseTagKey):
+ if (SQItem* parentSQItem = dynamic_cast< SQItem* > ( set ) )
+ {
+ newBinEntry->SetKey( parentSQItem->GetBaseTagKey()
+ + newBinEntry->GetKey() );
+ }
+
+ LoadDocEntry( newBinEntry );
+ if( !set->AddEntry( newBinEntry ) )
+ {
+ //Expect big troubles if here
+ //delete newBinEntry;
+ used=false;
+ }
+ }
+ else
{
/////////////////////// ValEntry
- ValEntry* newValEntry =
- new ValEntry( newDocEntry->GetDictEntry() ); //LEAK
- newValEntry->Copy( newDocEntry );
-
// When "set" is a Document, then we are at the top of the
// hierarchy and the Key is simply of the form ( group, elem )...
if (Document* dummy = dynamic_cast< Document* > ( set ) )
if( !set->AddEntry( newValEntry ) )
{
// If here expect big troubles
- delete newValEntry; //otherwise mem leak
+ //delete newValEntry; //otherwise mem leak
+ used=false;
}
if (delimitor)
{
- delete newDocEntry;
+ if(!used)
+ delete newDocEntry;
break;
}
if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max)
{
- delete newDocEntry;
+ if(!used)
+ delete newDocEntry;
break;
}
}
- else
- {
- if ( ! Global::GetVR()->IsVROfGdcmBinaryRepresentable(vr) )
- {
- ////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
- dbg.Verbose(0, "Document::ParseDES: neither Valentry, "
- "nor BinEntry. Probably unknown VR.");
- }
-
- //////////////////// BinEntry or UNKOWN VR:
- BinEntry* newBinEntry = new BinEntry( newDocEntry ); //LEAK
-
- // When "this" is a Document the Key is simply of the
- // form ( group, elem )...
- if (Document* dummy = dynamic_cast< Document* > ( set ) )
- {
- (void)dummy;
- newBinEntry->SetKey( newBinEntry->GetKey() );
- }
- // but when "this" is a SQItem, we are inserting this new
- // valEntry in a sequence item, and the kay has the
- // generalized form (refer to \ref BaseTagKey):
- if (SQItem* parentSQItem = dynamic_cast< SQItem* > ( set ) )
- {
- newBinEntry->SetKey( parentSQItem->GetBaseTagKey()
- + newBinEntry->GetKey() );
- }
-
- LoadDocEntry( newBinEntry );
- if( !set->AddEntry( newBinEntry ) )
- {
- //Expect big troubles if here
- delete newBinEntry;
- }
- }
if ( ( newDocEntry->GetGroup() == 0x7fe0 )
&& ( newDocEntry->GetElement() == 0x0010 ) )
TransferSyntaxType ts = GetTransferSyntax();
if ( ts == RLELossless )
{
- long PositionOnEntry = Fp->tellg();
+ long positionOnEntry = Fp->tellg();
Fp->seekg( newDocEntry->GetOffset(), std::ios::beg );
ComputeRLEInfo();
- Fp->seekg( PositionOnEntry, std::ios::beg );
+ Fp->seekg( positionOnEntry, std::ios::beg );
}
else if ( IsJPEG() )
{
- long PositionOnEntry = Fp->tellg();
+ long positionOnEntry = Fp->tellg();
Fp->seekg( newDocEntry->GetOffset(), std::ios::beg );
ComputeJPEGFragmentInfo();
- Fp->seekg( PositionOnEntry, std::ios::beg );
+ Fp->seekg( positionOnEntry, std::ios::beg );
}
}
// Just to make sure we are at the beginning of next entry.
- SkipToNextDocEntry(newDocEntry);
- //delete newDocEntry;
+ SkipToNextDocEntry(offsetEntry,readEntry);
}
else
{
}
}
// no other way to create it ...
- SeqEntry* newSeqEntry =
- new SeqEntry( newDocEntry->GetDictEntry() );
- newSeqEntry->Copy( newDocEntry );
newSeqEntry->SetDelimitorMode( delim_mode );
// At the top of the hierarchy, stands a Document. When "set"
set->AddEntry( newSeqEntry );
if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max)
{
- delete newDocEntry;
break;
}
}
- delete newDocEntry;
+
+ if(!used)
+ delete newDocEntry;
}
}
/**
* \brief Find the Value Representation of the current Dicom Element.
- * @param entry
+ * @return Value Representation of the current Entry
*/
std::string Document::FindDocEntryVR()
{
* \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
* \warning NOT end user intended method !
* @param entry entry to skip
*/
-void Document::SkipToNextDocEntry(DocEntry *entry)
+void Document::SkipToNextDocEntry(long offset,long readLgth)
{
- Fp->seekg((long)(entry->GetOffset()), std::ios::beg);
- Fp->seekg( (long)(entry->GetReadLength()), std::ios::cur);
+ Fp->seekg((long)(offset), std::ios::beg);
+ Fp->seekg( (long)(readLgth), std::ios::cur);
}
/**
}
HandleBrokenEndian(group, elem);
- std::string vr=FindDocEntryVR();
+ std::string vr = FindDocEntryVR();
+ std::string realVR = vr;
+
+ if( vr == GDCM_UNKNOWN)
+ {
+ DictEntry *dictEntry = GetDictEntryByNumber(group,elem);
+ if( dictEntry )
+ realVR = dictEntry->GetVR();
+ }
+
+ DocEntry *newEntry;
+ if( Global::GetVR()->IsVROfSequence(realVR) )
+ newEntry = NewSeqEntryByNumber(group, elem);
+ else if( Global::GetVR()->IsVROfStringRepresentable(realVR) )
+ newEntry = NewValEntryByNumber(group, elem,vr);
+ else
+ newEntry = NewBinEntryByNumber(group, elem,vr);
- DocEntry *newEntry = NewDocEntryByNumber(group, elem, vr);
if( vr == GDCM_UNKNOWN )
{
if( Filetype == ExplicitVR )