Program: gdcm
Module: $RCSfile: gdcmDocument.cxx,v $
Language: C++
- Date: $Date: 2004/10/20 14:30:40 $
- Version: $Revision: 1.106 $
+ Date: $Date: 2004/11/09 21:55:55 $
+ Version: $Revision: 1.119 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
#include "gdcmDebug.h"
#include <vector>
+#include <iomanip>
// For nthos:
-#ifdef _MSC_VER
+#if defined(_MSC_VER) || defined(__BORLANDC__)
#include <winsock.h>
#else
#include <netinet/in.h>
#endif
-#include <iomanip>
-
namespace gdcm
{
-
-// Implicit VR Little Endian
-#define UI1_2_840_10008_1_2 "1.2.840.10008.1.2"
-// Explicit VR Little Endian
-#define UI1_2_840_10008_1_2_1 "1.2.840.10008.1.2.1"
-// Deflated Explicit VR Little Endian
-#define UI1_2_840_10008_1_2_1_99 "1.2.840.10008.1.2.1.99"
-// Explicit VR Big Endian
-#define UI1_2_840_10008_1_2_2 "1.2.840.10008.1.2.2"
-// JPEG Baseline (Process 1)
-#define UI1_2_840_10008_1_2_4_50 "1.2.840.10008.1.2.4.50"
-// JPEG Extended (Process 2 & 4)
-#define UI1_2_840_10008_1_2_4_51 "1.2.840.10008.1.2.4.51"
-// JPEG Extended (Process 3 & 5)
-#define UI1_2_840_10008_1_2_4_52 "1.2.840.10008.1.2.4.52"
-// JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8)
-#define UI1_2_840_10008_1_2_4_53 "1.2.840.10008.1.2.4.53"
-// JPEG Full Progression, Non-Hierarchical (Process 10 & 12)
-#define UI1_2_840_10008_1_2_4_55 "1.2.840.10008.1.2.4.55"
-// JPEG Lossless, Non-Hierarchical (Process 14)
-#define UI1_2_840_10008_1_2_4_57 "1.2.840.10008.1.2.4.57"
-// JPEG Lossless, Hierarchical, First-Order Prediction (Process 14,
-// [Selection Value 1])
-#define UI1_2_840_10008_1_2_4_70 "1.2.840.10008.1.2.4.70"
-// JPEG 2000 Lossless
-#define UI1_2_840_10008_1_2_4_90 "1.2.840.10008.1.2.4.90"
-// JPEG 2000
-#define UI1_2_840_10008_1_2_4_91 "1.2.840.10008.1.2.4.91"
-// RLE Lossless
-#define UI1_2_840_10008_1_2_5 "1.2.840.10008.1.2.5"
-// UI1_1_2_840_10008_1_2_5
-#define str2num(str, typeNum) *((typeNum *)(str))
+static const char *TransferSyntaxStrings[] = {
+ // Implicit VR Little Endian
+ "1.2.840.10008.1.2",
+ // Explicit VR Little Endian
+ "1.2.840.10008.1.2.1",
+ // Deflated Explicit VR Little Endian
+ "1.2.840.10008.1.2.1.99",
+ // Explicit VR Big Endian
+ "1.2.840.10008.1.2.2",
+ // JPEG Baseline (Process 1)
+ "1.2.840.10008.1.2.4.50",
+ // JPEG Extended (Process 2 & 4)
+ "1.2.840.10008.1.2.4.51",
+ // JPEG Extended (Process 3 & 5)
+ "1.2.840.10008.1.2.4.52",
+ // JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8)
+ "1.2.840.10008.1.2.4.53",
+ // JPEG Full Progression, Non-Hierarchical (Process 10 & 12)
+ "1.2.840.10008.1.2.4.55",
+ // JPEG Lossless, Non-Hierarchical (Process 14)
+ "1.2.840.10008.1.2.4.57",
+ // JPEG Lossless, Hierarchical, First-Order Prediction (Process 14, [Selection Value 1])
+ "1.2.840.10008.1.2.4.70",
+ // JPEG 2000 Lossless
+ "1.2.840.10008.1.2.4.90",
+ // JPEG 2000
+ "1.2.840.10008.1.2.4.91",
+ // RLE Lossless
+ "1.2.840.10008.1.2.5",
+ // Unknown
+ "Unknown Transfer Syntax"
+};
//-----------------------------------------------------------------------------
// Refer to Document::CheckSwap()
* \brief constructor
* @param filename file to be opened for parsing
*/
-Document::Document( std::string const & filename )
- : ElementSet(-1)
+Document::Document( std::string const & filename ) : ElementSet(-1)
{
SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
Filename = filename;
dbg.Verbose(0, "Document::Document: starting parsing of file: ",
Filename.c_str());
- rewind(Fp);
+ Fp->seekg( 0, std::ios_base::beg);
- fseek(Fp,0L,SEEK_END);
- long lgt = ftell(Fp);
+ Fp->seekg(0, std::ios_base::end);
+ long lgt = Fp->tellg();
- rewind(Fp);
+ Fp->seekg( 0, std::ios_base::beg);
CheckSwap();
- long beg = ftell(Fp);
+ long beg = Fp->tellg();
lgt -= beg;
ParseDES( this, beg, lgt, false); // le Load sera fait a la volee
- rewind(Fp);
+ Fp->seekg( 0, std::ios_base::beg);
// Load 'non string' values
* \brief This default constructor doesn't parse the file. You should
* then invoke \ref Document::SetFileName and then the parsing.
*/
-Document::Document()
- :ElementSet(-1)
+Document::Document() : ElementSet(-1)
{
SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
Initialise();
//delete it->second; //temp remove
}
TagHT.clear();
+ delete RLEInfo;
+ delete JPEGInfo;
}
//-----------------------------------------------------------------------------
* the current document. False either when the document contains
* no Transfer Syntax, or when the Tranfer Syntaxes doesn't match.
*/
-bool Document::IsGivenTransferSyntax(std::string const & syntaxToCheck)
+TransferSyntaxType Document::GetTransferSyntax()
{
DocEntry *entry = GetDocEntryByNumber(0x0002, 0x0010);
if ( !entry )
{
- return false;
+ return UnknownTS;
}
// The entry might be present but not loaded (parsing and loading
// The actual transfer (as read from disk) might be padded. We
// first need to remove the potential padding. We can make the
// weak assumption that padding was not executed with digits...
- if ( transfer.length() == 0 ) { // for brain damaged headers
- return false;
+ if ( transfer.length() == 0 )
+ {
+ // for brain damaged headers
+ return UnknownTS;
}
- while ( ! isdigit(transfer[transfer.length()-1]) )
+ while ( !isdigit(transfer[transfer.length()-1]) )
{
transfer.erase(transfer.length()-1, 1);
}
- if ( transfer == syntaxToCheck )
+ for (int i = 0; TransferSyntaxStrings[i] != NULL; i++)
{
- return true;
+ if ( TransferSyntaxStrings[i] == transfer )
+ {
+ return TransferSyntaxType(i);
+ }
}
}
- return false;
-}
-
-/**
- * \brief Determines if the Transfer Syntax of the present document
- * corresponds to a Implicit Value Representation of
- * Little Endian.
- * \sa \ref Document::IsGivenTransferSyntax.
- * @return True when ImplicitVRLittleEndian found. False in all other cases.
- */
-bool Document::IsImplicitVRLittleEndianTransferSyntax()
-{
- return IsGivenTransferSyntax(UI1_2_840_10008_1_2);
-}
-
-/**
- * \brief Determines if the Transfer Syntax was already encountered
- * and if it corresponds to a ExplicitVRLittleEndian one.
- * @return True when ExplicitVRLittleEndian found. False in all other cases.
- */
-bool Document::IsExplicitVRLittleEndianTransferSyntax()
-{
- return IsGivenTransferSyntax(UI1_2_840_10008_1_2_1);
-}
-
-/**
- * \brief Determines if the Transfer Syntax was already encountered
- * and if it corresponds to a DeflatedExplicitVRLittleEndian one.
- * @return True when DeflatedExplicitVRLittleEndian found. False in all other cases.
- */
-bool Document::IsDeflatedExplicitVRLittleEndianTransferSyntax()
-{
- return IsGivenTransferSyntax(UI1_2_840_10008_1_2_1_99);
-}
-
-/**
- * \brief Determines if the Transfer Syntax was already encountered
- * and if it corresponds to a Explicit VR Big Endian one.
- * @return True when big endian found. False in all other cases.
- */
-bool Document::IsExplicitVRBigEndianTransferSyntax()
-{
- return IsGivenTransferSyntax(UI1_2_840_10008_1_2_2);
-}
-
-/**
- * \brief Determines if the Transfer Syntax was already encountered
- * and if it corresponds to a JPEGBaseLineProcess1 one.
- * @return True when JPEGBaseLineProcess1found. False in all other cases.
- */
-bool Document::IsJPEGBaseLineProcess1TransferSyntax()
-{
- return IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_50);
-}
-
-/**
- * \brief Determines if the Transfer Syntax was already encountered
- * and if it corresponds to a JPEGExtendedProcess2-4 one.
- * @return True when JPEGExtendedProcess2-4 found. False in all other cases.
- */
-bool Document::IsJPEGExtendedProcess2_4TransferSyntax()
-{
- return IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_51);
-}
-
-/**
- * \brief Determines if the Transfer Syntax was already encountered
- * and if it corresponds to a JPEGExtendeProcess3-5 one.
- * @return True when JPEGExtendedProcess3-5 found. False in all other cases.
- */
-bool Document::IsJPEGExtendedProcess3_5TransferSyntax()
-{
- return IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_52);
+ return UnknownTS;
}
-/**
- * \brief Determines if the Transfer Syntax was already encountered
- * and if it corresponds to a JPEGSpectralSelectionProcess6-8 one.
- * @return True when JPEGSpectralSelectionProcess6-8 found. False in all
- * other cases.
- */
-bool Document::IsJPEGSpectralSelectionProcess6_8TransferSyntax()
-{
- return IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_53);
-}
-
-/**
- * \brief Determines if the Transfer Syntax was already encountered
- * and if it corresponds to a RLE Lossless one.
- * @return True when RLE Lossless found. False in all
- * other cases.
- */
-bool Document::IsRLELossLessTransferSyntax()
-{
- return IsGivenTransferSyntax(UI1_2_840_10008_1_2_5);
-}
-
-/**
- * \brief Determines if Transfer Syntax was already encountered
- * and if it corresponds to a JPEG Lossless one.
- * @return True when RLE Lossless found. False in all
- * other cases.
- */
-
bool Document::IsJPEGLossless()
{
- return ( IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_55)
- || IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_57)
- || IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_70) );
+ TransferSyntaxType r = GetTransferSyntax();
+ return r == JPEGFullProgressionProcess10_12
+ || r == JPEGLosslessProcess14
+ || r == JPEGLosslessProcess14_1;
}
/**
*/
bool Document::IsJPEG2000()
{
- return ( IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_90)
- || IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_91) );
+ TransferSyntaxType r = GetTransferSyntax();
+ return r == JPEG2000Lossless || r == JPEG2000;
}
/**
* of Jpeg encoded Pixel data.
* @return True when any form of JPEG found. False otherwise.
*/
-bool Document::IsJPEGTransferSyntax()
+bool Document::IsJPEG()
{
- return ( IsJPEGBaseLineProcess1TransferSyntax()
- || IsJPEGExtendedProcess2_4TransferSyntax()
- || IsJPEGExtendedProcess3_5TransferSyntax()
- || IsJPEGSpectralSelectionProcess6_8TransferSyntax()
- || IsJPEGLossless()
- || IsJPEG2000() );
+ TransferSyntaxType r = GetTransferSyntax();
+ return r == JPEGBaselineProcess1
+ || r == JPEGExtendedProcess2_4
+ || r == JPEGExtendedProcess3_5
+ || r == JPEGSpectralSelectionProcess6_8
+ || IsJPEGLossless()
+ || IsJPEG2000();
}
-
/**
* \brief Determines if the Transfer Syntax corresponds to encapsulated
* of encoded Pixel Data (as opposed to native).
* @return True when encapsulated. False when native.
*/
-bool Document::IsEncapsulateTransferSyntax()
+bool Document::IsEncapsulate()
{
- return ( IsJPEGTransferSyntax()
- || IsRLELossLessTransferSyntax() );
+ TransferSyntaxType r = GetTransferSyntax();
+ return IsJPEG() || r == RLELossless;
}
/**
* checks the preamble when existing.
* @return The FILE pointer on success.
*/
-FILE* Document::OpenFile()
+std::ifstream* Document::OpenFile()
{
- Fp = fopen(Filename.c_str(),"rb");
+ Fp = new std::ifstream(Filename.c_str(), std::ios::in | std::ios::binary);
if(!Fp)
{
}
uint16_t zero;
- fread(&zero, (size_t)2, (size_t)1, Fp);
+ Fp->read((char*)&zero, (size_t)2 );
//ACR -- or DICOM with no Preamble --
if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200 )
}
//DICOM
- fseek(Fp, 126L, SEEK_CUR);
+ Fp->seekg(126L, std::ios_base::cur);
char dicm[4];
- fread(dicm, (size_t)4, (size_t)1, Fp);
+ Fp->read(dicm, (size_t)4);
if( memcmp(dicm, "DICM", 4) == 0 )
{
return Fp;
}
- fclose(Fp);
+ Fp->close();
dbg.Verbose( 0,
"Document::OpenFile not DICOM/ACR (missing preamble)",
Filename.c_str());
*/
bool Document::CloseFile()
{
- int closed = fclose(Fp);
+ Fp->close();
+ delete Fp;
Fp = 0;
- return closed;
+ return true; //FIXME how do we detect a non-close ifstream ?
}
/**
* (ACR-NEMA, ExplicitVR, ImplicitVR)
* \return Always true.
*/
-void Document::Write(FILE* fp,FileType filetype)
+void Document::Write(std::ofstream* fp, FileType filetype)
{
/// \todo move the following lines (and a lot of others, to be written)
/// to a future function CheckAndCorrectHeader
if (filetype == ImplicitVR)
{
- std::string implicitVRTransfertSyntax = UI1_2_840_10008_1_2;
- ReplaceOrCreateByNumber(implicitVRTransfertSyntax,0x0002, 0x0010);
+ std::string ts =
+ Util::DicomString( TransferSyntaxStrings[ImplicitVRLittleEndian] );
+ ReplaceOrCreateByNumber(ts, 0x0002, 0x0010);
/// \todo Refer to standards on page 21, chapter 6.2
/// "Value representation": values with a VR of UI shall be
if (filetype == ExplicitVR)
{
- std::string explicitVRTransfertSyntax = UI1_2_840_10008_1_2_1;
- ReplaceOrCreateByNumber(explicitVRTransfertSyntax,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
std::string const & value,
uint16_t group,
uint16_t elem,
- std::string const & VR )
+ TagName const & vr )
{
ValEntry* valEntry = 0;
DocEntry* currentEntry = GetDocEntryByNumber( group, elem);
DictEntry* dictEntry = pubDict->GetDictEntryByNumber(group, elem);
if (!dictEntry)
{
- currentEntry = NewDocEntryByNumber(group, elem,VR);
+ currentEntry = NewDocEntryByNumber(group, elem, vr);
}
else
{
valEntry = new ValEntry(currentEntry);
if ( !AddEntry(valEntry))
{
+ delete valEntry;
dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: AddEntry"
" failed allthough this is a creation.");
}
+ // This is the reason why NewDocEntryByNumber are a real
+ // bad habit !!! FIXME
+ delete currentEntry;
}
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;
int lgth,
uint16_t group,
uint16_t elem,
- std::string const& VR )
+ TagName const & vr )
{
BinEntry* binEntry = 0;
DocEntry* currentEntry = GetDocEntryByNumber( group, elem);
if (!dictEntry)
{
- currentEntry = NewDocEntryByNumber(group, elem, VR);
+ currentEntry = NewDocEntryByNumber(group, elem, vr);
}
else
{
* \return pointer to the modified/created SeqEntry (NULL when creation
* failed).
*/
-SeqEntry* Document::ReplaceOrCreateByNumber(
- uint16_t group,
- uint16_t elem)
+SeqEntry* Document::ReplaceOrCreateByNumber( uint16_t group, uint16_t elem)
{
SeqEntry* b = 0;
DocEntry* a = GetDocEntryByNumber( group, elem);
* \return boolean
*/
bool Document::ReplaceIfExistByNumber(std::string const & value,
- uint16_t group, uint16_t elem )
+ uint16_t group, uint16_t elem )
{
SetEntryByNumber(value, group, elem);
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;
}
/**
* @return Corresponding element value when it exists,
* and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
*/
-std::string Document::GetEntryByName(TagName const& tagName)
+std::string Document::GetEntryByName(TagName const & tagName)
{
DictEntry* dictEntry = RefPubDict->GetDictEntryByName(tagName);
if( !dictEntry )
}
DocEntry* elem = GetDocEntryByNumber(dictEntry->GetGroup(),
- dictEntry->GetElement());
+ dictEntry->GetElement());
return elem->GetVR();
}
* @param tagName name of the searched Dicom Element.
* @return true when found
*/
-bool Document::SetEntryByName(std::string const & content,std::string const & tagName)
+bool Document::SetEntryByName(std::string const & content,
+ TagName const & tagName)
{
DictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName);
if( !dictEntry )
* @param element element number of the Dicom Element to modify
*/
bool Document::SetEntryByNumber(std::string const& content,
- uint16_t group,
- uint16_t element)
+ uint16_t group, uint16_t element)
{
int c;
int l;
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 Dicom Element to modify
* @param element element number of the Dicom Element to modify
*/
-bool Document::SetEntryByNumber(uint8_t*content,
- int lgth,
- uint16_t group,
- uint16_t element)
+bool Document::SetEntryByNumber(uint8_t*content, int lgth,
+ uint16_t group, uint16_t element)
{
(void)lgth; //not used
TagKey key = DictEntry::TranslateToKey(group, element);
* @return true on success, false otherwise.
*/
bool Document::SetEntryLengthByNumber(uint32_t l,
- uint16_t group,
- uint16_t element)
+ uint16_t group, uint16_t element)
{
/// \todo use map methods, instead of multimap JPR
TagKey key = DictEntry::TranslateToKey(group, element);
return NULL;
}
size_t o =(size_t)docElement->GetOffset();
- fseek(Fp, o, SEEK_SET);
+ Fp->seekg( o, std::ios_base::beg);
size_t l = docElement->GetLength();
uint8_t* a = new uint8_t[l];
if(!a)
dbg.Verbose(0, "Document::LoadEntryBinArea cannot allocate a");
return NULL;
}
- size_t l2 = fread(a, 1, l , Fp);
- if( l != l2 )
+ Fp->read((char*)a, l);
+ if( Fp->fail() || Fp->eof() )//Fp->gcount() == 1
{
delete[] a;
return NULL;
}
- /// \todo Drop any already existing void area! JPR
+ /// \todo Drop any already existing void area! JPR
if( !SetEntryBinAreaByNumber( a, group, elem ) )
{
dbg.Verbose(0, "Document::LoadEntryBinArea setting failed.");
void* Document::LoadEntryBinArea(BinEntry* element)
{
size_t o =(size_t)element->GetOffset();
- fseek(Fp, o, SEEK_SET);
+ Fp->seekg(o, std::ios_base::beg);
size_t l = element->GetLength();
uint8_t* a = new uint8_t[l];
if( !a )
}
element->SetBinArea((uint8_t*)a);
/// \todo check the result
- size_t l2 = fread(a, 1, l , Fp);
- if( l != l2 )
+ Fp->read((char*)a, l);
+ if( Fp->fail() || Fp->eof()) //Fp->gcount() == 1
{
delete[] a;
return NULL;
* @return
*/
bool Document::SetEntryBinAreaByNumber(uint8_t* area,
- uint16_t group,
- uint16_t element)
+ uint16_t group, uint16_t element)
{
DocEntry* currentEntry = GetDocEntryByNumber(group, element);
if ( !currentEntry )
* @return Corresponding Dicom Element when it exists, and NULL
* otherwise.
*/
-DocEntry* Document::GetDocEntryByName(std::string const & tagName)
+DocEntry* Document::GetDocEntryByName(TagName const & tagName)
{
DictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName);
if( !dictEntry )
* @param element Element number of the searched Dicom Element
* @return
*/
-DocEntry* Document::GetDocEntryByNumber(uint16_t group,
- uint16_t element)
+DocEntry* Document::GetDocEntryByNumber(uint16_t group, uint16_t element)
{
TagKey key = DictEntry::TranslateToKey(group, element);
if ( !TagHT.count(key))
* ValEntry.
* @return When present, the corresponding ValEntry.
*/
-ValEntry* Document::GetValEntryByNumber(uint16_t group,
- uint16_t element)
+ValEntry* Document::GetValEntryByNumber(uint16_t group, uint16_t element)
{
DocEntry* currentEntry = GetDocEntryByNumber(group, element);
if ( !currentEntry )
*/
void Document::LoadDocEntrySafe(DocEntry * entry)
{
- long PositionOnEntry = ftell(Fp);
+ long PositionOnEntry = Fp->tellg();
LoadDocEntry(entry);
- fseek(Fp, PositionOnEntry, SEEK_SET);
+ Fp->seekg(PositionOnEntry, std::ios_base::beg);
}
/**
* \brief Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries)
* @return length of the parsed set.
*/
-void Document::ParseDES(DocEntrySet *set,
- long offset,
- long l_max,
- bool delim_mode)
+void Document::ParseDES(DocEntrySet *set, long offset,
+ long l_max, bool delim_mode)
{
DocEntry *newDocEntry = 0;
while (true)
{
- if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
+ if ( !delim_mode && (Fp->tellg()-offset) >= l_max)
{
break;
}
{
break;
}
- if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
+ if ( !delim_mode && (Fp->tellg()-offset) >= l_max)
{
break;
}
//////////////////// BinEntry or UNKOWN VR:
BinEntry* newBinEntry =
- new BinEntry( newDocEntry->GetDictEntry() );
+ new BinEntry( newDocEntry->GetDictEntry() ); //LEAK
newBinEntry->Copy( newDocEntry );
// When "this" is a Document the Key is simply of the
if ( ( newDocEntry->GetGroup() == 0x7fe0 )
&& ( newDocEntry->GetElement() == 0x0010 ) )
{
- if ( IsRLELossLessTransferSyntax() )
+ TransferSyntaxType ts = GetTransferSyntax();
+ if ( ts == RLELossless )
{
- long PositionOnEntry = ftell(Fp);
- fseek( Fp, newDocEntry->GetOffset(), SEEK_SET );
+ long PositionOnEntry = Fp->tellg();
+ Fp->seekg( newDocEntry->GetOffset(), std::ios_base::beg );
ComputeRLEInfo();
- fseek( Fp, PositionOnEntry, SEEK_SET );
+ Fp->seekg( PositionOnEntry, std::ios_base::beg );
}
- else
- if ( IsJPEGTransferSyntax() )
+ else if ( IsJPEG() )
{
- long PositionOnEntry = ftell(Fp);
- fseek( Fp, newDocEntry->GetOffset(), SEEK_SET );
+ long PositionOnEntry = Fp->tellg();
+ Fp->seekg( newDocEntry->GetOffset(), std::ios_base::beg );
ComputeJPEGFragmentInfo();
- fseek( Fp, PositionOnEntry, SEEK_SET );
+ Fp->seekg( PositionOnEntry, std::ios_base::beg );
}
}
l, delim_mode);
}
set->AddEntry( newSeqEntry );
- if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
+ if ( !delim_mode && (Fp->tellg()-offset) >= l_max)
{
break;
}
* @return parsed length for this level
*/
void Document::ParseSQ( SeqEntry* seqEntry,
- long offset, long l_max, bool delim_mode)
+ long offset, long l_max, bool delim_mode)
{
int SQItemNumber = 0;
bool dlm_mod;
break;
}
}
- if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
+ if ( !delim_mode && (Fp->tellg()-offset) >= l_max)
{
break;
}
seqEntry->AddEntry( itemSQ, SQItemNumber );
SQItemNumber++;
- if ( !delim_mode && ( ftell(Fp) - offset ) >= l_max )
+ if ( !delim_mode && ( Fp->tellg() - offset ) >= l_max )
{
break;
}
*/
void Document::LoadDocEntry(DocEntry* entry)
{
- size_t item_read;
uint16_t group = entry->GetGroup();
std::string vr = entry->GetVR();
uint32_t length = entry->GetLength();
- fseek(Fp, (long)entry->GetOffset(), SEEK_SET);
+ Fp->seekg((long)entry->GetOffset(), std::ios_base::beg);
// A SeQuence "contains" a set of Elements.
// (fffe e000) tells us an Element is beginning
}
// to be sure we are at the end of the value ...
- fseek(Fp,(long)entry->GetOffset()+(long)entry->GetLength(),SEEK_SET);
+ 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
- //std::string newValue(length,0);
- //item_read = fread(&(newValue[0]), (size_t)length, (size_t)1, Fp);
- //rah !! I can't believe it could work, normally this is a const char* !!!
+ // FIXME: We need an additional byte for storing \0 that is not on disk
char *str = new char[length+1];
- item_read = fread(str, (size_t)length, (size_t)1, Fp);
- str[length] = '\0';
- std::string newValue = str;
+ 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);
+ //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 ( item_read != 1 )
+ {
+ if ( Fp->fail() || Fp->eof())//Fp->gcount() == 1
{
dbg.Verbose(1, "Document::LoadDocEntry",
"unread element value");
// 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.
- fseek(Fp, 2L, SEEK_CUR);
+ Fp->seekg( 2L, std::ios_base::cur);
uint32_t length32 = ReadInt32();
if ( (vr == "OB" || vr == "OW") && length32 == 0xffffffff )
// 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 = ftell(Fp);
- fseek(Fp,0L,SEEK_END);
- long lengthUntilEOF = ftell(Fp) - currentPosition;
- fseek(Fp, currentPosition, SEEK_SET);
+ long currentPosition = Fp->tellg();
+ Fp->seekg(0L,std::ios_base::end);
+ long lengthUntilEOF = Fp->tellg() - currentPosition;
+ Fp->seekg(currentPosition, std::ios_base::beg);
entry->SetLength(lengthUntilEOF);
return;
}
// big endian and proceed...
if ( element == 0x0000 && length16 == 0x0400 )
{
- if ( !IsExplicitVRBigEndianTransferSyntax() )
+ TransferSyntaxType ts = GetTransferSyntax();
+ if ( ts != ExplicitVRBigEndian )
{
throw FormatError( "Document::FindDocEntryLength()",
" not explicit VR." );
char vr[3];
- long positionOnEntry = ftell(Fp);
+ 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
// is in explicit VR and try to fix things if it happens not to be
// the case.
- fread (vr, (size_t)2,(size_t)1, Fp);
+ Fp->read (vr, (size_t)2);
vr[2] = 0;
if( !CheckDocEntryVR(entry, vr) )
{
- fseek(Fp, positionOnEntry, SEEK_SET);
+ Fp->seekg(positionOnEntry, std::ios_base::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
*/
void Document::SkipToNextDocEntry(DocEntry *entry)
{
- fseek(Fp, (long)(entry->GetOffset()), SEEK_SET);
- fseek(Fp, (long)(entry->GetReadLength()), SEEK_CUR);
+ Fp->seekg((long)(entry->GetOffset()), std::ios_base::beg);
+ Fp->seekg( (long)(entry->GetReadLength()), std::ios_base::cur);
}
/**
* @param foundLength fist assumption about length
*/
void Document::FixDocEntryFoundLength(DocEntry *entry,
- uint32_t foundLength)
+ uint32_t foundLength)
{
entry->SetReadLength( foundLength ); // will be updated only if a bug is found
if ( foundLength == 0xffffffff)
{
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
// encounter such an ill-formed image, we simply display a warning
// message and proceed on parsing (while crossing fingers).
std::ostringstream s;
- long filePosition = ftell(Fp);
+ long filePosition = Fp->tellg();
s << "Erroneous Group Length element length on : (" \
<< std::hex << group << " , " << element
<< ") -before- position x(" << filePosition << ")"
throw( FormatUnexpected )
{
// See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
- long positionOnEntry = ftell(Fp);
+ long positionOnEntry = Fp->tellg();
bool foundSequenceDelimiter = false;
uint32_t totalLength = 0;
{
dbg.Verbose(1, "Document::FindDocEntryLengthOB: neither an Item "
"tag nor a Sequence delimiter tag.");
- fseek(Fp, positionOnEntry, SEEK_SET);
+ Fp->seekg(positionOnEntry, std::ios_base::beg);
throw FormatUnexpected("Document::FindDocEntryLengthOB()",
"Neither an Item tag nor a Sequence "
"delimiter tag.");
break;
}
}
- fseek(Fp, positionOnEntry, SEEK_SET);
+ Fp->seekg( positionOnEntry, std::ios_base::beg);
return totalLength;
}
throw( FormatError )
{
uint16_t g;
- size_t item_read = fread (&g, (size_t)2,(size_t)1, Fp);
- if ( item_read != 1 )
+ Fp->read ((char*)&g, (size_t)2);
+ if ( Fp->fail() )
+ {
+ throw FormatError( "Document::ReadInt16()", " file error." );
+ }
+ if( Fp->eof() )
{
- if( ferror(Fp) )
- {
- throw FormatError( "Document::ReadInt16()", " file error." );
- }
throw FormatError( "Document::ReadInt16()", "EOF." );
}
g = SwapShort(g);
throw( FormatError )
{
uint32_t g;
- size_t item_read = fread (&g, (size_t)4,(size_t)1, Fp);
- if ( item_read != 1 )
+ Fp->read ((char*)&g, (size_t)4);
+ if ( Fp->fail() )
+ {
+ throw FormatError( "Document::ReadInt32()", " file error." );
+ }
+ if( Fp->eof() )
{
- if( ferror(Fp) )
- {
- throw FormatError( "Document::ReadInt16()", " file error." );
- }
throw FormatError( "Document::ReadInt32()", "EOF." );
}
g = SwapLong(g);
void Document::SkipBytes(uint32_t nBytes)
{
//FIXME don't dump the returned value
- (void)fseek(Fp, (long)nBytes, SEEK_CUR);
+ Fp->seekg((long)nBytes, std::ios_base::cur);
}
/**
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).
// The easiest case is the one of a DICOM header, since it possesses a
// file preamble where it suffice to look for the string "DICM".
- int lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, Fp);
- (void)lgrLue; //FIXME not used
+ Fp->read(deb, HEADER_LENGTH_TO_READ);
char *entCur = deb + 128;
if( memcmp(entCur, "DICM", (size_t)4) == 0 )
// Position the file position indicator at first tag (i.e.
// after the file preamble and the "DICM" string).
- rewind(Fp);
- fseek (Fp, 132L, SEEK_SET);
+ Fp->seekg(0, std::ios_base::beg);
+ Fp->seekg ( 132L, std::ios_base::beg);
return true;
} // End of DicomV3
// preamble. We can reset the file position indicator to where the data
// is (i.e. the beginning of the file).
dbg.Verbose(1, "Document::CheckSwap:", "not a DICOM Version3 file");
- rewind(Fp);
+ Fp->seekg(0, std::ios_base::beg);
// Our next best chance would be to be considering a 'clean' ACR/NEMA file.
// By clean we mean that the length of the first tag is written down.
return 0;
}
- newEntry->SetOffset(ftell(Fp));
+ newEntry->SetOffset(Fp->tellg());
return newEntry;
}
*/
bool Document::ReadTag(uint16_t testGroup, uint16_t testElement)
{
- long positionOnEntry = ftell(Fp);
- long currentPosition = ftell(Fp); // On debugging purposes
+ long positionOnEntry = Fp->tellg();
+ long currentPosition = Fp->tellg(); // On debugging purposes
//// 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;
s << " at address: " << (unsigned)currentPosition << std::endl;
dbg.Verbose(0, "Document::ReadItemTagLength: wrong Item Tag found:");
dbg.Verbose(0, s.str().c_str());
- fseek(Fp, positionOnEntry, SEEK_SET);
+ Fp->seekg(positionOnEntry, std::ios_base::beg);
return false;
}
*/
uint32_t Document::ReadTagLength(uint16_t testGroup, uint16_t testElement)
{
- long positionOnEntry = ftell(Fp);
+ long positionOnEntry = Fp->tellg();
(void)positionOnEntry;
if ( !ReadTag(testGroup, testElement) )
}
//// Then read the associated Item Length
- long currentPosition = ftell(Fp);
+ long currentPosition = Fp->tellg();
uint32_t itemLength = ReadInt32();
{
std::ostringstream s;
if ( itemLength != 0 )
{
char* basicOffsetTableItemValue = new char[itemLength + 1];
- fread(basicOffsetTableItemValue, itemLength, 1, Fp);
+ Fp->read(basicOffsetTableItemValue, itemLength);
#ifdef GDCM_DEBUG
for (unsigned int i=0; i < itemLength; i += 4 )
*/
void Document::ComputeRLEInfo()
{
- if ( ! IsRLELossLessTransferSyntax() )
+ TransferSyntaxType ts = GetTransferSyntax();
+ if ( ts != RLELossless )
{
return;
}
// Offset Table information on fragments of this current Frame.
// Note that the fragment pixels themselves are not loaded
// (but just skipped).
- long frameOffset = ftell(Fp);
+ long frameOffset = Fp->tellg();
uint32_t nbRleSegments = ReadInt32();
+ if ( nbRleSegments > 16 )
+ {
+ // There should be at most 15 segments (refer to RLEFrame class)
+ dbg.Verbose(0, "Document::ComputeRLEInfo: too many segments.");
+ }
uint32_t rleSegmentOffsetTable[15];
for( int k = 1; k <= 15; k++ )
void Document::ComputeJPEGFragmentInfo()
{
// If you need to, look for comments of ComputeRLEInfo().
- if ( ! IsJPEGTransferSyntax() )
+ if ( ! IsJPEG() )
{
return;
}
long fragmentLength;
while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) )
{
- long fragmentOffset = ftell(Fp);
+ long fragmentOffset = Fp->tellg();
// Store the collected info
JPEGFragment* newFragment = new JPEGFragment;
* @param set The structure to be traversed (recursively).
*/
void Document::BuildFlatHashTableRecurse( TagDocEntryHT& builtHT,
- DocEntrySet* set )
+ DocEntrySet* set )
{
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)