# gdcmDataSet.h

Go to the documentation of this file.

    00001 /*=========================================================================
    00002
    00003   Program: GDCM (Grassroots DICOM). A DICOM library
    00004   Module:  $URL$
    00005
    00006   Copyright (c) 2006-2009 Mathieu Malaterre
    00007   All rights reserved.
    00008   See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
    00009
    00010      This software is distributed WITHOUT ANY WARRANTY; without even
    00011      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
    00012      PURPOSE.  See the above copyright notice for more information.
    00013
    00014 =========================================================================*/
    00015 #ifndef __gdcmDataSet_h
    00016 #define __gdcmDataSet_h
    00017
    00018 #include "gdcmDataElement.h"
    00019 #include "gdcmTag.h"
    00020 #include "gdcmVR.h"
    00021 #include "gdcmElement.h"
    00022
    00023 #include <set>
    00024 #include <iterator>
    00025
    00026 namespace gdcm
    00027 {
    00028 class GDCM_EXPORT DataElementException : public std::exception {};
    00029
    00030 class PrivateTag;
    00055 class GDCM_EXPORT DataSet
    00056 {
    00057   friend class CSAHeader;
    00058 public:
    00059   typedef std::set<DataElement> DataElementSet;
    00060   typedef DataElementSet::const_iterator ConstIterator;
    00061   typedef DataElementSet::iterator Iterator;
    00062   typedef DataElementSet::size_type SizeType;
    00063   //typedef typename DataElementSet::iterator iterator;
    00064   ConstIterator Begin() const { return DES.begin(); }
    00065   Iterator Begin() { return DES.begin(); }
    00066   ConstIterator End() const { return DES.end(); }
    00067   Iterator End() { return DES.end(); }
    00068   const DataElementSet &GetDES() const { return DES; }
    00069   DataElementSet &GetDES() { return DES; }
    00070   void Clear() {
    00071     DES.clear();
    00072     assert( DES.empty() );
    00073   }
    00074
    00075   unsigned int Size() const {
    00076     return DES.size();
    00077   }
    00078
    00079   void Print(std::ostream &os, std::string const &indent = "") const {
    00080     // CT_Phillips_JPEG2K_Decompr_Problem.dcm has a SQ of length == 0
    00081     //int s = DES.size();
    00082     //assert( s );
    00083     //std::copy(DES.begin(), DES.end(),
    00084     //  std::ostream_iterator<DataElement>(os, "\n"));
    00085     ConstIterator it = DES.begin();
    00086     for( ; it != DES.end(); ++it)
    00087       {
    00088       os << indent << *it << "\n";
    00089       }
    00090   }
    00091
    00092   template <typename TDE>
    00093   unsigned int ComputeGroupLength(Tag const &tag) const
    00094     {
    00095     assert( tag.GetElement() == 0x0 );
    00096     const DataElement r(tag);
    00097     ConstIterator it = DES.find(r);
    00098     unsigned int res = 0;
    00099     for( ++it; it != DES.end()
    00100       && it->GetTag().GetGroup() == tag.GetGroup(); ++it)
    00101       {
    00102       assert( it->GetTag().GetElement() != 0x0 );
    00103       assert( it->GetTag().GetGroup() == tag.GetGroup() );
    00104       res += it->GetLength<TDE>();
    00105       }
    00106     return res;
    00107     }
    00108
    00109   template <typename TDE>
    00110   VL GetLength() const {
    00111     if( DES.empty() ) return 0;
    00112     assert( !DES.empty() );
    00113     VL ll = 0;
    00114     assert( ll == 0 );
    00115     ConstIterator it = DES.begin();
    00116     for( ; it != DES.end(); ++it)
    00117       {
    00118       assert( !(it->GetLength<TDE>().IsUndefined()) );
    00119       VL len = it->GetLength<TDE>();
    00120       if ( it->GetTag() != Tag(0xfffe,0xe00d) )
    00121         {
    00122         ll += it->GetLength<TDE>();
    00123         }
    00124       }
    00125     return ll;
    00126   }
    00129   void Insert(const DataElement& de) {
    00130     // FIXME: there is a special case where a dataset can have value < 0x8, see:
    00131     // $ gdcmdump --csa gdcmData/SIEMENS-JPEG-CorruptFrag.dcm
    00132     if( de.GetTag().GetGroup() >= 0x0008 || de.GetTag().GetGroup() == 0x4 )
    00133       {
    00134       InsertDataElement( de );
    00135       }
    00136     else
    00137       {
    00138       gdcmErrorMacro( "Cannot add element with group < 0x0008 and != 0x4 in the dataset" );
    00139       }
    00140   }
    00142   void Replace(const DataElement& de) {
    00143     if( DES.find(de) != DES.end() ) DES.erase(de);
    00144     Insert(de);
    00145   }
    00147   SizeType Remove(const Tag& tag) {
    00148     DataElementSet::size_type count = DES.erase(tag);
    00149     assert( count == 0 || count == 1 );
    00150     return count;
    00151   }
    00152
    00156   //DataElement& GetDataElement(const Tag &t) {
    00157   //  DataElement r(t);
    00158   //  Iterator it = DES.find(r);
    00159   //  if( it != DES.end() )
    00160   //    return *it;
    00161   //  return GetDEEnd();
    00162   //  }
    00163   const DataElement& GetDataElement(const Tag &t) const {
    00164     const DataElement r(t);
    00165     ConstIterator it = DES.find(r);
    00166     if( it != DES.end() )
    00167       return *it;
    00168     return GetDEEnd();
    00169     }
    00170   const DataElement& operator[] (const Tag &t) const { return GetDataElement(t); }
    00171   const DataElement& operator() (uint16_t group, uint16_t element) const { return GetDataElement( Tag(group,element) ); }
    00172
    00174   std::string GetPrivateCreator(const Tag &t) const;
    00175
    00177   bool FindDataElement(const PrivateTag &t) const;
    00179   const DataElement& GetDataElement(const PrivateTag &t) const;
    00180
    00181   // DUMB: this only search within the level of the current DataSet
    00182   bool FindDataElement(const Tag &t) const {
    00183     const DataElement r(t);
    00184     //ConstIterator it = DES.find(r);
    00185     if( DES.find(r) != DES.end() )
    00186       {
    00187       return true;
    00188       }
    00189     return false;
    00190     }
    00191
    00192   // WARNING:
    00193   // This only search at the same level as the DataSet is !
    00194   const DataElement& FindNextDataElement(const Tag &t) const {
    00195     const DataElement r(t);
    00196     ConstIterator it = DES.lower_bound(r);
    00197     if( it != DES.end() )
    00198       return *it;
    00199     return GetDEEnd();
    00200     }
    00201
    00203   bool IsEmpty() const { return DES.empty(); };
    00204
    00205   DataSet& operator=(DataSet const &val)
    00206   {
    00207     DES = val.DES;
    00208     return *this;
    00209   }
    00210
    00211 /*
    00212   template <typename TOperation>
    00213   void ExecuteOperation(TOperation & operation) {
    00214     assert( !DES.empty() );
    00215     DataElementSet::iterator it = Begin();
    00216     for( ; it != End(); ++it)
    00217       {
    00218       DataElement &de = (DataElement&)*it;
    00219       operation( de );
    00220       }
    00221   }
    00222 */
    00223
    00224   template <typename TDE, typename TSwap>
    00225   std::istream &ReadNested(std::istream &is);
    00226
    00227   template <typename TDE, typename TSwap>
    00228   std::istream &Read(std::istream &is);
    00229
    00230   template <typename TDE, typename TSwap>
    00231   std::istream &ReadUpToTag(std::istream &is, const Tag &t, std::set<Tag> const & skiptags);
    00232
    00233   template <typename TDE, typename TSwap>
    00234   std::istream &ReadUpToTagWithLength(std::istream &is, const Tag &t, VL & length);
    00235
    00236   template <typename TDE, typename TSwap>
    00237   std::ostream const &Write(std::ostream &os) const;
    00238
    00239   template <typename TDE, typename TSwap>
    00240   std::istream &ReadWithLength(std::istream &is, VL &length);
    00241
    00242 protected:
    00243   /* GetDEEnd is a Win32 only issue, one cannot use a dllexported
    00244    * static member data in an inline function, otherwise symbol
    00245    * will get reported as missing in any dll using the inlined function
    00246    */
    00247   const DataElement& GetDEEnd() const;
    00248
    00249   // This function is not safe, it does not check for the value of the tag
    00250   // so depending whether we are getting called from a dataset or file meta header
    00251   // the condition is different
    00252   void InsertDataElement(const DataElement& de) {
    00253     //if( de.GetTag() == Tag(0xfffe,0xe00d) ) return;
    00254     //if( de.GetTag() == Tag(0xfffe,0xe0dd) ) return;
    00255     std::pair<Iterator,bool> pr = DES.insert(de);
    00256 #ifndef NDEBUG
    00257     if( pr.second == false )
    00258       {
    00259       gdcmWarningMacro( "DataElement: " << de << " was already found, skipping duplicate entry.\n"
    00260         "Original entry kept is: " << *pr.first );
    00261       }
    00262 #endif
    00263     }
    00264
    00265 protected:
    00266   // Internal function, that will compute the actual Tag (if found) of
    00267   // a requested Private Tag (XXXX,YY,"PRIVATE")
    00268   Tag ComputeDataElement(const PrivateTag & t) const;
    00269
    00270 private:
    00271   DataElementSet DES;
    00272   static DataElement DEEnd;
    00273   friend std::ostream& operator<<(std::ostream &_os, const DataSet &val);
    00274 };
    00275 //-----------------------------------------------------------------------------
    00276 inline std::ostream& operator<<(std::ostream &os, const DataSet &val)
    00277 {
    00278   val.Print(os);
    00279   return os;
    00280 }
    00281
    00282 #if defined(SWIGPYTHON) || defined(SWIGCSHARP) || defined(SWIGJAVA)
    00283 /*
    00284  * HACK: I need this temp class to be able to manipulate a std::set from python,
    00285  * swig does not support wrapping of simple class like std::set...
    00286  */
    00287 class SWIGDataSet
    00288 {
    00289 public:
    00290   SWIGDataSet(DataSet &des):Internal(des),it(des.Begin()) {}
    00291   const DataElement& GetCurrent() const { return *it; }
    00292   void Start() { it = Internal.Begin(); }
    00293   bool IsAtEnd() const { return it == Internal.End(); }
    00294   void Next() { ++it; }
    00295 private:
    00296   DataSet & Internal;
    00297   DataSet::ConstIterator it;
    00298 };
    00299 #endif /* SWIG */
    00300
    00306 } // end namespace gdcm
    00307
    00308 #include "gdcmDataSet.txx"
    00309
    00310 #endif //__gdcmDataSet_h
    00311