Program: gdcm
Module: $RCSfile: gdcmDocument.cxx,v $
Language: C++
- Date: $Date: 2004/10/24 03:33:40 $
- Version: $Revision: 1.111 $
+ Date: $Date: 2004/11/16 14:48:19 $
+ Version: $Revision: 1.128 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
#include <iomanip>
// For nthos:
-#ifdef _MSC_VER
+#if defined(_MSC_VER) || defined(__BORLANDC__)
#include <winsock.h>
#else
#include <netinet/in.h>
Filename = filename;
Initialise();
+ Fp = 0;
if ( !OpenFile() )
{
return;
*/
Document::Document() : ElementSet(-1)
{
+ Fp = 0;
+
SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
Initialise();
+ SwapCode = 0;
+ Filetype = ExplicitVR;
PrintLevel = 1; // 'Medium' print level by default
}
RefPubDict = NULL;
RefShaDict = NULL;
- // Recursive clean up of sequences
- for (TagDocEntryHT::const_iterator it = TagHT.begin();
- it != TagHT.end(); ++it )
- {
- //delete it->second; //temp remove
- }
- TagHT.clear();
+ delete RLEInfo;
+ delete JPEGInfo;
}
//-----------------------------------------------------------------------------
return true;
}
-
/**
- * \brief Internal function that checks whether the Transfer Syntax given
- * as argument is the one present in the current document.
- * @param syntaxToCheck The transfert syntax we need to check against.
- * @return True when SyntaxToCheck corresponds to the Transfer Syntax of
- * the current document. False either when the document contains
- * no Transfer Syntax, or when the Tranfer Syntaxes doesn't match.
+ * \brief Accessor to the Transfer Syntax (when present) of the
+ * current document (it internally handles reading the
+ * value from disk when only parsing occured).
+ * @return The encountered Transfer Syntax of the current document.
*/
TransferSyntaxType Document::GetTransferSyntax()
{
*/
std::ifstream* Document::OpenFile()
{
+ if (Filename.length() == 0) return 0;
+ if(Fp)
+ {
+ dbg.Verbose( 0,
+ "Document::OpenFile is already opened when opening: ",
+ Filename.c_str());
+ }
+
Fp = new std::ifstream(Filename.c_str(), std::ios::in | std::ios::binary);
if(!Fp)
return Fp;
}
- Fp->close();
+ CloseFile();
dbg.Verbose( 0,
"Document::OpenFile not DICOM/ACR (missing preamble)",
Filename.c_str());
*/
bool Document::CloseFile()
{
- Fp->close();
- delete Fp;
- Fp = 0;
+ if( Fp )
+ {
+ Fp->close();
+ delete Fp;
+ Fp = 0;
+ }
- return true; //FIXME how do we detect a non-close ifstream ?
+ return true; //FIXME how do we detect a non-close ifstream ?
}
/**
if (filetype == ImplicitVR)
{
- std::string ts = TransferSyntaxStrings[ImplicitVRLittleEndian];
+ std::string ts =
+ Util::DicomString( TransferSyntaxStrings[ImplicitVRLittleEndian] );
ReplaceOrCreateByNumber(ts, 0x0002, 0x0010);
/// \todo Refer to standards on page 21, chapter 6.2
if (filetype == ExplicitVR)
{
- std::string ts = TransferSyntaxStrings[ExplicitVRLittleEndian];
- ReplaceOrCreateByNumber(ts, 0x0002, 0x0010);
+ std::string ts =
+ Util::DicomString( TransferSyntaxStrings[ExplicitVRLittleEndian] );
+ ReplaceOrCreateByNumber(ts, 0x0002, 0x0010); //LEAK
/// \todo Refer to standards on page 21, chapter 6.2
/// "Value representation": values with a VR of UI shall be
* @param value (string) 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-
+ * @param vr V(alue) R(epresentation) of the Entry -if private Entry-
* \return pointer to the modified/created Header Entry (NULL when creation
* failed).
*/
" NewDocEntryByNumber failed.");
return NULL;
}
+
valEntry = new ValEntry(currentEntry);
+ delete currentEntry;
+
if ( !AddEntry(valEntry))
{
+ delete valEntry;
dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: AddEntry"
" failed allthough this is a creation.");
+ return NULL;
}
}
else
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;
bool Document::CheckIfEntryExistByNumber(uint16_t group, uint16_t element )
{
const std::string &key = DictEntry::TranslateToKey(group, element );
- return TagHT.count(key);
+ return TagHT.count(key) != 0;
}
/**
* @param tagName name of the searched Dicom Element.
* @return true when found
*/
-bool Document::SetEntryByName(std::string const & content,
- TagName const & tagName)
+bool Document::SetEntryByName( std::string const & content,
+ TagName const & tagName)
{
DictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName);
if( !dictEntry )
return false;
}
// Non even content must be padded with a space (020H)...
- std::string finalContent = content;
- if( finalContent.length() % 2 )
- {
- finalContent += '\0'; // ... therefore we padd with (000H) .!?!
- }
+ 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();
* @param group group number of the Entry
* @param elem element number of the Entry
*/
-void* Document::LoadEntryBinArea(uint16_t group, uint16_t elem)
+void Document::LoadEntryBinArea(uint16_t group, uint16_t elem)
{
+ // Search the corresponding DocEntry
DocEntry *docElement = GetDocEntryByNumber(group, elem);
if ( !docElement )
- {
- return NULL;
- }
+ return;
+
size_t o =(size_t)docElement->GetOffset();
Fp->seekg( o, std::ios_base::beg);
size_t l = docElement->GetLength();
if(!a)
{
dbg.Verbose(0, "Document::LoadEntryBinArea cannot allocate a");
- return NULL;
+ return;
}
+
+ // Read the value
Fp->read((char*)a, l);
if( Fp->fail() || Fp->eof() )//Fp->gcount() == 1
{
delete[] a;
- return NULL;
+ return;
}
- /// \todo Drop any already existing void area! JPR
+
+ // Set the value to the DocEntry
if( !SetEntryBinAreaByNumber( a, group, elem ) )
{
+ delete[] a;
dbg.Verbose(0, "Document::LoadEntryBinArea setting failed.");
}
- return a;
}
/**
* \brief Loads (from disk) the element content
* when a string is not suitable
* @param element Entry whose binArea is going to be loaded
*/
-void* Document::LoadEntryBinArea(BinEntry* element)
+void Document::LoadEntryBinArea(BinEntry* element)
{
size_t o =(size_t)element->GetOffset();
Fp->seekg(o, std::ios_base::beg);
if( !a )
{
dbg.Verbose(0, "Document::LoadEntryBinArea cannot allocate a");
- return NULL;
+ return;
}
- element->SetBinArea((uint8_t*)a);
+
/// \todo check the result
Fp->read((char*)a, l);
if( Fp->fail() || Fp->eof()) //Fp->gcount() == 1
{
delete[] a;
- return NULL;
+ return;
}
- return a;
+ element->SetBinArea((uint8_t*)a);
}
/**
{
return false;
}
+
if ( BinEntry* binEntry = dynamic_cast<BinEntry*>(currentEntry) )
{
binEntry->SetBinArea( area );
return true;
}
- return true;
+
+ return false;
}
/**
{
/////////////////////// ValEntry
ValEntry* newValEntry =
- new ValEntry( newDocEntry->GetDictEntry() );
+ new ValEntry( newDocEntry->GetDictEntry() ); //LEAK
newValEntry->Copy( newDocEntry );
// When "set" is a Document, then we are at the top of the
+ newValEntry->GetKey() );
}
- set->AddEntry( newValEntry );
LoadDocEntry( newValEntry );
- if (newValEntry->IsItemDelimitor())
+ bool delimitor=newValEntry->IsItemDelimitor();
+ if( !set->AddEntry( newValEntry ) )
+ {
+ // If here expect big troubles
+ delete newValEntry; //otherwise mem leak
+ }
+
+ if (delimitor)
{
break;
}
}
//////////////////// BinEntry or UNKOWN VR:
- BinEntry* newBinEntry =
- new BinEntry( newDocEntry->GetDictEntry() );
- newBinEntry->Copy( newDocEntry );
+/* BinEntry* newBinEntry =
+ new BinEntry( newDocEntry->GetDictEntry() ); //LEAK
+ newBinEntry->Copy( newDocEntry );*/
+ BinEntry* newBinEntry = new BinEntry( newDocEntry ); //LEAK
// When "this" is a Document the Key is simply of the
// form ( group, elem )...
+ newBinEntry->GetKey() );
}
- set->AddEntry( newBinEntry );
LoadDocEntry( newBinEntry );
+ if( !set->AddEntry( newBinEntry ) )
+ {
+ //Expect big troubles if here
+ delete newBinEntry;
+ }
}
if ( ( newDocEntry->GetGroup() == 0x7fe0 )
s << " x(" << std::hex << entry->GetLength() << ")";
binEntryPtr->SetValue(s.str());
}
- // Be carefull : a BinEntry IS_A ValEntry ...
+ // Be carefull : a BinEntry IS_A ValEntry ...
else if (ValEntry* valEntryPtr = dynamic_cast< ValEntry* >(entry) )
{
// s << "gdcm::NotLoaded. (ValEntry)";
}
// to be sure we are at the end of the value ...
- Fp->seekg((long)entry->GetOffset()+(long)entry->GetLength(),std::ios_base::beg);
+ Fp->seekg((long)entry->GetOffset()+(long)entry->GetLength(),
+ std::ios_base::beg);
return;
}
return;
}
- // We need an additional byte for storing \0 that is not on disk
+ // 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';
- std::string newValue = str;
+ 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);
+ //dbg.Verbose(0, "Warning: bad length: ", length );
+ dbg.Verbose(0, "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())//Fp->gcount() == 1
{
dbg.Verbose(1, "Document::LoadDocEntry",
{
uint16_t element = entry->GetElement();
uint16_t group = entry->GetGroup();
- std::string vr = entry->GetVR();
+ const std::string & vr = entry->GetVR();
uint32_t length = entry->GetLength();
// When we have some semantics on the element we just read, and if we
Fp->read ((char*)&g, (size_t)2);
if ( Fp->fail() )
{
- throw FormatError( "Document::ReadInt16()", " file error." );
+ throw FormatError( "Document::ReadInt16()", " file error." );
}
if( Fp->eof() )
{
uint32_t s32;
uint16_t s16;
- char deb[HEADER_LENGTH_TO_READ];
+ char deb[256]; //HEADER_LENGTH_TO_READ];
// First, compare HostByteOrder and NetworkByteOrder in order to
// determine if we shall need to swap bytes (i.e. the Endian type).
+/**
+ * \brief Handle broken private tag from Philips NTSCAN
+ * where the endianess is being switch to BigEndian for no
+ * apparent reason
+ * @return no return
+ */
+void Document::HandleBrokenEndian(uint16_t group, uint16_t elem)
+{
+ // Endian reversion. Some files contain groups of tags with reversed endianess.
+ static int reversedEndian = 0;
+ // try to fix endian switching in the middle of headers
+ if ((group == 0xfeff) && (elem == 0x00e0))
+ {
+ // start endian swap mark for group found
+ reversedEndian++;
+ SwitchSwapToBigEndian();
+ // fix the tag
+ group = 0xfffe;
+ elem = 0xe000;
+ }
+ else if ((group == 0xfffe) && (elem == 0xe00d) && reversedEndian)
+ {
+ // end of reversed endian group
+ reversedEndian--;
+ SwitchSwapToBigEndian();
+ }
+
+}
+
/**
* \brief Read the next tag but WITHOUT loading it's value
* (read the 'Group Number', the 'Element Number',
return 0;
}
+ HandleBrokenEndian(group, elem);
DocEntry *newEntry = NewDocEntryByNumber(group, elem);
FindDocEntryVR(newEntry);
//// Read the Item Tag group and element, and make
// sure they are what we expected:
- uint16_t itemTagGroup = ReadInt16();
- uint16_t itemTagElement = ReadInt16();
+ uint16_t itemTagGroup;
+ uint16_t itemTagElement;
+ try
+ {
+ itemTagGroup = ReadInt16();
+ itemTagElement = ReadInt16();
+ }
+ catch ( FormatError e )
+ {
+ //std::cerr << e << std::endl;
+ return false;
+ }
if ( itemTagGroup != testGroup || itemTagElement != testElement )
{
std::ostringstream s;
dbg.Verbose(0, "Document::ComputeRLEInfo: too many segments.");
}
- uint32_t rleSegmentOffsetTable[15];
+ uint32_t rleSegmentOffsetTable[16];
for( int k = 1; k <= 15; k++ )
{
rleSegmentOffsetTable[k] = ReadInt32();
{
if (ElementSet* elementSet = dynamic_cast< ElementSet* > ( set ) )
{
- TagDocEntryHT* currentHT = elementSet->GetTagHT();
- for( TagDocEntryHT::const_iterator i = currentHT->begin();
- i != currentHT->end();
+ TagDocEntryHT const & currentHT = elementSet->GetTagHT();
+ for( TagDocEntryHT::const_iterator i = currentHT.begin();
+ i != currentHT.end();
++i)
{
DocEntry* entry = i->second;
if ( SeqEntry* seqEntry = dynamic_cast<SeqEntry*>(entry) )
{
- ListSQItem& items = seqEntry->GetSQItems();
+ const ListSQItem& items = seqEntry->GetSQItems();
for( ListSQItem::const_iterator item = items.begin();
item != items.end();
++item)
if (SQItem* SQItemSet = dynamic_cast< SQItem* > ( set ) )
{
- ListDocEntry& currentList = SQItemSet->GetDocEntries();
- for (ListDocEntry::iterator i = currentList.begin();
- i != currentList.end();
- ++i)
+ const ListDocEntry& currentList = SQItemSet->GetDocEntries();
+ for (ListDocEntry::const_iterator i = currentList.begin();
+ i != currentList.end();
+ ++i)
{
DocEntry* entry = *i;
if ( SeqEntry* seqEntry = dynamic_cast<SeqEntry*>(entry) )
{
- ListSQItem& items = seqEntry->GetSQItems();
+ const ListSQItem& items = seqEntry->GetSQItems();
for( ListSQItem::const_iterator item = items.begin();
item != items.end();
++item)