GDCM  2.2.0
gdcmDataSet.h
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: GDCM (Grassroots DICOM). A DICOM library
4 
5  Copyright (c) 2006-2011 Mathieu Malaterre
6  All rights reserved.
7  See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
8 
9  This software is distributed WITHOUT ANY WARRANTY; without even
10  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11  PURPOSE. See the above copyright notice for more information.
12 
13 =========================================================================*/
14 #ifndef GDCMDATASET_H
15 #define GDCMDATASET_H
16 
17 #include "gdcmDataElement.h"
18 #include "gdcmTag.h"
19 #include "gdcmVR.h"
20 #include "gdcmElement.h"
21 
22 #include <set>
23 #include <iterator>
24 
25 namespace gdcm
26 {
27 class GDCM_EXPORT DataElementException : public std::exception {};
28 
29 class PrivateTag;
55 {
56  friend class CSAHeader;
57 public:
58  typedef std::set<DataElement> DataElementSet;
59  typedef DataElementSet::const_iterator ConstIterator;
60  typedef DataElementSet::iterator Iterator;
61  typedef DataElementSet::size_type SizeType;
62  //typedef typename DataElementSet::iterator iterator;
63  ConstIterator Begin() const { return DES.begin(); }
64  Iterator Begin() { return DES.begin(); }
65  ConstIterator End() const { return DES.end(); }
66  Iterator End() { return DES.end(); }
67  const DataElementSet &GetDES() const { return DES; }
68  DataElementSet &GetDES() { return DES; }
69  void Clear() {
70  DES.clear();
71  assert( DES.empty() );
72  }
73 
74  SizeType Size() const {
75  return DES.size();
76  }
77 
78  void Print(std::ostream &os, std::string const &indent = "") const {
79  // CT_Phillips_JPEG2K_Decompr_Problem.dcm has a SQ of length == 0
80  //int s = DES.size();
81  //assert( s );
82  //std::copy(DES.begin(), DES.end(),
83  // std::ostream_iterator<DataElement>(os, "\n"));
84  ConstIterator it = DES.begin();
85  for( ; it != DES.end(); ++it)
86  {
87  os << indent << *it << "\n";
88  }
89  }
90 
91  template <typename TDE>
92  unsigned int ComputeGroupLength(Tag const &tag) const
93  {
94  assert( tag.GetElement() == 0x0 );
95  const DataElement r(tag);
96  ConstIterator it = DES.find(r);
97  unsigned int res = 0;
98  for( ++it; it != DES.end()
99  && it->GetTag().GetGroup() == tag.GetGroup(); ++it)
100  {
101  assert( it->GetTag().GetElement() != 0x0 );
102  assert( it->GetTag().GetGroup() == tag.GetGroup() );
103  res += it->GetLength<TDE>();
104  }
105  return res;
106  }
107 
108  template <typename TDE>
109  VL GetLength() const {
110  if( DES.empty() ) return 0;
111  assert( !DES.empty() );
112  VL ll = 0;
113  assert( ll == 0 );
114  ConstIterator it = DES.begin();
115  for( ; it != DES.end(); ++it)
116  {
117  assert( !(it->GetLength<TDE>().IsUndefined()) );
118  if ( it->GetTag() != Tag(0xfffe,0xe00d) )
119  {
120  ll += it->GetLength<TDE>();
121  }
122  }
123  return ll;
124  }
127  void Insert(const DataElement& de) {
128  // FIXME: there is a special case where a dataset can have value < 0x8, see:
129  // $ gdcmdump --csa gdcmData/SIEMENS-JPEG-CorruptFrag.dcm
130  if( de.GetTag().GetGroup() >= 0x0008 || de.GetTag().GetGroup() == 0x4 )
131  {
132  // prevent user error:
133  if( de.GetTag() == Tag(0xfffe,0xe00d)
134  || de.GetTag() == Tag(0xfffe,0xe0dd)
135  || de.GetTag() == Tag(0xfffe,0xe000) )
136  {
137  }
138  else
139  {
140  InsertDataElement( de );
141  }
142  }
143  else
144  {
145  gdcmErrorMacro( "Cannot add element with group < 0x0008 and != 0x4 in the dataset: " << de.GetTag() );
146  }
147  }
149  void Replace(const DataElement& de) {
150  if( DES.find(de) != DES.end() ) DES.erase(de);
151  Insert(de);
152  }
154  void ReplaceEmpty(const DataElement& de) {
155  ConstIterator it = DES.find(de);
156  if( it != DES.end() && it->IsEmpty() )
157  DES.erase(de);
158  Insert(de);
159  }
161  SizeType Remove(const Tag& tag) {
162  DataElementSet::size_type count = DES.erase(tag);
163  assert( count == 0 || count == 1 );
164  return count;
165  }
166 
170  //DataElement& GetDataElement(const Tag &t) {
171  // DataElement r(t);
172  // Iterator it = DES.find(r);
173  // if( it != DES.end() )
174  // return *it;
175  // return GetDEEnd();
176  // }
177  const DataElement& GetDataElement(const Tag &t) const {
178  const DataElement r(t);
179  ConstIterator it = DES.find(r);
180  if( it != DES.end() )
181  return *it;
182  return GetDEEnd();
183  }
184  const DataElement& operator[] (const Tag &t) const { return GetDataElement(t); }
185  const DataElement& operator() (uint16_t group, uint16_t element) const { return GetDataElement( Tag(group,element) ); }
186 
188  std::string GetPrivateCreator(const Tag &t) const;
189 
191  bool FindDataElement(const PrivateTag &t) const;
193  const DataElement& GetDataElement(const PrivateTag &t) const;
194 
195  // DUMB: this only search within the level of the current DataSet
196  bool FindDataElement(const Tag &t) const {
197  const DataElement r(t);
198  //ConstIterator it = DES.find(r);
199  if( DES.find(r) != DES.end() )
200  {
201  return true;
202  }
203  return false;
204  }
205 
206  // WARNING:
207  // This only search at the same level as the DataSet is !
208  const DataElement& FindNextDataElement(const Tag &t) const {
209  const DataElement r(t);
210  ConstIterator it = DES.lower_bound(r);
211  if( it != DES.end() )
212  return *it;
213  return GetDEEnd();
214  }
215 
217  bool IsEmpty() const { return DES.empty(); };
218 
219  DataSet& operator=(DataSet const &val)
220  {
221  DES = val.DES;
222  return *this;
223  }
224 
225 /*
226  template <typename TOperation>
227  void ExecuteOperation(TOperation & operation) {
228  assert( !DES.empty() );
229  DataElementSet::iterator it = Begin();
230  for( ; it != End(); ++it)
231  {
232  DataElement &de = (DataElement&)*it;
233  operation( de );
234  }
235  }
236 */
237 
238  template <typename TDE, typename TSwap>
239  std::istream &ReadNested(std::istream &is);
240 
241  template <typename TDE, typename TSwap>
242  std::istream &Read(std::istream &is);
243 
244  template <typename TDE, typename TSwap>
245  std::istream &ReadUpToTag(std::istream &is, const Tag &t, std::set<Tag> const & skiptags);
246 
247  template <typename TDE, typename TSwap>
248  std::istream &ReadUpToTagWithLength(std::istream &is, const Tag &t, VL & length);
249 
250  template <typename TDE, typename TSwap>
251  std::istream &ReadSelectedTags(std::istream &is, const std::set<Tag> & tags);
252  template <typename TDE, typename TSwap>
253  std::istream &ReadSelectedTagsWithLength(std::istream &is, const std::set<Tag> & tags, VL & length);
254 
255  template <typename TDE, typename TSwap>
256  std::ostream const &Write(std::ostream &os) const;
257 
258  template <typename TDE, typename TSwap>
259  std::istream &ReadWithLength(std::istream &is, VL &length);
260 
261 protected:
262  /* GetDEEnd is a Win32 only issue, one cannot use a dllexported
263  * static member data in an inline function, otherwise symbol
264  * will get reported as missing in any dll using the inlined function
265  */
266  const DataElement& GetDEEnd() const;
267 
268  // This function is not safe, it does not check for the value of the tag
269  // so depending whether we are getting called from a dataset or file meta header
270  // the condition is different
271  void InsertDataElement(const DataElement& de) {
272  //if( de.GetTag() == Tag(0xfffe,0xe00d) ) return;
273  //if( de.GetTag() == Tag(0xfffe,0xe0dd) ) return;
274 #ifndef NDEBUG
275  std::pair<Iterator,bool> pr = DES.insert(de);
276  if( pr.second == false )
277  {
278  gdcmWarningMacro( "DataElement: " << de << " was already found, skipping duplicate entry.\n"
279  "Original entry kept is: " << *pr.first );
280  }
281 #else
282  DES.insert(de);
283 #endif
284  assert( de.IsEmpty() || de.GetVL() == de.GetValue().GetLength() );
285  }
286 
287 protected:
288  // Internal function, that will compute the actual Tag (if found) of
289  // a requested Private Tag (XXXX,YY,"PRIVATE")
290  Tag ComputeDataElement(const PrivateTag & t) const;
291 
292 private:
293  DataElementSet DES;
294  static DataElement DEEnd;
295  friend std::ostream& operator<<(std::ostream &_os, const DataSet &val);
296 };
297 //-----------------------------------------------------------------------------
298 inline std::ostream& operator<<(std::ostream &os, const DataSet &val)
299 {
300  val.Print(os);
301  return os;
302 }
303 
304 #if defined(SWIGPYTHON) || defined(SWIGCSHARP) || defined(SWIGJAVA)
305 /*
306  * HACK: I need this temp class to be able to manipulate a std::set from python,
307  * swig does not support wrapping of simple class like std::set...
308  */
309 class SWIGDataSet
310 {
311 public:
312  SWIGDataSet(DataSet &des):Internal(des),it(des.Begin()) {}
313  const DataElement& GetCurrent() const { return *it; }
314  void Start() { it = Internal.Begin(); }
315  bool IsAtEnd() const { return it == Internal.End(); }
316  void Next() { ++it; }
317 private:
318  DataSet & Internal;
320 };
321 #endif /* SWIG */
322 
328 } // end namespace gdcm
329 
330 #include "gdcmDataSet.txx"
331 
332 #endif //GDCMDATASET_H

Generated on Wed Jun 13 2012 20:40:37 for GDCM by doxygen 1.8.1
SourceForge.net Logo