]> Creatis software - gdcm.git/blobdiff - src/gdcmParser.cxx
* Bug fix on field having a VR = 'UI'. Assume that is a string field
[gdcm.git] / src / gdcmParser.cxx
index ec1dcb9f06b7d4dcc2085e97aa9fdc7a2689f7e8..ad61419132e4bc03917241f98abd6e0d7defe346 100644 (file)
 # else
 #  include <sstream>
 #endif
+#  include <iomanip>
+
+#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"
 
 //-----------------------------------------------------------------------------
 // Refer to gdcmParser::CheckSwap()
@@ -93,7 +99,7 @@ gdcmParser::~gdcmParser (void)
   *          both from the H Table and the chained list
   * @return
   */ 
-void gdcmParser::PrintPubEntry(std::ostream & os) 
+void gdcmParser::PrintEntry(std::ostream & os) 
 {
    std::ostringstream s;   
           
@@ -181,21 +187,13 @@ bool gdcmParser::SetShaDict(DictKey dictName)
  */
 bool gdcmParser::IsReadable(void) 
 {
-   std::string res = GetEntryByNumber(0x0028, 0x0005);
-   if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 ) 
-   {
-      return false; // Image Dimensions
-   }
+   if(filetype==Unknown)
+      return(false);
 
-   if ( !GetHeaderEntryByNumber(0x0028, 0x0100) )
-      return false; // "Bits Allocated"
-   if ( !GetHeaderEntryByNumber(0x0028, 0x0101) )
-      return false; // "Bits Stored"
-   if ( !GetHeaderEntryByNumber(0x0028, 0x0102) )
-      return false; // "High Bit"
-   if ( !GetHeaderEntryByNumber(0x0028, 0x0103) )
-      return false; // "Pixel Representation"
-   return true;
+   if(listEntries.size()<=0)
+      return(false);
+
+   return(true);
 }
 
 /**
@@ -213,7 +211,7 @@ bool gdcmParser::IsImplicitVRLittleEndianTransferSyntax(void)
    LoadHeaderEntrySafe(Element);
 
    std::string Transfer = Element->GetValue();
-   if ( Transfer == "1.2.840.10008.1.2" )
+   if ( Transfer == UI1_2_840_10008_1_2 )
       return true;
    return false;
 }
@@ -233,7 +231,7 @@ bool gdcmParser::IsExplicitVRLittleEndianTransferSyntax(void)
    LoadHeaderEntrySafe(Element);
 
    std::string Transfer = Element->GetValue();
-   if ( Transfer == "1.2.840.10008.1.2.1" )
+   if ( Transfer == UI1_2_840_10008_1_2_1 )
       return true;
    return false;
 }
@@ -253,7 +251,7 @@ bool gdcmParser::IsDeflatedExplicitVRLittleEndianTransferSyntax(void)
    LoadHeaderEntrySafe(Element);
 
    std::string Transfer = Element->GetValue();
-   if ( Transfer == "1.2.840.10008.1.2.1.99" )
+   if ( Transfer == UI1_2_840_10008_1_2_1_99 )
       return true;
    return false;
 }
@@ -273,7 +271,7 @@ bool gdcmParser::IsExplicitVRBigEndianTransferSyntax(void)
    LoadHeaderEntrySafe(Element);
 
    std::string Transfer = Element->GetValue();
-   if ( Transfer == "1.2.840.10008.1.2.2" )  //1.2.2 ??? A verifier !
+   if ( Transfer == UI1_2_840_10008_1_2_2 )  //1.2.2 ??? A verifier !
       return true;
    return false;
 }
@@ -324,7 +322,6 @@ FILE *gdcmParser::OpenFile(bool exception_on_error)
     dbg.Verbose(0, "gdcmParser::gdcmParser not DICOM/ACR", filename.c_str());
   }
   else {
-    std::cerr<<filename.c_str()<<std::endl;
     dbg.Verbose(0, "gdcmParser::gdcmParser cannot open file", filename.c_str());
   }
   return(NULL);
@@ -375,7 +372,7 @@ bool gdcmParser::Write(FILE *fp, FileType type)
 
    if (type == ImplicitVR) 
    {
-      std::string implicitVRTransfertSyntax = "1.2.840.10008.1.2";
+      std::string implicitVRTransfertSyntax = UI1_2_840_10008_1_2;
       ReplaceOrCreateByNumber(implicitVRTransfertSyntax,0x0002, 0x0010);
       
       //FIXME Refer to standards on page 21, chapter 6.2 "Value representation":
@@ -387,7 +384,7 @@ bool gdcmParser::Write(FILE *fp, FileType type)
 
    if (type == ExplicitVR) 
    {
-      std::string explicitVRTransfertSyntax = "1.2.840.10008.1.2.1";
+      std::string explicitVRTransfertSyntax = UI1_2_840_10008_1_2_1;
       ReplaceOrCreateByNumber(explicitVRTransfertSyntax,0x0002, 0x0010);
       
       //FIXME Refer to standards on page 21, chapter 6.2 "Value representation":
@@ -760,9 +757,6 @@ bool gdcmParser::SetEntryVoidAreaByNumber(void * area,guint16 group, guint16 ele
  */
 void gdcmParser::UpdateShaEntries(void)
 {
-   if(!RefShaDict)
-      return;
-
    gdcmDictEntry *entry;
    std::string vr;
 
@@ -771,16 +765,33 @@ void gdcmParser::UpdateShaEntries(void)
        ++it)
    {
       // Odd group => from public dictionary
-      if((*it)->GetGroup()%1==0)
+      if((*it)->GetGroup()%2==0)
          continue;
 
       // Peer group => search the corresponding dict entry
-      entry=RefShaDict->GetDictEntryByNumber((*it)->GetGroup(),(*it)->GetElement());
+      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);
-         vr=(*it)->GetVR();
          CheckHeaderEntryVR(*it,vr);
