GDCM 2.2.1

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

- File List
- File Members

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;
54 class GDCM_EXPORT DataSet
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;
319 DataSet::ConstIterator it;
320 };
321 #endif /* SWIG */
322
328 } // end namespace gdcm
329
330 #include "gdcmDataSet.txx"
331
332 #endif //GDCMDATASET_H