GDCM
2.2.3
|
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 #include "gdcmMediaStorage.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 if ( it->GetTag() != Tag(0xfffe,0xe00d) ) 00120 { 00121 ll += it->GetLength<TDE>(); 00122 } 00123 } 00124 return ll; 00125 } 00128 void Insert(const DataElement& de) { 00129 // FIXME: there is a special case where a dataset can have value < 0x8, see: 00130 // $ gdcmdump --csa gdcmData/SIEMENS-JPEG-CorruptFrag.dcm 00131 if( de.GetTag().GetGroup() >= 0x0008 || de.GetTag().GetGroup() == 0x4 ) 00132 { 00133 // prevent user error: 00134 if( de.GetTag() == Tag(0xfffe,0xe00d) 00135 || de.GetTag() == Tag(0xfffe,0xe0dd) 00136 || de.GetTag() == Tag(0xfffe,0xe000) ) 00137 { 00138 } 00139 else 00140 { 00141 InsertDataElement( de ); 00142 } 00143 } 00144 else 00145 { 00146 gdcmErrorMacro( "Cannot add element with group < 0x0008 and != 0x4 in the dataset: " << de.GetTag() ); 00147 } 00148 } 00150 void Replace(const DataElement& de) { 00151 if( DES.find(de) != DES.end() ) DES.erase(de); 00152 Insert(de); 00153 } 00155 void ReplaceEmpty(const DataElement& de) { 00156 ConstIterator it = DES.find(de); 00157 if( it != DES.end() && it->IsEmpty() ) 00158 DES.erase(de); 00159 Insert(de); 00160 } 00162 SizeType Remove(const Tag& tag) { 00163 DataElementSet::size_type count = DES.erase(tag); 00164 assert( count == 0 || count == 1 ); 00165 return count; 00166 } 00167 00171 //DataElement& GetDataElement(const Tag &t) { 00172 // DataElement r(t); 00173 // Iterator it = DES.find(r); 00174 // if( it != DES.end() ) 00175 // return *it; 00176 // return GetDEEnd(); 00177 // } 00178 const DataElement& GetDataElement(const Tag &t) const { 00179 const DataElement r(t); 00180 ConstIterator it = DES.find(r); 00181 if( it != DES.end() ) 00182 return *it; 00183 return GetDEEnd(); 00184 } 00185 const DataElement& operator[] (const Tag &t) const { return GetDataElement(t); } 00186 const DataElement& operator() (uint16_t group, uint16_t element) const { return GetDataElement( Tag(group,element) ); } 00187 00189 std::string GetPrivateCreator(const Tag &t) const; 00190 00192 bool FindDataElement(const PrivateTag &t) const; 00194 const DataElement& GetDataElement(const PrivateTag &t) const; 00195 00196 // DUMB: this only search within the level of the current DataSet 00197 bool FindDataElement(const Tag &t) const { 00198 const DataElement r(t); 00199 //ConstIterator it = DES.find(r); 00200 if( DES.find(r) != DES.end() ) 00201 { 00202 return true; 00203 } 00204 return false; 00205 } 00206 00207 // WARNING: 00208 // This only search at the same level as the DataSet is ! 00209 const DataElement& FindNextDataElement(const Tag &t) const { 00210 const DataElement r(t); 00211 ConstIterator it = DES.lower_bound(r); 00212 if( it != DES.end() ) 00213 return *it; 00214 return GetDEEnd(); 00215 } 00216 00218 bool IsEmpty() const { return DES.empty(); }; 00219 00220 DataSet& operator=(DataSet const &val) 00221 { 00222 DES = val.DES; 00223 return *this; 00224 } 00225 00226 /* 00227 template <typename TOperation> 00228 void ExecuteOperation(TOperation & operation) { 00229 assert( !DES.empty() ); 00230 DataElementSet::iterator it = Begin(); 00231 for( ; it != End(); ++it) 00232 { 00233 DataElement &de = (DataElement&)*it; 00234 operation( de ); 00235 } 00236 } 00237 */ 00238 00239 template <typename TDE, typename TSwap> 00240 std::istream &ReadNested(std::istream &is); 00241 00242 template <typename TDE, typename TSwap> 00243 std::istream &Read(std::istream &is); 00244 00245 template <typename TDE, typename TSwap> 00246 std::istream &ReadUpToTag(std::istream &is, const Tag &t, std::set<Tag> const & skiptags); 00247 00248 template <typename TDE, typename TSwap> 00249 std::istream &ReadUpToTagWithLength(std::istream &is, const Tag &t, VL & length); 00250 00251 template <typename TDE, typename TSwap> 00252 std::istream &ReadSelectedTags(std::istream &is, const std::set<Tag> & tags); 00253 template <typename TDE, typename TSwap> 00254 std::istream &ReadSelectedTagsWithLength(std::istream &is, const std::set<Tag> & tags, VL & length); 00255 00256 template <typename TDE, typename TSwap> 00257 std::ostream const &Write(std::ostream &os) const; 00258 00259 template <typename TDE, typename TSwap> 00260 std::istream &ReadWithLength(std::istream &is, VL &length); 00261 00262 MediaStorage GetMediaStorage() const; 00263 00264 protected: 00265 /* GetDEEnd is a Win32 only issue, one cannot use a dllexported 00266 * static member data in an inline function, otherwise symbol 00267 * will get reported as missing in any dll using the inlined function 00268 */ 00269 const DataElement& GetDEEnd() const; 00270 00271 // This function is not safe, it does not check for the value of the tag 00272 // so depending whether we are getting called from a dataset or file meta header 00273 // the condition is different 00274 void InsertDataElement(const DataElement& de) { 00275 //if( de.GetTag() == Tag(0xfffe,0xe00d) ) return; 00276 //if( de.GetTag() == Tag(0xfffe,0xe0dd) ) return; 00277 #ifndef NDEBUG 00278 std::pair<Iterator,bool> pr = DES.insert(de); 00279 if( pr.second == false ) 00280 { 00281 gdcmWarningMacro( "DataElement: " << de << " was already found, skipping duplicate entry.\n" 00282 "Original entry kept is: " << *pr.first ); 00283 } 00284 #else 00285 DES.insert(de); 00286 #endif 00287 assert( de.IsEmpty() || de.GetVL() == de.GetValue().GetLength() ); 00288 } 00289 00290 protected: 00291 // Internal function, that will compute the actual Tag (if found) of 00292 // a requested Private Tag (XXXX,YY,"PRIVATE") 00293 Tag ComputeDataElement(const PrivateTag & t) const; 00294 00295 private: 00296 DataElementSet DES; 00297 static DataElement DEEnd; 00298 friend std::ostream& operator<<(std::ostream &_os, const DataSet &val); 00299 }; 00300 //----------------------------------------------------------------------------- 00301 inline std::ostream& operator<<(std::ostream &os, const DataSet &val) 00302 { 00303 val.Print(os); 00304 return os; 00305 } 00306 00307 #if defined(SWIGPYTHON) || defined(SWIGCSHARP) || defined(SWIGJAVA) 00308 /* 00309 * HACK: I need this temp class to be able to manipulate a std::set from python, 00310 * swig does not support wrapping of simple class like std::set... 00311 */ 00312 class SWIGDataSet 00313 { 00314 public: 00315 SWIGDataSet(DataSet &des):Internal(des),it(des.Begin()) {} 00316 const DataElement& GetCurrent() const { return *it; } 00317 void Start() { it = Internal.Begin(); } 00318 bool IsAtEnd() const { return it == Internal.End(); } 00319 void Next() { ++it; } 00320 private: 00321 DataSet & Internal; 00322 DataSet::ConstIterator it; 00323 }; 00324 #endif /* SWIG */ 00325 00331 } // end namespace gdcm 00332 00333 #include "gdcmDataSet.txx" 00334 00335 #endif //GDCMDATASET_H