GDCM 3.0.24
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#include "gdcmMediaStorage.h"
22
23#include <set>
24#include <iterator>
25
26namespace gdcm_ns
27{
28class GDCM_EXPORT DataElementException : public std::exception {};
29
30class PrivateTag;
56{
57 friend class CSAHeader;
58public:
59 typedef std::set<DataElement> DataElementSet;
60 typedef DataElementSet::const_iterator ConstIterator;
61 typedef DataElementSet::iterator Iterator;
62 typedef DataElementSet::size_type SizeType;
63 //typedef typename DataElementSet::iterator iterator;
64 ConstIterator Begin() const { return DES.begin(); }
65 Iterator Begin() { return DES.begin(); }
66 ConstIterator End() const { return DES.end(); }
67 Iterator End() { return DES.end(); }
68 const DataElementSet &GetDES() const { return DES; }
69 DataElementSet &GetDES() { return DES; }
70 void Clear() {
71 DES.clear();
72 assert( DES.empty() );
73 }
74
75 SizeType Size() const {
76 return DES.size();
77 }
78
79 void Print(std::ostream &os, std::string const &indent = "") const {
80 // CT_Phillips_JPEG2K_Decompr_Problem.dcm has a SQ of length == 0
81 //int s = DES.size();
82 //assert( s );
83 //std::copy(DES.begin(), DES.end(),
84 // std::ostream_iterator<DataElement>(os, "\n"));
85 ConstIterator it = DES.begin();
86 for( ; it != DES.end(); ++it)
87 {
88 os << indent << *it << "\n";
89 }
90 }
91
92 template <typename TDE>
93 unsigned int ComputeGroupLength(Tag const &tag) const
94 {
95 assert( tag.GetElement() == 0x0 );
96 const DataElement r(tag);
97 ConstIterator it = DES.find(r);
98 unsigned int res = 0;
99 for( ++it; it != DES.end()
100 && it->GetTag().GetGroup() == tag.GetGroup(); ++it)
101 {
102 assert( it->GetTag().GetElement() != 0x0 );
103 assert( it->GetTag().GetGroup() == tag.GetGroup() );
104 res += it->GetLength<TDE>();
105 }
106 return res;
107 }
108
109 template <typename TDE>
110 VL GetLength() const {
111 if( DES.empty() ) return 0;
112 assert( !DES.empty() );
113 VL ll = 0;
114 assert( ll == 0 );
115 ConstIterator it = DES.begin();
116 for( ; it != DES.end(); ++it)
117 {
118 assert( !(it->GetLength<TDE>().IsUndefined()) );
119 if ( it->GetTag() != Tag(0xfffe,0xe00d) )
120 {
121 ll += it->GetLength<TDE>();
122 }
123 }
124 return ll;
125 }
128 void Insert(const DataElement& de) {
129 // FIXME: there is a special case where a dataset can have value < 0x8, see:
130 // $ gdcmdump --csa gdcmData/SIEMENS-JPEG-CorruptFrag.dcm
131 if( de.GetTag().GetGroup() >= 0x0008 || de.GetTag().GetGroup() == 0x4 )
132 {
133 // prevent user error:
134 if( de.GetTag() == Tag(0xfffe,0xe00d)
135 || de.GetTag() == Tag(0xfffe,0xe0dd)
136 || de.GetTag() == Tag(0xfffe,0xe000) )
137 {
138 }
139 else
140 {
141 InsertDataElement( de );
142 }
143 }
144 else
145 {
146 gdcmErrorMacro( "Cannot add element with group < 0x0008 and != 0x4 in the dataset: " << de.GetTag() );
147 }
148 }
150 void Replace(const DataElement& de) {
151 ConstIterator it = DES.find(de);
152 if( it != DES.end() )
153 {
154 // detect loop:
155 gdcmAssertAlwaysMacro( &*it != &de );
156 DES.erase(it);
157 }
158 DES.insert(de);
159 }
161 void ReplaceEmpty(const DataElement& de) {
162 ConstIterator it = DES.find(de);
163 if( it != DES.end() && it->IsEmpty() )
164 {
165 // detect loop:
166 gdcmAssertAlwaysMacro( &*it != &de );
167 DES.erase(it);
168 }
169 DES.insert(de);
170 }
172 SizeType Remove(const Tag& tag) {
173 DataElementSet::size_type count = DES.erase(tag);
174 assert( count == 0 || count == 1 );
175 return count;
176 }
177
181 //DataElement& GetDataElement(const Tag &t) {
182 // DataElement r(t);
183 // Iterator it = DES.find(r);
184 // if( it != DES.end() )
185 // return *it;
186 // return GetDEEnd();
187 // }
188 const DataElement& GetDataElement(const Tag &t) const {
189 const DataElement r(t);
190 ConstIterator it = DES.find(r);
191 if( it != DES.end() )
192 return *it;
193 return GetDEEnd();
194 }
195 const DataElement& operator[] (const Tag &t) const { return GetDataElement(t); }
196 const DataElement& operator() (uint16_t group, uint16_t element) const { return GetDataElement( Tag(group,element) ); }
197
200 std::string GetPrivateCreator(const Tag &t) const;
201
203 PrivateTag GetPrivateTag(const Tag &t) const;
204
206 bool FindDataElement(const PrivateTag &t) const;
208 const DataElement& GetDataElement(const PrivateTag &t) const;
209
210 // DUMB: this only search within the level of the current DataSet
211 bool FindDataElement(const Tag &t) const {
212 const auto it = GetDataElement(t);
213 // Return if tag is found
214 return it != GetDEEnd();
215 }
216
217 // WARNING:
218 // This only search at the same level as the DataSet is !
219 const DataElement& FindNextDataElement(const Tag &t) const {
220 const DataElement r(t);
221 ConstIterator it = DES.lower_bound(r);
222 if( it != DES.end() )
223 return *it;
224 return GetDEEnd();
225 }
226
228 bool IsEmpty() const { return DES.empty(); }
229
231 = default;
232
233 template <typename TDE, typename TSwap>
234 std::istream &ReadNested(std::istream &is);
235
236 template <typename TDE, typename TSwap>
237 std::istream &Read(std::istream &is);
238
239 template <typename TDE, typename TSwap>
240 std::istream &ReadUpToTag(std::istream &is, const Tag &t, std::set<Tag> const & skiptags);
241
242 template <typename TDE, typename TSwap>
243 std::istream &ReadUpToTagWithLength(std::istream &is, const Tag &t, std::set<Tag> const & skiptags, VL & length);
244
245 template <typename TDE, typename TSwap>
246 std::istream &ReadSelectedTags(std::istream &is, const std::set<Tag> & tags, bool readvalues = true);
247 template <typename TDE, typename TSwap>
248 std::istream &ReadSelectedTagsWithLength(std::istream &is, const std::set<Tag> & tags, VL & length, bool readvalues = true);
249
250 template <typename TDE, typename TSwap>
251 std::istream &ReadSelectedPrivateTags(std::istream &is, const std::set<PrivateTag> & tags, bool readvalues = true);
252 template <typename TDE, typename TSwap>
253 std::istream &ReadSelectedPrivateTagsWithLength(std::istream &is, const std::set<PrivateTag> & tags, VL & length, bool readvalues = true);
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
262
263protected:
264 /* GetDEEnd is a Win32 only issue, one cannot use a dllexported
265 * static member data in an inline function, otherwise symbol
266 * will get reported as missing in any dll using the inlined function
267 */
268 const DataElement& GetDEEnd() const;
269
270 // This function is not safe, it does not check for the value of the tag
271 // so depending whether we are getting called from a dataset or file meta header
272 // the condition is different
274 //if( de.GetTag() == Tag(0xfffe,0xe00d) ) return;
275 //if( de.GetTag() == Tag(0xfffe,0xe0dd) ) return;
276#ifndef NDEBUG
277 std::pair<Iterator,bool> pr = DES.insert(de);
278 if( pr.second == false )
279 {
280 gdcmWarningMacro( "DataElement: " << de << " was already found, skipping duplicate entry.\n"
281 "Original entry kept is: " << *pr.first );
282 }
283#else
284 DES.insert(de);
285#endif
286 assert( de.IsEmpty() || de.GetVL() == de.GetValue().GetLength() );
287 }
288
289protected:
290 // Internal function, that will compute the actual Tag (if found) of
291 // a requested Private Tag (XXXX,YY,"PRIVATE")
293
294private:
295 DataElementSet DES;
296 static DataElement DEEnd;
297 friend std::ostream& operator<<(std::ostream &_os, const DataSet &);
298};
299//-----------------------------------------------------------------------------
300inline std::ostream& operator<<(std::ostream &os, const DataSet &val)
301{
302 val.Print(os);
303 return os;
304}
305
306#if defined(SWIGPYTHON) || defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPHP)
307/*
308 * HACK: I need this temp class to be able to manipulate a std::set from python,
309 * swig does not support wrapping of simple class like std::set...
310 */
311class SWIGDataSet
312{
313public:
314 SWIGDataSet(DataSet &des):Internal(des),it(des.Begin()) {}
315 const DataElement& GetCurrent() const { return *it; }
316 void Start() { it = Internal.Begin(); }
317 bool IsAtEnd() const { return it == Internal.End(); }
318 void Next() { ++it; }
319private:
320 DataSet & Internal;
321 DataSet::ConstIterator it;
322};
323#endif /* SWIG */
324
330} // end namespace gdcm_ns
331
332#include "gdcmDataSet.txx"
333
334#endif //GDCMDATASET_H
Class for CSAHeader.
Definition gdcmCSAHeader.h:64
Definition gdcmDataSet.h:28
Class to represent a Data Element either Implicit or Explicit.
Definition gdcmDataElement.h:59
const VL & GetVL() const
Get VL.
Definition gdcmDataElement.h:74
const Tag & GetTag() const
Get Tag.
Definition gdcmDataElement.h:67
bool IsEmpty() const
Check if Data Element is empty.
Definition gdcmDataElement.h:106
Value const & GetValue() const
Set/Get Value (bytes array, SQ of items, SQ of fragments):
Definition gdcmDataElement.h:94
Class to represent a Data Set (which contains Data Elements)
Definition gdcmDataSet.h:56
DataElementSet::iterator Iterator
Definition gdcmDataSet.h:61
const DataElement & GetDataElement(const Tag &t) const
Definition gdcmDataSet.h:188
DataSet & operator=(DataSet const &)=default
void InsertDataElement(const DataElement &de)
Definition gdcmDataSet.h:273
Tag ComputeDataElement(const PrivateTag &t) const
std::istream & ReadSelectedTags(std::istream &is, const std::set< Tag > &tags, bool readvalues=true)
Iterator End()
Definition gdcmDataSet.h:67
PrivateTag GetPrivateTag(const Tag &t) const
Return the private tag of the private tag 't', private creator will be set to empty if not found.
void Clear()
Definition gdcmDataSet.h:70
const DataElement & FindNextDataElement(const Tag &t) const
Definition gdcmDataSet.h:219
void ReplaceEmpty(const DataElement &de)
Only replace a DICOM attribute when it is missing or empty.
Definition gdcmDataSet.h:161
bool FindDataElement(const PrivateTag &t) const
Look up if private tag 't' is present in the dataset:
MediaStorage GetMediaStorage() const
std::string GetPrivateCreator(const Tag &t) const
DataElementSet::const_iterator ConstIterator
Definition gdcmDataSet.h:60
const DataElementSet & GetDES() const
Definition gdcmDataSet.h:68
bool IsEmpty() const
Returns if the dataset is empty.
Definition gdcmDataSet.h:228
std::istream & Read(std::istream &is)
SizeType Remove(const Tag &tag)
Completely remove a dataelement from the dataset.
Definition gdcmDataSet.h:172
const DataElement & GetDataElement(const PrivateTag &t) const
Return the dataelement.
std::istream & ReadNested(std::istream &is)
DataElementSet::size_type SizeType
Definition gdcmDataSet.h:62
std::istream & ReadSelectedPrivateTags(std::istream &is, const std::set< PrivateTag > &tags, bool readvalues=true)
std::ostream const & Write(std::ostream &os) const
void Insert(const DataElement &de)
Definition gdcmDataSet.h:128
ConstIterator Begin() const
Definition gdcmDataSet.h:64
Iterator Begin()
Definition gdcmDataSet.h:65
std::istream & ReadSelectedTagsWithLength(std::istream &is, const std::set< Tag > &tags, VL &length, bool readvalues=true)
void Print(std::ostream &os, std::string const &indent="") const
Definition gdcmDataSet.h:79
std::set< DataElement > DataElementSet
Definition gdcmDataSet.h:59
VL GetLength() const
Definition gdcmDataSet.h:110
bool FindDataElement(const Tag &t) const
Definition gdcmDataSet.h:211
std::istream & ReadUpToTagWithLength(std::istream &is, const Tag &t, std::set< Tag > const &skiptags, VL &length)
SizeType Size() const
Definition gdcmDataSet.h:75
void Replace(const DataElement &de)
Replace a dataelement with another one.
Definition gdcmDataSet.h:150
unsigned int ComputeGroupLength(Tag const &tag) const
Definition gdcmDataSet.h:93
const DataElement & GetDEEnd() const
std::istream & ReadWithLength(std::istream &is, VL &length)
DataElementSet & GetDES()
Definition gdcmDataSet.h:69
std::istream & ReadUpToTag(std::istream &is, const Tag &t, std::set< Tag > const &skiptags)
std::istream & ReadSelectedPrivateTagsWithLength(std::istream &is, const std::set< PrivateTag > &tags, VL &length, bool readvalues=true)
ConstIterator End() const
Definition gdcmDataSet.h:66
MediaStorage.
Definition gdcmMediaStorage.h:44
Class to represent a Private DICOM Data Element (Attribute) Tag (Group, Element, Owner)
Definition gdcmPrivateTag.h:39
Class to represent a DICOM Data Element (Attribute) Tag (Group, Element).
Definition gdcmTag.h:39
uint16_t GetGroup() const
Returns the 'Group number' of the given Tag.
Definition gdcmTag.h:55
uint16_t GetElement() const
Returns the 'Element number' of the given Tag.
Definition gdcmTag.h:57
Value Length.
Definition gdcmVL.h:30
VL GetLength() const
Definition gdcmVL.h:68
virtual VL GetLength() const =0
#define gdcmAssertAlwaysMacro(arg)
AssertAlways.
Definition gdcmTrace.h:228
#define gdcmWarningMacro(msg)
Warning.
Definition gdcmTrace.h:142
#define gdcmErrorMacro(msg)
Error this is pretty bad, more than just warning It could mean lost of data, something not handle....
Definition gdcmTrace.h:165
#define GDCM_EXPORT
Definition gdcmWin32.h:34
std::ostream & operator<<(std::ostream &os, const Directory &d)
Definition gdcmDirectory.h:88