+
+         (*it)->SetValue(GetHeaderEntryValue(*it));
+      }
+      else
+      {
+         // Remove precedent value transformation
+         (*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr));
       }
    }
 }
@@ -1086,6 +1097,17 @@ guint32 gdcmParser::SwapLong(guint32 a)
    return(a);
 }
 
+/**
+ * \ingroup gdcmParser
+ * \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));
+}
+
 /**
  * \ingroup gdcmParser
  * \brief   Swaps the bytes so they agree with the processor order
@@ -1098,6 +1120,16 @@ guint16 gdcmParser::SwapShort(guint16 a)
    return (a);
 }
 
+/**
+ * \ingroup gdcmParser
+ * \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
 /**
@@ -1129,8 +1161,8 @@ void gdcmParser::LoadHeaderEntries(void)
       i != GetListEntry().end();
       ++i)
    {
-         LoadHeaderEntry(*i);
-   }   
+      LoadHeaderEntry(*i);
+   }
             
    rewind(fp);
 
@@ -1238,7 +1270,7 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry)
       guint32 NewInt;
       std::ostringstream s;
       int nbInt;
-      if (vr == "US" || vr == "SS") 
+      if (vr == "US" || vr == "SS")
       {
          nbInt = length / 2;
          NewInt = ReadInt16();
@@ -1253,7 +1285,7 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry)
             }
          }
                        
-      } 
+      }
       else if (vr == "UL" || vr == "SL") 
       {
          nbInt = length / 4;
@@ -1268,7 +1300,7 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry)
                s << NewInt;
             }
          }
-      }                                        
+      }
 #ifdef GDCM_NO_ANSI_STRING_STREAM
       s << std::ends; // to avoid oddities on Solaris
 #endif //GDCM_NO_ANSI_STRING_STREAM
@@ -1277,24 +1309,19 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry)
    }
    
    // We need an additional byte for storing \0 that is not on disk
-   char* NewValue = (char*)malloc(length+1);
-   if( !NewValue) 
-   {
-      dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue");
-      return;
-   }
-   NewValue[length]= 0;
-   
-   item_read = fread(NewValue, (size_t)length, (size_t)1, fp);
+   std::string NewValue(length,0);
+   item_read = fread(&(NewValue[0]), (size_t)length, (size_t)1, fp);
    if ( item_read != 1 ) 
    {
-      free(NewValue);
       dbg.Verbose(1, "gdcmParser::LoadElementValue","unread element value");
       Entry->SetValue("gdcm::UnRead");
       return;
    }
-   Entry->SetValue(NewValue);
-   free(NewValue);
+
+   if( (vr == "UI") ) // Because of correspondance with the VR dic
+      Entry->SetValue(NewValue.c_str());
+   else
+      Entry->SetValue(NewValue);
 }
 
 /**
@@ -1306,7 +1333,7 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry)
  * \        when position to be taken care of     
  * @param   newHeaderEntry
  */
