From: jpr Date: Wed, 9 Jun 2004 08:41:02 +0000 (+0000) Subject: Still in a debugging status. X-Git-Tag: Version0.5.bp~145 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=5c198a737e21a72460f81e81a1b9405b5a591b60;p=gdcm.git Still in a debugging status. Don't use it (except Eric) --- diff --git a/Testing/TestDicomDir.cxx b/Testing/TestDicomDir.cxx index aa4c176d..35d17d65 100644 --- a/Testing/TestDicomDir.cxx +++ b/Testing/TestDicomDir.cxx @@ -1,6 +1,6 @@ #include #include "gdcm.h" -#include "gdcmHeaderEntry.h" +#include "gdcmDocEntry.h" #include "gdcmDicomDir.h" #include @@ -8,7 +8,6 @@ int TestDicomDir(int argc, char* argv[]) { gdcmDicomDir *e1; - ListTag::iterator deb , fin; ListDicomDirPatient::iterator itPatient; ListDicomDirStudy::iterator itStudy; @@ -37,7 +36,7 @@ int TestDicomDir(int argc, char* argv[]) } // Simple examples of structure exploitation -// DON'T REMOVE neither the folowing code, nor the commented out lines +// DON'T REMOVE neither the following code, nor the commented out lines /* cout << std::endl << std::endl diff --git a/src/gdcm.h b/src/gdcm.h index bae51665..9aa9d3d4 100644 --- a/src/gdcm.h +++ b/src/gdcm.h @@ -20,10 +20,10 @@ #include "gdcmDict.h" #include "gdcmDictSet.h" -#include "gdcmParser.h" - -#include "gdcmHeaderEntry.h" - +//#include "gdcmParser.h" +#include "gdcmDocument.h" +//#include "gdcmHeaderEntry.h" +//#include "gdcmDocEntry.h" #include "gdcmHeader.h" #include "gdcmHeaderHelper.h" #include "gdcmFile.h" diff --git a/src/gdcmDicomDir.cxx b/src/gdcmDicomDir.cxx index f4dc21dc..9981e367 100644 --- a/src/gdcmDicomDir.cxx +++ b/src/gdcmDicomDir.cxx @@ -119,13 +119,18 @@ gdcmDicomDir::gdcmDicomDir(bool exception_on_error): startArg= NULL; progressArg= NULL; endArg= NULL; - +cout << "gdcmDicomDir::gdcmDicomDir(bool exception_on_error) sortie gdcmDocument +" +<< endl; progress=0.0; abort=false; std::string pathBidon = ""; // Sorry, NULL not allowed ... SetElement(pathBidon, GDCM_DICOMDIR_META, NULL); // Set the META elements - + +cout << "gdcmDicomDir::gdcmDicomDir apres SetElement " << endl; AddDicomDirMeta(); + cout << "gdcmDicomDir::gdcmDicomDir apres AddDicomDirMeta " << endl; + } diff --git a/src/gdcmDicomDirPatient.cxx b/src/gdcmDicomDirPatient.cxx index 33ae75b9..5c42ad6d 100644 --- a/src/gdcmDicomDirPatient.cxx +++ b/src/gdcmDicomDirPatient.cxx @@ -18,7 +18,12 @@ gdcmDicomDirPatient::gdcmDicomDirPatient(gdcmSQItem *s, TagDocEntryHT *ptagHT): { docEntries = s->GetDocEntries(); } - +/** + * \ingroup gdcmDicomDirPatient + * \brief Constructor + * @param ptagHT pointer to the HTable (gdcmObject needs it + * to build the gdcmHeaderEntries) + */ gdcmDicomDirPatient::gdcmDicomDirPatient(TagDocEntryHT *ptagHT): gdcmObject(ptagHT) { diff --git a/src/gdcmDicomDirSerie.cxx b/src/gdcmDicomDirSerie.cxx index f632168c..f3566ae0 100644 --- a/src/gdcmDicomDirSerie.cxx +++ b/src/gdcmDicomDirSerie.cxx @@ -17,6 +17,12 @@ gdcmDicomDirSerie::gdcmDicomDirSerie(gdcmSQItem *s, TagDocEntryHT *ptagHT): { docEntries = s->GetDocEntries(); } + +/** + * \brief Constructor + * @param ptagHT pointer to the HTable (gdcmObject needs it + * to build the gdcmDocEntries) + */ gdcmDicomDirSerie::gdcmDicomDirSerie(TagDocEntryHT *ptagHT): gdcmObject(ptagHT) { diff --git a/src/gdcmDicomDirStudy.cxx b/src/gdcmDicomDirStudy.cxx index df6b97ca..9a9f401c 100644 --- a/src/gdcmDicomDirStudy.cxx +++ b/src/gdcmDicomDirStudy.cxx @@ -18,7 +18,12 @@ gdcmDicomDirStudy::gdcmDicomDirStudy(gdcmSQItem *s, TagDocEntryHT *ptagHT): { docEntries = s->GetDocEntries(); } - +/** + * \ingroup gdcmDicomDirStudy + * \brief constructor + * @param ptagHT pointer to the HTable (gdcmObject needs it + * to build the gdcmHeaderEntries) + */ gdcmDicomDirStudy::gdcmDicomDirStudy(TagDocEntryHT *ptagHT): gdcmObject(ptagHT) { diff --git a/src/gdcmDocEntry.cxx b/src/gdcmDocEntry.cxx index 668fbefc..e1154793 100644 --- a/src/gdcmDocEntry.cxx +++ b/src/gdcmDocEntry.cxx @@ -24,6 +24,11 @@ gdcmDocEntry::gdcmDocEntry(gdcmDictEntry* in) { entry = in; } +/** + * \ingroup gdcmDocEntry + * \brief Canonical Printer + * @param os ostream we want to print in + */ void gdcmDocEntry::Print(std::ostream & os) { std::ostringstream s; s << std::endl; @@ -117,7 +122,6 @@ guint32 gdcmDocEntry::GetFullLength(void) { * \ingroup gdcmDocEntry * \brief Copies all the attributes from an other DocEntry */ - void gdcmDocEntry::Copy (gdcmDocEntry* e) { this->entry = e->entry; this->UsableLength = e->UsableLength; @@ -128,13 +132,20 @@ void gdcmDocEntry::Copy (gdcmDocEntry* e) { // TODO : remove gdcmDocEntry SQDepth } +/** + * \ingroup gdcmDocEntry + * \brief tells us if entry is the first one of a Sequence Item (fffe,e00d) + */ bool gdcmDocEntry::isItemDelimitor() { if ( (GetGroup() == 0xfffe) && (GetElement() == 0xe00d) ) return true; else return false; } - +/** + * \ingroup gdcmDocEntry + * \brief tells us if entry is the last one of a 'no length' Sequence fffe,e0dd) + */ bool gdcmDocEntry::isSequenceDelimitor() { if (GetGroup() == 0xfffe && GetElement() == 0xe0dd) return true; diff --git a/src/gdcmDocEntry.h b/src/gdcmDocEntry.h index d165fd40..b04768fe 100644 --- a/src/gdcmDocEntry.h +++ b/src/gdcmDocEntry.h @@ -107,9 +107,6 @@ public: virtual void Print (std::ostream & os = std::cout); void gdcmDocEntry::PrintCommonPart(std::ostream & os); - - /// Gets the depth level of a Dicom Header Entry embedded in a SeQuence - inline int GetSQDepthLevel(void) { return (SQDepthLevel); }; guint32 GetFullLength(void); @@ -118,23 +115,23 @@ public: bool isItemDelimitor(); bool isSequenceDelimitor(); + /// \brief Gets the depth level of a Dicom header entry embedded in a SeQuence inline int GetDepthLevel(void) {return(SQDepthLevel);} - void SetDepthLevel(int depth) + + /// \brief Sets the depth level of a Dicom header entry embedded in a SeQuence + inline void SetDepthLevel(int depth) {SQDepthLevel = depth;} private: // FIXME: In fact we should be more specific and use : // friend gdcmDocEntry * gdcmHeader::ReadNextElement(void); - friend class gdcmHeader; - - /// Sets the depth level of a Dicom Header Entry embedded in a SeQuence - inline void SetSQDepthLevel(int depthLevel) { SQDepthLevel = depthLevel; }; - + friend class gdcmHeader; protected: // Variables + /// \brief pointer to the underlying Dicom dictionary element gdcmDictEntry *entry; /// \brief Updated from ReadLength, by FixFoungLentgh() for fixing a bug diff --git a/src/gdcmDocEntrySet.h b/src/gdcmDocEntrySet.h index 94566ad2..9a216477 100644 --- a/src/gdcmDocEntrySet.h +++ b/src/gdcmDocEntrySet.h @@ -16,25 +16,40 @@ public: gdcmDocEntrySet(int depth = 0); ~gdcmDocEntrySet(void); +/// \brief adds any type of entry to the entry set (pure vitual) virtual bool AddEntry(gdcmDocEntry *Entry) = 0; // pure virtual - bool CheckEntryVR(gdcmDocEntry *Entry, std::string vr); + +// bool CheckEntryVR(gdcmDocEntry *Entry, std::string vr); + +/// \brief prints any type of entry to the entry set (pure vitual) virtual void Print (std::ostream & os = std::cout) = 0;// pure virtual + /// \brief Gets the depth level of a Dicom Header Entry embedded in a SeQuence inline int GetDepthLevel(void) {return(SQDepthLevel);} - void SetDepthLevel(int depth) + + /// \brief Sets the depth level of a Dicom Header Entry embedded in a SeQuence + inline void SetDepthLevel(int depth) {SQDepthLevel = depth;} protected: - void gdcmDocEntrySet::FindDocEntryLength (gdcmDocEntry *Entry); +// void gdcmDocEntrySet::FindDocEntryLength (gdcmDocEntry *Entry); // DocEntry related utilities + /// \brief Build a new Element Value from all the low level arguments. + /// Check for existence of dictionary entry, and build + /// a default one when absent (pure virtual) virtual gdcmDocEntry *NewDocEntryByNumber(guint16 group, guint16 element)=0; // pure virtual - virtual gdcmDocEntry *NewDocEntryByName (std::string Name)=0;// pure virtual + /// \brief Build a new Element Value from all the low level arguments. + /// Check for existence of dictionary entry, and build + /// a default one when absent (pure virtual) + virtual gdcmDocEntry *NewDocEntryByName (std::string Name)=0;// pure virtual + + /// Gives the depth level of the element set inside SeQuences int SQDepthLevel; private: diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 7a987771..e4e8fd1e 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -414,10 +414,9 @@ bool gdcmDocument::Write(FILE *fp, FileType type) { /** * \brief Modifies the value of a given Header Entry (Dicom Element) * when it exists. Create it with the given value when unexistant. - * \warning Adds the Header Entry to the HTable, NOT to the chained List * @param Value Value to be set - * @param Group Group of the Entry - * @param Elem Element of the Entry + * @param Group Group number of the Entry + * @param Elem Element number of the Entry * \return pointer to the modified/created Header Entry (NULL when creation * failed). */ @@ -444,8 +443,8 @@ gdcmDocEntry * gdcmDocument::ReplaceOrCreateByNumber( * \brief Set a new value if the invoked element exists * Seems to be useless !!! * @param Value new element value - * @param Group group of the Entry - * @param Elem element of the Entry + * @param Group group number of the Entry + * @param Elem element number of the Entry * \return boolean */ bool gdcmDocument::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) @@ -459,9 +458,8 @@ bool gdcmDocument::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 El // Protected /** - * \brief Checks if a given Dicom Element exists - * within the H table - * @param group Group number of the searched Dicom Element + * \brief Checks if a given Dicom Element exists within the H table + * @param group Group number of the searched Dicom Element * @param element Element number of the searched Dicom Element * @return number of occurences */ @@ -515,8 +513,8 @@ std::string gdcmDocument::GetEntryVRByName(std::string tagName) { * \brief Searches within Header Entries (Dicom Elements) parsed with * the public and private dictionaries * for the element value representation of a given tag. - * @param group Group of the searched tag. - * @param element Element of the searched tag. + * @param group Group number of the searched tag. + * @param element Element number of the searched tag. * @return Corresponding element value representation when it exists, * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ @@ -536,8 +534,8 @@ std::string gdcmDocument::GetEntryByNumber(guint16 group, guint16 element){ * to convert the string typed content to caller's native type * (think of C++ vs Python). The VR is actually of a higher level * of semantics than just the native C++ type. - * @param group Group of the searched tag. - * @param element Element of the searched tag. + * @param group Group number of the searched tag. + * @param element Element number of the searched tag. * @return Corresponding element value representation when it exists, * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ @@ -552,8 +550,8 @@ std::string gdcmDocument::GetEntryVRByNumber(guint16 group, guint16 element) { * \brief Searches within Header Entries (Dicom Elements) parsed with * the public and private dictionaries * for the value length of a given tag.. - * @param group Group of the searched tag. - * @param element Element of the searched tag. + * @param group Group number of the searched tag. + * @param element Element number of the searched tag. * @return Corresponding element length; -2 if not found */ int gdcmDocument::GetEntryLengthByNumber(guint16 group, guint16 element) { @@ -582,8 +580,8 @@ bool gdcmDocument::SetEntryByName(std::string content,std::string tagName) { * through it's (group, element) and modifies it's content with * the given value. * @param content new value to substitute with - * @param group group of the Dicom Element to modify - * @param element element of the Dicom Element to modify + * @param group group number of the Dicom Element to modify + * @param element element number of the Dicom Element to modify */ bool gdcmDocument::SetEntryByNumber(std::string content, guint16 group, @@ -625,8 +623,8 @@ bool gdcmDocument::SetEntryByNumber(std::string content, * the given value. * \warning Use with extreme caution. * @param l new length to substitute with - * @param group group of the Entry to modify - * @param element element of the Entry to modify + * @param group group number of the Entry to modify + * @param element element number of the Entry to modify * @return true on success, false otherwise. */ bool gdcmDocument::SetEntryLengthByNumber(guint32 l, @@ -645,8 +643,8 @@ bool gdcmDocument::SetEntryLengthByNumber(guint32 l, /** * \brief Gets (from Header) the offset of a 'non string' element value * (LoadElementValues has already be executed) - * @param Group group of the Entry - * @param Elem element of the Entry + * @param Group group number of the Entry + * @param Elem element number of the Entry * @return File Offset of the Element Value */ size_t gdcmDocument::GetEntryOffsetByNumber(guint16 Group, guint16 Elem) @@ -664,8 +662,8 @@ size_t gdcmDocument::GetEntryOffsetByNumber(guint16 Group, guint16 Elem) /** * \brief Gets (from Header) a 'non string' element value * (LoadElementValues has already be executed) - * @param Group group of the Entry - * @param Elem element of the Entry + * @param Group group number of the Entry + * @param Elem element number of the Entry * @return Pointer to the 'non string' area */ void * gdcmDocument::GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem) @@ -683,8 +681,8 @@ void * gdcmDocument::GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem) /** * \brief Loads (from disk) the element content * when a string is not suitable - * @param Group group of the Entry - * @param Elem element of the Entry + * @param Group group number of the Entry + * @param Elem element number of the Entry */ void *gdcmDocument::LoadEntryVoidArea(guint16 Group, guint16 Elem) { @@ -713,7 +711,7 @@ void *gdcmDocument::LoadEntryVoidArea(guint16 Group, guint16 Elem) /** * \brief Sets a 'non string' value to a given Dicom Element * @param area - * @param group Group number of the searched Dicom Element + * @param group Group number of the searched Dicom Element * @param element Element number of the searched Dicom Element * @return */ @@ -909,15 +907,23 @@ void gdcmDocument::WriteEntryValue(gdcmDocEntry *tag, FILE *_fp,FileType type) if (group == 0xfffe) // Delimiters have no associated value: return; - + + //-------------------------------- + // + // FIXME + // + // ------------------------------- + + +/* // to go on compiling void *voidArea; - // voidArea = tag->GetVoidArea(); // to go on compiling + voidArea = tag->GetVoidArea(); // to go on compiling if (voidArea != NULL) { // there is a 'non string' LUT, overlay, etc fwrite ( voidArea,(size_t)lgr ,(size_t)1 ,_fp); // Elem value return; } - +*/ if (vr == "US" || vr == "SS") { // some 'Short integer' fields may be mulivaluated @@ -967,17 +973,20 @@ void gdcmDocument::WriteEntryValue(gdcmDocEntry *tag, FILE *_fp,FileType type) bool gdcmDocument::WriteEntry(gdcmDocEntry *tag, FILE *_fp,FileType type) { guint32 length = tag->GetLength(); - + gdcmValEntry * Vtag = (gdcmValEntry *) tag; +std::cout << "gdcmDocument::WriteEntry Vtag->GetValue() " << Vtag->GetValue() << std::endl; // The value of a tag MUST (see the DICOM norm) be an odd number of // bytes. When this is not the case, pad with an additional byte: if(length%2==1) { -// tag->SetValue(tag->GetValue()+"\0"); // to go on compiling - tag->SetLength(tag->GetReadLength()+1); + Vtag->SetValue(Vtag->GetValue()+"\0"); + Vtag->SetLength(Vtag->GetReadLength()+1); } - WriteEntryTagVRLength(tag, _fp, type); - WriteEntryValue(tag, _fp, type); + WriteEntryTagVRLength(Vtag, _fp, type); + std::cout << "after WriteEntryTagVRLength " << std::endl; + WriteEntryValue(Vtag, _fp, type); + std::cout << "after WriteEntryValue " << std::endl; return true; } @@ -990,7 +999,6 @@ bool gdcmDocument::WriteEntry(gdcmDocEntry *tag, FILE *_fp,FileType type) * (function CheckHeaderCoherence to be written) * \warning DON'T try, right now, to write a DICOM image * from an ACR Header (meta elements will be missing!) - * \sa WriteEntriesDeprecated (Special temporary method for Theralys) * @param type type of the File to be written * (ACR-NEMA, ExplicitVR, ImplicitVR) * @param _fp already open file pointer @@ -1002,11 +1010,15 @@ bool gdcmDocument::WriteEntries(FILE *_fp,FileType type) // FIXME : explore recursively the whole structure... /// \todo (?) check write failures (after *each* fwrite) - + + std::cout << "--------------------- gdcmDocument::WriteEntries " << std::endl; for (TagDocEntryHT::iterator tag2=tagHT.begin(); tag2 != tagHT.end(); ++tag2) { + + (*tag2).second->Print(); + if ( type == gdcmACR ){ if ((*tag2).second->GetGroup() < 0x0008) // Ignore pure DICOM V3 groups @@ -1016,11 +1028,15 @@ bool gdcmDocument::WriteEntries(FILE *_fp,FileType type) continue; if ((*tag2).second->GetVR() == "SQ" ) // ignore Sequences continue; - if ((*tag2).second->GetSQDepthLevel() != 0) // Not only ignore the SQ element - continue; + //if ((*tag2).second->GetDepthLevel() != 0) // Not only ignore the SQ element + // continue; } - if (! WriteEntry((*tag2).second,_fp,type) ) + if (! WriteEntry((*tag2).second,_fp,type) ) { + std::cout << "Write Failure " << std::endl; return false; + } else { + + } } return true; } @@ -2238,8 +2254,8 @@ gdcmDocEntry *gdcmDocument::NewDocEntryByName(std::string Name) /** * \brief Request a new virtual dict entry to the dict set - * @param group group of the underlying DictEntry - * @param element element of the underlying DictEntry + * @param group group number of the underlying DictEntry + * @param element element number of the underlying DictEntry * @param vr VR of the underlying DictEntry * @param fourth owner group * @param name english name @@ -2256,8 +2272,8 @@ gdcmDictEntry *gdcmDocument::NewVirtualDictEntry(guint16 group, guint16 element, * \brief Build a new Element Value from all the low level arguments. * Check for existence of dictionary entry, and build * a default one when absent. - * @param Group group of the underlying DictEntry - * @param Elem element of the underlying DictEntry + * @param Group group number of the underlying DictEntry + * @param Elem element number of the underlying DictEntry */ gdcmDocEntry *gdcmDocument::NewDocEntryByNumber(guint16 Group, guint16 Elem) { diff --git a/src/gdcmDocument.h b/src/gdcmDocument.h index bebde32a..fdab6009 100644 --- a/src/gdcmDocument.h +++ b/src/gdcmDocument.h @@ -10,22 +10,20 @@ #include "gdcmException.h" #include "gdcmDictSet.h" #include "gdcmDocEntry.h" -//#include "gdcmSeqEntry.h" + class gdcmSeqEntry; + #include "gdcmDocEntrySet.h" #include "gdcmElementSet.h" #include #include - //----------------------------------------------------------------------------- typedef std::string VRKey; typedef std::string VRAtr; typedef std::map VRHT; // Value Representation Hash Table -typedef std::map TagDocEntryHT; - //----------------------------------------------------------------------------- /** * \brief used by both gdcmHeader and gdcmDicomDir diff --git a/src/gdcmFile.h b/src/gdcmFile.h index e978703b..794e2b27 100644 --- a/src/gdcmFile.h +++ b/src/gdcmFile.h @@ -97,22 +97,26 @@ private: bool gdcm_read_RLE_file (FILE *fp,void * image_buffer); // Variables - /// Header to use to load the file - gdcmHeader *Header; + + /// \brief Header to use to load the file + gdcmHeader *Header; + + /// \brief Oops ! Eric : help me bool SelfHeader; + /// \brief to hold the Pixels (when read) void* PixelData; - /// Area length to receive the pixels + /// \brief Area length to receive the pixels size_t lgrTotaleRaw; - /// Area length to receive the RGB pixels + /// \brief Area length to receive the RGB pixels /// from Grey Plane + Palette Color size_t lgrTotale; - /// ==1 if GetImageDataRaw was used - /// ==0 if GetImageData was used - /// ==-1 if ImageData never read + /// \brief ==1 if GetImageDataRaw was used + /// ==0 if GetImageData was used + /// ==-1 if ImageData never read int PixelRead; /// weather already parsed diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index 15bf00f6..553997c5 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -80,65 +80,6 @@ gdcmHeader::~gdcmHeader (void) { //----------------------------------------------------------------------------- // Print -// see gdcmParser.cxx - -/** - * \ingroup gdcmHeader - * \brief Prints the Header Entries (Dicom Elements) - * from the chained list - * and skips the elements belonging to a SeQuence - * @return - */ -void gdcmHeader::PrintEntryNoSQ(std::ostream & os) { - -// FIXME : Is it of any use, now? - -/* - int depth; - for (ListTag::iterator i = listEntries.begin(); - i != listEntries.end(); - ++i) - { - depth= (*i)->GetSQDepthLevel(); - if ( depth != 0 ){ - continue; - } - (*i)->SetPrintLevel(printLevel); - (*i)->Print(os); - } - */ -} - -/** - * \ingroup gdcmHeader - * \brief Prints the Header Entries (Dicom Elements) - * from the chained list - * and indents the elements belonging to any SeQuence - * \warning : will be removed - * @return - */ -void gdcmHeader::PrintEntryNiceSQ(std::ostream & os) { - -/* - std::ostringstream tab; - tab << " "; - - int depth; - for (ListTag::iterator i = listEntries.begin(); - i != listEntries.end(); - ++i) { - depth= (*i)->GetSQDepthLevel(); - if (depth != 0) { - for (int k=0;kSetPrintLevel(printLevel); - (*i)->Print(os); - - } // end for - - */ -} //----------------------------------------------------------------------------- // Public @@ -828,9 +769,11 @@ void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { } return(false); } - +// Replaced by gdcmDocument::WriteEntry +/* bool gdcmHeader::WriteEntry(gdcmDocEntry *tag, FILE *_fp,FileType type) { +cout << " gdcmHeader::WriteEntry : entree " << endl; guint32 length = tag->GetLength(); // The value of a tag MUST (see the DICOM norm) be an odd number of @@ -848,17 +791,10 @@ bool gdcmHeader::WriteEntry(gdcmDocEntry *tag, FILE *_fp,FileType type) // FIX : we loose trailing elements (RAB, right now) guint16 el = tag->GetElement(); guint16 group = tag->GetGroup(); - int compte =0; - if ((group == GrPixel) && (el == NumPixel) ) { - compte++; - if (compte == countGrPixel) {// we passed *all* the GrPixel,NumPixel - return false; - } - } WriteEntryValue(tag, _fp, type); return true; } - +*/ //----------------------------------------------------------------------------- // Protected diff --git a/src/gdcmHeader.h b/src/gdcmHeader.h index a6a861c1..17052f4e 100644 --- a/src/gdcmHeader.h +++ b/src/gdcmHeader.h @@ -29,24 +29,19 @@ class GDCM_EXPORT gdcmHeader : public gdcmDocument { protected: - /// In some cases (e.g. for some ACR-NEMA images) the Header Entry Element + /// \brief In some cases (e.g. for some ACR-NEMA images) the Header Entry Element /// Number of the 'Pixel Element' is *not* found at 0x0010. In order to /// make things easier the parser shall store the proper value in /// NumPixel to provide a unique access facility. See also the constructor /// \ref gdcmHeader::gdcmHeader guint16 NumPixel; - /// In some cases (e.g. for some ACR-NEMA images) the header entry for + /// \brief In some cases (e.g. for some ACR-NEMA images) the header entry for /// the group of pixels is *not* found at 0x7fe0. In order to /// make things easier the parser shall store the proper value in /// GrPixel to provide a unique access facility. See also the constructor /// \ref gdcmHeader::gdcmHeader guint16 GrPixel; - /// Some DICOM files may contain several images (e.g. a icon, followd by - /// the image itself. Hence the tag (GrPixel,NumPixel) might appear - /// several times. countGrPixel is the number of occurences of the - /// tag of pixels (i.e. (GrPixel,NumPixel)) contained in the header. - /// TODO : will be dealt with SQ tree-like stucture - int countGrPixel; + public: gdcmHeader(bool exception_on_error = false); gdcmHeader(const char *filename, @@ -143,11 +138,7 @@ public: bool operator<(gdcmHeader &header); - bool WriteEntry(gdcmDocEntry *tag,FILE *_fp,FileType type); - - - virtual void PrintEntryNoSQ (std::ostream &os = std::cout); - virtual void PrintEntryNiceSQ(std::ostream &os = std::cout); +// bool WriteEntry(gdcmDocEntry *tag,FILE *_fp,FileType type); protected: //CLEANME int write(std::ostream&); diff --git a/src/gdcmHeaderEntry.cxx b/src/gdcmHeaderEntry.cxx deleted file mode 100644 index b445b624..00000000 --- a/src/gdcmHeaderEntry.cxx +++ /dev/null @@ -1,158 +0,0 @@ -// gdcmHeaderEntry.cxx -//----------------------------------------------------------------------------- -// -#include "gdcmHeaderEntry.h" -#include "gdcmTS.h" -#include "gdcmGlobal.h" -#include "gdcmUtil.h" - -#include // for std::ios::left, ... - - -#define MAX_SIZE_PRINT_ELEMENT_VALUE 64 - -//----------------------------------------------------------------------------- -// Constructor / Destructor -/** - * \ingroup gdcmHeaderEntry - * \brief Constructor from a given gdcmDictEntry - * @param in Pointer to existing dictionary entry - */ -gdcmHeaderEntry::gdcmHeaderEntry(gdcmDictEntry* in) { - ImplicitVR = false; - voidArea = NULL; // unsecure memory area to hold 'non string' values - entry = in; -} - -//----------------------------------------------------------------------------- -// Print -/** - * \ingroup gdcmHeaderEntry - * \brief canonical Printer - */ -void gdcmHeaderEntry::Print(std::ostream & os) { - size_t o; - unsigned short int g, e; - char st[20]; - TSKey v; - std::string d2, vr; - gdcmTS * ts = gdcmGlobal::GetTS(); - std::ostringstream s; - guint32 lgth; - char greltag[10]; //group element tag - - g = GetGroup(); - e = GetElement(); - v = GetValue(); - o = GetOffset(); - vr = GetVR(); - sprintf(greltag,"%04x|%04x ",g,e); - s << greltag ; - - d2 = CreateCleanString(v); // replace non printable characters by '.' - if (printLevel>=2) { - s << "lg : "; - lgth = GetReadLength(); // ReadLength, as opposed to UsableLength - if (lgth == 0xffffffff) { - sprintf(st,"x(ffff)"); // I said : "x(ffff)" ! - s.setf(std::ios::left); - s << std::setw(10-strlen(st)) << " "; - s << st << " "; - s.setf(std::ios::left); - s << std::setw(8) << "-1"; - } else { - sprintf(st,"x(%x)",lgth); - s.setf(std::ios::left); - s << std::setw(10-strlen(st)) << " "; - s << st << " "; - s.setf(std::ios::left); - s << std::setw(8) << lgth; - } - s << " Off.: "; - sprintf(st,"x(%x)",o); - s << std::setw(10-strlen(st)) << " "; - s << st << " "; - s << std::setw(8) << o; - } - - s << "[" << vr << "] "; - - if (printLevel>=1) { - s.setf(std::ios::left); - s << std::setw(66-GetName().length()) << " "; - } - - s << "[" << GetName()<< "]"; - - if (voidArea != NULL) { - s << " [gdcm::Non String Data Loaded in Unsecure Area (" - << GetLength() << ") ]"; - } - - else { - if( (GetLength()=3) || - (d2.find("gdcm::NotLoaded.") < d2.length()) ) - s << " [" << d2 << "]"; - else - s << " [gdcm::too long for print (" << GetLength() << ") ]"; - } - - // Display the UID value (instead of displaying only the rough code) - if (g == 0x0002) { // Any more to be displayed ? - if ( (e == 0x0010) || (e == 0x0002) ) - s << " ==>\t[" << ts->GetValue(v) << "]"; - } else { - if (g == 0x0008) { - if ( (e == 0x0016) || (e == 0x1150) ) - s << " ==>\t[" << ts->GetValue(v) << "]"; - } else { - if (g == 0x0004) { - if ( (e == 0x1510) || (e == 0x1512) ) - s << " ==>\t[" << ts->GetValue(v) << "]"; - } - } - } - //if (e == 0x0000) { // elem 0x0000 --> group length - if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") ) { - if (v == "4294967295") // to avoid troubles in convertion - sprintf (st," x(ffffffff)"); - else { - if ( GetLength() !=0 ) - sprintf(st," x(%x)", atoi(v.c_str()));//FIXME - else - sprintf(st," "); - } - s << st; - } - s << std::endl; - os << s.str(); -} - -//----------------------------------------------------------------------------- -// Public - -/** - * \ingroup gdcmHeaderEntry - * \brief Gets the full length of the HeaderEntry (not only value length) - */ -guint32 gdcmHeaderEntry::GetFullLength(void) { - guint32 l; - l = GetLength(); - if ( IsImplicitVR() ) - l = l + 8; // 2 (gr) + 2 (el) + 4 (lgth) - else - if ( GetVR()=="OB" || GetVR()=="OW" || GetVR()=="SQ" ) - l = l + 12; // 2 (gr) + 2 (el) + 2 (vr) + 2 (unused) + 4 (lgth) - else - l = l + 8; // 2 (gr) + 2 (el) + 2 (vr) + 2 (lgth) - return(l); -} - -//----------------------------------------------------------------------------- -// Protected - -//----------------------------------------------------------------------------- -// Private - -//----------------------------------------------------------------------------- diff --git a/src/gdcmHeaderEntry.h b/src/gdcmHeaderEntry.h deleted file mode 100644 index 178cefff..00000000 --- a/src/gdcmHeaderEntry.h +++ /dev/null @@ -1,169 +0,0 @@ -// gdcmHeaderEntry.h -//----------------------------------------------------------------------------- -#ifndef GDCMHeaderEntry_H -#define GDCMHeaderEntry_H - -#include -#include - -#include "gdcmDictEntry.h" -class gdcmHeader; - -//----------------------------------------------------------------------------- -/** - * \ingroup gdcmHeaderEntry - * \brief The dicom header of a Dicom file contains a set of such entries - * (when successfuly parsed against a given Dicom dictionary) - */ -class GDCM_EXPORT gdcmHeaderEntry { -public: - gdcmHeaderEntry(gdcmDictEntry*); - - /// Returns the Dicom Group number of the current Dicom Header Entry - inline guint16 GetGroup(void) { return entry->GetGroup(); }; - - /// Returns the Dicom Element number of the current Dicom Header Entry - inline guint16 GetElement(void) { return entry->GetElement();}; - - /// Returns the 'key' of the current Dicom Header Entry - inline std::string GetKey(void) { return entry->GetKey(); }; - - /// \brief Returns the 'Name' '(e.g. "Patient's Name") found in the Dicom - /// Dictionnary of the current Dicom Header Entry - inline std::string GetName(void) { return entry->GetName(); }; - - /// \brief Returns the 'Value Representation' (e.g. "PN" : Person Name, - /// "SL" : Signed Long), found in the Dicom Header or in the Dicom - /// Dictionnary, of the current Dicom Header Entry - inline std::string GetVR(void) { return entry->GetVR(); }; - - /// \brief Returns the 'Value' (e.g. "Dupond Marcel") converted into a - /// 'string', if it's stored as an integer in the Dicom Header of the - /// current Dicom Header Entry - inline std::string GetValue(void) { return value; }; - - /// \brief Returns the area value of the current Dicom Header Entry - /// when it's not string-translatable (e.g : a LUT table) - inline void * GetVoidArea(void) { return voidArea; }; - - /// \brief Returns offset (since the beginning of the file, including - /// the File Pramble, if any) of the value of the current Dicom HeaderEntry - /// \warning offset of the *value*, not of the Dicom Header Entry - inline size_t GetOffset(void) { return Offset; }; - - /// \brief Returns the actual value length of the current Dicom Header Entry - /// \warning this value is not *allways* the one stored in the Dicom Header - /// in case of well knowned bugs - inline guint32 GetLength(void) { return UsableLength; }; - - /// \brief Returns the 'read length' of the current Dicom Header Entry - /// \warning this value is the one stored in the Dicom Header but not - /// mandatoryly the one thats's used (in case on SQ, or delimiters, - /// the usable length is set to zero) - inline guint32 GetReadLength(void) { return ReadLength; }; - - /// Sets the 'Value Representation' of the current Dicom Header Entry - inline void SetVR(std::string v) { entry->SetVR(v); }; - - /// \brief Sets both 'Read Length' and 'Usable Length' of the current - /// Dicom Header Entry - inline void SetLength(guint32 l) { ReadLength=UsableLength=l;}; - - // The following 3 members, for internal use only ! - - /// \brief Sets only 'Read Length' (*not* 'Usable Length') of the current - /// Dicom Header Entry - inline void SetReadLength(guint32 l) { ReadLength = l; }; - - /// \brief Sets only 'Usable Length' (*not* 'Read Length') of the current - /// Dicom Header Entry - inline void SetUsableLength(guint32 l) { UsableLength = l; }; - - /// Sets the value (string) of the current Dicom Header Entry - inline void SetValue(std::string val) { value = val; }; - - /// Sets the value (non string) of the current Dicom Header Entry - inline void SetVoidArea(void * area) { voidArea = area; }; - - /// \brief Sets the offset of the Dicom Element - /// \warning use with caution ! - /// @param of offset to be set - inline void gdcmHeaderEntry::SetOffset(size_t of) { Offset = of; }; - - /// Sets to TRUE the ImplicitVr flag of the current Dicom Element - inline void gdcmHeaderEntry::SetImplicitVR(void) { ImplicitVR = true; }; - - /// \brief Tells us if the current Dicom Element was checked as ImplicitVr - /// @return true if the current Dicom Element was checked as ImplicitVr - inline bool gdcmHeaderEntry::IsImplicitVR(void) { return ImplicitVR; }; - - /// \brief Tells us if the VR of the current Dicom Element is Unkonwn - /// @return true if the VR is unkonwn - inline bool gdcmHeaderEntry::IsVRUnknown(void) - { return entry->IsVRUnknown(); }; - - /// \brief Sets the DicEntry of the current Dicom Element - /// @param NewEntry pointer to the DictEntry - inline void gdcmHeaderEntry::SetDictEntry(gdcmDictEntry *NewEntry) - { entry = NewEntry; }; - - /// \brief Gets the DicEntry of the current Dicom Element - /// @return The DicEntry of the current Dicom Element - gdcmDictEntry * gdcmHeaderEntry::GetDictEntry(void) { return entry; }; - - /// \brief Sets the print level for the Dicom Header Elements - /// \note 0 for Light Print; 1 for 'medium' Print, 2 for Heavy - void SetPrintLevel(int level) { printLevel = level; }; - - void Print (std::ostream & os = std::cout); - - /// Gets the depth level of a Dicom Header Entry embedded in a SeQuence - inline int GetSQDepthLevel(void) { return (SQDepthLevel); }; - - guint32 GetFullLength(void); - -private: - // FIXME: In fact we should be more specific and use : - // friend gdcmHeaderEntry * gdcmHeader::ReadNextElement(void); - friend class gdcmHeader; - - /// Sets the depth level of a Dicom Header Entry embedded in a SeQuence - inline void SetSQDepthLevel(int depthLevel) { SQDepthLevel = depthLevel; }; - -// Variables - gdcmDictEntry *entry; - - /// \brief Updated from ReadLength, by FixFoungLentgh() for fixing a bug - /// in the header or helping the parser going on - guint32 UsableLength; - - /// \brief Length actually read on disk (before FixFoundLength). ReadLength - /// will be updated only when FixFoundLength actually fixes a bug in the - /// header, not when it performs a trick to help the Parser going on. - guint32 ReadLength; - - /// \brief Even when reading explicit vr files, some elements happen to - /// be implicit. Flag them here since we can't use the entry->vr without - /// breaking the underlying dictionary. - bool ImplicitVR; - - /// \brief Header Entry value, stores as a std::string (VR will be used, - /// later, to decode) - std::string value; - - /// \brief unsecure memory area to hold 'non string' values - /// (ie : Lookup Tables, overlays) - void *voidArea; - - /// Offset from the begining of file for direct user access - size_t Offset; - - /// How many details are to be printed (value : 0,1,2) - int printLevel; - - /// Gives the depth level of elements inside SeQuences - int SQDepthLevel; -}; - -//----------------------------------------------------------------------------- -#endif diff --git a/src/gdcmParser.cxx b/src/gdcmParser.cxx deleted file mode 100644 index 332b415a..00000000 --- a/src/gdcmParser.cxx +++ /dev/null @@ -1,2413 +0,0 @@ -// gdcmParser.cxx -//----------------------------------------------------------------------------- -//#define UINT32_MAX (4294967295U) - - -#include "gdcmParser.h" -#include "gdcmGlobal.h" -#include "gdcmUtil.h" -#include "gdcmDebug.h" - -#include -#include - -// For nthos: -#ifdef _MSC_VER - #include -#else - #include -#endif - -# include - -#define UI1_2_840_10008_1_2 "1.2.840.10008.1.2" -#define UI1_2_840_10008_1_2_1 "1.2.840.10008.1.2.1" -#define UI1_2_840_10008_1_2_2 "1.2.840.10008.1.2.2" -#define UI1_2_840_10008_1_2_1_99 "1.2.840.10008.1.2.1.99" - -typedef struct { - guint32 totalSQlength; - guint32 alreadyParsedlength; -} pileElem; - -//----------------------------------------------------------------------------- -// Refer to gdcmParser::CheckSwap() -const unsigned int gdcmParser::HEADER_LENGTH_TO_READ = 256; - -// Refer to gdcmParser::SetMaxSizeLoadEntry() -const unsigned int gdcmParser::MAX_SIZE_LOAD_ELEMENT_VALUE = 4096; - -const unsigned int gdcmParser::MAX_SIZE_PRINT_ELEMENT_VALUE = 64; - -//----------------------------------------------------------------------------- -// Constructor / Destructor - -/** - * \brief constructor - * @param inFilename file to be opened for parsing - * @param exception_on_error whether we throw an exception or not - * @param enable_sequences = true to allow the header - * to be parsed *inside* the SeQuences, - * when they have an actual length - * \warning enable_sequences *has to be* true for reading PAPYRUS 3.0 files - * @param ignore_shadow to allow skipping the shadow elements, - * to save memory space. - * \warning The TRUE value for this param has to be used - * with a FALSE value for the 'enable_sequence' param. - * ('public elements' may be embedded in 'shadow Sequences') - */ -gdcmParser::gdcmParser(const char *inFilename, - bool exception_on_error, - bool enable_sequences, - bool ignore_shadow) { - enableSequences=enable_sequences; - ignoreShadow =ignore_shadow; - - SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); - filename = inFilename; - Initialise(); - - if ( !OpenFile(exception_on_error)) - return; - - LoadHeaderEntries(); - CloseFile(); - - wasUpdated = 0; // will be set to 1 if user adds an entry - printLevel = 1; // 'Medium' print level by default -} - -/** - * \brief constructor - * @param exception_on_error - */ -gdcmParser::gdcmParser(bool exception_on_error) { - (void)exception_on_error; - enableSequences=0; - - SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); - Initialise(); - - wasUpdated = 0; // will be set to 1 if user adds an entry - printLevel = 1; // 'Medium' print level by default -} - -/** - * \brief Canonical destructor. - */ -gdcmParser::~gdcmParser (void) { - RefPubDict = NULL; - RefShaDict = NULL; -} - -//----------------------------------------------------------------------------- -// Print -/** - * \brief Prints the Header Entries (Dicom Elements) - * from the chained list - * @return - */ -void gdcmParser::PrintEntry(std::ostream & os) { - - for (ListTag::iterator i = listEntries.begin(); - i != listEntries.end(); - ++i) - { - (*i)->SetPrintLevel(printLevel); - (*i)->Print(os); - } -} - - -/** - * \brief Prints The Dict Entries of THE public Dicom Dictionary - * @return - */ -void gdcmParser::PrintPubDict(std::ostream & os) { - RefPubDict->Print(os); -} - -/** - * \brief Prints The Dict Entries of THE shadow Dicom Dictionary - * @return - */ -void gdcmParser::PrintShaDict(std::ostream & os) { - RefShaDict->Print(os); -} - -//----------------------------------------------------------------------------- -// Public -/** - * \brief Get the public dictionary used - */ -gdcmDict *gdcmParser::GetPubDict(void) { - return(RefPubDict); -} - -/** - * \brief Get the shadow dictionary used - */ -gdcmDict *gdcmParser::GetShaDict(void) { - return(RefShaDict); -} - -/** - * \brief Set the shadow dictionary used - * \param dict dictionary to use in shadow - */ -bool gdcmParser::SetShaDict(gdcmDict *dict){ - RefShaDict=dict; - return(!RefShaDict); -} - -/** - * \brief Set the shadow dictionary used - * \param dictName name of the dictionary to use in shadow - */ -bool gdcmParser::SetShaDict(DictKey dictName){ - RefShaDict=gdcmGlobal::GetDicts()->GetDict(dictName); - return(!RefShaDict); -} - -/** - * \brief This predicate, based on hopefully reasonable heuristics, - * decides whether or not the current gdcmParser was properly parsed - * and contains the mandatory information for being considered as - * a well formed and usable Dicom/Acr File. - * @return true when gdcmParser is the one of a reasonable Dicom/Acr file, - * false otherwise. - */ -bool gdcmParser::IsReadable(void) { - if(filetype==gdcmUnknown) { - return(false); - } - if(listEntries.size()<=0) { - return(false); - } - - return(true); -} - -/** - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a ImplicitVRLittleEndian one. - * @return True when ImplicitVRLittleEndian found. False in all other cases. - */ -bool gdcmParser::IsImplicitVRLittleEndianTransferSyntax(void) { - gdcmHeaderEntry *Element = GetHeaderEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadHeaderEntrySafe(Element); - - std::string Transfer = Element->GetValue(); - if ( Transfer == UI1_2_840_10008_1_2 ) - return true; - return false; -} - -/** - * \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 gdcmParser::IsExplicitVRLittleEndianTransferSyntax(void) { - gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadHeaderEntrySafe(Element); - - std::string Transfer = Element->GetValue(); - if ( Transfer == UI1_2_840_10008_1_2_1 ) - return true; - return false; -} - -/** - * \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 gdcmParser::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) { - gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadHeaderEntrySafe(Element); - - std::string Transfer = Element->GetValue(); - if ( Transfer == UI1_2_840_10008_1_2_1_99 ) - return true; - return false; -} - -/** - * \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 gdcmParser::IsExplicitVRBigEndianTransferSyntax(void) { - gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadHeaderEntrySafe(Element); - - std::string Transfer = Element->GetValue(); - if ( Transfer == UI1_2_840_10008_1_2_2 ) //1.2.2 ??? A verifier ! - return true; - return false; -} - -/** - * \brief returns the File Type - * (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unfound) - * @return the FileType code - */ -FileType gdcmParser::GetFileType(void) { - return(filetype); -} - -/** - * \brief opens the file - * @param exception_on_error - * @return - */ -FILE *gdcmParser::OpenFile(bool exception_on_error) - throw(gdcmFileError) -{ - fp=fopen(filename.c_str(),"rb"); - if(exception_on_error) - { - if(!fp) - throw gdcmFileError("gdcmParser::gdcmParser(const char *, bool)"); - } - - if ( fp ) - { - guint16 zero; - fread(&zero, (size_t)2, (size_t)1, fp); - - //ACR -- or DICOM with no Preamble -- - if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200) - return(fp); - - //DICOM - fseek(fp, 126L, SEEK_CUR); - char dicm[4]; - fread(dicm, (size_t)4, (size_t)1, fp); - if( memcmp(dicm, "DICM", 4) == 0 ) - return(fp); - - fclose(fp); - dbg.Verbose(0, "gdcmParser::OpenFile not DICOM/ACR", filename.c_str()); - } - else { - dbg.Verbose(0, "gdcmParser::OpenFile cannot open file", filename.c_str()); - } - return(NULL); -} - -/** - * \brief closes the file - * @return TRUE if the close was successfull - */ -bool gdcmParser::CloseFile(void) { - int closed = fclose(fp); - fp = (FILE *)0; - if (! closed) - return false; - return true; -} - -/** - * \brief Writes in a file all the Header Entries (Dicom Elements) - * of the Chained List - * @param fp file pointer on an already open file - * @param type Type of the File to be written - * (ACR-NEMA, ExplicitVR, ImplicitVR) - * \return Always true. - */ -bool gdcmParser::Write(FILE *fp, FileType type) { -/// \todo -/// ============== -/// The stuff will have to be rewritten using the SeQuence based -/// tree-like stucture instead of the chained list . -/// (so we shall remove the GroupHT from the gdcmParser) -/// To be checked -/// ============= - - /// \todo move the following lines (and a lot of others, to be written) - /// to a future function CheckAndCorrectHeader - - /// \todo - /// Question : - /// Comment pourrait-on savoir si le DcmHeader vient d'un fichier - /// DicomV3 ou non (FileType est un champ de gdcmParser ...) - /// WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA - /// no way - /// a moins de se livrer a un tres complique ajout des champs manquants. - /// faire un CheckAndCorrectHeader (?) - - if (type == gdcmImplicitVR) - { - std::string implicitVRTransfertSyntax = UI1_2_840_10008_1_2; - ReplaceOrCreateByNumber(implicitVRTransfertSyntax,0x0002, 0x0010); - - /// \todo Refer to standards on page 21, chapter 6.2 - /// "Value representation": values with a VR of UI shall be - /// padded with a single trailing null - /// Dans le cas suivant on doit pader manuellement avec un 0 - - SetEntryLengthByNumber(18, 0x0002, 0x0010); - } - - if (type == gdcmExplicitVR) - { - std::string explicitVRTransfertSyntax = UI1_2_840_10008_1_2_1; - ReplaceOrCreateByNumber(explicitVRTransfertSyntax,0x0002, 0x0010); - - /// \todo Refer to standards on page 21, chapter 6.2 - /// "Value representation": values with a VR of UI shall be - /// padded with a single trailing null - /// Dans le cas suivant on doit pader manuellement avec un 0 - - SetEntryLengthByNumber(20, 0x0002, 0x0010); - } - -/** - * \todo rewrite later, if really usefull - * - * --> Warning : un-updated odd groups lengths can causes pb - * --> (xmedcon breaks) - * --> to be re- written with future org. - * - * if ( (type == ImplicitVR) || (type == ExplicitVR) ) - * UpdateGroupLength(false,type); - * if ( type == ACR) - * UpdateGroupLength(true,ACR); - */ - - WriteEntries(fp,type); - return(true); -} - -/** - * \brief Modifies the value of a given Header Entry (Dicom Element) - * when it exists. Create it with the given value when unexistant. - * \warning Adds the Header Entry to the HTable, NOT to the chained List - * @param Value Value to be set - * @param Group Group of the Entry - * @param Elem Element of the Entry - * \return pointer to the modified/created Header Entry (NULL when creation - * failed). - */ -gdcmHeaderEntry * gdcmParser::ReplaceOrCreateByNumber( - std::string Value, - guint16 Group, - guint16 Elem ){ - gdcmHeaderEntry* a; - a = GetHeaderEntryByNumber( Group, Elem); - if (a == NULL) { - a =NewHeaderEntryByNumber(Group, Elem); - if (a == NULL) - return NULL; - AddHeaderEntry(a); - } - //CLEANME SetEntryByNumber(Value, Group, Elem); - a->SetValue(Value); - return(a); -} - -/** - * \brief Set a new value if the invoked element exists - * Seems to be useless !!! - * @param Value new element value - * @param Group group of the Entry - * @param Elem element of the Entry - * \return boolean - */ -bool gdcmParser::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) -{ - std::string v = Value; - SetEntryByNumber(v, Group, Elem); - return true; -} - -//----------------------------------------------------------------------------- -// Protected - -/** - * \brief Checks if a given Dicom Element exists - * within the H table - * @param group Group number of the searched Dicom Element - * @param element Element number of the searched Dicom Element - * @return number of occurences - */ -int gdcmParser::CheckIfEntryExistByNumber(guint16 group, guint16 element ) { - std::string key = gdcmDictEntry::TranslateToKey(group, element ); - return (tagHT.count(key)); -} - -/** - * \brief Searches within Header Entries (Dicom Elements) parsed with - * the public and private dictionaries - * for the element value of a given tag. - * \warning Don't use any longer : use GetPubEntryByName - * @param tagName name of the searched element. - * @return Corresponding element value when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. - */ -std::string gdcmParser::GetEntryByName(std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); - if( dictEntry == NULL) - return GDCM_UNFOUND; - - return(GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement())); -} - -/** - * \brief Searches within Header Entries (Dicom Elements) parsed with - * the public and private dictionaries - * for the element value representation of a given tag. - * - * Obtaining the VR (Value Representation) might be needed by caller - * to convert the string typed content to caller's native type - * (think of C++ vs Python). The VR is actually of a higher level - * of semantics than just the native C++ type. - * @param tagName name of the searched element. - * @return Corresponding element value representation when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. - */ -std::string gdcmParser::GetEntryVRByName(std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); - if( dictEntry == NULL) - return GDCM_UNFOUND; - - gdcmHeaderEntry* elem = GetHeaderEntryByNumber(dictEntry->GetGroup(), - dictEntry->GetElement()); - return elem->GetVR(); -} - - -/** - * \brief Searches within Header Entries (Dicom Elements) parsed with - * the public and private dictionaries - * for the element value representation of a given tag. - * @param group Group of the searched tag. - * @param element Element of the searched tag. - * @return Corresponding element value representation when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. - */ -std::string gdcmParser::GetEntryByNumber(guint16 group, guint16 element){ - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! tagHT.count(key)) - return GDCM_UNFOUND; - return tagHT.find(key)->second->GetValue(); -} - -/** - * \brief Searches within Header Entries (Dicom Elements) parsed with - * the public and private dictionaries - * for the element value representation of a given tag.. - * - * Obtaining the VR (Value Representation) might be needed by caller - * to convert the string typed content to caller's native type - * (think of C++ vs Python). The VR is actually of a higher level - * of semantics than just the native C++ type. - * @param group Group of the searched tag. - * @param element Element of the searched tag. - * @return Corresponding element value representation when it exists, - * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. - */ -std::string gdcmParser::GetEntryVRByNumber(guint16 group, guint16 element) { - gdcmHeaderEntry* elem = GetHeaderEntryByNumber(group, element); - if ( !elem ) - return GDCM_UNFOUND; - return elem->GetVR(); -} - -/** - * \brief Searches within Header Entries (Dicom Elements) parsed with - * the public and private dictionaries - * for the value length of a given tag.. - * @param group Group of the searched tag. - * @param element Element of the searched tag. - * @return Corresponding element length; -2 if not found - */ -int gdcmParser::GetEntryLengthByNumber(guint16 group, guint16 element) { - gdcmHeaderEntry* elem = GetHeaderEntryByNumber(group, element); - if ( !elem ) - return -2; - return elem->GetLength(); -} -/** - * \brief Sets the value (string) of the Header Entry (Dicom Element) - * @param content string value of the Dicom Element - * @param tagName name of the searched Dicom Element. - * @return true when found - */ -bool gdcmParser::SetEntryByName(std::string content,std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); - if( dictEntry == NULL) - return false; - - return(SetEntryByNumber(content,dictEntry->GetGroup(), - dictEntry->GetElement())); -} - -/** - * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element) - * through it's (group, element) and modifies it's content with - * the given value. - * \warning Don't use any longer : use SetPubEntryByNumber - * @param content new value to substitute with - * @param group group of the Dicom Element to modify - * @param element element of the Dicom Element to modify - */ -bool gdcmParser::SetEntryByNumber(std::string content, - guint16 group, - guint16 element) -{ - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! tagHT.count(key)) - return false; - int l = content.length(); - if(l%2) // Non even length are padded with a space (020H). - { - l++; - content = content + '\0'; - } - - gdcmHeaderEntry * a; - IterHT p; - TagHeaderEntryHT::iterator p2; - // DO NOT remove the following lines : they explain the stuff - //p= tagHT.equal_range(key); // get a pair of iterators first-last synonym - //p2=p.first; // iterator on the first synonym - //a=p2->second; // H Table target column (2-nd col) - - // or, easier : - a = ((tagHT.equal_range(key)).first)->second; - - a-> SetValue(content); - - std::string vr = a->GetVR(); - - guint32 lgr; - if( (vr == "US") || (vr == "SS") ) - lgr = 2; - else if( (vr == "UL") || (vr == "SL") ) - lgr = 4; - else - lgr = l; - - a->SetLength(lgr); - return true; -} - -/** - * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element) - * in the PubHeaderEntrySet of this instance - * through it's (group, element) and modifies it's length with - * the given value. - * \warning Use with extreme caution. - * @param l new length to substitute with - * @param group group of the Entry to modify - * @param element element of the Entry to modify - * @return true on success, false otherwise. - */ -bool gdcmParser::SetEntryLengthByNumber(guint32 l, - guint16 group, - guint16 element) -{ - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! tagHT.count(key)) - return false; - if (l%2) l++; // length must be even - ( ((tagHT.equal_range(key)).first)->second )->SetLength(l); - - return true ; -} - -/** - * \brief Gets (from Header) the offset of a 'non string' element value - * (LoadElementValues has already be executed) - * @param Group group of the Entry - * @param Elem element of the Entry - * @return File Offset of the Element Value - */ -size_t gdcmParser::GetEntryOffsetByNumber(guint16 Group, guint16 Elem) -{ - gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem); - if (!Entry) - { - dbg.Verbose(1, "gdcmParser::GetHeaderEntryByNumber", - "failed to Locate gdcmHeaderEntry"); - return (size_t)0; - } - return Entry->GetOffset(); -} - -/** - * \brief Gets (from Header) a 'non string' element value - * (LoadElementValues has already be executed) - * @param Group group of the Entry - * @param Elem element of the Entry - * @return Pointer to the 'non string' area - */ -void * gdcmParser::GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem) -{ - gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem); - if (!Entry) - { - dbg.Verbose(1, "gdcmParser::GetHeaderEntryByNumber", - "failed to Locate gdcmHeaderEntry"); - return (NULL); - } - return Entry->GetVoidArea(); -} - -/** - * \brief Loads (from disk) the element content - * when a string is not suitable - * @param Group group of the Entry - * @param Elem element of the Entry - */ -void *gdcmParser::LoadEntryVoidArea(guint16 Group, guint16 Elem) -{ - gdcmHeaderEntry * Element= GetHeaderEntryByNumber(Group, Elem); - if ( !Element ) - return NULL; - size_t o =(size_t)Element->GetOffset(); - fseek(fp, o, SEEK_SET); - size_t l=Element->GetLength(); - char* a = new char[l]; - if(!a) - return NULL; - - SetEntryVoidAreaByNumber(a, Group, Elem); - /// \todo check the result - size_t l2 = fread(a, 1, l ,fp); - if(l != l2) - { - delete[] a; - return NULL; - } - - return a; -} - -/** - * \brief Sets a 'non string' value to a given Dicom Element - * @param area - * @param group Group number of the searched Dicom Element - * @param element Element number of the searched Dicom Element - * @return - */ -bool gdcmParser::SetEntryVoidAreaByNumber(void * area, - guint16 group, - guint16 element) -{ - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! tagHT.count(key)) - return false; - ( ((tagHT.equal_range(key)).first)->second )->SetVoidArea(area); - return true; -} - -/** - * \brief Update the entries with the shadow dictionary. - * Only non even entries are analyzed - */ -void gdcmParser::UpdateShaEntries(void) { - gdcmDictEntry *entry; - std::string vr; - - for(ListTag::iterator it=listEntries.begin(); - it!=listEntries.end(); - ++it) - { - // Odd group => from public dictionary - if((*it)->GetGroup()%2==0) - continue; - - // Peer group => search the corresponding dict entry - if(RefShaDict) - entry=RefShaDict->GetDictEntryByNumber((*it)->GetGroup(),(*it)->GetElement()); - else - entry=NULL; - - if((*it)->IsImplicitVR()) - vr="Implicit"; - else - vr=(*it)->GetVR(); - - (*it)->SetValue(GetHeaderEntryUnvalue(*it)); - if(entry){ - // Set the new entry and the new value - (*it)->SetDictEntry(entry); - CheckHeaderEntryVR(*it,vr); - - (*it)->SetValue(GetHeaderEntryValue(*it)); - } - else - { - // Remove precedent value transformation - (*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr)); - } - } -} - -/** - * \brief Searches within the Header Entries for a Dicom Element of - * a given tag. - * @param tagName name of the searched Dicom Element. - * @return Corresponding Dicom Element when it exists, and NULL - * otherwise. - */ - gdcmHeaderEntry *gdcmParser::GetHeaderEntryByName(std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); - if( dictEntry == NULL) - return NULL; - - return(GetHeaderEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement())); -} - -/** - * \brief retrieves a Dicom Element (the first one) using (group, element) - * \warning (group, element) IS NOT an identifier inside the Dicom Header - * if you think it's NOT UNIQUE, check the count number - * and use iterators to retrieve ALL the Dicoms Elements within - * a given couple (group, element) - * @param group Group number of the searched Dicom Element - * @param element Element number of the searched Dicom Element - * @return - */ -gdcmHeaderEntry* gdcmParser::GetHeaderEntryByNumber(guint16 group, guint16 element) -{ - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - if ( ! tagHT.count(key)) - return NULL; - return tagHT.find(key)->second; -} - -/** - * \brief retrieves the Dicom Elements (all of them) using (group, element) - * @param group Group number of the searched Dicom Element. - * @param element Element number of the searched Dicom Element. - * @return a range (i.e.pair<,>) containing all elements whose key is group|element) - */ - -IterHT gdcmParser::GetHeaderEntrySameNumber(guint16 group, guint16 element){ - TagKey key = gdcmDictEntry::TranslateToKey(group, element); - return (tagHT.equal_range(key)); -} - -/** - * \brief Loads the element while preserving the current - * underlying file position indicator as opposed to - * to LoadHeaderEntry that modifies it. - * @param entry Header Entry whose value shall be loaded. - * @return - */ -void gdcmParser::LoadHeaderEntrySafe(gdcmHeaderEntry * entry) { - long PositionOnEntry = ftell(fp); - LoadHeaderEntry(entry); - fseek(fp, PositionOnEntry, SEEK_SET); -} - -/** - * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader - * \warning : to be re-written using the chained list instead of the H table. - * \warning : DO NOT use (doesn't work any longer because of the multimap) - * \todo : to be re-written using the chained list instead of the H table - * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files) - * @param type Type of the File (ExplicitVR,ImplicitVR, ACR, ...) - */ -void gdcmParser::UpdateGroupLength(bool SkipSequence, FileType type) { - guint16 gr, el; - std::string vr; - - gdcmHeaderEntry *elem; - char trash[10]; - std::string str_trash; - - GroupKey key; - GroupHT groupHt; // to hold the length of each group - TagKey tk; - // remember : - // typedef std::map GroupHT; - - gdcmHeaderEntry *elemZ; - - // for each Tag in the DCM Header - - for (TagHeaderEntryHT::iterator tag2 = tagHT.begin(); - tag2 != tagHT.end(); - ++tag2) - { - elem = tag2->second; - gr = elem->GetGroup(); - el = elem->GetElement(); - vr = elem->GetVR(); - - sprintf(trash, "%04x", gr); - key = trash; // generate 'group tag' - - // if the caller decided not to take SEQUENCEs into account - // e.g : he wants to write an ACR-NEMA File - - if (SkipSequence && vr == "SQ") - continue; - - // Still unsolved problem : - // we cannot find the 'Sequence Delimitation Item' - // since it's at the end of the Hash Table - // (fffe,e0dd) - - // there is SEQUENCE in ACR-NEMA - // WARNING : - // --> la descente a l'interieur' des SQ - // devrait etre faite avec une liste chainee, pas avec une HTable... - - if ( groupHt.count(key) == 0) // we just read the first elem of a given group - { - if (el == 0x0000) // the first elem is 0x0000 - { - groupHt[key] = 0; // initialize group length - } - else - { - groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem - } - } - else // any elem but the first - { - if (type == gdcmExplicitVR) - { - if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) - { - groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes - } - } - groupHt[key] += 2 + 2 + 4 + elem->GetLength(); - } - } - - unsigned short int gr_bid; - - for (GroupHT::iterator g = groupHt.begin(); // for each group we found - g != groupHt.end(); - ++g) - { - // FIXME: g++ -Wall -Wstrict-prototypes reports on following line: - // warning: unsigned int format, different type arg - sscanf(g->first.c_str(),"%x",&gr_bid); //FIXME - tk = g->first + "|0000"; // generate the element full tag - - if ( tagHT.count(tk) == 0) // if element 0x0000 not found - { - gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL"); - elemZ = new gdcmHeaderEntry(tagZ); - elemZ->SetLength(4); - AddHeaderEntry(elemZ); // create it - } - else - { - elemZ=GetHeaderEntryByNumber(gr_bid, 0x0000); - } - sprintf(trash ,"%d",g->second); - str_trash=trash; - elemZ->SetValue(str_trash); - } -} - -/** - * \brief Writes in a file (according to the requested format) - * the group, the element, the value representation and the length - * of a single gdcmHeaderEntry passed as argument. - * @param tag pointer on the gdcmHeaderEntry to be written - * @param _fp already open file pointer - * @param type type of the File to be written - */ -void gdcmParser::WriteEntryTagVRLength(gdcmHeaderEntry *tag, - FILE *_fp, - FileType type) -{ - guint16 group = tag->GetGroup(); - std::string vr = tag->GetVR(); - guint16 el = tag->GetElement(); - guint32 lgr = tag->GetReadLength(); - - if ( (group == 0xfffe) && (el == 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; - - fwrite ( &group,(size_t)2 ,(size_t)1 ,_fp); //group - fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element - - if ( type == gdcmExplicitVR ) { - - // Special case of delimiters: - if (group == 0xfffe) { - // Delimiters have NO Value Representation and have NO length. - // Hence we skip writing the VR and length and we pad by writing - // 0xffffffff - - int ff=0xffffffff; - fwrite (&ff,(size_t)4 ,(size_t)1 ,_fp); - return; - } - - guint16 z=0; - guint16 shortLgr = lgr; - if (vr == "unkn") { // Unfound was 'written' - // deal with Little Endian - fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp); - fwrite ( &z, (size_t)2 ,(size_t)1 ,_fp); - } else { - fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp); - 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); - } else { - fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp); - } - } - } - else // IMPLICIT VR - { - fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp); - } -} - -/** - * \brief Writes in a file (according to the requested format) - * the value of a single gdcmHeaderEntry passed as argument. - * @param tag Pointer on the gdcmHeaderEntry to be written - * @param _fp Already open file pointer - * @param type type of the File to be written - */ -void gdcmParser::WriteEntryValue(gdcmHeaderEntry *tag, FILE *_fp,FileType type) -{ - (void)type; - guint16 group = tag->GetGroup(); - std::string vr = tag->GetVR(); - guint32 lgr = tag->GetReadLength(); - - if (vr == "SQ") - // SeQuences have no value: - return; - if (group == 0xfffe) - // Delimiters have no associated value: - return; - - void *voidArea; - voidArea = tag->GetVoidArea(); - if (voidArea != NULL) - { // there is a 'non string' LUT, overlay, etc - fwrite ( voidArea,(size_t)lgr ,(size_t)1 ,_fp); // Elem value - return; - } - - if (vr == "US" || vr == "SS") - { - // some 'Short integer' fields may be mulivaluated - // each single value is separated from the next one by '\' - // we split the string and write each value as a short int - std::vector tokens; - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (tag->GetValue(), tokens, "\\"); - for (unsigned int i=0; i tokens; - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (tag->GetValue(), tokens, "\\"); - for (unsigned int i=0; iGetValue().c_str(), (size_t)lgr ,(size_t)1, _fp); // Elem value -} - -/** - * \brief Writes in a file (according to the requested format) - * a single gdcmHeaderEntry passed as argument. - * \sa WriteEntryValue, WriteEntryTagVRLength. - * @param tag Pointer on the gdcmHeaderEntry to be written - * @param _fp Already open file pointer - * @param type type of the File to be written - */ - -bool gdcmParser::WriteEntry(gdcmHeaderEntry *tag, FILE *_fp,FileType type) -{ - guint32 length = tag->GetLength(); - - // The value of a tag MUST (see the DICOM norm) be an odd number of - // bytes. When this is not the case, pad with an additional byte: - if(length%2==1) - { - tag->SetValue(tag->GetValue()+"\0"); - tag->SetLength(tag->GetReadLength()+1); - } - - WriteEntryTagVRLength(tag, _fp, type); - WriteEntryValue(tag, _fp, type); - return true; -} - -/** - * \brief writes on disc according to the requested format - * (ACR-NEMA, ExplicitVR, ImplicitVR) the image - * using the Chained List - * \warning does NOT add the missing elements in the header : - * it's up to the user doing it ! - * (function CheckHeaderCoherence to be written) - * \warning DON'T try, right now, to write a DICOM image - * from an ACR Header (meta elements will be missing!) - * \sa WriteEntriesDeprecated (Special temporary method for Theralys) - * @param type type of the File to be written - * (ACR-NEMA, ExplicitVR, ImplicitVR) - * @param _fp already open file pointer - */ - -bool gdcmParser::WriteEntries(FILE *_fp,FileType type) -{ - /// \todo (?) check write failures (after *each* fwrite) - - for (ListTag::iterator tag2=listEntries.begin(); - tag2 != listEntries.end(); - ++tag2) - { - if ( type == gdcmACR ){ - if ((*tag2)->GetGroup() < 0x0008) - // Ignore pure DICOM V3 groups - continue; - if ((*tag2)->GetElement() %2) - // Ignore the "shadow" groups - continue; - if ((*tag2)->GetVR() == "SQ" ) // ignore Sequences - continue; - if ((*tag2)->GetSQDepthLevel() != 0) // Not only ignore the SQ element - continue; - } - if (! WriteEntry(*tag2,_fp,type) ) - return false; - } - return true; -} - -/** - * \brief writes on disc according to the requested format - * (ACR-NEMA, ExplicitVR, ImplicitVR) the image, - * using only the last synonym of each mutimap H Table post. - * \warning Uses the H Table, instead of the Chained List - * in order to be compliant with the old way to proceed - * (added elements taken in to account) - * Only THERALYS, during a transitory phase is supposed - * to use this method !!! - * \warning DON'T try, right now, to write a DICOM image - * from an ACR Header (meta elements will be missing!) - * \sa WriteEntries - * @param _fp already open file pointer - * @param type type of the File to be written - * (ACR-NEMA, ExplicitVR, ImplicitVR) - */ -void gdcmParser::WriteEntriesDeprecated(FILE *_fp,FileType type) { - - // restent a tester les echecs en ecriture (apres chaque fwrite) - - for (TagHeaderEntryHT::iterator tag2=tagHT.begin(); - tag2 != tagHT.end(); - ++tag2){ - if ( type == gdcmACR ){ - if ((*tag2->second).GetGroup() < 0x0008) continue; // ignore pure DICOM V3 groups - if ((*tag2->second).GetElement() %2) continue; // ignore shadow groups - if ((*tag2->second).GetVR() == "SQ" ) continue; // ignore Sequences - if ((*tag2->second).GetSQDepthLevel() != 0) continue; // Not only ignore the SQ element - } - if ( ! WriteEntry(tag2->second,_fp,type)) - break; - } -} - -/** - * \brief Swaps back the bytes of 4-byte long integer accordingly to - * processor order. - * @return The properly swaped 32 bits integer. - */ -guint32 gdcmParser::SwapLong(guint32 a) { - switch (sw) { - case 0 : - 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 : - dbg.Error(" gdcmParser::SwapLong : unset swap code"); - a=0; - } - return(a); -} - -/** - * \brief Unswaps back the bytes of 4-byte long integer accordingly to - * processor order. - * @return The properly unswaped 32 bits integer. - */ -guint32 gdcmParser::UnswapLong(guint32 a) { - return (SwapLong(a)); -} - -/** - * \brief Swaps the bytes so they agree with the processor order - * @return The properly swaped 16 bits integer. - */ -guint16 gdcmParser::SwapShort(guint16 a) { - if ( (sw==4321) || (sw==2143) ) - a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff)); - return (a); -} - -/** - * \brief Unswaps the bytes so they agree with the processor order - * @return The properly unswaped 16 bits integer. - */ -guint16 gdcmParser::UnswapShort(guint16 a) { - return (SwapShort(a)); -} - -//----------------------------------------------------------------------------- -// Private -/** - * \brief Parses the header of the file and load element values. - * @return false if file is not ACR-NEMA / PAPYRUS / DICOM - */ -bool gdcmParser::LoadHeaderEntries(bool exception_on_error) throw(gdcmFormatError) { - (void)exception_on_error; - rewind(fp); - if (!CheckSwap()) - return false; - - gdcmHeaderEntry *newHeaderEntry = (gdcmHeaderEntry *)0; - while ( (newHeaderEntry = ReadNextHeaderEntry()) ) { - SkipHeaderEntry(newHeaderEntry); - if ( (ignoreShadow==0) || (newHeaderEntry->GetGroup()%2) == 0) { - AddHeaderEntry(newHeaderEntry); - } - } - rewind(fp); - // Be carefull : merging this two loops may cause troubles ... - for (ListTag::iterator i = GetListEntry().begin(); - i != GetListEntry().end(); - ++i) - { - LoadHeaderEntry(*i); - } - rewind(fp); - - // Load 'non string' values - - std::string PhotometricInterpretation = GetEntryByNumber(0x0028,0x0004); - if( PhotometricInterpretation == "PALETTE COLOR " ) { - LoadEntryVoidArea(0x0028,0x1200); // gray LUT - LoadEntryVoidArea(0x0028,0x1201); // R LUT - LoadEntryVoidArea(0x0028,0x1202); // G LUT - LoadEntryVoidArea(0x0028,0x1203); // B LUT - - LoadEntryVoidArea(0x0028,0x1221); // Segmented Red Palette Color LUT Data - LoadEntryVoidArea(0x0028,0x1222); // Segmented Green Palette Color LUT Data - LoadEntryVoidArea(0x0028,0x1223); // Segmented Blue Palette Color LUT Data - } - //FIXME later : how to use it? - LoadEntryVoidArea(0x0028,0x3006); //LUT Data (CTX dependent) - - // -------------------------------------------------------------- - // Special Patch to allow gdcm to read ACR-LibIDO formated images - // - // if recognition code tells us we deal with a LibIDO image - // we switch lineNumber and columnNumber - // - std::string RecCode; - RecCode = GetEntryByNumber(0x0008, 0x0010); // recognition code - if (RecCode == "ACRNEMA_LIBIDO_1.1" || - RecCode == "CANRME_AILIBOD1_1." ) // for brain-damaged softwares - // with "little-endian strings" - { - filetype = gdcmACR_LIBIDO; - std::string rows = GetEntryByNumber(0x0028, 0x0010); - std::string columns = GetEntryByNumber(0x0028, 0x0011); - SetEntryByNumber(columns, 0x0028, 0x0010); - SetEntryByNumber(rows , 0x0028, 0x0011); - } - // ----------------- End of Special Patch ---------------- - return true; -} - -/** - * \brief Loads the element content if its length doesn't exceed - * the value specified with gdcmParser::SetMaxSizeLoadEntry() - * @param Entry Header Entry (Dicom Element) to be dealt with - */ -void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry) { - size_t item_read; - guint16 group = Entry->GetGroup(); - std::string vr= Entry->GetVR(); - guint32 length = Entry->GetLength(); - - fseek(fp, (long)Entry->GetOffset(), SEEK_SET); - - // A SeQuence "contains" a set of Elements. - // (fffe e000) tells us an Element is beginning - // (fffe e00d) tells us an Element just ended - // (fffe e0dd) tells us the current SeQuence just ended - if( group == 0xfffe ) { - Entry->SetValue("gdcm::Skipped"); - return; - } - - // When the length is zero things are easy: - if ( length == 0 ) { - Entry->SetValue(""); - return; - } - - // 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. - if (length > MaxSizeLoadEntry) { - std::ostringstream s; - s << "gdcm::NotLoaded."; - s << " Address:" << (long)Entry->GetOffset(); - s << " Length:" << Entry->GetLength(); - s << " x(" << std::hex << Entry->GetLength() << ")"; - Entry->SetValue(s.str()); - return; - } - - // Any compacter code suggested (?) - if ( IsHeaderEntryAnInteger(Entry) ) { - guint32 NewInt; - std::ostringstream s; - int nbInt; - // When short integer(s) are expected, read and convert the following - // n *two characters properly i.e. as short integers as opposed to strings. - // Elements with Value Multiplicity > 1 - // contain a set of integers (not a single one) - if (vr == "US" || vr == "SS") { - nbInt = length / 2; - NewInt = ReadInt16(); - s << NewInt; - if (nbInt > 1){ - for (int i=1; i < nbInt; i++) { - s << '\\'; - NewInt = ReadInt16(); - s << NewInt; - } - } - } - // When integer(s) are expected, read and convert the following - // n * four characters properly i.e. as integers as opposed to strings. - // Elements with Value Multiplicity > 1 - // contain a set of integers (not a single one) - else if (vr == "UL" || vr == "SL") { - nbInt = length / 4; - NewInt = ReadInt32(); - s << NewInt; - if (nbInt > 1) { - for (int i=1; i < nbInt; i++) { - s << '\\'; - NewInt = ReadInt32(); - s << NewInt; - } - } - } -#ifdef GDCM_NO_ANSI_STRING_STREAM - s << std::ends; // to avoid oddities on Solaris -#endif //GDCM_NO_ANSI_STRING_STREAM - - Entry->SetValue(s.str()); - 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); - if ( item_read != 1 ) { - dbg.Verbose(1, "gdcmParser::LoadElementValue","unread element value"); - Entry->SetValue("gdcm::UnRead"); - return; - } - - if( (vr == "UI") ) // Because of correspondance with the VR dic - Entry->SetValue(NewValue.c_str()); - else - Entry->SetValue(NewValue); -} - -/** - * \brief add a new Dicom Element pointer to - * the H Table and at the end of the chained List - * \warning push_bash in listEntries ONLY during ParseHeader - * \todo something to allow further Elements addition, - * (at their right place in the chained list) - * when position to be taken care of - * @param newHeaderEntry - */ -void gdcmParser::AddHeaderEntry(gdcmHeaderEntry *newHeaderEntry) { - tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) ); - listEntries.push_back(newHeaderEntry); - wasUpdated = 1; -} - -/** - * \brief Find the value Length of the passed Header Entry - * @param Entry Header Entry whose length of the value shall be loaded. - */ - void gdcmParser::FindHeaderEntryLength (gdcmHeaderEntry *Entry) { - guint16 element = Entry->GetElement(); - //guint16 group = Entry->GetGroup(); //FIXME - std::string vr = Entry->GetVR(); - guint16 length16; - - - if ( (filetype == gdcmExplicitVR) && (! Entry->IsImplicitVR()) ) - { - if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) - { - // The following reserved two bytes (see PS 3.5-2001, section - // 7.1.2 Data element structure with explicit vr p27) must be - // skipped before proceeding on reading the length on 4 bytes. - fseek(fp, 2L, SEEK_CUR); - guint32 length32 = ReadInt32(); - - if ( (vr == "OB") && (length32 == 0xffffffff) ) - { - Entry->SetLength(FindHeaderEntryLengthOB()); - return; - } - FixHeaderEntryFoundLength(Entry, length32); - return; - } - - // Length is encoded on 2 bytes. - length16 = ReadInt16(); - - // We can tell the current file is encoded in big endian (like - // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag - // and it's value is the one of the encoding of a big endian file. - // In order to deal with such big endian encoded files, we have - // (at least) two strategies: - // * when we load the "Transfer Syntax" tag with value of big endian - // encoding, we raise the proper flags. Then we wait for the end - // of the META group (0x0002) among which is "Transfer Syntax", - // before switching the swap code to big endian. We have to postpone - // the switching of the swap code since the META group is fully encoded - // in little endian, and big endian coding only starts at the next - // group. The corresponding code can be hard to analyse and adds - // many additional unnecessary tests for regular tags. - // * the second strategy consists in waiting for trouble, that shall - // appear when we find the first group with big endian encoding. This - // is easy to detect since the length of a "Group Length" tag (the - // ones with zero as element number) has to be of 4 (0x0004). When we - // encounter 1024 (0x0400) chances are the encoding changed and we - // found a group with big endian encoding. - // We shall use this second strategy. In order to make sure that we - // can interpret the presence of an apparently big endian encoded - // length of a "Group Length" without committing a big mistake, we - // add an additional check: we look in the already parsed elements - // for the presence of a "Transfer Syntax" whose value has to be "big - // endian encoding". When this is the case, chances are we have got our - // hands on a big endian encoded file: we switch the swap code to - // big endian and proceed... - if ( (element == 0x0000) && (length16 == 0x0400) ) - { - if ( ! IsExplicitVRBigEndianTransferSyntax() ) - { - dbg.Verbose(0, "gdcmParser::FindLength", "not explicit VR"); - errno = 1; - return; - } - length16 = 4; - SwitchSwapToBigEndian(); - // Restore the unproperly loaded values i.e. the group, the element - // and the dictionary entry depending on them. - guint16 CorrectGroup = SwapShort(Entry->GetGroup()); - guint16 CorrectElem = SwapShort(Entry->GetElement()); - gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup, - CorrectElem); - if (!NewTag) - { - // This correct tag is not in the dictionary. Create a new one. - NewTag = NewVirtualDictEntry(CorrectGroup, CorrectElem); - } - // FIXME this can create a memory leaks on the old entry that be - // left unreferenced. - Entry->SetDictEntry(NewTag); - } - - // Heuristic: well some files are really ill-formed. - if ( length16 == 0xffff) - { - length16 = 0; - //dbg.Verbose(0, "gdcmParser::FindLength", - // "Erroneous element length fixed."); - // Actually, length= 0xffff means that we deal with - // Unfound Sequence Length - } - FixHeaderEntryFoundLength(Entry, (guint32)length16); - return; - } - else - { - // Either implicit VR or a non DICOM conformal (see note below) explicit - // VR that ommited the VR of (at least) this element. Farts happen. - // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25 - // on Data elements "Implicit and Explicit VR Data Elements shall - // not coexist in a Data Set and Data Sets nested within it".] - // Length is on 4 bytes. - - FixHeaderEntryFoundLength(Entry, ReadInt32()); - return; - } -} - -/** - * \brief Find the Value Representation of the current Dicom Element. - * @param Entry - */ -void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *Entry) -{ - if (filetype != gdcmExplicitVR) - return; - - char VR[3]; - - long PositionOnEntry = ftell(fp); - // 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 - // cases (see e-film filtered files) one finds implicit VR tags mixed - // within an explicit VR file. Hence we make sure the present tag - // is in explicit VR and try to fix things if it happens not to be - // the case. - - (void)fread (&VR, (size_t)2,(size_t)1, fp); - VR[2]=0; - if(!CheckHeaderEntryVR(Entry,VR)) - { - fseek(fp, PositionOnEntry, SEEK_SET); - // 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 - // we know now our assumption on expliciteness is not furfilled. - // avoid . - if ( Entry->IsVRUnknown() ) - Entry->SetVR("Implicit"); - Entry->SetImplicitVR(); - } -} - -/** - * \brief Check the correspondance between the VR of the header entry - * and the taken VR. If they are different, the header entry is - * updated with the new VR. - * @param Entry Header Entry to check - * @param vr Dicom Value Representation - * @return false if the VR is incorrect of if the VR isn't referenced - * otherwise, it returns true -*/ -bool gdcmParser::CheckHeaderEntryVR(gdcmHeaderEntry *Entry, VRKey vr) -{ - char msg[100]; // for sprintf - bool RealExplicit = true; - - // Assume we are reading a falsely explicit VR file i.e. we reached - // a tag where we expect reading a VR but are in fact we read the - // first to bytes of the length. Then we will interogate (through find) - // the dicom_vr dictionary with oddities like "\004\0" which crashes - // both GCC and VC++ implementations of the STL map. Hence when the - // expected VR read happens to be non-ascii characters we consider - // we hit falsely explicit VR tag. - - if ( (!isalpha(vr[0])) && (!isalpha(vr[1])) ) - RealExplicit = false; - - // 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 ( RealExplicit && !gdcmGlobal::GetVR()->Count(vr) ) - RealExplicit= false; - - if ( !RealExplicit ) - { - // We thought this was explicit VR, but we end up with an - // implicit VR tag. Let's backtrack. - sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", - Entry->GetGroup(),Entry->GetElement()); - dbg.Verbose(1, "gdcmParser::FindVR: ",msg); - if (Entry->GetGroup()%2 && Entry->GetElement() == 0x0000) { // Group length is UL ! - gdcmDictEntry* NewEntry = NewVirtualDictEntry( - Entry->GetGroup(),Entry->GetElement(), - "UL","FIXME","Group Length"); - Entry->SetDictEntry(NewEntry); - } - return(false); - } - - if ( Entry->IsVRUnknown() ) - { - // When not a dictionary entry, we can safely overwrite the VR. - if (Entry->GetElement() == 0x0000) { // Group length is UL ! - Entry->SetVR("UL"); - } else { - Entry->SetVR(vr); - } - } - else if ( Entry->GetVR() != vr ) - { - // The VR present in the file and the dictionary disagree. We assume - // the file writer knew best and use the VR of the file. Since it would - // be unwise to overwrite the VR of a dictionary (since it would - // compromise it's next user), we need to clone the actual DictEntry - // and change the VR for the read one. - gdcmDictEntry* NewEntry = NewVirtualDictEntry( - Entry->GetGroup(),Entry->GetElement(), - vr,"FIXME",Entry->GetName()); - Entry->SetDictEntry(NewEntry); - } - return(true); -} - -/** - * \brief Get the transformed value of the header entry. The VR value - * is used to define the transformation to operate on the value - * \warning NOT end user intended method ! - * @param Entry - * @return Transformed entry value - */ -std::string gdcmParser::GetHeaderEntryValue(gdcmHeaderEntry *Entry) -{ - if ( (IsHeaderEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) ) - { - std::string val=Entry->GetValue(); - std::string vr=Entry->GetVR(); - guint32 length = Entry->GetLength(); - std::ostringstream s; - int nbInt; - - // When short integer(s) are expected, read and convert the following - // n * 2 bytes properly i.e. as a multivaluated strings - // (each single value is separated fromthe next one by '\' - // as usual for standard multivaluated filels - // Elements with Value Multiplicity > 1 - // contain a set of short integers (not a single one) - - if (vr == "US" || vr == "SS") - { - guint16 NewInt16; - - nbInt = length / 2; - for (int i=0; i < nbInt; i++) - { - if(i!=0) - s << '\\'; - NewInt16 = (val[2*i+0]&0xFF)+((val[2*i+1]&0xFF)<<8); - NewInt16 = SwapShort(NewInt16); - s << NewInt16; - } - } - - // When integer(s) are expected, read and convert the following - // n * 4 bytes properly i.e. as a multivaluated strings - // (each single value is separated fromthe next one by '\' - // as usual for standard multivaluated filels - // Elements with Value Multiplicity > 1 - // contain a set of integers (not a single one) - else if (vr == "UL" || vr == "SL") - { - guint32 NewInt32; - - nbInt = length / 4; - for (int i=0; i < nbInt; i++) - { - if(i!=0) - s << '\\'; - NewInt32= (val[4*i+0]&0xFF)+((val[4*i+1]&0xFF)<<8)+ - ((val[4*i+2]&0xFF)<<16)+((val[4*i+3]&0xFF)<<24); - NewInt32=SwapLong(NewInt32); - s << NewInt32; - } - } -#ifdef GDCM_NO_ANSI_STRING_STREAM - s << std::ends; // to avoid oddities on Solaris -#endif //GDCM_NO_ANSI_STRING_STREAM - return(s.str()); - } - - return(Entry->GetValue()); -} - -/** - * \brief Get the reverse transformed value of the header entry. The VR - * value is used to define the reverse transformation to operate on - * the value - * \warning NOT end user intended method ! - * @param Entry - * @return Reverse transformed entry value - */ -std::string gdcmParser::GetHeaderEntryUnvalue(gdcmHeaderEntry *Entry) -{ - if ( (IsHeaderEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) ) - { - std::string vr=Entry->GetVR(); - std::ostringstream s; - std::vector tokens; - - if (vr == "US" || vr == "SS") - { - guint16 NewInt16; - - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (Entry->GetValue(), tokens, "\\"); - for (unsigned int i=0; i>8)&0xFF); - } - tokens.clear(); - } - if (vr == "UL" || vr == "SL") - { - guint32 NewInt32; - - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (Entry->GetValue(), tokens, "\\"); - for (unsigned int i=0; i>8)&0xFF) - <<(char)((NewInt32>>16)&0xFF)<<(char)((NewInt32>>24)&0xFF); - } - tokens.clear(); - } - -#ifdef GDCM_NO_ANSI_STRING_STREAM - s << std::ends; // to avoid oddities on Solaris -#endif //GDCM_NO_ANSI_STRING_STREAM - return(s.str()); - } - - return(Entry->GetValue()); -} - -/** - * \brief Skip a given Header Entry - * \warning NOT end user intended method ! - * @param entry - */ -void gdcmParser::SkipHeaderEntry(gdcmHeaderEntry *entry) -{ - SkipBytes(entry->GetLength()); -} - -/** - * \brief When the length of an element value is obviously wrong (because - * the parser went Jabberwocky) one can hope improving things by - * applying this heuristic. - */ -void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry *Entry, guint32 FoundLength) -{ - Entry->SetReadLength(FoundLength); // will be updated only if a bug is found - if ( FoundLength == 0xffffffff) { - FoundLength = 0; - } - - guint16 gr =Entry->GetGroup(); - guint16 el =Entry->GetElement(); - - if (FoundLength%2) { - std::ostringstream s; - s << "Warning : Tag with uneven length " << FoundLength - << " in x(" << std::hex << gr << "," << el <<")" << std::dec; - dbg.Verbose(0,s.str().c_str()); - } - - // Sorry for the patch! - // XMedCom did the trick to read some naughty GE images ... - if (FoundLength == 13) { - // The following 'if' will be removed when there is no more - // images on Creatis HDs with a 13 length for Manufacturer... - if ( (Entry->GetGroup() != 0x0008) || - ( (Entry->GetElement() != 0x0070) && (Entry->GetElement() != 0x0080) ) ){ - // end of remove area - FoundLength =10; - Entry->SetReadLength(10); // a bug is to be fixed - } - } - - // to fix some garbage 'Leonardo' Siemens images - // May be commented out to avoid overhead - else if ( (Entry->GetGroup() == 0x0009) && - ( (Entry->GetElement() == 0x1113) || (Entry->GetElement() == 0x1114) ) ){ - FoundLength =4; - Entry->SetReadLength(4); // a bug is to be fixed - } - // end of fix - - // to try to 'go inside' SeQuences (with length), and not to skip them - else if ( Entry->GetVR() == "SQ") - { - if (enableSequences) // only if the user does want to ! - FoundLength =0; // ReadLength is unchanged - } - - // we found a 'delimiter' element - // fffe|xxxx is just a marker, we don't take its length into account - else if(Entry->GetGroup() == 0xfffe) - { - // *normally, fffe|0000 doesn't exist ! - if( Entry->GetElement() != 0x0000 ) // gdcm-MR-PHILIPS-16-Multi-Seq.dcm - // causes extra troubles :-( - FoundLength =0; - } - - Entry->SetUsableLength(FoundLength); -} - -/** - * \brief Apply some heuristics to predict whether the considered - * element value contains/represents an integer or not. - * @param Entry The element value on which to apply the predicate. - * @return The result of the heuristical predicate. - */ -bool gdcmParser::IsHeaderEntryAnInteger(gdcmHeaderEntry *Entry) { - guint16 element = Entry->GetElement(); - guint16 group = Entry->GetGroup(); - std::string vr = Entry->GetVR(); - guint32 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 - // able to swap it's element value properly. - if ( element == 0 ) // This is the group length of the group - { - if (length == 4) - return true; - else - { - std::ostringstream s; - int filePosition = ftell(fp); - s << "Erroneous Group Length element length on : (" \ - << std::hex << group << " , " << element - << ") -before- position x(" << filePosition << ")" - << "lgt : " << length; - // These 2 lines commented out : a *very dirty* patch - // to go on PrintHeader'ing gdcm-MR-PHILIPS-16-Multi-Seq.dcm. - // have a glance at offset x(8336) ... - // For *regular* headers, the test is useless.. - // lets's print a warning message and go on, - // instead of giving up with an error message - - //std::cout << s.str().c_str() << std::endl; - // dbg.Error("gdcmParser::IsHeaderEntryAnInteger", - // s.str().c_str()); - } - } - 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 - */ - - guint32 gdcmParser::FindHeaderEntryLengthOB(void) { - // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. - guint16 g; - guint16 n; - long PositionOnEntry = ftell(fp); - bool FoundSequenceDelimiter = false; - guint32 TotalLength = 0; - guint32 ItemLength; - - while ( ! FoundSequenceDelimiter) - { - g = ReadInt16(); - n = ReadInt16(); - if (errno == 1) - return 0; - TotalLength += 4; // We even have to decount the group and element - - if ( g != 0xfffe && g!=0xb00c ) //for bogus header - { - char msg[100]; // for sprintf. Sorry - sprintf(msg,"wrong group (%04x) for an item sequence (%04x,%04x)\n",g, g,n); - dbg.Verbose(1, "gdcmParser::FindLengthOB: ",msg); - errno = 1; - return 0; - } - if ( n == 0xe0dd || ( g==0xb00c && n==0x0eb6 ) ) // for bogus header - FoundSequenceDelimiter = true; - else if ( n != 0xe000 ) - { - char msg[100]; // for sprintf. Sorry - sprintf(msg,"wrong element (%04x) for an item sequence (%04x,%04x)\n", - n, g,n); - dbg.Verbose(1, "gdcmParser::FindLengthOB: ",msg); - errno = 1; - return 0; - } - ItemLength = ReadInt32(); - TotalLength += ItemLength + 4; // We add 4 bytes since we just read - // the ItemLength with ReadInt32 - SkipBytes(ItemLength); - } - fseek(fp, PositionOnEntry, SEEK_SET); - return TotalLength; -} - -/** - * \brief Reads a supposed to be 16 Bits integer - * (swaps it depending on processor endianity) - * @return read value - */ -guint16 gdcmParser::ReadInt16(void) { - guint16 g; - size_t item_read; - item_read = fread (&g, (size_t)2,(size_t)1, fp); - if ( item_read != 1 ) { - if(ferror(fp)) - dbg.Verbose(0, "gdcmParser::ReadInt16", " File Error"); - errno = 1; - return 0; - } - errno = 0; - g = SwapShort(g); - return g; -} - -/** - * \brief Reads a supposed to be 32 Bits integer - * (swaps it depending on processor endianity) - * @return read value - */ -guint32 gdcmParser::ReadInt32(void) { - guint32 g; - size_t item_read; - item_read = fread (&g, (size_t)4,(size_t)1, fp); - if ( item_read != 1 ) { - if(ferror(fp)) - dbg.Verbose(0, "gdcmParser::ReadInt32", " File Error"); - errno = 1; - return 0; - } - errno = 0; - g = SwapLong(g); - return g; -} - -/** - * \brief skips bytes inside the source file - * \warning NOT end user intended method ! - * @return - */ -void gdcmParser::SkipBytes(guint32 NBytes) { - //FIXME don't dump the returned value - (void)fseek(fp, (long)NBytes, SEEK_CUR); -} - -/** - * \brief Loads all the needed Dictionaries - * \warning NOT end user intended method ! - */ -void gdcmParser::Initialise(void) -{ - RefPubDict = gdcmGlobal::GetDicts()->GetDefaultPubDict(); - RefShaDict = (gdcmDict*)0; -} - -/** - * \brief Discover what the swap code is (among little endian, big endian, - * bad little endian, bad big endian). - * sw is set - * @return false when we are absolutely sure - * it's neither ACR-NEMA nor DICOM - * true when we hope ours assuptions are OK - */ -bool gdcmParser::CheckSwap() { - - // The only guaranted way of finding the swap code is to find a - // group tag since we know it's length has to be of four bytes i.e. - // 0x00000004. Finding the swap code in then straigthforward. Trouble - // occurs when we can't find such group... - - guint32 x=4; // x : for ntohs - bool net2host; // true when HostByteOrder is the same as NetworkByteOrder - guint32 s32; - guint16 s16; - - int lgrLue; - char *entCur; - char deb[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). - if (x==ntohs(x)) - net2host = true; - else - net2host = false; - - // 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". - lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp); - - entCur = deb + 128; - if(memcmp(entCur, "DICM", (size_t)4) == 0) { - dbg.Verbose(1, "gdcmParser::CheckSwap:", "looks like DICOM Version3"); - - // Next, determine the value representation (VR). Let's skip to the - // first element (0002, 0000) and check there if we find "UL" - // - or "OB" if the 1st one is (0002,0001) -, - // in which case we (almost) know it is explicit VR. - // WARNING: if it happens to be implicit VR then what we will read - // is the length of the group. If this ascii representation of this - // length happens to be "UL" then we shall believe it is explicit VR. - // FIXME: in order to fix the above warning, we could read the next - // element value (or a couple of elements values) in order to make - // sure we are not commiting a big mistake. - // We need to skip : - // * the 128 bytes of File Preamble (often padded with zeroes), - // * the 4 bytes of "DICM" string, - // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001) - // i.e. a total of 136 bytes. - entCur = deb + 136; - - // FIXME : FIXME: - // Sometimes (see : gdcmData/icone.dcm) group 0x0002 *is* Explicit VR, - // but elem 0002,0010 (Transfert Syntax) tells us the file is - // *Implicit* VR. -and it is !- - - if( (memcmp(entCur, "UL", (size_t)2) == 0) || - (memcmp(entCur, "OB", (size_t)2) == 0) || - (memcmp(entCur, "UI", (size_t)2) == 0) || - (memcmp(entCur, "CS", (size_t)2) == 0) ) // CS, to remove later - // when Write DCM *adds* - // FIXME - // Use gdcmParser::dicom_vr to test all the possibilities - // instead of just checking for UL, OB and UI !? group 0000 - { - filetype = gdcmExplicitVR; - dbg.Verbose(1, "gdcmParser::CheckSwap:", - "explicit Value Representation"); - } - else - { - filetype = gdcmImplicitVR; - dbg.Verbose(1, "gdcmParser::CheckSwap:", - "not an explicit Value Representation"); - } - - if (net2host) - { - sw = 4321; - dbg.Verbose(1, "gdcmParser::CheckSwap:", - "HostByteOrder != NetworkByteOrder"); - } - else - { - sw = 0; - dbg.Verbose(1, "gdcmParser::CheckSwap:", - "HostByteOrder = NetworkByteOrder"); - } - - // 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); - return true; - } // End of DicomV3 - - // 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). - dbg.Verbose(1, "gdcmParser::CheckSwap:", "not a DICOM Version3 file"); - rewind(fp); - - // 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. - // If this is the case and since the length of the first group HAS to be - // four (bytes), then determining the proper swap code is straightforward. - - entCur = deb + 4; - // We assume the array of char we are considering contains the binary - // representation of a 32 bits integer. Hence the following dirty - // trick : - s32 = *((guint32 *)(entCur)); - - switch (s32) { - case 0x00040000 : - sw = 3412; - filetype = gdcmACR; - return true; - case 0x04000000 : - sw = 4321; - filetype = gdcmACR; - return true; - case 0x00000400 : - sw = 2143; - filetype = gdcmACR; - return true; - case 0x00000004 : - sw = 0; - filetype = gdcmACR; - return true; - default : - - // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file. - // It is time for despaired wild guesses. - // So, let's check if this file wouldn't happen to be 'dirty' ACR/NEMA, - // i.e. the 'group length' element is not present : - - // check the supposed to be 'group number' - // 0x0002 or 0x0004 or 0x0008 - // to determine ' sw' value . - // Only 0 or 4321 will be possible - // (no oportunity to check for the formerly well known - // ACR-NEMA 'Bad Big Endian' or 'Bad Little Endian' - // if unsuccessfull (i.e. neither 0x0002 nor 0x0200 etc -4, 8-) - // the file IS NOT ACR-NEMA nor DICOM V3 - // Find a trick to tell it the caller... - - s16 = *((guint16 *)(deb)); - - switch (s16) { - case 0x0002 : - case 0x0004 : - case 0x0008 : - sw = 0; - filetype = gdcmACR; - return true; - case 0x0200 : - case 0x0400 : - case 0x0800 : - sw = 4321; - filetype = gdcmACR; - return true; - default : - dbg.Verbose(0, "gdcmParser::CheckSwap:", - "ACR/NEMA unfound swap info (Really hopeless !)"); - filetype = gdcmUnknown; - return false; - } - - // Then the only info we have is the net2host one. - //if (! net2host ) - // sw = 0; - //else - // sw = 4321; - //return; - } -} - -/** - * \brief Restore the unproperly loaded values i.e. the group, the element - * and the dictionary entry depending on them. - */ -void gdcmParser::SwitchSwapToBigEndian(void) -{ - dbg.Verbose(1, "gdcmParser::SwitchSwapToBigEndian", - "Switching to BigEndian mode."); - if ( sw == 0 ) - { - sw = 4321; - return; - } - if ( sw == 4321 ) - { - sw = 0; - return; - } - if ( sw == 3412 ) - { - sw = 2143; - return; - } - if ( sw == 2143 ) - sw = 3412; -} - -/** - * \brief during parsing, Header Elements too long are not loaded in memory - * @param NewSize - */ -void gdcmParser::SetMaxSizeLoadEntry(long NewSize) -{ - if (NewSize < 0) - return; - if ((guint32)NewSize >= (guint32)0xffffffff) - { - MaxSizeLoadEntry = 0xffffffff; - return; - } - MaxSizeLoadEntry = NewSize; -} - - -/** - * \brief Header Elements too long will not be printed - * \todo See comments of \ref gdcmParser::MAX_SIZE_PRINT_ELEMENT_VALUE - * @param NewSize - */ -void gdcmParser::SetMaxSizePrintEntry(long NewSize) -{ - if (NewSize < 0) - return; - if ((guint32)NewSize >= (guint32)0xffffffff) - { - MaxSizePrintEntry = 0xffffffff; - return; - } - MaxSizePrintEntry = NewSize; -} - -/** - * \brief Searches both the public and the shadow dictionary (when they - * exist) for the presence of the DictEntry with given name. - * The public dictionary has precedence on the shadow one. - * @param Name name of the searched DictEntry - * @return Corresponding DictEntry when it exists, NULL otherwise. - */ -gdcmDictEntry *gdcmParser::GetDictEntryByName(std::string Name) -{ - gdcmDictEntry *found = (gdcmDictEntry *)0; - if (!RefPubDict && !RefShaDict) - { - dbg.Verbose(0, "gdcmParser::GetDictEntry", - "we SHOULD have a default dictionary"); - } - if (RefPubDict) - { - found = RefPubDict->GetDictEntryByName(Name); - if (found) - return found; - } - if (RefShaDict) - { - found = RefShaDict->GetDictEntryByName(Name); - if (found) - return found; - } - return found; -} - -/** - * \brief Searches both the public and the shadow dictionary (when they - * exist) for the presence of the DictEntry with given - * group and element. The public dictionary has precedence on the - * shadow one. - * @param group group of the searched DictEntry - * @param element element of the searched DictEntry - * @return Corresponding DictEntry when it exists, NULL otherwise. - */ -gdcmDictEntry *gdcmParser::GetDictEntryByNumber(guint16 group,guint16 element) -{ - gdcmDictEntry *found = (gdcmDictEntry *)0; - if (!RefPubDict && !RefShaDict) - { - dbg.Verbose(0, "gdcmParser::GetDictEntry", - "we SHOULD have a default dictionary"); - } - if (RefPubDict) - { - found = RefPubDict->GetDictEntryByNumber(group, element); - if (found) - return found; - } - if (RefShaDict) - { - found = RefShaDict->GetDictEntryByNumber(group, element); - if (found) - return found; - } - return found; -} - -/** - * \brief Read the next tag but WITHOUT loading it's value - * @return On succes the newly created HeaderEntry, NULL on failure. - */ -gdcmHeaderEntry *gdcmParser::ReadNextHeaderEntry(void) { - guint16 g,n; - gdcmHeaderEntry *NewEntry; - g = ReadInt16(); - n = ReadInt16(); - - if (errno == 1) - // We reached the EOF (or an error occured) therefore - // header parsing has to be considered as finished. - return (gdcmHeaderEntry *)0; - -// Pb : how to propagate the element length (used in SkipHeaderEntry) -// direct call to SkipBytes ? - -// if (ignoreShadow == 1 && g%2 ==1) - // if user wants to skip shadow groups - // and current element *is* a shadow element - // we don't create anything -// return (gdcmHeaderEntry *)1; // to tell caller it's NOT finished - - NewEntry = NewHeaderEntryByNumber(g, n); - FindHeaderEntryVR(NewEntry); - FindHeaderEntryLength(NewEntry); - - if (errno == 1) { - // Call it quits - return NULL; - } - NewEntry->SetOffset(ftell(fp)); - return NewEntry; -} - -/** - * \brief Build a new Element Value from all the low level arguments. - * Check for existence of dictionary entry, and build - * a default one when absent. - * @param Name Name of the underlying DictEntry - */ -gdcmHeaderEntry *gdcmParser::NewHeaderEntryByName(std::string Name) -{ - gdcmDictEntry *NewTag = GetDictEntryByName(Name); - if (!NewTag) - NewTag = NewVirtualDictEntry(0xffff, 0xffff, "LO", "unkn", Name); - - gdcmHeaderEntry* NewEntry = new gdcmHeaderEntry(NewTag); - if (!NewEntry) - { - dbg.Verbose(1, "gdcmParser::ObtainHeaderEntryByName", - "failed to allocate gdcmHeaderEntry"); - return (gdcmHeaderEntry *)0; - } - return NewEntry; -} - -/** - * \brief Request a new virtual dict entry to the dict set - * @param group group of the underlying DictEntry - * @param element element of the underlying DictEntry - * @param vr VR of the underlying DictEntry - * @param fourth owner group - * @param name english name - */ -gdcmDictEntry *gdcmParser::NewVirtualDictEntry(guint16 group, guint16 element, - std::string vr, - std::string fourth, - std::string name) -{ - return gdcmGlobal::GetDicts()->NewVirtualDictEntry(group,element,vr,fourth,name); -} - -/** - * \brief Build a new Element Value from all the low level arguments. - * Check for existence of dictionary entry, and build - * a default one when absent. - * @param Group group of the underlying DictEntry - * @param Elem element of the underlying DictEntry - */ -gdcmHeaderEntry *gdcmParser::NewHeaderEntryByNumber(guint16 Group, guint16 Elem) -{ - // Find out if the tag we encountered is in the dictionaries: - gdcmDictEntry *DictEntry = GetDictEntryByNumber(Group, Elem); - if (!DictEntry) - DictEntry = NewVirtualDictEntry(Group, Elem); - - gdcmHeaderEntry *NewEntry = new gdcmHeaderEntry(DictEntry); - if (!NewEntry) - { - dbg.Verbose(1, "gdcmParser::NewHeaderEntryByNumber", - "failed to allocate gdcmHeaderEntry"); - return NULL; - } - return NewEntry; -} - -/// \todo Never used; commented out, waiting for removal. -/** - * \brief Small utility function that creates a new manually crafted - * (as opposed as read from the file) gdcmHeaderEntry with user - * specified name and adds it to the public tag hash table. - * \note A fake TagKey is generated so the PubDict can keep it's coherence. - * @param NewTagName The name to be given to this new tag. - * @param VR The Value Representation to be given to this new tag. - * @return The newly hand crafted Element Value. - */ -//gdcmHeaderEntry *gdcmParser::NewManualHeaderEntryToPubDict(std::string NewTagName, -// std::string VR) -//{ -// gdcmHeaderEntry *NewEntry = NULL; -// guint32 StuffGroup = 0xffff; // Group to be stuffed with additional info -// guint32 FreeElem = 0; -// gdcmDictEntry *DictEntry = NULL; -// -// FreeElem = GenerateFreeTagKeyInGroup(StuffGroup); -// if (FreeElem == UINT32_MAX) -// { -// dbg.Verbose(1, "gdcmHeader::NewManualHeaderEntryToPubDict", -// "Group 0xffff in Public Dict is full"); -// return NULL; -// } -// -// DictEntry = NewVirtualDictEntry(StuffGroup, FreeElem, -// VR, "GDCM", NewTagName); -// NewEntry = new gdcmHeaderEntry(DictEntry); -// AddHeaderEntry(NewEntry); -// return NewEntry; -//} - -/** - * \brief Generate a free TagKey i.e. a TagKey that is not present - * in the TagHt dictionary. - * @param group The generated tag must belong to this group. - * @return The element of tag with given group which is fee. - */ -guint32 gdcmParser::GenerateFreeTagKeyInGroup(guint16 group) -{ - for (guint32 elem = 0; elem < UINT32_MAX; elem++) - { - TagKey key = gdcmDictEntry::TranslateToKey(group, elem); - if (tagHT.count(key) == 0) - return elem; - } - return UINT32_MAX; -} - -//----------------------------------------------------------------------------- diff --git a/src/gdcmParser.h b/src/gdcmParser.h deleted file mode 100644 index 3bdc99a0..00000000 --- a/src/gdcmParser.h +++ /dev/null @@ -1,275 +0,0 @@ -// gdcmParser.h -//----------------------------------------------------------------------------- -#ifndef GDCMPARSER_H -#define GDCMPARSER_H - -#include "gdcmCommon.h" - -#include "gdcmVR.h" -#include "gdcmTS.h" -#include "gdcmException.h" -#include "gdcmDictSet.h" -#include "gdcmHeaderEntry.h" - -#include -#include - - - -//----------------------------------------------------------------------------- -typedef std::string VRKey; -typedef std::string VRAtr; -typedef std::map VRHT; // Value Representation Hash Table - -typedef std::multimap TagHeaderEntryHT; -typedef std::pair PairHT; -typedef std::pair IterHT; -/// for linking together the Elements -typedef std::list ListTag; - -typedef std::string GroupKey; -typedef std::map GroupHT; - -//----------------------------------------------------------------------------- -/** - * \brief used by both gdcmHeader and gdcmDicomDir - */ -class GDCM_EXPORT gdcmParser -{ -private: - /// Public dictionary used to parse this header - gdcmDict *RefPubDict; - - /// \brief Optional "shadow dictionary" (private elements) used to parse - /// this header - gdcmDict *RefShaDict; - - /// Equals 1 if a gdcmHeaderEntry was added post parsing - int wasUpdated; - - /// \brief Equals =1 if user wants to skip shadow groups while parsing - /// (to save space) - int ignoreShadow; - - /// \brief Size threshold above which an element value will NOT be loaded - /// in memory (to avoid loading the image/volume itself). By default, - /// this upper bound is fixed to 1024 bytes (which might look reasonable - /// when one considers the definition of the various VR contents). - guint32 MaxSizeLoadEntry; - - /// \brief Size threshold above which an element value will NOT be *printed* - /// in order no to polute the screen output. By default, this upper bound - /// is fixed to 64 bytes. - guint32 MaxSizePrintEntry; - -protected: - /// Refering underlying filename. - std::string filename; - - /// \brief SWap code (e.g. Big Endian, Little Endian, Bad Big Endian, - /// Bad Little Endian) according to the processor Endianity and - /// what is written on disc. - int sw; - - /// File Pointer, opened during Header parsing. - FILE *fp; - - /// ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown - FileType filetype; - - /// After opening the file, we read HEADER_LENGTH_TO_READ bytes. - static const unsigned int HEADER_LENGTH_TO_READ; - - /// \brief Elements whose value is longer than MAX_SIZE_LOAD_ELEMENT_VALUE - /// are NOT loaded. - static const unsigned int MAX_SIZE_LOAD_ELEMENT_VALUE; - - /// \brief Elements whose value is longer than MAX_SIZE_PRINT_ELEMENT_VALUE - /// are NOT printed. - /// \todo Currently not used since collides with #define in - /// \ref gdcmHeaderEntry.cxx. See also - /// \ref gdcmParser::SetMaxSizePrintEntry() - static const unsigned int MAX_SIZE_PRINT_ELEMENT_VALUE; - - /// Hash Table (multimap), to provide fast access - TagHeaderEntryHT tagHT; - - /// Chained list, to keep the 'spacial' ordering - ListTag listEntries; - - /// Will be set 1 if user asks to 'go inside' the 'sequences' (VR = "SQ") - int enableSequences; - - /// \brief Amount of printed details for each Header Entry (Dicom Element): - /// 0 : stands for the least detail level. - int printLevel; - -public: - - -// Print - /// Canonical Printing method (see also gdcmParser::SetPrintLevel) - virtual void Print (std::ostream &os = std::cout) - {PrintEntry(os);}; - virtual void PrintEntry (std::ostream &os = std::cout); - - // the 2 following will be merged - virtual void PrintPubDict (std::ostream &os = std::cout); - virtual void PrintShaDict (std::ostream &os = std::cout); - -// Dictionnaries - gdcmDict *GetPubDict(void); - gdcmDict *GetShaDict(void); - bool SetShaDict(gdcmDict *dict); - bool SetShaDict(DictKey dictName); - -// Informations contained in the parser - virtual bool IsReadable(void); - bool IsImplicitVRLittleEndianTransferSyntax(void); - bool IsExplicitVRLittleEndianTransferSyntax(void); - bool IsDeflatedExplicitVRLittleEndianTransferSyntax(void); - bool IsExplicitVRBigEndianTransferSyntax(void); - FileType GetFileType(void); - -// Read (used in gdcmFile, gdcmDicomDir) - FILE *OpenFile(bool exception_on_error = false) throw(gdcmFileError); - bool CloseFile(void); - -// Write (used in gdcmFile, gdcmDicomDir) - virtual bool Write(FILE *, FileType); - virtual void WriteEntryTagVRLength(gdcmHeaderEntry *tag, - FILE *_fp, FileType type); - virtual void WriteEntryValue(gdcmHeaderEntry *tag,FILE *_fp,FileType type); - virtual bool WriteEntry(gdcmHeaderEntry *tag,FILE *_fp,FileType type); - virtual bool WriteEntries(FILE *_fp,FileType type); - void WriteEntriesDeprecated(FILE *_fp,FileType type); // JPR - - gdcmHeaderEntry * ReplaceOrCreateByNumber(std::string Value, - guint16 Group, guint16 Elem); - bool ReplaceIfExistByNumber (char *Value, guint16 Group, guint16 Elem); - -// System access - guint16 SwapShort(guint16); // needed by gdcmFile - guint32 SwapLong(guint32); // needed by gdcmFile - guint16 UnswapShort(guint16); // needed by gdcmFile - guint32 UnswapLong(guint32); // needed by gdcmFile - -protected: - // Constructor and destructor are protected to forbid end user - // to instanciate from this class gdcmParser (only gdcmHeader and - // gdcmDicomDir are meaningfull). - gdcmParser(bool exception_on_error = false); - gdcmParser(const char *inFilename, - bool exception_on_error = false, - bool enable_sequences = false, - bool ignore_shadow = false); - virtual ~gdcmParser(void); -// Entry - int CheckIfEntryExistByNumber(guint16 Group, guint16 Elem ); // int ! - virtual std::string GetEntryByName (std::string tagName); - virtual std::string GetEntryVRByName (std::string tagName); - virtual std::string GetEntryByNumber (guint16 group, guint16 element); - virtual std::string GetEntryVRByNumber(guint16 group, guint16 element); - virtual int GetEntryLengthByNumber(guint16 group, guint16 element); - - virtual bool SetEntryByName (std::string content, std::string tagName); - virtual bool SetEntryByNumber(std::string content, - guint16 group, guint16 element); - virtual bool SetEntryLengthByNumber(guint32 length, - guint16 group, guint16 element); - - virtual size_t GetEntryOffsetByNumber (guint16 Group, guint16 Elem); - virtual void *GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem); - virtual void *LoadEntryVoidArea (guint16 Group, guint16 Element); - virtual bool SetEntryVoidAreaByNumber(void *a, guint16 Group, guint16 Elem); - - virtual void UpdateShaEntries(void); - -// Header entry - gdcmHeaderEntry *GetHeaderEntryByNumber (guint16 group, guint16 element); - gdcmHeaderEntry *GetHeaderEntryByName (std::string Name); - IterHT GetHeaderEntrySameNumber(guint16 group, guint16 element); -// IterHT GetHeaderEntrySameName (std::string Name); - - void LoadHeaderEntrySafe(gdcmHeaderEntry *); - - void UpdateGroupLength(bool SkipSequence = false, - FileType type = gdcmImplicitVR); - - void AddHeaderEntry (gdcmHeaderEntry *); - - -private: - // Read - bool LoadHeaderEntries(bool exception_on_error = false) throw(gdcmFormatError); - - void LoadHeaderEntry (gdcmHeaderEntry *); - void FindHeaderEntryLength(gdcmHeaderEntry *); - void FindHeaderEntryVR (gdcmHeaderEntry *); - bool CheckHeaderEntryVR (gdcmHeaderEntry *, VRKey); - - std::string GetHeaderEntryValue (gdcmHeaderEntry *); - std::string GetHeaderEntryUnvalue(gdcmHeaderEntry *); - - void SkipHeaderEntry (gdcmHeaderEntry *); - void FixHeaderEntryFoundLength(gdcmHeaderEntry *, guint32); - bool IsHeaderEntryAnInteger (gdcmHeaderEntry *); - - guint32 FindHeaderEntryLengthOB(void); - - guint16 ReadInt16(void); - guint32 ReadInt32(void); - void SkipBytes(guint32); - - void Initialise(void); - bool CheckSwap(void); - void SwitchSwapToBigEndian(void); - void SetMaxSizeLoadEntry(long); - void SetMaxSizePrintEntry(long); - - // DictEntry related utilities - gdcmDictEntry *GetDictEntryByName (std::string Name); - gdcmDictEntry *GetDictEntryByNumber(guint16, guint16); - gdcmDictEntry *NewVirtualDictEntry(guint16 group, - guint16 element, - std::string vr = "unkn", - std::string fourth = "unkn", - std::string name = "unkn"); - //gdcmDictEntry *NewVirtualDictEntry(gdcmHeaderEntry *); // never defined - - // HeaderEntry related utilities - - gdcmHeaderEntry *ReadNextHeaderEntry (void); - gdcmHeaderEntry *NewHeaderEntryByNumber(guint16 group, - guint16 element); - gdcmHeaderEntry *NewHeaderEntryByName (std::string Name); - - // Deprecated (Not used) --> commented out - //gdcmHeaderEntry *NewManualHeaderEntryToPubDict(std::string NewTagName, - // std::string VR); - - guint32 GenerateFreeTagKeyInGroup(guint16 group); - -public: -// Accessors: - /// Accessor to \ref printLevel - void SetPrintLevel(int level) { printLevel = level; }; - - /// Accessor to \ref filename - inline std::string GetFileName(void) {return filename;} - - /// Accessor to \ref filename - inline void SetFileName(char* fileName) {filename = fileName;} - - /// Accessor to \ref gdcmParser::tagHT - inline TagHeaderEntryHT &GetEntry(void) { return tagHT; }; - - /// Accessor to \ref gdcmParser::listEntries - inline ListTag &GetListEntry(void) { return listEntries; }; - - /// 'Swap code' accessor (see \ref sw ) - inline int GetSwapCode(void) { return sw; } -}; - -//----------------------------------------------------------------------------- -#endif diff --git a/src/gdcmSQItem.cxx b/src/gdcmSQItem.cxx index ce080c60..eda6b094 100644 --- a/src/gdcmSQItem.cxx +++ b/src/gdcmSQItem.cxx @@ -58,7 +58,9 @@ gdcmSQItem::~gdcmSQItem() //----------------------------------------------------------------------------- // Public - +/** + * \brief adds any Entry (Dicom Element) to the Sequence Item + */ bool gdcmSQItem::AddEntry(gdcmDocEntry *entry) { docEntries.push_back(entry); //TODO : check if it worked @@ -128,6 +130,8 @@ bool gdcmSQItem::AddEntry(gdcmDocEntry *entry) { // Private // end-user intended : the guy *wants* to create his own SeQuence ?!? + +/// \brief to be written if really usefull gdcmDocEntry *gdcmSQItem::NewDocEntryByNumber(guint16 group, guint16 element) { // TODO @@ -136,6 +140,7 @@ gdcmDocEntry *gdcmSQItem::NewDocEntryByNumber(guint16 group, return a; } +/// \brief to be written if really usefull gdcmDocEntry *gdcmSQItem::NewDocEntryByName (std::string Name) { // TODO gdcmDocEntry *a; @@ -143,7 +148,7 @@ gdcmDocEntry *gdcmSQItem::NewDocEntryByName (std::string Name) { return a; } -/* +/** * \ingroup gdcmSQItem * \brief Gets a Dicom Element inside a SQ Item Entry, by name * @return @@ -156,7 +161,7 @@ gdcmDocEntry *gdcmSQItem::NewDocEntryByName (std::string Name) { return GetDocEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()); } -/* +/** * \ingroup gdcmSQItem * \brief Gets a Dicom Element inside a SQ Item Entry, by number * @return @@ -169,7 +174,7 @@ gdcmDocEntry *gdcmSQItem::GetDocEntryByNumber(guint16 group, guint16 element) { return NULL; } -/* +/** * \ingroup gdcmSQItem * \brief Get the value of a Dicom Element inside a SQ Item Entry, by number * @return diff --git a/src/gdcmSQItem.h b/src/gdcmSQItem.h index fa5f2559..a2eefbf3 100644 --- a/src/gdcmSQItem.h +++ b/src/gdcmSQItem.h @@ -55,10 +55,9 @@ protected: /// \brief SQ Item ordinal number int SQItemNumber; -/** -* \brief pointer to the HTable of the gdcmDocument, -* (because we don't know it within any gdcmObject nor any gdcmSQItem) -*/ + +///\brief pointer to the HTable of the gdcmDocument, +/// (because we don't know it within any gdcmObject nor any gdcmSQItem) TagDocEntryHT *ptagHT; private: diff --git a/src/gdcmSeqEntry.cxx b/src/gdcmSeqEntry.cxx index 39f4c98a..237265b5 100644 --- a/src/gdcmSeqEntry.cxx +++ b/src/gdcmSeqEntry.cxx @@ -86,10 +86,11 @@ void gdcmSeqEntry::AddEntry(gdcmSQItem *sqItem) { items.push_back(sqItem); } - +/// \brief Sets the depth level of a Sequence Entry embedded in a SeQuence void gdcmSeqEntry::SetDepthLevel(int depth) { SQDepthLevel = depth; } + //----------------------------------------------------------------------------- // Protected @@ -99,22 +100,28 @@ void gdcmSeqEntry::SetDepthLevel(int depth) { // end-user intended : the guy *wants* to create his own SeQuence ?!? +/// \brief to be written, if really usefull gdcmDocEntry *gdcmSeqEntry::NewDocEntryByNumber(guint16 group, guint16 element) { -// TODO +// TODO + std::cout << "TODO : gdcmSeqEntry::NewDocEntryByNumber " << endl; gdcmDocEntry *a; return a; } +/// \brief to be written, if really usefull gdcmDocEntry *gdcmSeqEntry::NewDocEntryByName (std::string Name) { // TODO : + std::cout << "TODO : gdcmSeqEntry::NewDocEntryByName " << endl; gdcmDocEntry *a; return a; } +/// \brief to be written, if really usefull gdcmDocEntry *gdcmSeqEntry::GetDocEntryByNumber(guint16 group, guint16 element) { // TODO + std::cout << "TODO : gdcmSeqEntry::GetDocEntryByNumber " << endl; gdcmDocEntry *a; return a; } diff --git a/src/gdcmSeqEntry.h b/src/gdcmSeqEntry.h index 9b9e6076..e197bc04 100644 --- a/src/gdcmSeqEntry.h +++ b/src/gdcmSeqEntry.h @@ -58,8 +58,6 @@ private: /// \brief sequence terminator item gdcmDocEntry *seq_term; - //int SQDepthLevel; - }; diff --git a/src/gdcmValEntry.h b/src/gdcmValEntry.h index 6721b8d8..e27db5d9 100644 --- a/src/gdcmValEntry.h +++ b/src/gdcmValEntry.h @@ -33,7 +33,8 @@ public: protected: - char* voidArea; // clean it out later + /// \brief for 'non string' values. Will be move to gdcmBinEntry, later + char* voidArea; // clean it out later private: