GDCM 2.0.17
|
00001 /*========================================================================= 00002 00003 Program: GDCM (Grassroots DICOM). A DICOM library 00004 Module: $URL$ 00005 00006 Copyright (c) 2006-2010 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 SizeType 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 // prevent user error: 00135 if( de.GetTag() == Tag(0xfffe,0xe00d) 00136 || de.GetTag() == Tag(0xfffe,0xe0dd) 00137 || de.GetTag() == Tag(0xfffe,0xe000) ) 00138 { 00139 } 00140 else 00141 { 00142 InsertDataElement( de ); 00143 } 00144 } 00145 else 00146 { 00147 gdcmErrorMacro( "Cannot add element with group < 0x0008 and != 0x4 in the dataset: " << de.GetTag() ); 00148 } 00149 } 00151 void Replace(const DataElement& de) { 00152 if( DES.find(de) != DES.end() ) DES.erase(de); 00153 Insert(de); 00154 } 00156 void ReplaceEmpty(const DataElement& de) { 00157 ConstIterator it = DES.find(de); 00158 if( it != DES.end() && it->IsEmpty() ) 00159 DES.erase(de); 00160 Insert(de); 00161 } 00163 SizeType Remove(const Tag& tag) { 00164 DataElementSet::size_type count = DES.erase(tag); 00165 assert( count == 0 || count == 1 ); 00166 return count; 00167 } 00168 00172 //DataElement& GetDataElement(const Tag &t) { 00173 // DataElement r(t); 00174 // Iterator it = DES.find(r); 00175 // if( it != DES.end() ) 00176 // return *it; 00177 // return GetDEEnd(); 00178 // } 00179 const DataElement& GetDataElement(const Tag &t) const { 00180 const DataElement r(t); 00181 ConstIterator it = DES.find(r); 00182 if( it != DES.end() ) 00183 return *it; 00184 return GetDEEnd(); 00185 } 00186 const DataElement& operator[] (const Tag &t) const { return GetDataElement(t); } 00187 const DataElement& operator() (uint16_t group, uint16_t element) const { return GetDataElement( Tag(group,element) ); } 00188 00190 std::string GetPrivateCreator(const Tag &t) const; 00191 00193 bool FindDataElement(const PrivateTag &t) const; 00195 const DataElement& GetDataElement(const PrivateTag &t) const; 00196 00197 // DUMB: this only search within the level of the current DataSet 00198 bool FindDataElement(const Tag &t) const { 00199 const DataElement r(t); 00200 //ConstIterator it = DES.find(r); 00201 if( DES.find(r) != DES.end() ) 00202 { 00203 return true; 00204 } 00205 return false; 00206 } 00207 00208 // WARNING: 00209 // This only search at the same level as the DataSet is ! 00210 const DataElement& FindNextDataElement(const Tag &t) const { 00211 const DataElement r(t); 00212 ConstIterator it = DES.lower_bound(r); 00213 if( it != DES.end() ) 00214 return *it; 00215 return GetDEEnd(); 00216 } 00217 00219 bool IsEmpty() const { return DES.empty(); }; 00220 00221 DataSet& operator=(DataSet const &val) 00222 { 00223 DES = val.DES; 00224 return *this; 00225 } 00226 00227 /* 00228 template <typename TOperation> 00229 void ExecuteOperation(TOperation & operation) { 00230 assert( !DES.empty() ); 00231 DataElementSet::iterator it = Begin(); 00232 for( ; it != End(); ++it) 00233 { 00234 DataElement &de = (DataElement&)*it; 00235 operation( de ); 00236 } 00237 } 00238 */ 00239 00240 template <typename TDE, typename TSwap> 00241 std::istream &ReadNested(std::istream &is); 00242 00243 template <typename TDE, typename TSwap> 00244 std::istream &Read(std::istream &is); 00245 00246 template <typename TDE, typename TSwap> 00247 std::istream &ReadUpToTag(std::istream &is, const Tag &t, std::set<Tag> const & skiptags); 00248 00249 template <typename TDE, typename TSwap> 00250 std::istream &ReadUpToTagWithLength(std::istream &is, const Tag &t, VL & length); 00251 00252 template <typename TDE, typename TSwap> 00253 std::istream &ReadSelectedTags(std::istream &is, const std::set<Tag> & tags); 00254 template <typename TDE, typename TSwap> 00255 std::istream &ReadSelectedTagsWithLength(std::istream &is, const std::set<Tag> & tags, VL & length); 00256 00257 template <typename TDE, typename TSwap> 00258 std::ostream const &Write(std::ostream &os) const; 00259 00260 template <typename TDE, typename TSwap> 00261 std::istream &ReadWithLength(std::istream &is, VL &length); 00262 00263 protected: 00264 /* GetDEEnd is a Win32 only issue, one cannot use a dllexported 00265 * static member data in an inline function, otherwise symbol 00266 * will get reported as missing in any dll using the inlined function 00267 */ 00268 const DataElement& GetDEEnd() const; 00269 00270 // This function is not safe, it does not check for the value of the tag 00271 // so depending whether we are getting called from a dataset or file meta header 00272 // the condition is different 00273 void InsertDataElement(const DataElement& de) { 00274 //if( de.GetTag() == Tag(0xfffe,0xe00d) ) return; 00275 //if( de.GetTag() == Tag(0xfffe,0xe0dd) ) return; 00276 std::pair<Iterator,bool> pr = DES.insert(de); 00277 #ifndef NDEBUG 00278 if( pr.second == false ) 00279 { 00280 gdcmWarningMacro( "DataElement: " << de << " was already found, skipping duplicate entry.\n" 00281 "Original entry kept is: " << *pr.first ); 00282 } 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