GDCM
2.0.18
|
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