GDCM 2.2.0

- Main Page
- Related Pages
- Namespaces
- Classes
- Files
- Directories
- Examples

- File List
- File Members

gdcmDataSet.h
Go to the documentation of this file.

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