From 1ce6ae86daabc8b64c9309acce4ecf137ee79f07 Mon Sep 17 00:00:00 2001 From: jpr Date: Mon, 31 Jan 2005 12:19:32 +0000 Subject: [PATCH] Cosmetics --- ChangeLog | 8 +- Testing/CMakeLists.txt | 11 +- src/gdcmDebug.h | 6 +- src/gdcmDicomDirPatient.cxx | 6 +- src/gdcmDicomDirStudy.cxx | 6 +- src/gdcmDict.h | 11 +- src/gdcmDocEntry.h | 11 +- src/gdcmDocument.cxx | 717 +++++++++++++++++------------------- src/gdcmDocument.h | 39 +- src/gdcmSQItem.cxx | 8 +- src/gdcmSQItem.h | 5 +- src/gdcmSeqEntry.cxx | 16 +- src/gdcmSeqEntry.h | 9 +- src/gdcmSerieHeader.cxx | 10 +- 14 files changed, 409 insertions(+), 454 deletions(-) diff --git a/ChangeLog b/ChangeLog index d7fb1b5b..237d1f0f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -991,7 +991,7 @@ 2004-10-13 Eric Boix * Doc/Website/MailingList.html added (Sidebar.html changed accordingly). * gdcmPython/gdcm.i: fix for compilation of wrappers (Note: %include order - matters, as stated in warning note at begining of %include section). + matters, as stated in warning note at beginning of %include section). * src/gdcmDicomDir*.[cxx|h]: coding style * src/gdcmDocument.h: doxygen \ref seems uncompatible with \todo. * src/gdcmJpeg8.cxx: doxygen fix. @@ -3133,7 +3133,7 @@ entries within the associated public Dicom dictionary resp. the same information but sorted by the fourth field (PAT, IMG, DIR) of the dictionary. - - Dicts/dicomV3.dic Entries which had and unspecified fourth field + - Dicts/dicomV3.dic Entries which had an unspecified fourth field are now in the "???" group. - python/gdcm.i changed accordingly, - python/demo/printGroupedPublicDict.py added, that gives an example @@ -3222,7 +3222,7 @@ 2002-11-18 Eric Boix * src/gdcm.h and gdcmHeader.cxx are now "Big Endian transfer syntax" - aware. See the strategy comments in gdcmHeader::FindeLength(). + aware. See the strategy comments in gdcmHeader::FindLength(). * Test/test.cxx now accepts a filename as first argument. * Data/US-PAL-8-10x-echo.dcm and US-RGB-8-epicard.dcm added. * python/testSuite.py changed to integrate test on above files. @@ -3285,7 +3285,7 @@ 2002-10-31 Eric Boix * Straightforward temporary fixes for swig to build the python wrappers. src/Makefile now has a python working entry [by working we mean - that we can import de shadow classes without errors]. + that we can import the shadow classes without errors]. 2002-10-29 Eric Boix * hashtest.cxx removed (since already in Test) diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index 48a2fb54..0fd9aa46 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -150,16 +150,13 @@ SET(BLACK_LIST # Just to remember this format exist, and is gdcm::Header compliant # (NOT gdcm::File ...) # any contribution is welcome - "PET-cardio-Multiframe-Papyrus.dcm" - - # JPR love to add code in gdcm without even runing the tests - "D_CLUNIE_CT1_J2KI.dcm" - "D_CLUNIE_CT1_J2KR.dcm" - "D_CLUNIE_CT1_JLSL.dcm" + "PET-cardio-Multiframe-Papyrus.dcm" "D_CLUNIE_CT1_JLSN.dcm" + "D_CLUNIE_CT1_JLSL.dcm" + "D_CLUNIE_CT1_J2KR.dcm" + "D_CLUNIE_CT1_J2KI.dcm" ) - # Add a special test that requires dciodvfy from dicom3tools INCLUDE(${GDCM_SOURCE_DIR}/FindDicom3Tools.cmake) diff --git a/src/gdcmDebug.h b/src/gdcmDebug.h index 37d1f28a..edb114fd 100644 --- a/src/gdcmDebug.h +++ b/src/gdcmDebug.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDebug.h,v $ Language: C++ - Date: $Date: 2005/01/27 11:55:57 $ - Version: $Revision: 1.25 $ + Date: $Date: 2005/01/31 12:19:33 $ + Version: $Revision: 1.26 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -39,7 +39,7 @@ namespace gdcm * - warning : for warning about DICOM quality (kosher) * * A debugging message is only show if the flag is on (DebugFlag) - * This is static var and can be set at begining of code: + * This is static var and can be set at beginning of code: * gdcm::Debug::SetDebugOn(); */ class GDCM_EXPORT Debug diff --git a/src/gdcmDicomDirPatient.cxx b/src/gdcmDicomDirPatient.cxx index 9b4cd7cd..ea7d00fc 100644 --- a/src/gdcmDicomDirPatient.cxx +++ b/src/gdcmDicomDirPatient.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDicomDirPatient.cxx,v $ Language: C++ - Date: $Date: 2005/01/28 17:01:29 $ - Version: $Revision: 1.34 $ + Date: $Date: 2005/01/31 12:19:33 $ + Version: $Revision: 1.35 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -92,7 +92,7 @@ void DicomDirPatient::WriteContent(std::ofstream *fp, FileType t) } /** - * \brief adds a new Patient at the begining of the PatientList + * \brief adds a new Patient at the beginning of the PatientList * of a partially created DICOMDIR */ DicomDirStudy* DicomDirPatient::NewStudy() diff --git a/src/gdcmDicomDirStudy.cxx b/src/gdcmDicomDirStudy.cxx index 4075c914..6cac6beb 100644 --- a/src/gdcmDicomDirStudy.cxx +++ b/src/gdcmDicomDirStudy.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDicomDirStudy.cxx,v $ Language: C++ - Date: $Date: 2005/01/28 17:01:29 $ - Version: $Revision: 1.33 $ + Date: $Date: 2005/01/31 12:19:33 $ + Version: $Revision: 1.34 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -92,7 +92,7 @@ void DicomDirStudy::WriteContent(std::ofstream *fp, FileType t) } /** - * \brief adds a new Serie at the begining of the SerieList + * \brief adds a new Serie at the beginning of the SerieList * of a partially created DICOMDIR */ DicomDirSerie *DicomDirStudy::NewSerie() diff --git a/src/gdcmDict.h b/src/gdcmDict.h index d42548c0..04e80eee 100644 --- a/src/gdcmDict.h +++ b/src/gdcmDict.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDict.h,v $ Language: C++ - Date: $Date: 2005/01/24 14:14:11 $ - Version: $Revision: 1.35 $ + Date: $Date: 2005/01/31 12:19:33 $ + Version: $Revision: 1.36 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -37,7 +37,6 @@ typedef std::map TagKeyHT; // std::list > EntryNamesByCatMap; //----------------------------------------------------------------------------- /** - * \ingroup Dict * \brief Dict acts a memory representation of a dicom dictionary i.e. * it is a container for a collection of dictionary entries. * The dictionary is loaded from in an ascii file. @@ -49,12 +48,12 @@ typedef std::map TagKeyHT; class GDCM_EXPORT Dict : public Base { public: - Dict(void); - Dict(std::string const & filename); + Dict(); + Dict(std::string const &filename); ~Dict(); // Print - void Print(std::ostream &os = std::cout, std::string const & indent = ""); + void Print(std::ostream &os = std::cout, std::string const &indent = ""); // Entries void ClearEntry (); diff --git a/src/gdcmDocEntry.h b/src/gdcmDocEntry.h index 02debe38..a76778b6 100644 --- a/src/gdcmDocEntry.h +++ b/src/gdcmDocEntry.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocEntry.h,v $ Language: C++ - Date: $Date: 2005/01/30 17:30:57 $ - Version: $Revision: 1.43 $ + Date: $Date: 2005/01/31 12:19:33 $ + Version: $Revision: 1.44 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -43,6 +43,8 @@ public: DocEntry(DictEntry*); virtual ~DocEntry() {}; + virtual void Print (std::ostream &os = std::cout, std::string const &indent = ""); + /// Returns the Dicom Group number of the current Dicom entry uint16_t GetGroup() { return DicomDict->GetGroup(); }; @@ -77,7 +79,6 @@ public: /// \warning offset of the *value*, not of the Dicom entry size_t GetOffset() { return Offset; }; - /// \brief Sets only 'Read Length' (*not* 'Usable Length') of the current /// Dicom entry void SetReadLength(uint32_t l) { ReadLength = l; }; @@ -133,8 +134,6 @@ public: bool IsItemDelimitor(); bool IsSequenceDelimitor(); - virtual void Print (std::ostream &os = std::cout, std::string const & indent = ""); - protected: /// \brief pointer to the underlying Dicom dictionary element DictEntry *DicomDict; @@ -151,7 +150,7 @@ protected: /// breaking the underlying dictionary. bool ImplicitVR; - /// Offset from the begining of file for direct user access + /// Offset from the beginning of file for direct user access size_t Offset; /// \brief Generalized key of this DocEntry (for details on diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index f6b6f99d..5dd5ef26 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.cxx,v $ Language: C++ - Date: $Date: 2005/01/28 10:34:28 $ - Version: $Revision: 1.216 $ + Date: $Date: 2005/01/31 12:19:34 $ + Version: $Revision: 1.217 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -125,7 +125,7 @@ Document::Document( std::string const &filename ) : ElementSet(-1) CloseFile(); - // -------------------------------------------------------------- + // ---------------------------- // Specific code to allow gdcm to read ACR-LibIDO formated images // Note: ACR-LibIDO is an extension of the ACR standard that was // used at CREATIS. For the time being (say a couple years) @@ -147,7 +147,7 @@ Document::Document( std::string const &filename ) : ElementSet(-1) SetValEntry(columns, 0x0028, 0x0010); SetValEntry(rows , 0x0028, 0x0011); } - // ----------------- End of ACR-LibIDO kludge ------------------ + // --- End of ACR-LibIDO kludge --- } /** @@ -262,6 +262,46 @@ bool Document::IsReadable() return true; } +/** + * \brief Predicate for dicom version 3 file. + * @return True when the file is a dicom version 3. + */ +bool Document::IsDicomV3() +{ + // Checking if Transfer Syntax exists is enough + // Anyway, it's to late check if the 'Preamble' was found ... + // And ... would it be a rich idea to check ? + // (some 'no Preamble' DICOM images exist !) + return GetDocEntry(0x0002, 0x0010) != NULL; +} + +/** + * \brief Predicate for Papyrus file + * Dedicated to whomsoever it may concern + * @return True when the file is a Papyrus file. + */ +bool Document::IsPapyrus() +{ + // check for Papyrus private Sequence + DocEntry *e = GetDocEntry(0x0041, 0x1050); + if ( !e ) + return false; + // check if it's actually a Sequence + if ( !dynamic_cast(e) ) + return false; + return true; +} + +/** + * \brief returns the File Type + * (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown) + * @return the FileType code + */ +FileType Document::GetFileType() +{ + return Filetype; +} + /** * \brief Accessor to the Transfer Syntax (when present) of the * current document (it internally handles reading the @@ -300,45 +340,77 @@ std::string Document::GetTransferSyntax() } /** - * \brief Predicate for dicom version 3 file. - * @return True when the file is a dicom version 3. + * \brief Accesses the info from 0002,0010 : Transfer Syntax and TS + * @return The full Transfer Syntax Name (as opposed to Transfer Syntax UID) */ -bool Document::IsDicomV3() +std::string Document::GetTransferSyntaxName() { - // Checking if Transfer Syntax exists is enough - // Anyway, it's to late check if the 'Preamble' was found ... - // And ... would it be a rich idea to check ? - // (some 'no Preamble' DICOM images exist !) - return GetDocEntry(0x0002, 0x0010) != NULL; -} + // use the TS (TS : Transfer Syntax) + std::string transferSyntax = GetEntryValue(0x0002,0x0010); + + if ( (transferSyntax.find(GDCM_NOTLOADED) < transferSyntax.length()) ) + { + gdcmErrorMacro( "Transfer Syntax not loaded. " << std::endl + << "Better you increase MAX_SIZE_LOAD_ELEMENT_VALUE" ); + return "Uncompressed ACR-NEMA"; + } + if ( transferSyntax == GDCM_UNFOUND ) + { + gdcmVerboseMacro( "Unfound Transfer Syntax (0002,0010)"); + return "Uncompressed ACR-NEMA"; + } + + // we do it only when we need it + const TSKey &tsName = Global::GetTS()->GetValue( transferSyntax ); + // Global::GetTS() is a global static you shall never try to delete it! + return tsName; +} +// +// --------------- Swap Code ------------------ /** - * \brief Predicate for Papyrus file - * Dedicated to whomsoever it may concern - * @return True when the file is a Papyrus file. + * \brief Swaps the bytes so they agree with the processor order + * @return The properly swaped 16 bits integer. */ -bool Document::IsPapyrus() +uint16_t Document::SwapShort(uint16_t a) { - // check for Papyrus private Sequence - DocEntry *e = GetDocEntry(0x0041, 0x1050); - if ( !e ) - return false; - // check if it's actually a Sequence - if ( !dynamic_cast(e) ) - return false; - return true; + if ( SwapCode == 4321 || SwapCode == 2143 ) + { + a = ((( a << 8 ) & 0x0ff00 ) | (( a >> 8 ) & 0x00ff ) ); + } + return a; } /** - * \brief returns the File Type - * (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown) - * @return the FileType code + * \brief Swaps back the bytes of 4-byte long integer accordingly to + * processor order. + * @return The properly swaped 32 bits integer. */ -FileType Document::GetFileType() +uint32_t Document::SwapLong(uint32_t a) { - return Filetype; -} + switch (SwapCode) + { + case 1234 : + break; + case 4321 : + a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) | + ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) ); + break; + case 3412 : + a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) ); + break; + case 2143 : + a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); + break; + default : + gdcmErrorMacro( "Unset swap code:" << SwapCode ); + a = 0; + } + return a; +} +// +// -----------------File I/O --------------- /** * \brief Tries to open the file \ref Document::Filename and * checks the preamble when existing. @@ -463,8 +535,9 @@ void Document::WriteContent(std::ofstream *fp, FileType filetype) ElementSet::WriteContent(fp, filetype); // This one is recursive } -//----------------------------------------------------------------------------- -// Protected +// ----------------------------------------- +// Content entries + /** * \brief Loads (from disk) the element content * when a string is not suitable @@ -524,32 +597,6 @@ void Document::LoadEntryBinArea(BinEntry *elem) CloseFile(); } -/** - * \brief Sets a 'non string' value to a given Dicom Element - * @param area area containing the 'non string' value - * @param group Group number of the searched Dicom Element - * @param elem Element number of the searched Dicom Element - * @return - */ -/*bool Document::SetEntryBinArea(uint8_t *area, - uint16_t group, uint16_t elem) -{ - DocEntry *currentEntry = GetDocEntry(group, elem); - if ( !currentEntry ) - { - return false; - } - - if ( BinEntry *binEntry = dynamic_cast(currentEntry) ) - { - binEntry->SetBinArea( area ); - return true; - } - - return false; -}*/ - - /** * \brief Loads the element while preserving the current * underlying file position indicator as opposed to @@ -567,64 +614,109 @@ void Document::LoadDocEntrySafe(DocEntry *entry) } } +//----------------------------------------------------------------------------- +// Protected + +// Constructors and destructors are protected to avoid user to invoke directly + /** - * \brief Swaps back the bytes of 4-byte long integer accordingly to - * processor order. - * @return The properly swaped 32 bits integer. + * \brief Reads a supposed to be 16 Bits integer + * (swaps it depending on processor endianity) + * @return read value */ -uint32_t Document::SwapLong(uint32_t a) +uint16_t Document::ReadInt16() + throw( FormatError ) { - switch (SwapCode) + uint16_t g; + Fp->read ((char*)&g, (size_t)2); + if ( Fp->fail() ) { - case 1234 : - break; - case 4321 : - a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) | - ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) ); - break; - case 3412 : - a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) ); - break; - case 2143 : - a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); - break; - default : - gdcmErrorMacro( "Unset swap code:" << SwapCode ); - a = 0; + throw FormatError( "Document::ReadInt16()", " file error." ); } - return a; -} + if( Fp->eof() ) + { + throw FormatError( "Document::ReadInt16()", "EOF." ); + } + g = SwapShort(g); + return g; +} /** - * \brief Unswaps back the bytes of 4-byte long integer accordingly to - * processor order. - * @return The properly unswaped 32 bits integer. + * \brief Reads a supposed to be 32 Bits integer + * (swaps it depending on processor endianity) + * @return read value */ -uint32_t Document::UnswapLong(uint32_t a) +uint32_t Document::ReadInt32() + throw( FormatError ) { - return SwapLong(a); + uint32_t g; + Fp->read ((char*)&g, (size_t)4); + if ( Fp->fail() ) + { + throw FormatError( "Document::ReadInt32()", " file error." ); + } + if( Fp->eof() ) + { + throw FormatError( "Document::ReadInt32()", "EOF." ); + } + g = SwapLong(g); + return g; } /** - * \brief Swaps the bytes so they agree with the processor order - * @return The properly swaped 16 bits integer. + * \brief skips bytes inside the source file + * \warning NOT end user intended method ! + * @return */ -uint16_t Document::SwapShort(uint16_t a) +void Document::SkipBytes(uint32_t nBytes) { - if ( SwapCode == 4321 || SwapCode == 2143 ) - { - a = ((( a << 8 ) & 0x0ff00 ) | (( a >> 8 ) & 0x00ff ) ); - } - return a; + //FIXME don't dump the returned value + Fp->seekg((long)nBytes, std::ios::cur); } /** - * \brief Unswaps the bytes so they agree with the processor order - * @return The properly unswaped 16 bits integer. + * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader + * @param filetype Type of the File to be written */ -uint16_t Document::UnswapShort(uint16_t a) +int Document::ComputeGroup0002Length( FileType filetype ) { - return SwapShort(a); + uint16_t gr; + std::string vr; + + int groupLength = 0; + bool found0002 = false; + + // for each zero-level Tag in the DCM Header + DocEntry *entry = GetFirstEntry(); + while( entry ) + { + gr = entry->GetGroup(); + + if( gr == 0x0002 ) + { + found0002 = true; + + if( entry->GetElement() != 0x0000 ) + { + vr = entry->GetVR(); + + if( filetype == ExplicitVR ) + { + if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) + { + // explicit VR AND OB, OW, SQ : 4 more bytes + groupLength += 4; + } + } + groupLength += 2 + 2 + 4 + entry->GetLength(); + } + } + else if (found0002 ) + break; + + entry = GetNextEntry(); + } + return groupLength; } //----------------------------------------------------------------------------- @@ -885,9 +977,9 @@ void Document::ParseSQ( SeqEntry *seqEntry, } /** - * \brief Loads the element content if its length doesn't exceed - * the value specified with Document::SetMaxSizeLoadEntry() - * @param entry Header Entry (Dicom Element) to be dealt with + * \brief Loads the element content if its length doesn't exceed + * the value specified with Document::SetMaxSizeLoadEntry() + * @param entry Header Entry (Dicom Element) to be dealt with */ void Document::LoadDocEntry(DocEntry *entry) { @@ -1056,7 +1148,6 @@ void Document::LoadDocEntry(DocEntry *entry) } } - /** * \brief Find the value Length of the passed Header Entry * @param entry Header Entry whose length of the value shall be loaded. @@ -1204,6 +1295,63 @@ void Document::FindDocEntryLength( DocEntry *entry ) } } +/** + * \brief Find the Length till the next sequence delimiter + * \warning NOT end user intended method ! + * @return + */ +uint32_t Document::FindDocEntryLengthOBOrOW() + throw( FormatUnexpected ) +{ + // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. + long positionOnEntry = Fp->tellg(); + bool foundSequenceDelimiter = false; + uint32_t totalLength = 0; + + while ( !foundSequenceDelimiter ) + { + uint16_t group; + uint16_t elem; + try + { + group = ReadInt16(); + elem = ReadInt16(); + } + catch ( FormatError ) + { + throw FormatError("Unexpected end of file encountered during ", + "Document::FindDocEntryLengthOBOrOW()"); + } + // We have to decount the group and element we just read + totalLength += 4; + if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) ) + { + long filePosition = Fp->tellg(); + gdcmVerboseMacro( "Neither an Item tag nor a Sequence delimiter tag on :" + << std::hex << group << " , " << elem + << ") -before- position x(" << filePosition << ")" ); + + Fp->seekg(positionOnEntry, std::ios::beg); + throw FormatUnexpected( "Neither an Item tag nor a Sequence delimiter tag."); + } + if ( elem == 0xe0dd ) + { + foundSequenceDelimiter = true; + } + uint32_t itemLength = ReadInt32(); + // We add 4 bytes since we just read the ItemLength with ReadInt32 + totalLength += itemLength + 4; + SkipBytes(itemLength); + + if ( foundSequenceDelimiter ) + { + break; + } + } + Fp->seekg( positionOnEntry, std::ios::beg); + return totalLength; +} + /** * \brief Find the Value Representation of the current Dicom Element. * @return Value Representation of the current Entry @@ -1324,7 +1472,6 @@ std::string Document::GetDocEntryValue(DocEntry *entry) #endif //GDCM_NO_ANSI_STRING_STREAM return s.str(); } - return ((ValEntry *)entry)->GetValue(); } @@ -1395,7 +1542,7 @@ void Document::SkipDocEntry(DocEntry *entry) } /** - * \brief Skips to the begining of the next Header Entry + * \brief Skips to the beginning of the next Header Entry * \warning NOT end user intended method ! * @param currentDocEntry entry to skip */ @@ -1474,8 +1621,7 @@ void Document::FixDocEntryFoundLength(DocEntry *entry, { foundLength = 0; } - } - + } entry->SetLength(foundLength); } @@ -1508,138 +1654,21 @@ bool Document::IsDocEntryAnInteger(DocEntry *entry) // gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm]. // Since for dicom compliant and well behaved headers, the present // test is useless (and might even look a bit paranoid), when we - // 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 : (" - << std::hex << group << " , " << elem - << ") -before- position x(" << filePosition << ")" - << "lgt : " << length ); - } - } - - if ( vr == "UL" || vr == "US" || vr == "SL" || vr == "SS" ) - { - return true; - } - return false; -} - -/** - * \brief Find the Length till the next sequence delimiter - * \warning NOT end user intended method ! - * @return - */ - -uint32_t Document::FindDocEntryLengthOBOrOW() - throw( FormatUnexpected ) -{ - // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. - long positionOnEntry = Fp->tellg(); - bool foundSequenceDelimiter = false; - uint32_t totalLength = 0; - - while ( !foundSequenceDelimiter ) - { - uint16_t group; - uint16_t elem; - try - { - group = ReadInt16(); - elem = ReadInt16(); - } - catch ( FormatError ) - { - throw FormatError("Unexpected end of file encountered during ", - "Document::FindDocEntryLengthOBOrOW()"); - } - - // We have to decount the group and element we just read - totalLength += 4; - - if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) ) - { - long filePosition = Fp->tellg(); - gdcmVerboseMacro( "Neither an Item tag nor a Sequence delimiter tag on :" - << std::hex << group << " , " << elem - << ") -before- position x(" << filePosition << ")" ); - - Fp->seekg(positionOnEntry, std::ios::beg); - throw FormatUnexpected( "Neither an Item tag nor a Sequence delimiter tag."); - } - - if ( elem == 0xe0dd ) - { - foundSequenceDelimiter = true; - } - - uint32_t itemLength = ReadInt32(); - // We add 4 bytes since we just read the ItemLength with ReadInt32 - totalLength += itemLength + 4; - SkipBytes(itemLength); - - if ( foundSequenceDelimiter ) - { - break; - } - } - Fp->seekg( positionOnEntry, std::ios::beg); - return totalLength; -} - -/** - * \brief Reads a supposed to be 16 Bits integer - * (swaps it depending on processor endianity) - * @return read value - */ -uint16_t Document::ReadInt16() - throw( FormatError ) -{ - uint16_t g; - Fp->read ((char*)&g, (size_t)2); - if ( Fp->fail() ) - { - throw FormatError( "Document::ReadInt16()", " file error." ); - } - if( Fp->eof() ) - { - throw FormatError( "Document::ReadInt16()", "EOF." ); + // 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 : (" + << std::hex << group << " , " << elem + << ") -before- position x(" << filePosition << ")" + << "lgt : " << length ); + } } - g = SwapShort(g); - return g; -} -/** - * \brief Reads a supposed to be 32 Bits integer - * (swaps it depending on processor endianity) - * @return read value - */ -uint32_t Document::ReadInt32() - throw( FormatError ) -{ - uint32_t g; - Fp->read ((char*)&g, (size_t)4); - if ( Fp->fail() ) - { - throw FormatError( "Document::ReadInt32()", " file error." ); - } - if( Fp->eof() ) + if ( vr == "UL" || vr == "US" || vr == "SL" || vr == "SS" ) { - throw FormatError( "Document::ReadInt32()", "EOF." ); - } - g = SwapLong(g); - return g; -} - -/** - * \brief skips bytes inside the source file - * \warning NOT end user intended method ! - * @return - */ -void Document::SkipBytes(uint32_t nBytes) -{ - //FIXME don't dump the returned value - Fp->seekg((long)nBytes, std::ios::cur); + return true; + } + return false; } /** @@ -1879,7 +1908,6 @@ void Document::SetMaxSizeLoadEntry(long newSize) MaxSizeLoadEntry = newSize; } - /** * \brief Header Elements too long will not be printed * \todo See comments of \ref Document::MAX_SIZE_PRINT_ELEMENT_VALUE @@ -1900,104 +1928,6 @@ void Document::SetMaxSizePrintEntry(long newSize) } - -/** - * \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++; - SwitchByteSwapCode(); - // fix the tag - group = 0xfffe; - elem = 0xe000; - } - else if (group == 0xfffe && elem == 0xe00d && reversedEndian) - { - // end of reversed endian group - reversedEndian--; - SwitchByteSwapCode(); - } -} - -/** - * \brief Accesses the info from 0002,0010 : Transfer Syntax and TS - * @return The full Transfer Syntax Name (as opposed to Transfer Syntax UID) - */ -std::string Document::GetTransferSyntaxName() -{ - // use the TS (TS : Transfer Syntax) - std::string transferSyntax = GetEntryValue(0x0002,0x0010); - - if ( (transferSyntax.find(GDCM_NOTLOADED) < transferSyntax.length()) ) - { - gdcmErrorMacro( "Transfer Syntax not loaded. " << std::endl - << "Better you increase MAX_SIZE_LOAD_ELEMENT_VALUE" ); - return "Uncompressed ACR-NEMA"; - } - if ( transferSyntax == GDCM_UNFOUND ) - { - gdcmVerboseMacro( "Unfound Transfer Syntax (0002,0010)"); - return "Uncompressed ACR-NEMA"; - } - - // we do it only when we need it - const TSKey &tsName = Global::GetTS()->GetValue( transferSyntax ); - - // Global::GetTS() is a global static you shall never try to delete it! - return tsName; -} - -/** - * \brief Group 0002 is always coded Little Endian - * whatever Transfer Syntax is - * @return no return - */ -void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) -{ - // Endian reversion. Some files contain groups of tags with reversed endianess. - if ( !Group0002Parsed && group != 0x0002) - { - Group0002Parsed = true; - // we just came out of group 0002 - // if Transfer syntax is Big Endian we have to change CheckSwap - - std::string ts = GetTransferSyntax(); - if ( !Global::GetTS()->IsTransferSyntax(ts) ) - { - gdcmVerboseMacro("True DICOM File, with NO Tansfer Syntax: " << ts ); - return; - } - - // Group 0002 is always 'Explicit ...' enven when Transfer Syntax says 'Implicit ..." - - if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian ) - { - Filetype = ImplicitVR; - } - - // FIXME Strangely, this works with - //'Implicit VR Transfer Syntax (GE Private) - if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian ) - { - gdcmVerboseMacro("Transfer Syntax Name = [" - << GetTransferSyntaxName() << "]" ); - SwitchByteSwapCode(); - group = SwapShort(group); - elem = SwapShort(elem); - } - } -} - /** * \brief Read the next tag but WITHOUT loading it's value * (read the 'Group Number', the 'Element Number', @@ -2026,7 +1956,7 @@ DocEntry *Document::ReadNextDocEntry() // Sometimes file contains groups of tags with reversed endianess. HandleBrokenEndian(group, elem); -// In 'true DICOM' files Group 0002 is always little endian + // In 'true DICOM' files Group 0002 is always little endian if ( HasDCMPreamble ) HandleOutOfGroup0002(group, elem); @@ -2082,7 +2012,77 @@ DocEntry *Document::ReadNextDocEntry() return newEntry; } -//GenerateFreeTagKeyInGroup? What was it designed for ?!? +/** + * \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++; + SwitchByteSwapCode(); + // fix the tag + group = 0xfffe; + elem = 0xe000; + } + else if (group == 0xfffe && elem == 0xe00d && reversedEndian) + { + // end of reversed endian group + reversedEndian--; + SwitchByteSwapCode(); + } +} + +/** + * \brief Group 0002 is always coded Little Endian + * whatever Transfer Syntax is + * @return no return + */ +void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) +{ + // Endian reversion. Some files contain groups of tags with reversed endianess. + if ( !Group0002Parsed && group != 0x0002) + { + Group0002Parsed = true; + // we just came out of group 0002 + // if Transfer syntax is Big Endian we have to change CheckSwap + + std::string ts = GetTransferSyntax(); + if ( !Global::GetTS()->IsTransferSyntax(ts) ) + { + gdcmVerboseMacro("True DICOM File, with NO Tansfer Syntax: " << ts ); + return; + } + + // Group 0002 is always 'Explicit ...' enven when Transfer Syntax says 'Implicit ..." + + if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian ) + { + Filetype = ImplicitVR; + } + + // FIXME Strangely, this works with + //'Implicit VR Transfer Syntax (GE Private) + if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian ) + { + gdcmVerboseMacro("Transfer Syntax Name = [" + << GetTransferSyntaxName() << "]" ); + SwitchByteSwapCode(); + group = SwapShort(group); + elem = SwapShort(elem); + } + } +} + +// GenerateFreeTagKeyInGroup? +// --> What was it designed for ?!? /** * \brief Generate a free TagKey i.e. a TagKey that is not present * in the TagHt dictionary. @@ -2167,51 +2167,6 @@ bool Document::operator<(Document &document) 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; - std::string vr; - - int groupLength = 0; - bool found0002 = false; - - // for each zero-level Tag in the DCM Header - DocEntry *entry = GetFirstEntry(); - while( entry ) - { - gr = entry->GetGroup(); - - if( gr == 0x0002 ) - { - found0002 = true; - - if( entry->GetElement() != 0x0000 ) - { - vr = entry->GetVR(); - - if( filetype == ExplicitVR ) - { - if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) - { - // explicit VR AND OB, OW, SQ : 4 more bytes - groupLength += 4; - } - } - groupLength += 2 + 2 + 4 + entry->GetLength(); - } - } - else if (found0002 ) - break; - - entry = GetNextEntry(); - } - return groupLength; -} - /* * \brief Walk recursively the given \ref DocEntrySet, and feed * the given hash table (\ref TagDocEntryHT) with all the diff --git a/src/gdcmDocument.h b/src/gdcmDocument.h index 45388b1a..c51a7d5d 100644 --- a/src/gdcmDocument.h +++ b/src/gdcmDocument.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.h,v $ Language: C++ - Date: $Date: 2005/01/26 17:17:31 $ - Version: $Revision: 1.102 $ + Date: $Date: 2005/01/31 12:19:34 $ + Version: $Revision: 1.103 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -42,11 +42,6 @@ class Dict; class GDCM_EXPORT Document : public ElementSet { public: -// Informations contained in the gdcm::Document - virtual bool IsReadable(); - FileType GetFileType(); - - std::string GetTransferSyntax(); // Dictionaries virtual void PrintPubDict (std::ostream &os = std::cout); @@ -57,19 +52,31 @@ public: bool SetShaDict(Dict* dict); bool SetShaDict(DictKey const &dictName); +// Informations contained in the gdcm::Document + virtual bool IsReadable(); + bool IsDicomV3(); + bool IsPapyrus(); + FileType GetFileType(); + std::string GetTransferSyntax(); + /// Return the Transfer Syntax as a string + std::string GetTransferSyntaxName(); + // Swap code /// 'Swap code' accessor (see \ref SwapCode ) int GetSwapCode() { return SwapCode; } // System access (meaning endian related !?) - uint16_t SwapShort(uint16_t); // needed by Document - uint32_t SwapLong(uint32_t); // needed by Document - uint16_t UnswapShort(uint16_t); // needed by Document - uint32_t UnswapLong(uint32_t); // needed by Document + uint16_t SwapShort(uint16_t); + uint32_t SwapLong(uint32_t); + /// \brief Unswaps back the bytes of 2-bytes long integer + /// so they agree with the processor order. + uint16_t UnswapShort(uint16_t a) { return SwapShort(a);} + /// \brief Unswaps back the bytes of 4-byte long integer + /// so they agree with the processor order. + uint32_t UnswapLong(uint32_t a) { return SwapLong(a);} // Ordering of Documents bool operator<(Document &document); -public: // File I/O /// Accessor to \ref Filename const std::string &GetFileName() const { return Filename; } @@ -87,12 +94,6 @@ public: void LoadDocEntrySafe(DocEntry *entry); - /// Return the Transfer Syntax as a string - std::string GetTransferSyntaxName(); - - bool IsDicomV3(); - bool IsPapyrus(); - protected: // Methods // Constructor and destructor are protected to forbid end user @@ -105,7 +106,6 @@ protected: uint16_t ReadInt16() throw ( FormatError ); uint32_t ReadInt32() throw ( FormatError ); void SkipBytes(uint32_t); - int ComputeGroup0002Length( FileType filetype ); // Variables @@ -162,7 +162,6 @@ private: std::string GetDocEntryValue (DocEntry *entry); std::string GetDocEntryUnvalue(DocEntry *entry); - void SkipDocEntry (DocEntry *entry); void SkipToNextDocEntry (DocEntry *entry); diff --git a/src/gdcmSQItem.cxx b/src/gdcmSQItem.cxx index 945ad0b2..d4ee46f9 100644 --- a/src/gdcmSQItem.cxx +++ b/src/gdcmSQItem.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSQItem.cxx,v $ Language: C++ - Date: $Date: 2005/01/30 17:30:57 $ - Version: $Revision: 1.62 $ + Date: $Date: 2005/01/31 12:19:34 $ + Version: $Revision: 1.63 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -155,7 +155,7 @@ void SQItem::ClearEntry() } /** - * \brief adds any Entry (Dicom Element) to the Sequence Item + * \brief Adds any Entry (Dicom Element) to the Sequence Item * @param entry Entry to add */ bool SQItem::AddEntry(DocEntry *entry) @@ -237,7 +237,7 @@ DocEntry *SQItem::GetNextEntry() /** * \brief Gets a Dicom Element inside a SQ Item Entry - * @param group Group number of the Entry + * @param group Group number of the Entry * @param elem Element number of the Entry * @return Entry whose (group,elem) was passed. 0 if not found */ diff --git a/src/gdcmSQItem.h b/src/gdcmSQItem.h index 23c5586f..f1d10054 100644 --- a/src/gdcmSQItem.h +++ b/src/gdcmSQItem.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSQItem.h,v $ Language: C++ - Date: $Date: 2005/01/25 15:44:24 $ - Version: $Revision: 1.37 $ + Date: $Date: 2005/01/31 12:19:34 $ + Version: $Revision: 1.38 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -65,6 +65,7 @@ public: /// \brief Accessor on \ref SQDepthLevel. int GetDepthLevel() { return SQDepthLevel; } + /// \brief Accessor on \ref SQDepthLevel. void SetDepthLevel(int depth) { SQDepthLevel = depth; } diff --git a/src/gdcmSeqEntry.cxx b/src/gdcmSeqEntry.cxx index 78911b13..feadac76 100644 --- a/src/gdcmSeqEntry.cxx +++ b/src/gdcmSeqEntry.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSeqEntry.cxx,v $ Language: C++ - Date: $Date: 2005/01/24 16:10:53 $ - Version: $Revision: 1.50 $ + Date: $Date: 2005/01/31 12:19:34 $ + Version: $Revision: 1.51 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -184,7 +184,7 @@ SQItem *SeqEntry::GetNextSQItem() /** * \brief return a pointer to the SQItem referenced by its ordinal number. * Returns the first item when argument is negative. - * Returns the last item when argument is bigger than the total + * Returns the last item when argument is bigger than the total * item number. */ SQItem *SeqEntry::GetSQItem(int nb) @@ -206,15 +206,23 @@ SQItem *SeqEntry::GetSQItem(int nb) return *(Items.end()); } -/// \brief retuens the number of SQItems within the current Sequence +/// \brief returns the number of SQItems within the current Sequence unsigned int SeqEntry::GetNumberOfSQItems() { return Items.size(); } /// \brief adds the passed ITEM to the ITEM chained List for this SeQuence. +/// @param sqItem SQItem to be pushed back in the SeqEntry +/// @param itemNumber ordinal number of the SQItem +/// \note NOT end-user intendend method ! void SeqEntry::AddSQItem(SQItem *sqItem, int itemNumber) { +// FIXME : SQItemNumber is supposed to be the ordinal number of the SQItem +// within the Sequence. +// Either only 'push_back' is allowed, +// and we just have to do something like SeqEntry::lastNb++ +// Or we can add (or remove) anywhere, and SQItemNumber will be broken sqItem->SetSQItemNumber(itemNumber); Items.push_back(sqItem); } diff --git a/src/gdcmSeqEntry.h b/src/gdcmSeqEntry.h index 6676c754..5e1f996c 100644 --- a/src/gdcmSeqEntry.h +++ b/src/gdcmSeqEntry.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSeqEntry.h,v $ Language: C++ - Date: $Date: 2005/01/20 11:26:18 $ - Version: $Revision: 1.30 $ + Date: $Date: 2005/01/31 12:19:34 $ + Version: $Revision: 1.31 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -46,12 +46,11 @@ public: void Print(std::ostream &os = std::cout, std::string const & indent = "" ); void WriteContent(std::ofstream *fp, FileType filetype); - /// returns the SQITEM chained List for this SeQuence. - //ListSQItem const &GetSQItems() const { return Items; } SQItem *GetFirstSQItem(); SQItem *GetNextSQItem(); SQItem *GetSQItem(int itemNumber); unsigned int GetNumberOfSQItems(); + void AddSQItem(SQItem *it, int itemNumber); /// Sets the delimitor mode void SetDelimitorMode(bool dm) { DelimitorMode = dm; } @@ -60,8 +59,6 @@ public: void SetDelimitationItem(DocEntry *e) { SeqTerm = e;} DocEntry *GetDelimitationItem() { return SeqTerm;} - void AddSQItem(SQItem *it, int itemNumber); - /// Gets the depth level int GetDepthLevel() const { return SQDepthLevel; } diff --git a/src/gdcmSerieHeader.cxx b/src/gdcmSerieHeader.cxx index 4c2ac383..93402bf1 100644 --- a/src/gdcmSerieHeader.cxx +++ b/src/gdcmSerieHeader.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSerieHeader.cxx,v $ Language: C++ - Date: $Date: 2005/01/31 03:22:26 $ - Version: $Revision: 1.16 $ + Date: $Date: 2005/01/31 12:19:34 $ + Version: $Revision: 1.17 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -85,9 +85,9 @@ void SerieHeader::Print() for (GdcmFileList::iterator it = (itl->second)->begin(); it != (itl->second)->end(); ++it) - { - std::cout << " --- " << (*it)->GetFileName() << std::endl; - } + { + std::cout << " --- " << (*it)->GetFileName() << std::endl; + } ++itl; } } -- 2.45.1