From 0accc3e4b95c96903d4fb6a792d657bf1e509375 Mon Sep 17 00:00:00 2001 From: jpr Date: Thu, 24 Jun 2004 18:03:14 +0000 Subject: [PATCH] Jean-Pierre Roux FIX : Write - All the Sequences and Sequence Item are now written as 'no length' stuff, and a Sequence Delimitor aor an Item Delimitor is added a the end, when necessary. - A lot of brain-damaged images, that were read correctly are now written correctly - length compatible BinEntry are now loaded correctly (even for odd groups) - Note : only Explicit Value Representation was checked. (question : is implicit VR really necessary for gdcm ?) --- src/gdcmBinEntry.cxx | 13 ++++++-- src/gdcmDocEntry.cxx | 30 +++++++++++------ src/gdcmDocument.cxx | 77 +++++++++++++++++++++++++++++--------------- src/gdcmDocument.h | 5 +-- src/gdcmSQItem.cxx | 17 ++++++++-- src/gdcmSeqEntry.cxx | 26 ++++++++++++--- src/gdcmValEntry.cxx | 6 ++-- src/gdcmValEntry.h | 11 ++++--- 8 files changed, 131 insertions(+), 54 deletions(-) diff --git a/src/gdcmBinEntry.cxx b/src/gdcmBinEntry.cxx index e57f5dfb..ae4c5be8 100644 --- a/src/gdcmBinEntry.cxx +++ b/src/gdcmBinEntry.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmBinEntry.cxx,v $ Language: C++ - Date: $Date: 2004/06/23 15:01:57 $ - Version: $Revision: 1.17 $ + Date: $Date: 2004/06/24 18:03:14 $ + Version: $Revision: 1.18 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -66,6 +66,7 @@ void gdcmBinEntry::Print(std::ostream &os) { gdcmDocEntry::Print(os); std::ostringstream s; + void *voidArea = GetVoidArea(); if (voidArea != NULL) { s << " [gdcm::Binary data loaded with length is " @@ -73,7 +74,13 @@ void gdcmBinEntry::Print(std::ostream &os) } else { - s << " [gdcm::Binary data NOT loaded]"; + if ( GetLength() == 0 ) + s << " []"; + else + { + s << " [gdcm::Binary data NOT loaded]"; + } + } os << s.str(); } diff --git a/src/gdcmDocEntry.cxx b/src/gdcmDocEntry.cxx index 522b1667..69d07b06 100644 --- a/src/gdcmDocEntry.cxx +++ b/src/gdcmDocEntry.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocEntry.cxx,v $ Language: C++ - Date: $Date: 2004/06/23 13:02:36 $ - Version: $Revision: 1.9 $ + Date: $Date: 2004/06/24 18:03:14 $ + Version: $Revision: 1.10 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -107,6 +107,7 @@ void gdcmDocEntry::Print(std::ostream & os) { */ void gdcmDocEntry::Write(FILE *fp, FileType filetype) { + guint32 FFFF = 0xffffffff; guint16 group = GetGroup(); VRKey vr = GetVR(); guint16 el = GetElement(); @@ -151,13 +152,18 @@ void gdcmDocEntry::Write(FILE *fp, FileType filetype) { fwrite ( &z, (size_t)2 ,(size_t)1 ,fp); } else { fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,fp); - -// TODO : better we set SQ length to ffffffff -// and write a Sequence Delimitor Item at the end of the Sequence! + if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) { fwrite ( &z, (size_t)2 ,(size_t)1 ,fp); - fwrite ( &lgr,(size_t)4 ,(size_t)1 ,fp); + if (vr == "SQ") { + // we set SQ length to ffffffff + // and we shall write a Sequence Delimitor Item + // at the end of the Sequence! + fwrite ( &FFFF,(size_t)4 ,(size_t)1 ,fp); + } else { + fwrite ( &lgr,(size_t)4 ,(size_t)1 ,fp); + } } else { fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,fp); } @@ -165,7 +171,11 @@ void gdcmDocEntry::Write(FILE *fp, FileType filetype) { } else // IMPLICIT VR { - fwrite ( &lgr,(size_t)4 ,(size_t)1 ,fp); + if (vr == "SQ") { + fwrite ( &FFFF,(size_t)4 ,(size_t)1 ,fp); + } else { + fwrite ( &lgr,(size_t)4 ,(size_t)1 ,fp); + } } } @@ -205,7 +215,8 @@ void gdcmDocEntry::Copy (gdcmDocEntry* e) { /** * \ingroup gdcmDocEntry - * \brief tells us if entry is the first one of a Sequence Item (fffe,e00d) + * \brief tells us if entry is the last one of a 'no length' SequenceItem + * (fffe,e00d) */ bool gdcmDocEntry::isItemDelimitor() { if ( (GetGroup() == 0xfffe) && (GetElement() == 0xe00d) ) @@ -215,7 +226,8 @@ bool gdcmDocEntry::isItemDelimitor() { } /** * \ingroup gdcmDocEntry - * \brief tells us if entry is the last one of a 'no length' Sequence fffe,e0dd) + * \brief tells us if entry is the last one of a 'no length' Sequence + * (fffe,e0dd) */ bool gdcmDocEntry::isSequenceDelimitor() { if (GetGroup() == 0xfffe && GetElement() == 0xe0dd) diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index bf4d3d49..5a71e670 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.cxx,v $ Language: C++ - Date: $Date: 2004/06/23 16:34:36 $ - Version: $Revision: 1.31 $ + Date: $Date: 2004/06/24 18:03:14 $ + Version: $Revision: 1.32 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -74,9 +74,9 @@ const unsigned int gdcmDocument::HEADER_LENGTH_TO_READ = 256; // Refer to gdcmDocument::SetMaxSizeLoadEntry() -const unsigned int gdcmDocument::MAX_SIZE_LOAD_ELEMENT_VALUE = 4096; +const unsigned int gdcmDocument::MAX_SIZE_LOAD_ELEMENT_VALUE = 0x7fffffff;// 4096; -const unsigned int gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE = 64; +const unsigned int gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE = 0x7fffffff;//64; //----------------------------------------------------------------------------- // Constructor / Destructor @@ -126,8 +126,8 @@ gdcmDocument::gdcmDocument(std::string const & inFilename, long l=ParseDES( this, beg, lgt, false); // le Load sera fait a la volee (void)l; //is l used anywhere ? - - rewind(fp); + + rewind(fp); // Load 'non string' values @@ -144,7 +144,7 @@ gdcmDocument::gdcmDocument(std::string const & inFilename, } //FIXME later : how to use it? LoadEntryVoidArea(0x0028,0x3006); //LUT Data (CTX dependent) - + CloseFile(); // -------------------------------------------------------------- @@ -571,10 +571,9 @@ bool gdcmDocument::WriteF(FileType filetype) { * if ( filetype == ACR) * UpdateGroupLength(true,ACR); */ - - gdcmElementSet::Write(fp,filetype); + + gdcmElementSet::Write(fp,filetype); - /// WriteEntries(fp,type); // old stuff return true; } @@ -968,7 +967,31 @@ void *gdcmDocument::LoadEntryVoidArea(guint16 Group, guint16 Elem) delete[] a; return NULL; } - + return a; +} +/** + * \brief Loads (from disk) the element content + * when a string is not suitable + * @param Element Entry whose voidArea is going to be loaded + */ +void *gdcmDocument::LoadEntryVoidArea(gdcmBinEntry *Element) +{ + size_t o =(size_t)Element->GetOffset(); + fseek(fp, o, SEEK_SET); + size_t l = Element->GetLength(); + char* a = new char[l]; + if(!a) { + dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea cannot allocate a"); + return NULL; + } + Element->SetVoidArea((void *)a); + /// \todo check the result + size_t l2 = fread(a, 1, l ,fp); + if(l != l2) + { + delete[] a; + return NULL; + } return a; } @@ -1066,7 +1089,7 @@ void gdcmDocument::UpdateShaEntries(void) { */ gdcmDocEntry* gdcmDocument::GetDocEntryByNumber(guint16 group, guint16 element) { - TagKey key = gdcmDictEntry::TranslateToKey(group, element); + TagKey key = gdcmDictEntry::TranslateToKey(group, element); if ( ! tagHT.count(key)) return NULL; return tagHT.find(key)->second; @@ -1364,11 +1387,11 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry *Entry) // The elements whose length is bigger than the specified upper bound // are not loaded. Instead we leave a short notice of the offset of // the element content and it's length. - + + std::ostringstream s; if (length > MaxSizeLoadEntry) { if (gdcmBinEntry* BinEntryPtr = dynamic_cast< gdcmBinEntry* >(Entry) ) - { - std::ostringstream s; + { s << "gdcm::NotLoaded (BinEntry)"; s << " Address:" << (long)Entry->GetOffset(); s << " Length:" << Entry->GetLength(); @@ -1377,17 +1400,16 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry *Entry) } // to be sure we are at the end of the value ... fseek(fp,(long)Entry->GetOffset()+(long)Entry->GetLength(),SEEK_SET); - return; - // Be carefull : a BinEntry IS_A ValEntry ... + return; + // Be carefull : a BinEntry IS_A ValEntry ... if (gdcmValEntry* ValEntryPtr = dynamic_cast< gdcmValEntry* >(Entry) ) { - std::ostringstream s; s << "gdcm::NotLoaded. (ValEntry)"; s << " Address:" << (long)Entry->GetOffset(); s << " Length:" << Entry->GetLength(); s << " x(" << std::hex << Entry->GetLength() << ")"; ValEntryPtr->SetValue(s.str()); - } + } // to be sure we are at the end of the value ... fseek(fp,(long)Entry->GetOffset()+(long)Entry->GetLength(),SEEK_SET); return; @@ -1395,9 +1417,12 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry *Entry) // When we find a BinEntry not very much can be done : if (gdcmBinEntry* BinEntryPtr = dynamic_cast< gdcmBinEntry* >(Entry) ) { - LoadEntryVoidArea (BinEntryPtr->GetGroup(),BinEntryPtr->GetElement()); - return; - } + + LoadEntryVoidArea(BinEntryPtr); + s << "gdcm::Loaded (BinEntry)"; + BinEntryPtr->SetValue(s.str()); + return; + } // Any compacter code suggested (?) @@ -1448,7 +1473,7 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry *Entry) // 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); - if (gdcmValEntry* ValEntry = dynamic_cast< gdcmValEntry* >(Entry) ) { + if (gdcmValEntry* ValEntry = dynamic_cast< gdcmValEntry* >(Entry) ) { if ( item_read != 1 ) { dbg.Verbose(1, "gdcmDocument::LoadElementValue","unread element value"); ValEntry->SetValue("gdcm::UnRead"); @@ -1460,9 +1485,9 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry *Entry) else ValEntry->SetValue(NewValue); } else { - // fusible - std::cout << "Should have a ValEntry, here !" << std::endl; - } + // fusible + std::cout << "Should have a ValEntry, here !" << std::endl; + } } diff --git a/src/gdcmDocument.h b/src/gdcmDocument.h index 5a85583e..4a5873f0 100644 --- a/src/gdcmDocument.h +++ b/src/gdcmDocument.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.h,v $ Language: C++ - Date: $Date: 2004/06/22 14:57:11 $ - Version: $Revision: 1.14 $ + Date: $Date: 2004/06/24 18:03:14 $ + Version: $Revision: 1.15 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -152,6 +152,7 @@ public: bool ReplaceIfExistByNumber (char *Value, guint16 Group, guint16 Elem); virtual void *LoadEntryVoidArea (guint16 Group, guint16 Element); + virtual void *LoadEntryVoidArea (gdcmBinEntry*); // System access guint16 SwapShort(guint16); // needed by gdcmFile diff --git a/src/gdcmSQItem.cxx b/src/gdcmSQItem.cxx index f0fa2503..417093d0 100644 --- a/src/gdcmSQItem.cxx +++ b/src/gdcmSQItem.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSQItem.cxx,v $ Language: C++ - Date: $Date: 2004/06/23 13:02:36 $ - Version: $Revision: 1.16 $ + Date: $Date: 2004/06/24 18:03:14 $ + 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 @@ -92,6 +92,19 @@ void gdcmSQItem::Write(FILE *fp,FileType filetype) i != docEntries.end(); ++i) { + // Item Delimitor Item IS the last one of a 'no length' SQItem + // (when it exists) we don't write it right now + // It will be written outside, because ALL the SQItems are written + // as 'no length' + if ( (*i)->isItemDelimitor() ) + break; + if ( ((*i)->GetGroup() == 0xfffe) && ((*i)->GetElement() == 0x0000) ) + // Fix in order to make some MR PHILIPS images e-film readable + // see gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm: + // we just *always* ignore spurious fffe|0000 tag ! + return; + // It's up to the gdcmDocEntry Writter to write the SQItem begin element + // (fffe|e000) as a 'no length' one (*i)->Write(fp, filetype); } } diff --git a/src/gdcmSeqEntry.cxx b/src/gdcmSeqEntry.cxx index 6026a867..fd4d2499 100644 --- a/src/gdcmSeqEntry.cxx +++ b/src/gdcmSeqEntry.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSeqEntry.cxx,v $ Language: C++ - Date: $Date: 2004/06/23 15:01:57 $ - Version: $Revision: 1.19 $ + Date: $Date: 2004/06/24 18:03:14 $ + Version: $Revision: 1.20 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -45,7 +45,6 @@ gdcmSeqEntry::~gdcmSeqEntry() { for(ListSQItem::iterator cc = items.begin();cc != items.end();++cc) { delete *cc; - std::cout << "delete SQItem" <Write(fp, filetype); - } + (*cc)->Write(fp, filetype); + + fwrite ( &item_term_gr,(size_t)2 ,(size_t)1 ,fp); + fwrite ( &item_term_el,(size_t)2 ,(size_t)1 ,fp); + fwrite ( &seq_term_lg,(size_t)4 ,(size_t)1 ,fp); + } + //we force the writting of a Sequence Delimitaion item + // because we wrote the Sequence as a 'no Length' sequence + fwrite ( &seq_term_gr,(size_t)2 ,(size_t)1 ,fp); + fwrite ( &seq_term_el,(size_t)2 ,(size_t)1 ,fp); + fwrite ( &seq_term_lg,(size_t)4 ,(size_t)1 ,fp); } //----------------------------------------------------------------------------- diff --git a/src/gdcmValEntry.cxx b/src/gdcmValEntry.cxx index c0082d83..3c58e701 100644 --- a/src/gdcmValEntry.cxx +++ b/src/gdcmValEntry.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmValEntry.cxx,v $ Language: C++ - Date: $Date: 2004/06/23 13:02:36 $ - Version: $Revision: 1.13 $ + Date: $Date: 2004/06/24 18:03:14 $ + Version: $Revision: 1.14 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -137,7 +137,7 @@ void gdcmValEntry::Write(FILE *fp, FileType filetype) { gdcmDocEntry::Write(fp, filetype); std::string vr=GetVR(); - int lgr=GetLength(); + int lgr=GetReadLength(); if (vr == "US" || vr == "SS") { // some 'Short integer' fields may be mulivaluated diff --git a/src/gdcmValEntry.h b/src/gdcmValEntry.h index 3adc99fa..c2a21b84 100644 --- a/src/gdcmValEntry.h +++ b/src/gdcmValEntry.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmValEntry.h,v $ Language: C++ - Date: $Date: 2004/06/23 13:02:36 $ - Version: $Revision: 1.16 $ + Date: $Date: 2004/06/24 18:03:14 $ + 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 @@ -46,7 +46,10 @@ public: /// Sets the value (string) of the current Dicom Document Entry inline void SetValue(std::string val) { value = val; }; - + + /// Sets the value (void *) of the current Dicom Document Entry + inline void SetVoidArea(void * val) { voidArea = val; }; + virtual void Print(std::ostream &os = std::cout); virtual void Write(FILE *fp, FileType filetype); protected: @@ -59,7 +62,7 @@ private: // Members : /// \brief Document Entry value, internaly represented as a std::string - /// The Value Representation (\ref gdcmVR) is indenpendently used + /// The Value Representation (\ref gdcmVR) is independently used /// in order to interpret (decode) this field. std::string value; }; -- 2.48.1