-void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry) 
+void gdcmParser::AddHeaderEntry(gdcmHeaderEntry *newHeaderEntry) 
 {
    tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) );
    listEntries.push_back(newHeaderEntry); 
@@ -1320,7 +1347,7 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry)
 
  * @return 
  */
- void gdcmParser::FindHeaderEntryLength (gdcmHeaderEntry * Entry) 
+ void gdcmParser::FindHeaderEntryLength (gdcmHeaderEntry *Entry) 
  {
    guint16 element = Entry->GetElement();
    guint16 group   = Entry->GetGroup();
@@ -1333,7 +1360,7 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry)
                      "we reached 7fe0 0010");
    }   
    
-   if ( (filetype == ExplicitVR) && ! Entry->IsImplicitVr() ) 
+   if ( (filetype == ExplicitVR) && (! Entry->IsImplicitVR()) ) 
    {
       if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) 
       {
@@ -1421,15 +1448,17 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry)
       FixHeaderEntryFoundLength(Entry, (guint32)length16);
       return;
    }
-
-   // Either implicit VR or a non DICOM conformal (see not 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;
+   else
+   {
+      // Either implicit VR or a non DICOM conformal (see not 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;
+   }
 }
 
 /**
@@ -1466,7 +1495,7 @@ void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *Entry)
       // avoid  .
       if ( Entry->IsVRUnknown() )
          Entry->SetVR("Implicit");
-      Entry->SetImplicitVr();
+      Entry->SetImplicitVR();
    }
 }
 
@@ -1480,7 +1509,7 @@ void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *Entry)
  * @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)
+bool gdcmParser::CheckHeaderEntryVR(gdcmHeaderEntry *Entry, VRKey vr)
 {
    char msg[100]; // for sprintf
    bool RealExplicit = true;
@@ -1525,22 +1554,131 @@ bool gdcmParser::CheckHeaderEntryVR   (gdcmHeaderEntry *Entry, VRKey vr)
       // 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* NewTag = NewVirtualDictEntry(Entry->GetGroup(),
-                                 Entry->GetElement(),
-                                 vr,
-                                 "FIXME",
-                                 Entry->GetName());
-      Entry->SetDictEntry(NewTag);
+      gdcmDictEntry* NewEntry = NewVirtualDictEntry(
+                                 Entry->GetGroup(),Entry->GetElement(),
+                                 vr,"FIXME",Entry->GetName());
+      Entry->SetDictEntry(NewEntry);
    }
    return(true); 
 }
 
 /**
  * \ingroup gdcmParser
- * \brief  Skip a given Header Entry 
+ * \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 
+ * @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;
+
+      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;
+         }
+      }
+
+      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());
+}
+
+/**
+ * \ingroup gdcmParser
+ * \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<std::string> 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<tokens.size();i++) 
+         {
+            NewInt16 = atoi(tokens[i].c_str());
+            s<<(NewInt16&0xFF)<<((NewInt16>>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<tokens.size();i++) 
+         {
+            NewInt32 = atoi(tokens[i].c_str());
+            s<<(char)(NewInt32&0xFF)<<(char)((NewInt32>>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());
+}
+
+/**
+ * \ingroup gdcmParser
+ * \brief   Skip a given Header Entry 
+ * \warning NOT end user intended method !
+ * @param   entry 
  */
 void gdcmParser::SkipHeaderEntry(gdcmHeaderEntry *entry) 
 {
@@ -2145,11 +2283,11 @@ gdcmDictEntry *gdcmParser::NewVirtualDictEntry(guint16 group, guint16 element,
 gdcmHeaderEntry *gdcmParser::NewHeaderEntryByNumber(guint16 Group, guint16 Elem) 
 {
    // Find out if the tag we encountered is in the dictionaries:
-   gdcmDictEntry *NewTag = GetDictEntryByNumber(Group, Elem);
-   if (!NewTag)
-      NewTag = NewVirtualDictEntry(Group, Elem);
+   gdcmDictEntry *DictEntry = GetDictEntryByNumber(Group, Elem);
+   if (!DictEntry)
+      DictEntry = NewVirtualDictEntry(Group, Elem);
 
-   gdcmHeaderEntry* NewEntry = new gdcmHeaderEntry(NewTag);
+   gdcmHeaderEntry *NewEntry = new gdcmHeaderEntry(DictEntry);
    if (!NewEntry) 
    {
       dbg.Verbose(1, "gdcmParser::NewHeaderEntryByNumber",