Program: gdcm
Module: $RCSfile: gdcmDocument.cxx,v $
Language: C++
- Date: $Date: 2005/02/01 10:29:55 $
- Version: $Revision: 1.218 $
+ Date: $Date: 2005/02/14 10:45:04 $
+ Version: $Revision: 1.230 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
#include <vector>
#include <iomanip>
-
-// For nthos:
-#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
- #include <winsock.h>
-#endif
-
-#ifdef CMAKE_HAVE_NETINET_IN_H
- #include <netinet/in.h>
-#endif
+#include <fstream>
namespace gdcm
{
* \brief constructor
* @param filename 'Document' (File or DicomDir) 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;
Group0002Parsed = false;
- gdcmVerboseMacro( "Starting parsing of file: " << Filename.c_str());
- // Fp->seekg( 0, std::ios::beg);
-
- Fp->seekg(0, std::ios::end);
+ gdcmWarningMacro( "Starting parsing of file: " << Filename.c_str());
+
+ Fp->seekg(0, std::ios::end);
long lgt = Fp->tellg();
- Fp->seekg( 0, std::ios::beg);
+ Fp->seekg(0, std::ios::beg);
CheckSwap();
long beg = Fp->tellg();
* \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)
{
Fp = 0;
{
if( Filetype == Unknown)
{
- gdcmVerboseMacro( "Wrong filetype");
+ gdcmWarningMacro( "Wrong filetype");
return false;
}
if ( IsEmpty() )
{
- gdcmVerboseMacro( "No tag in internal hash table.");
+ gdcmWarningMacro( "No tag in internal hash table.");
return false;
}
}
if ( transferSyntax == GDCM_UNFOUND )
{
- gdcmVerboseMacro( "Unfound Transfer Syntax (0002,0010)");
+ gdcmWarningMacro( "Unfound Transfer Syntax (0002,0010)");
return "Uncompressed ACR-NEMA";
}
{
if ( SwapCode == 4321 || SwapCode == 2143 )
{
- a = ((( a << 8 ) & 0x0ff00 ) | (( a >> 8 ) & 0x00ff ) );
+ //a = ((( a << 8 ) & 0xff00 ) | (( a >> 8 ) & 0x00ff ) );
+ // Save CPU time
+ a = ( a << 8 ) | ( a >> 8 );
}
return a;
}
case 1234 :
break;
case 4321 :
- a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) |
- ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) );
+// a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) |
+// ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) );
+// save CPU time
+ a=( ( a<<24) | ((a<<8) & 0x00ff0000) |
+ ((a>>8) & 0x0000ff00) | (a>>24) );
break;
case 3412 :
- a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
+// a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
+ a=( (a<<16) | (a>>16) );
break;
case 2143 :
a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) );
if(Fp)
{
- gdcmVerboseMacro( "File already open: " << Filename.c_str());
+ gdcmWarningMacro( "File already open: " << Filename.c_str());
CloseFile();
}
return 0;
}
- uint16_t zero;
+ uint16_t zero = 0;
Fp->read((char*)&zero, (size_t)2);
if( Fp->eof() )
{
{
std::string msg
= Util::Format("ACR/DICOM with no preamble: (%04x)\n", zero);
- gdcmVerboseMacro( msg.c_str() );
+ gdcmWarningMacro( msg.c_str() );
return Fp;
}
//DICOM
Fp->seekg(126L, std::ios::cur);
- char dicm[4];
+ char dicm[4] = {' ',' ',' ',' '};
Fp->read(dicm, (size_t)4);
if( Fp->eof() )
{
}
CloseFile();
- gdcmVerboseMacro( "Not DICOM/ACR (missing preamble)" << Filename.c_str());
+ gdcmWarningMacro( "Not DICOM/ACR (missing preamble)" << Filename.c_str());
return 0;
}
delete Fp;
Fp = 0;
}
- return true; //FIXME how do we detect a non-closed ifstream ?
+ return true;
}
/**
fp->write("DICM", 4);
}
-/*
- * \todo rewrite later, if really usefull
- * - 'Group Length' element is optional in DICOM
- * - but un-updated odd groups lengthes can causes pb
- * (xmedcon breaker)
- *
- * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) )
- * UpdateGroupLength(false,filetype);
- * if ( filetype == ACR)
- * UpdateGroupLength(true,ACR);
- */
-
+ /*
+ * \todo rewrite later, if really usefull
+ * - 'Group Length' element is optional in DICOM
+ * - but un-updated odd groups lengthes can causes pb
+ * (xmedcon breaker)
+ *
+ * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) )
+ * UpdateGroupLength(false,filetype);
+ * if ( filetype == ACR)
+ * UpdateGroupLength(true,ACR);
+ */
+
ElementSet::WriteContent(fp, filetype); // This one is recursive
}
uint8_t *a = new uint8_t[l];
if( !a )
{
- gdcmVerboseMacro( "Cannot allocate BinEntry content");
+ gdcmWarningMacro( "Cannot allocate BinEntry content");
return;
}
- /// \todo check the result
Fp->read((char*)a, l);
if( Fp->fail() || Fp->eof())
{
* \brief Loads the element while preserving the current
* underlying file position indicator as opposed to
* LoadDocEntry that modifies it.
- * @param entry Header Entry whose value will be loaded.
- * @return
+ * @param entry DocEntry whose value will be loaded.
*/
void Document::LoadDocEntrySafe(DocEntry *entry)
{
}
}
+/**
+ * \brief Compares two documents, according to \ref DicomDir rules
+ * \warning Does NOT work with ACR-NEMA files
+ * \todo Find a trick to solve the pb (use RET fields ?)
+ * @param document to compare with current one
+ * @return true if 'smaller'
+ */
+bool Document::operator<(Document &document)
+{
+ // Patient Name
+ std::string s1 = GetEntryValue(0x0010,0x0010);
+ std::string s2 = document.GetEntryValue(0x0010,0x0010);
+ if(s1 < s2)
+ {
+ return true;
+ }
+ else if( s1 > s2 )
+ {
+ return false;
+ }
+ else
+ {
+ // Patient ID
+ s1 = GetEntryValue(0x0010,0x0020);
+ s2 = document.GetEntryValue(0x0010,0x0020);
+ if ( s1 < s2 )
+ {
+ return true;
+ }
+ else if ( s1 > s2 )
+ {
+ return false;
+ }
+ else
+ {
+ // Study Instance UID
+ s1 = GetEntryValue(0x0020,0x000d);
+ s2 = document.GetEntryValue(0x0020,0x000d);
+ if ( s1 < s2 )
+ {
+ return true;
+ }
+ else if( s1 > s2 )
+ {
+ return false;
+ }
+ else
+ {
+ // Serie Instance UID
+ s1 = GetEntryValue(0x0020,0x000e);
+ s2 = document.GetEntryValue(0x0020,0x000e);
+ if ( s1 < s2 )
+ {
+ return true;
+ }
+ else if( s1 > s2 )
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return false;
+}
+
//-----------------------------------------------------------------------------
// Protected
/**
* \brief Reads a supposed to be 16 Bits integer
- * (swaps it depending on processor endianity)
+ * (swaps it depending on processor endianness)
* @return read value
*/
uint16_t Document::ReadInt16()
/**
* \brief Reads a supposed to be 32 Bits integer
- * (swaps it depending on processor endianity)
+ * (swaps it depending on processor endianness)
* @return read value
*/
uint32_t Document::ReadInt32()
//-----------------------------------------------------------------------------
// Private
+/**
+ * \brief Loads all the needed Dictionaries
+ * \warning NOT end user intended method !
+ */
+void Document::Initialize()
+{
+ RefPubDict = Global::GetDicts()->GetDefaultPubDict();
+ RefShaDict = NULL;
+ Filetype = Unknown;
+}
+
/**
* \brief Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries)
* @return length of the parsed set.
!Global::GetVR()->IsVROfBinaryRepresentable(vr) )
{
////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
- gdcmVerboseMacro( std::hex << newDocEntry->GetGroup()
+ gdcmWarningMacro( std::hex << newDocEntry->GetGroup()
<< "|" << newDocEntry->GetElement()
<< " : Neither Valentry, nor BinEntry."
"Probably unknown VR.");
{
dlm_mod = false;
}
- // FIXME, TODO
- // when we're here, element fffe,e000 is already passed.
- // it's lost for the SQItem we're going to process !!
-
- //ParseDES(itemSQ, newDocEntry->GetOffset(), l, dlm_mod);
- //delete newDocEntry; // FIXME well ... it's too late to use it !
// Let's try :------------
// remove fff0,e000, created out of the SQItem
return;
}
- /// \todo Any compacter code suggested (?)
if ( IsDocEntryAnInteger(entry) )
{
uint32_t NewInt;
if( length % 2 )
{
newValue = Util::DicomString(str, length+1);
- gdcmVerboseMacro("Warning: bad length: " << length <<
+ gdcmWarningMacro("Warning: bad length: " << length <<
",For string :" << newValue.c_str());
// Since we change the length of string update it length
//entry->SetReadLength(length+1);
{
if ( Fp->fail() || Fp->eof())
{
- gdcmVerboseMacro("Unread element value");
+ gdcmWarningMacro("Unread element value");
valEntry->SetValue(GDCM_UNREAD);
return;
}
if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) )
{
long filePosition = Fp->tellg();
- gdcmVerboseMacro( "Neither an Item tag nor a Sequence delimiter tag on :"
+ gdcmWarningMacro( "Neither an Item tag nor a Sequence delimiter tag on :"
<< std::hex << group << " , " << elem
<< ") -before- position x(" << filePosition << ")" );
*/
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;
if ( foundLength % 2)
{
- gdcmVerboseMacro( "Warning : Tag with uneven length " << foundLength
+ gdcmWarningMacro( "Warning : Tag with uneven length " << foundLength
<< " in x(" << std::hex << gr << "," << elem <<")");
}
if ( gr != 0x0008 || ( elem != 0x0070 && elem != 0x0080 ) )
{
foundLength = 10;
- entry->SetReadLength(10); /// \todo a bug is to be fixed !?
+ entry->SetReadLength(10); // a bug is to be fixed !?
}
}
else if ( gr == 0x0009 && ( elem == 0x1113 || elem == 0x1114 ) )
{
foundLength = 4;
- entry->SetReadLength(4); /// \todo a bug is to be fixed !?
+ entry->SetReadLength(4); // a bug is to be fixed !?
}
else if ( entry->GetVR() == "SQ" )
*/
bool Document::IsDocEntryAnInteger(DocEntry *entry)
{
- uint16_t elem = entry->GetElement();
- uint16_t group = entry->GetGroup();
+ uint16_t elem = entry->GetElement();
+ uint16_t group = entry->GetGroup();
const std::string &vr = entry->GetVR();
- uint32_t length = entry->GetLength();
+ uint32_t length = entry->GetLength();
// When we have some semantics on the element we just read, and if we
// a priori know we are dealing with an integer, then we shall be
// encounter such an ill-formed image, we simply display a warning
// message and proceed on parsing (while crossing fingers).
long filePosition = Fp->tellg();
- gdcmVerboseMacro( "Erroneous Group Length element length on : ("
+ gdcmWarningMacro( "Erroneous Group Length element length on : ("
<< std::hex << group << " , " << elem
<< ") -before- position x(" << filePosition << ")"
<< "lgt : " << length );
return false;
}
-/**
- * \brief Loads all the needed Dictionaries
- * \warning NOT end user intended method !
- */
-void Document::Initialize()
-{
- RefPubDict = Global::GetDicts()->GetDefaultPubDict();
- RefShaDict = NULL;
- Filetype = Unknown;
-}
-
/**
* \brief Discover what the swap code is (among little endian, big endian,
* bad little endian, bad big endian).
// 0x00000004. Finding the swap code in then straigthforward. Trouble
// occurs when we can't find such group...
- uint32_t x = 4; // x : for ntohs
- bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
uint32_t s32;
uint16_t s16;
// First, compare HostByteOrder and NetworkByteOrder in order to
// determine if we shall need to swap bytes (i.e. the Endian type).
- if ( x == ntohs(x) )
- {
- net2host = true;
- }
- else
- {
- net2host = false;
- }
+ bool net2host = Util::IsCurrentProcessorBigEndian();
// The easiest case is the one of a 'true' DICOM header, we just have
// to look for the string "DICM" inside the file preamble.
char *entCur = deb + 128;
if( memcmp(entCur, "DICM", (size_t)4) == 0 )
{
- gdcmVerboseMacro( "Looks like DICOM Version3 (preamble + DCM)" );
+ gdcmWarningMacro( "Looks like DICOM Version3 (preamble + DCM)" );
// Group 0002 should always be VR, and the first element 0000
// Let's be carefull (so many wrong headers ...)
// instead of just checking for UL, OB and UI !? group 0000
{
Filetype = ExplicitVR;
- gdcmVerboseMacro( "Group 0002 : Explicit Value Representation");
+ gdcmWarningMacro( "Group 0002 : Explicit Value Representation");
}
else
{
Filetype = ImplicitVR;
- gdcmVerboseMacro( "Group 0002 :Not an explicit Value Representation;"
+ gdcmWarningMacro( "Group 0002 :Not an explicit Value Representation;"
<< "Looks like a bugged Header!");
}
if ( net2host )
{
SwapCode = 4321;
- gdcmVerboseMacro( "HostByteOrder != NetworkByteOrder");
+ gdcmWarningMacro( "HostByteOrder != NetworkByteOrder");
}
else
{
SwapCode = 1234;
- gdcmVerboseMacro( "HostByteOrder = NetworkByteOrder");
+ gdcmWarningMacro( "HostByteOrder = NetworkByteOrder");
}
// Position the file position indicator at first tag
// Alas, this is not a DicomV3 file and whatever happens there is no file
// preamble. We can reset the file position indicator to where the data
// is (i.e. the beginning of the file).
- gdcmVerboseMacro( "Not a DICOM Version3 file");
+ gdcmWarningMacro( "Not a DICOM Version3 file");
Fp->seekg(0, std::ios::beg);
// Our next best chance would be to be considering a 'clean' ACR/NEMA file.
Filetype = ACR;
return true;
default :
- gdcmVerboseMacro( "ACR/NEMA unfound swap info (Really hopeless !)");
+ gdcmWarningMacro( "ACR/NEMA unfound swap info (Really hopeless !)");
Filetype = Unknown;
return false;
}
*/
void Document::SwitchByteSwapCode()
{
- gdcmVerboseMacro( "Switching Byte Swap code from "<< SwapCode);
+ gdcmWarningMacro( "Switching Byte Swap code from "<< SwapCode);
if ( SwapCode == 1234 )
{
SwapCode = 4321;
/**
* \brief during parsing, Header Elements too long are not loaded in memory
- * @param newSize
+ * @param newSize new size
*/
void Document::SetMaxSizeLoadEntry(long newSize)
{
/**
* \brief Header Elements too long will not be printed
- * \todo See comments of \ref Document::MAX_SIZE_PRINT_ELEMENT_VALUE
- * @param newSize
+ * See comments of \ref Document::MAX_SIZE_PRINT_ELEMENT_VALUE
+ * @param newSize new size
*/
void Document::SetMaxSizePrintEntry(long newSize)
{
{
// We reached the EOF (or an error occured) therefore
// header parsing has to be considered as finished.
- //std::cout << e;
return 0;
}
std::string msg;
msg = Util::Format("Entry (%04x,%04x) should be Explicit VR\n",
newEntry->GetGroup(), newEntry->GetElement());
- gdcmVerboseMacro( msg.c_str() );
+ gdcmWarningMacro( msg.c_str() );
}
}
newEntry->SetImplicitVR();
std::string ts = GetTransferSyntax();
if ( !Global::GetTS()->IsTransferSyntax(ts) )
{
- gdcmVerboseMacro("True DICOM File, with NO Tansfer Syntax: " << ts );
+ gdcmWarningMacro("True DICOM File, with NO Tansfer Syntax: " << ts );
return;
}
//'Implicit VR Transfer Syntax (GE Private)
if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian )
{
- gdcmVerboseMacro("Transfer Syntax Name = ["
+ gdcmWarningMacro("Transfer Syntax Name = ["
<< GetTransferSyntaxName() << "]" );
SwitchByteSwapCode();
group = SwapShort(group);
}
}
-/**
- * \brief Compares two documents, according to \ref DicomDir rules
- * \warning Does NOT work with ACR-NEMA files
- * \todo Find a trick to solve the pb (use RET fields ?)
- * @param document
- * @return true if 'smaller'
- */
-bool Document::operator<(Document &document)
-{
- // Patient Name
- std::string s1 = GetEntryValue(0x0010,0x0010);
- std::string s2 = document.GetEntryValue(0x0010,0x0010);
- if(s1 < s2)
- {
- return true;
- }
- else if( s1 > s2 )
- {
- return false;
- }
- else
- {
- // Patient ID
- s1 = GetEntryValue(0x0010,0x0020);
- s2 = document.GetEntryValue(0x0010,0x0020);
- if ( s1 < s2 )
- {
- return true;
- }
- else if ( s1 > s2 )
- {
- return false;
- }
- else
- {
- // Study Instance UID
- s1 = GetEntryValue(0x0020,0x000d);
- s2 = document.GetEntryValue(0x0020,0x000d);
- if ( s1 < s2 )
- {
- return true;
- }
- else if( s1 > s2 )
- {
- return false;
- }
- else
- {
- // Serie Instance UID
- s1 = GetEntryValue(0x0020,0x000e);
- s2 = document.GetEntryValue(0x0020,0x000e);
- if ( s1 < s2 )
- {
- return true;
- }
- else if( s1 > s2 )
- {
- return false;
- }
- }
- }
- }
- return false;
-}
-
//-----------------------------------------------------------------------------
// Print
-/**
- * \brief Prints The Dict Entries of THE public Dicom Dictionary
- * @param os ostream to print to
- * @return
- */
-void Document::PrintPubDict(std::ostream &os)
-{
- RefPubDict->SetPrintLevel(PrintLevel);
- RefPubDict->Print(os);
-}
-
-/**
- * \brief Prints The Dict Entries of THE shadow Dicom Dictionary
- * @param os ostream to print to
- * @return
- */
-void Document::PrintShaDict(std::ostream &os)
-{
- RefShaDict->SetPrintLevel(PrintLevel);
- RefShaDict->Print(os);
-}
//-----------------------------------------------------------------------------
} // end namespace gdcm