X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmParser.cxx;h=03fdde5d55a873c1a69c6f3574ca2b2f36062b0d;hb=9b3db5f141ec2b11eadefaa2ea2a3a20058b37f9;hp=42db7b9f395e4baa8cc1cc6fbc81bf8608b72dc8;hpb=be592d55a8d38139cea05c9b22292af14645133b;p=gdcm.git diff --git a/src/gdcmParser.cxx b/src/gdcmParser.cxx index 42db7b9f..03fdde5d 100644 --- a/src/gdcmParser.cxx +++ b/src/gdcmParser.cxx @@ -3,6 +3,7 @@ #include "gdcmParser.h" #include "gdcmUtil.h" #include +#include // For nthos: #ifdef _MSC_VER @@ -65,8 +66,8 @@ // // Other usefull abreviations : - //Radiographic view associated with Patient Position (0018,5100). - // Defined Terms: + // Radiographic view associated with Patient Position (0018,5100). + // Defined Terms: // // AP = Anterior/Posterior // PA = Posterior/Anterior @@ -95,7 +96,7 @@ const unsigned int gdcmParser::MAX_SIZE_PRINT_ELEMENT_VALUE = 64; * \ingroup gdcmParser * \brief constructor * @param inFilename - * @param exception_on_error + * @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 @@ -112,7 +113,7 @@ gdcmParser::gdcmParser(const char *inFilename, enableSequences=enable_sequences; ignoreShadow =ignore_shadow; - SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); + SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); filename = inFilename; Initialise(); @@ -183,7 +184,7 @@ void gdcmParser::PrintPubDict(std::ostream & os) { /** * \ingroup gdcmParser - * \brief Prints The Dict Entries of THE shadow Dicom Dictionnry + * \brief Prints The Dict Entries of THE shadow Dicom Dictionnary * @return */ void gdcmParser::PrintShaDict(std::ostream & os) { @@ -453,22 +454,28 @@ bool gdcmParser::Write(FILE *fp, FileType type) { * \ingroup gdcmParser * \brief Modifies the value of a given Header Entry (Dicom Element) * if it exists; Creates it with the given value if it doesn't + * \warning : adds the Header Entry to the HTable, NOT to the chained List * @param Value passed as a std::string - * @param Group - * @param Elem - * \return false only if new element creation fails + * @param Group group of the Entry + * @param Elem element of the Entry + * \return pointer to the created Header Entry + * NULL if creation failed */ -bool gdcmParser::ReplaceOrCreateByNumber(std::string Value, +gdcmHeaderEntry * gdcmParser::ReplaceOrCreateByNumber( + std::string Value, guint16 Group, - guint16 Elem ){ - if (CheckIfEntryExistByNumber(Group, Elem) == 0) { + guint16 Elem ){ + gdcmHeaderEntry* a; + a = GetHeaderEntryByNumber( Group, Elem); + if (a == NULL) { gdcmHeaderEntry *a =NewHeaderEntryByNumber(Group, Elem); if (a == NULL) - return false; + return NULL; AddHeaderEntry(a); } - SetEntryByNumber(Value, Group, Elem); - return(true); + //SetEntryByNumber(Value, Group, Elem); + a->SetValue(Value); + return(a); } /** @@ -478,20 +485,24 @@ bool gdcmParser::ReplaceOrCreateByNumber(std::string Value, * @param Value passed as a char* * @param Group group of the Entry * @param Elem element of the Entry - * \return boolean + * \return pointer to the created Header Entry + * NULL if creation failed * */ -bool gdcmParser::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Elem ) { +gdcmHeaderEntry * gdcmParser::ReplaceOrCreateByNumber( + char* Value, + guint16 Group, + guint16 Elem ) { gdcmHeaderEntry* nvHeaderEntry=NewHeaderEntryByNumber(Group, Elem); if(!nvHeaderEntry) - return(false); + return(NULL); AddHeaderEntry(nvHeaderEntry); std::string v = Value; SetEntryByNumber(v, Group, Elem); - return(true); + return(nvHeaderEntry); } /** @@ -808,7 +819,7 @@ bool gdcmParser::SetEntryVoidAreaByNumber(void * area, /** * \ingroup gdcmParser * \brief Update the entries with the shadow dictionary. - * Only non even entries are analyzed + * Only non even entries are analyzed */ void gdcmParser::UpdateShaEntries(void) { gdcmDictEntry *entry; @@ -1021,19 +1032,14 @@ void gdcmParser::UpdateGroupLength(bool SkipSequence, FileType type) { /** * \ingroup gdcmParser * \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 temporay method for Theralys) + * (ACR-NEMA, ExplicitVR, ImplicitVR) ONE + * gdcmHeaderEntry + * @param tag pointer on the gdcmHeaderEntry to be written * @param type type of the File to be written * (ACR-NEMA, ExplicitVR, ImplicitVR) * @param _fp already open file pointer */ -void gdcmParser::WriteEntries(FILE *_fp,FileType type) +void gdcmParser::WriteEntry(gdcmHeaderEntry *tag, FILE *_fp,FileType type) { guint16 gr, el; guint32 lgr; @@ -1045,46 +1051,36 @@ void gdcmParser::WriteEntries(FILE *_fp,FileType type) guint16 valZero =0; void *voidArea; std::vector tokens; - - // TODO : function CheckHeaderCoherence to be written - - // uses now listEntries to iterate, not TagHt! - // - // pb : gdcmParser.Add does NOT update listEntries - // TODO : find a trick (in STL?) to do it, at low cost ! void *ptr; int ff=0xffffffff; // TODO (?) tester les echecs en ecriture (apres chaque fwrite) int compte =0; - - for (ListTag::iterator tag2=listEntries.begin(); - tag2 != listEntries.end(); - ++tag2) - { + itsTimeToWritePixels = false; + + gr = tag->GetGroup(); + el = tag->GetElement(); + lgr = tag->GetReadLength(); + val = tag->GetValue().c_str(); + vr = tag->GetVR(); + voidArea = tag->GetVoidArea(); + // === Deal with the length // -------------------- - if(((*tag2)->GetLength())%2==1) + if((tag->GetLength())%2==1) { - (*tag2)->SetValue((*tag2)->GetValue()+"\0"); - (*tag2)->SetLength((*tag2)->GetReadLength()+1); + tag->SetValue(tag->GetValue()+"\0"); + tag->SetLength(tag->GetReadLength()+1); } - - gr = (*tag2)->GetGroup(); - el = (*tag2)->GetElement(); - lgr = (*tag2)->GetReadLength(); - val = (*tag2)->GetValue().c_str(); - vr = (*tag2)->GetVR(); - voidArea = (*tag2)->GetVoidArea(); if ( type == ACR ) { - if (gr < 0x0008) continue; // ignore pure DICOM V3 groups - if (gr %2) continue; // ignore shadow groups - if (vr == "SQ" ) continue; // ignore Sequences + if (gr < 0x0008) return; // ignore pure DICOM V3 groups + if (gr %2) return; // ignore shadow groups + if (vr == "SQ" ) return; // ignore Sequences // TODO : find a trick to *skip* the SeQuences ! // Not only ignore the SQ element - if (gr == 0xfffe ) continue; // ignore delimiters + if (gr == 0xfffe ) return; // ignore delimiters } fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group @@ -1095,9 +1091,16 @@ void gdcmParser::WriteEntries(FILE *_fp,FileType type) guint16 z=0, shortLgr; if (gr == 0xfffe) { // NO Value Representation for 'delimiters' - // no length : write ffffffff + // no length : write ffffffff + + // special patch to make some MR PHILIPS + if (el == 0x0000) return; // images e-film readable // see gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm + // from Hospital Guy de Chauliac, + // Montpellier + // we just ignore spurious fffe|0000 tag ! + fwrite (&ff,(size_t)4 ,(size_t)1 ,_fp); - continue; // NO value for 'delimiters' + return; // NO value for 'delimiters' } shortLgr=lgr; @@ -1122,19 +1125,19 @@ void gdcmParser::WriteEntries(FILE *_fp,FileType type) // === Deal with the value // ------------------- - if (vr == "SQ") continue; // no "value" to write for the SEQuences - if (gr == 0xfffe)continue; // no "value" to write for the delimiters + if (vr == "SQ") return; // no "value" to write for the SEQuences + if (gr == 0xfffe)return; // no "value" to write for the delimiters if (voidArea != NULL) { // there is a 'non string' LUT, overlay, etc fwrite ( voidArea,(size_t)lgr ,(size_t)1 ,_fp); // Elem value - continue; + return; } if (vr == "US" || vr == "SS") { tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize ((*tag2)->GetValue(), tokens, "\\"); + Tokenize (tag->GetValue(), tokens, "\\"); for (unsigned int i=0; iGetValue(), tokens, "\\"); + Tokenize (tag->GetValue(), tokens, "\\"); for (unsigned int i=0; i tokens; - void *ptr; - - // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian // restent a tester les echecs en ecriture (apres chaque fwrite) for (TagHeaderEntryHT::iterator tag2=tagHT.begin(); tag2 != tagHT.end(); ++tag2){ - - gr = tag2->second->GetGroup(); - el = tag2->second->GetElement(); - lgr = tag2->second->GetLength(); - val = tag2->second->GetValue().c_str(); - vr = tag2->second->GetVR(); - - // std::cout << "Tag "<< std::hex << gr << " " << el << std::endl; - - if ( type == ACR ) { - if (gr < 0x0008) continue; // ignore pure DICOM V3 groups - if (gr %2) continue; // ignore shadow groups - if (vr == "SQ" ) continue; // ignore Sequences - if (gr == 0xfffe ) continue; // ignore delimiters - } - - fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group - fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element - - if ( (type == ExplicitVR) && (gr <= 0x0002) ) { - // EXPLICIT VR - guint16 z=0, shortLgr; - 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 { - shortLgr=lgr; - fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp); - } - } else { // IMPLICIT VR - fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp); - } - - if (vr == "US" || vr == "SS") { - tokens.erase(tokens.begin(),tokens.end()); // clean any previous value - Tokenize (tag2->second->GetValue(), tokens, "\\"); - for (unsigned int i=0; isecond->GetValue(), tokens, "\\"); - for (unsigned int i=0; isecond,_fp,type); + if (itsTimeToWritePixels) + break; } } - - - - - /** * \ingroup gdcmParser * \brief Swaps back the bytes of 4-byte long integer accordingly to @@ -1524,7 +1482,7 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry) { /** * \ingroup gdcmParser * \brief add a new Dicom Element pointer to - * the H Table and to the chained List + * 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) @@ -1941,31 +1899,20 @@ void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry *Entry, guint32 Found } // a SeQuence Element is beginning - // Let's forget it's length - // (we want to 'go inside') - - // Pb : *normaly* fffe|e000 is just a marker, its length *should be* zero - // in gdcm-MR-PHILIPS-16-Multi-Seq.dcm we find lengthes as big as 28800 - // if we set the length to zero IsHeaderEntryAnInteger() breaks... - // if we don't, we lost 28800 characters from the Header :-( - + // fffe|e000 is just a marker, its length *should be* zero else if(Entry->GetGroup() == 0xfffe) { - // cout << "ReadLength " <GetReadLength() << " UsableLength " << FoundLength << endl; - // Entry->Print(); - // sometimes, length seems to be wrong - FoundLength =0; // some more clever checking to be done ! - // I give up! - // only gdcm-MR-PHILIPS-16-Multi-Seq.dcm - // causes troubles :-( - } - + // *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); } /** * \ingroup gdcmParser - * \brief Apply some heuristics to predict wether the considered + * \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. @@ -2104,7 +2051,7 @@ guint32 gdcmParser::ReadInt32(void) { /** * \ingroup gdcmParser - * \brief + * \brief skips bytes inside the source file * \warning NOT end user intended method ! * @return */ @@ -2115,7 +2062,8 @@ void gdcmParser::SkipBytes(guint32 NBytes) { /** * \ingroup gdcmParser - * \brief + * \brief Loads all the needed Dictionaries + * \warning NOT end user intended method ! */ void gdcmParser::Initialise(void) { @@ -2310,7 +2258,8 @@ bool gdcmParser::CheckSwap() { /** * \ingroup gdcmParser - * \brief + * \brief Restore the unproperly loaded values i.e. the group, the element + * and the dictionary entry depending on them. */ void gdcmParser::SwitchSwapToBigEndian(void) {