1 /*
2  *
3  *  Copyright (C) 1994-2020, OFFIS e.V.
4  *  All rights reserved.  See COPYRIGHT file for details.
5  *
6  *  This software and supporting documentation were developed by
7  *
8  *    OFFIS e.V.
9  *    R&D Division Health
10  *    Escherweg 2
11  *    D-26121 Oldenburg, Germany
12  *
13  *
14  *  Module:  dcmdata
15  *
16  *  Author:  Gerd Ehlers
17  *
18  *  Purpose:
19  *  This file contains the interface to routines which provide
20  *  DICOM object encoding/decoding, search and lookup facilities.
21  *
22  */
23 
24 
25 #ifndef DCOBJECT_H
26 #define DCOBJECT_H
27 
28 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
29 
30 #include "dcmtk/ofstd/ofglobal.h"
31 #include "dcmtk/dcmdata/dcerror.h"
32 #include "dcmtk/dcmdata/dcxfer.h"
33 #include "dcmtk/dcmdata/dctag.h"
34 #include "dcmtk/dcmdata/dcstack.h"
35 
36 
37 // forward declarations
38 class DcmItem;
39 class DcmJsonFormat;
40 class DcmOutputStream;
41 class DcmInputStream;
42 class DcmWriteCache;
43 class DcmSpecificCharacterSet;
44 
45 // include this file in doxygen documentation
46 
47 /** @file dcobject.h
48  *  @brief interface to DICOM object/dataset handling
49  */
50 
51 // Undefined Length Identifier now defined in dctypes.h
52 
53 // Maximum number of read bytes for a Value Element
54 const Uint32 DCM_MaxReadLength = 4096;
55 
56 // Maximum length of tag and length in a DICOM element
57 const Uint32 DCM_TagInfoLength = 12;
58 
59 // Optimum line length if not all data printed
60 const Uint32 DCM_OptPrintLineLength = 70;
61 
62 // Optimum value length if not all data printed
63 const Uint32 DCM_OptPrintValueLength = 40;
64 
65 // Optimum attribute name length (for tree output)
66 const Uint32 DCM_OptPrintAttributeNameLength = 35;
67 
68 /** This flags defines whether automatic correction should be applied to input
69  *  data (e.g.\ stripping of padding blanks, removal of blanks in UIDs, etc).
70  *  Default is enabled.
71  */
72 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmEnableAutomaticInputDataCorrection; /* default OFTrue */
73 
74 /** This flag defines the handling of illegal odd-length attributes: If flag is
75  *  true, odd lengths are respected (i.e.\ an odd number of bytes is read from
76  *  the input stream.) After successful reading, padding to even number of bytes
77  *  is enforced by adding a zero pad byte if dcmEnableAutomaticInputDataCorrection
78  *  is true. Otherwise the odd number of bytes remains as read.
79  *
80  *  If flag is false, old (pre DCMTK 3.5.2) behaviour applies: The length field
81  *  implicitly incremented and an even number of bytes is read from the stream.
82  */
83 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmAcceptOddAttributeLength; /* default OFTrue */
84 
85 /** This flag defines how UN attributes with undefined length are treated
86  *  by the parser when reading. The default is to expect the content of the
87  *  UN element (up to and including the sequence delimitation item)
88  *  to be encoded in Implicit VR Little Endian, as described in CP 246.
89  *  DCMTK expects the attribute to be encoded like a DICOM sequence, i.e.
90  *  the content of each item is parsed as a DICOM dataset.
91  *  If the flag is disabled old (pre DCMTK 3.5.4) behaviour applies: The
92  *  attribute is treated as if it was an Explicit VR SQ element.
93  *
94  *  Note that the flag only affects the read behaviour but not the write
95  *  behaviour - DCMTK will never write UN elements with undefined length.
96  */
97 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmEnableCP246Support; /* default OFTrue */
98 
99 /** DCMTK releases up to 3.5.3 created a non-conforming byte stream
100  *  as input to the MAC algorithm when creating or verifying digital signatures
101  *  including compressed pixel data (i.e.\ signatures including attribute
102  *  (7FE0,0010) in an encapsulated transfer syntax). This has been fixed
103  *  in DCMTK 3.5.4, but this flag allows to revert to the old behavior
104  *  in order to create or verify signatures that are compatible with older
105  *  releases. Default is "off" (OFFalse).
106  */
107 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmEnableOldSignatureFormat; /* default OFFalse */
108 
109 /** This flag defines whether the transfer syntax for uncompressed datasets
110  *  is detected automatically.  The automatic detection has been introduced
111  *  since there are (incorrectly encoded) DICOM dataset stored with a
112  *  different transfer syntax than specified in the meta header.
113  */
114 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmAutoDetectDatasetXfer; /* default OFFalse */
115 
116 /** This flag defines how non-standard VRs are treated by the parser when
117  *  reading. The default is to treat data element with non-standard VR as
118  *  unknown. If this flag is enabled, the parser will try to read the data
119  *  element with Implicit VR Little Endian transfer syntax.
120  */
121 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmAcceptUnexpectedImplicitEncoding; /* default OFFalse */
122 
123 /** This flag defines how the element's VR is treated by the parser when
124  *  reading from a dataset with explicit VR encoding. By default, the
125  *  VR from the dataset is used. If this flag is enabled and the VR of the
126  *  tag is defined in the data dictionary, the parser will use the VR from
127  *  the data dictionary (and ignore the one from the dataset). This flag is,
128  *  therefore, useful for reading incorrectly encoded DICOM datasets.
129  */
130 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmPreferVRFromDataDictionary; /* default OFFalse */
131 
132 /** This flag defines how the element's length field is interpreted when reading
133  *  from a dataset with explicit VR encoding and the data dictionary doesn't
134  *  agree with the VR from the dataset. By default, the length field is assumed
135  *  to match the size of the VR in the dataset. If this flag is enabled and the
136  *  tag is defined in the data dictionary, the parser will use the size for the
137  *  VR from the data dictionary (and ignore the one from the dataset). This flag
138  *  is, therefore, useful for reading incorrectly encoded DICOM datasets.
139  */
140 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmPreferLengthFieldSizeFromDataDictionary; /* default OFFalse */
141 
142 /** This flag indicates, whether private attributes with implicit transfer
143  *  syntax having a maximum length should be handled as sequences (ignoring
144  *  any dictionary entries for that tag). This can happen, if for example
145  *  a private creator element is illegally inserted with VR SQ
146  *  (undefined length and implicit coding). The parser usually would then
147  *  try to parse the element with VR=LO (private creator) with maximum
148  *  length, which would lead to an error. The default behaviour is to
149  *  rely on the dictionary.
150  */
151 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmReadImplPrivAttribMaxLengthAsSQ; /* default OFFalse */
152 
153 /** This flag indicates, whether parsing errors during reading
154  *  should be ignored, i.e.\ whether the parser should try to recover and
155  *  parse the rest of the stream.
156  *  This flag does not work for all parsing errors (at this time)
157  *  making sense but was introduced afterwards.
158  */
159 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmIgnoreParsingErrors; /* default OFFalse */
160 
161 /** This flag indicates, whether parsing should stop after a certain
162  *  element in the stream was parsed. This is especially useful for
163  *  datasets containing garbage at the end, usually after the Pixel
164  *  Data attribute. To prevent the parser for "stumbling" over that
165  *  garbage, it is possible to tell the parser to stop after a
166  *  specific element. The flag is only sensitive to elements on
167  *  dataset level, i.e. inside sequence any occurrence of the specified
168  *  tag is ignored. Caution: Note that if Pixel Data is chosen
169  *  as stop element, any attributes behind will not be parsed, e. g.
170  *  any digital signature attributes coming after.
171  *  Default is (0xffff,0xffff), which means that the feature is
172  *  disabled.
173  */
174 extern DCMTK_DCMDATA_EXPORT OFGlobal<DcmTagKey> dcmStopParsingAfterElement; /* default OFTrue */
175 
176 /** This flag influences behaviour when writing a dataset with items
177  *  and sequences set to be encoded with explicit length. It is possible
178  *  that the content of a sequence (or item) has an encoded length greater
179  *  than the maximum 32-bit value that can be written to the sequence (item)
180  *  length field. If this flag is enabled (OFTrue) then the encoding of the
181  *  very sequence (item) is switched to undefined length encoding. Any
182  *  contained items (sequences) will be encoded explicitly if possible.
183  *  Default is OFTrue, i.e. encoding is switched to implicit if maximum
184  *  size of length field is exceeded.
185  */
186 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmWriteOversizedSeqsAndItemsUndefined; /* default OFTrue */
187 
188 /** This flag allows for ignoring the value of (0002,0000) File Meta Information
189  *  Group Length which is useful in cases where this value is incorrect.  If the
190  *  header length is ignored, the behavior is identical to the case when no value
191  *  is available (i.e. all elements are read as long as the group number is 0x0002).
192  */
193 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmIgnoreFileMetaInformationGroupLength; /* default OFFalse */
194 
195 /** This flag enables the replacement of a wrong delimitation item at the end of
196  *  a sequence or item.  This is because there are incorrect systems that write
197  *  a Sequence Delimitation Item (fffe,e0dd) at the end of an item or an Item
198  *  Delimitation Item (fffe,e00d) at the end of a sequence.  By default, no
199  *  delimitation items are replaced.
200  */
201 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmReplaceWrongDelimitationItem; /* default OFFalse */
202 
203 /** This flag enables the "silent" conversion of illegal OB/OW elements
204  *  with undefined length (other than PixelData) to SQ elements while reading.
205  *  The default behaviour is to reject such elements with an error message.
206  */
207 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmConvertUndefinedLengthOBOWtoSQ; /* default OFFalse */
208 
209 /** This flag enables the "silent" conversion of incorrectly encoded
210  *  VOI LUT Sequence elements with VR=OW and explicit length into a sequence.
211  *  This incorrect encoding was detected "in the wild" in 2016.
212  */
213 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmConvertVOILUTSequenceOWtoSQ; /* default OFFalse */
214 
215 /** This flag influences the behaviour when reading Pixel Data elements.
216  *  Pixel Data in those top level datasets that are using a compression-enabled
217  *  Transfer Syntax (with few exceptions such as Deflated TS),
218  *  is being stored in an encapsulated way. That means DICOM requires that the
219  *  Pixel Data then element uses an undefined length and internally uses a
220  *  pseudo sequence structure called Pixel Sequence with Pixel items inside.
221  *  If this flag is set to OFFalse (default), an error is reported when reading
222  *  datasets with encapsulated Transfer Syntaxes but with Pixel Data being
223  *  stored using explicit length encoding.
224  *  If this flag is set to OFTrue, such an invalid Pixel Data encoding is
225  *  accepted and the element is read with the given length as if it would be the
226  *  case for datasets in uncompressed transfer syntaxes.
227  */
228 extern DCMTK_DCMDATA_EXPORT OFGlobal<OFBool> dcmUseExplLengthPixDataForEncTS; /* default OFFalse */
229 
230 /** Abstract base class for most classes in module dcmdata. As a rule of thumb,
231  *  everything that is either a dataset or that can be identified with a DICOM
232  *  attribute tag is derived from class DcmObject.
233  */
234 class DCMTK_DCMDATA_EXPORT DcmObject
235 {
236  public:
237 
238     /** constructor.
239      *  Create new object from given tag and length.
240      *  @param tag DICOM tag for the new element
241      *  @param len value length for the new element
242      */
243     DcmObject(const DcmTag &tag, const Uint32 len = 0);
244 
245     /** copy constructor
246      *  @param obj item to be copied
247      */
248     DcmObject(const DcmObject &obj);
249 
250     /// destructor
251     virtual ~DcmObject();
252 
253     /** clone method
254      *  @return deep copy of this object
255      */
256     virtual DcmObject *clone() const = 0;
257 
258     /** copy assignment operator
259      *  @param obj object to be copied
260      *  @return reference to this object
261      */
262     DcmObject &operator=(const DcmObject &obj);
263 
264     /** Virtual object copying. This method can be used for DcmObject
265      *  and derived classes to get a deep copy of an object. Internally
266      *  the assignment operator is called if the given DcmObject parameter
267      *  is of the same type as "this" object instance. If not, an error
268      *  is returned. This function permits copying an object by value
269      *  in a virtual way which therefore is different to just calling the
270      *  assignment operator of DcmElement which could result in slicing
271      *  the object.
272      *  @param rhs - [in] The instance to copy from. Has to be of the same
273      *                class type as "this" object
274      *  @return EC_Normal if copying was successful, error otherwise
275      */
276     virtual OFCondition copyFrom(const DcmObject &rhs) = 0;
277 
278     /** return identifier for this class. Every class derived from this class
279      *  returns a unique value of type enum DcmEVR for this call. This is used
280      *  as a "poor man's RTTI" to correctly identify instances derived from
281      *  this class even on compilers not supporting RTTI.
282      *  @return type identifier of this class
283      */
284     virtual DcmEVR ident() const = 0;
285 
286     /** return the value representation assigned to this object.
287      *  If object was read from a stream, this method returns the VR
288      *  that was defined in the stream for this object. It is, therefore,
289      *  possible that the VR does not match the one defined in the data
290      *  dictionary for the tag assigned to this object.
291      *  @return VR of this object
292      */
getVR()293     inline DcmEVR getVR() const { return Tag.getEVR(); }
294 
295     /** check if this element is a string type, based on the VR.
296      *  Since the check is based on the VR and not on the class,
297      *  the result of this method is not a guarantee that the object
298      *  can be safely casted to one of the string-VR subclasses.
299      *  @return true if this object is a string VR, false otherwise
300      */
isaString()301     inline OFBool isaString() const { return Tag.getVR().isaString(); }
302 
303     /** check if this element is a leaf node in a dataset tree.
304      *  All subclasses of DcmElement except for DcmSequenceOfItems
305      *  are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset etc.
306      *  are not.
307      *  @return true if leaf node, false otherwise
308      */
309     virtual OFBool isLeaf() const = 0;
310 
311     /** check if this element is nested in a sequence of items, i.e.\ not a
312      *  top-level or stand-alone element
313      *  @return true if this element is nested, false otherwise
314      */
315     virtual OFBool isNested() const;
316 
317     /** print object to a stream
318      *  @param out output stream
319      *  @param flags optional flag used to customize the output (see DCMTypes::PF_xxx)
320      *  @param level current level of nested items. Used for indentation.
321      *  @param pixelFileName not used (used in certain sub-classes of this class)
322      *  @param pixelCounter not used (used in certain sub-classes of this class)
323      */
324     virtual void print(STD_NAMESPACE ostream &out,
325                        const size_t flags = 0,
326                        const int level = 0,
327                        const char *pixelFileName = NULL,
328                        size_t *pixelCounter = NULL) = 0;
329 
330     /** return the current transfer (read/write) state of this object.
331      *  @return transfer state of this object
332      */
transferState()333     inline E_TransferState transferState() const { return fTransferState; }
334 
335     /** initialize the transfer state of this object. This method must be called
336      *  before this object is written to a stream or read (parsed) from a stream.
337      */
338     virtual void transferInit(void);
339 
340     /** finalize the transfer state of this object. This method must be called
341      *  when reading/writing this object from/to a stream has been completed.
342      */
343     virtual void transferEnd(void);
344 
345     /** get root dataset/item (top-level) that contains this object. Internally,
346      *  the list of parent pointers is followed in order to find the root. If
347      *  this object has no parent item, a pointer to this object is returned
348      *  instead.
349      *  @return pointer to the root dataset/item (might be NULL)
350      */
351     DcmItem *getRootItem();
352 
353     /** get parent item of this object. In case of a top-level element, this is
354      *  either the main dataset or the file meta-information. In case of a nested
355      *  element, this is the surrounding item.
356      *  @return pointer to the parent item of this object (might be NULL)
357      */
358     virtual DcmItem *getParentItem();
359 
360     /** get parent of this object. If this object is an element that has been
361      *  inserted into a dataset/item, the parent is this particular dataset/item.
362      *  If this object is an item that has been inserted into a sequence, the
363      *  parent is this particular sequence. If this object has not been inserted
364      *  into a dataset/item or sequence, NULL is returned.
365      *  @return pointer to the parent of this object (might be NULL)
366      */
getParent()367     inline DcmObject *getParent() { return Parent; }
368 
369     /** get parent of this object. If this object is an element that has been
370      *  inserted into a dataset/item, the parent is this particular dataset/item.
371      *  If this object is an item that has been inserted into a sequence, the
372      *  parent is this particular sequence. If this object has not been inserted
373      *  into a dataset/item or sequence, NULL is returned.
374      *  @return pointer to the parent of this object (might be NULL)
375      */
getParent()376     inline const DcmObject *getParent() const { return Parent; }
377 
378     /** set parent of this object. NULL means no parent.
379      *  NB: This method is used by derived classes for internal purposes only.
380      *  @param parent pointer to the parent of this object
381      */
setParent(DcmObject * parent)382     inline void setParent(DcmObject *parent) { Parent = parent; }
383 
384     /** return the group number of the attribute tag for this object
385      *  @return group number of the attribute tag for this object
386      */
getGTag()387     inline Uint16 getGTag() const { return Tag.getGTag(); }
388 
389     /** return the element number of the attribute tag for this object
390      *  @return element number of the attribute tag for this object
391      */
getETag()392     inline Uint16 getETag() const { return Tag.getETag(); }
393 
394     /** return const reference to the attribute tag for this object
395      *  @return const reference to the attribute tag for this object
396      */
getTag()397     inline const DcmTag &getTag() const { return Tag; }
398 
399     /** assign group tag (but not element tag) of the attribute tag for this object.
400      *  This is sometimes useful when creating repeating group elements.
401      *  @param gtag new attribute group tag
402      */
setGTag(Uint16 gtag)403     inline void setGTag(Uint16 gtag) { Tag.setGroup(gtag); }
404 
405     /** assign a new Value Representation (VR) to this object. This operation
406      *  is only supported for very few subclasses derived from this class,
407      *  in particular for classes handling pixel data which may either be
408      *  of OB or OW value representation.
409      *  @param vr value representation
410      *  @return EC_Normal if successful, an error code otherwise
411      */
setVR(DcmEVR)412     virtual OFCondition setVR(DcmEVR /*vr*/) { return EC_IllegalCall; }
413 
414     /** get value multiplicity of this object.
415      *  Please note that depending on the Value Representation (VR), subclasses
416      *  derived from this class either return the number of currently stored
417      *  values or the constant value 1 (as defined in the DICOM standard).
418      *  See getNumberOfValues(), which always returns the number of stored values.
419      *  @return value multiplicity of this object
420      */
421     virtual unsigned long getVM() = 0;
422 
423     /** get number of values stored in this object
424      *  @return number of values in this object
425      */
426     virtual unsigned long getNumberOfValues() = 0;
427 
428     /** calculate the length of this DICOM element when encoded with the
429      *  given transfer syntax and the given encoding type for sequences.
430      *  For elements, the length includes the length of the tag, length field,
431      *  VR field and the value itself, for items and sequences it returns
432      *  the length of the complete item or sequence including delimitation tags
433      *  if applicable.
434      *  @warning Since calcElementLength() returns a 32 bit integer, an
435      *    overflow during calculation is possible for some derived classes that
436      *    actually represent a compound value (e.g. items like DcmPixelItem).
437      *    Such overflows will be detected, in which case the maximum possible
438      *    value will be returned instead, coinciding with DCM_UndefinedLength.
439      *  @warning The implementation in DcmPixelData may return zero if no
440      *    conforming representation exists and set the
441      *    EC_RepresentationNotFound error flag to indicated it.
442      *  @warning When calculation the length of a sequence or an item
443      *    containing multiple attributes, the implementation may return
444      *    DCM_UndefinedLength to indicate a value that can not be encoded as
445      *    a 32 bit length field. It will even do so if
446      *    "dcmWriteOversizedSeqsAndItemsUndefined" is disabled, but then also
447      *    set the EC_SeqOrItemContentOverflow error flag (inside getLength())
448      *    to indicated it.
449      *  @note Just check for zero or DCM_UndefinedLength return value and then
450      *    have a look at the error flag in either case.
451      *  @param xfer transfer syntax for length calculation
452      *  @param enctype sequence encoding type for length calculation
453      *  @return length of DICOM element
454      */
455     virtual Uint32 calcElementLength(const E_TransferSyntax xfer,
456                                      const E_EncodingType enctype) = 0;
457 
458     /** calculate the value length (without attribute tag, VR and length field)
459      *  of this DICOM element when encoded with the given transfer syntax and
460      *  the given encoding type for sequences. Never returns undefined length.
461      *  @param xfer transfer syntax for length calculation
462      *  @param enctype sequence encoding type for length calculation
463      *  @return value length of DICOM element
464      */
465     virtual Uint32 getLength(const E_TransferSyntax xfer = EXS_LittleEndianImplicit,
466                              const E_EncodingType enctype = EET_UndefinedLength) = 0;
467 
468     /** check if this DICOM object can be encoded in the given transfer syntax.
469      *  @param newXfer transfer syntax in which the DICOM object is to be encoded
470      *  @param oldXfer transfer syntax in which the DICOM object was read or created.
471      *  @return true if object can be encoded in desired transfer syntax, false otherwise.
472      */
473     virtual OFBool canWriteXfer(const E_TransferSyntax newXfer,
474                                 const E_TransferSyntax oldXfer) = 0;
475 
476     /** read object from a stream.
477      *  @param inStream DICOM input stream
478      *  @param ixfer transfer syntax to use when parsing
479      *  @param glenc handling of group length parameters
480      *  @param maxReadLength attribute values larger than this value are skipped
481      *    while parsing and read later upon first access if the stream type supports
482      *    this.
483      *  @return EC_Normal if successful, an error code otherwise
484      */
485     virtual OFCondition read(DcmInputStream &inStream,
486                              const E_TransferSyntax ixfer,
487                              const E_GrpLenEncoding glenc = EGL_noChange,
488                              const Uint32 maxReadLength = DCM_MaxReadLength) = 0;
489 
490     /** write object to a stream (abstract)
491      *  @param outStream DICOM output stream
492      *  @param oxfer output transfer syntax
493      *  @param enctype encoding types (undefined or explicit length)
494      *  @param wcache pointer to write cache object, may be NULL
495      *  @return status, EC_Normal if successful, an error code otherwise
496      */
497     virtual OFCondition write(DcmOutputStream &outStream,
498                               const E_TransferSyntax oxfer,
499                               const E_EncodingType enctype,
500                               DcmWriteCache *wcache) = 0;
501 
502     /** write object in XML format to a stream
503      *  @param out output stream to which the XML document is written
504      *  @param flags optional flag used to customize the output (see DCMTypes::XF_xxx)
505      *  @return status, always returns EC_Illegal Call
506      */
507     virtual OFCondition writeXML(STD_NAMESPACE ostream &out,
508                                  const size_t flags = 0);
509 
510     /** write object in JSON format to a stream
511      *  @param out output stream to which the JSON document is written
512      *  @param format used to format and customize the output
513      *  @return status, always returns EC_Illegal Call
514      */
515     virtual OFCondition writeJson(STD_NAMESPACE ostream &out,
516                                   DcmJsonFormat &format);
517 
518     /** special write method for creation of digital signatures (abstract)
519      *  @param outStream DICOM output stream
520      *  @param oxfer output transfer syntax
521      *  @param enctype encoding types (undefined or explicit length)
522      *  @param wcache pointer to write cache object, may be NULL
523      *  @return status, EC_Normal if successful, an error code otherwise
524      */
525     virtual OFCondition writeSignatureFormat(DcmOutputStream &outStream,
526                                              const E_TransferSyntax oxfer,
527                                              const E_EncodingType enctype,
528                                              DcmWriteCache *wcache) = 0;
529 
530     /** returns true if the current object may be included in a digital signature
531      *  @return true if signable, false otherwise
532      */
533     virtual OFBool isSignable() const;
534 
535     /** returns true if the object contains an element with Unknown VR at any nesting level
536      *  @return true if the object contains an element with Unknown VR, false otherwise
537      */
538     virtual OFBool containsUnknownVR() const;
539 
540     /** check if this object contains non-ASCII characters
541      *  @param checkAllStrings not used in this class
542      *  @return always returns false, i.e. no extended characters used
543      */
544     virtual OFBool containsExtendedCharacters(const OFBool checkAllStrings = OFFalse);
545 
546     /** check if this object is affected by SpecificCharacterSet
547      *  @return always returns false, i.e. not affected by SpecificCharacterSet
548      */
549     virtual OFBool isAffectedBySpecificCharacterSet() const;
550 
551     /** convert this object from the currently selected source character set to the
552      *  currently selected destination character set (if affected by SpecificCharacterSet)
553      *  @param converter character set converter to be used to convert the element values
554      *  @return always returns EC_Normal, since there is nothing to do in this base class
555      */
556     virtual OFCondition convertCharacterSet(DcmSpecificCharacterSet &converter);
557 
558     /** check if this object is empty
559      *  @param normalize normalize value before checking (ignore non-significant characters)
560      *  @return true if object is empty, i.e. has no value, false otherwise
561      */
562     virtual OFBool isEmpty(const OFBool normalize = OFTrue);
563 
564     /** clear (remove) attribute value
565      *  @return EC_Normal if successful, an error code otherwise
566      */
567     virtual OFCondition clear() = 0;
568 
569     /** check the currently stored element value
570      *  @param autocorrect correct value length if OFTrue
571      *  @return status, EC_Normal if value length is correct, an error code otherwise
572      */
573     virtual OFCondition verify(const OFBool autocorrect = OFFalse) = 0;
574 
575     /** this method is only used in container classes derived from this class,
576      *  that is, DcmItem and DcmSequenceOfItems. It returns a pointer to the
577      *  next object in the list AFTER the given object. If the caller passes NULL,
578      *  a pointer to the first object in the list is returned. If the given object
579      *  is not found, the given object is the last one in the list or the list is empty,
580      *  NULL is returned.
581      *  @param obj pointer to one object in the container; we are looking for the
582      *    next entry after this one. NULL if looking for the first entry.
583      *  @return pointer to next object in container or NULL if not found
584      */
585     virtual DcmObject *nextInContainer(const DcmObject *obj);
586 
587     /** this method enables a stack based, depth-first traversal of a complete
588      *  hierarchical DICOM dataset (that is, classes derived from DcmItem or
589      *  DcmSequenceOfItems). With each call of this method, the next object
590      *  in the tree is located and marked on the stack.
591      *  @param stack "cursor" for current position in the dataset. The stack
592      *    will contain a pointer to each dataset, sequence, item and element
593      *    from the main dataset down to the current element, and is updated
594      *    upon each call to this method. An empty stack is equivalent to a stack
595      *    containing a pointer to this object only.
596      *  @param intoSub if true, the nextObject method will perform a hierarchical
597      *    search through the dataset (depth-first), if false, only the current
598      *    container object will be traversed (e.g., all elements of an item
599      *    or all items of a sequence).
600      *  @return EC_Normal if value length is correct, an error code otherwise
601      */
602     virtual OFCondition nextObject(DcmStack &stack,
603                                    const OFBool intoSub);
604 
605     /** a complex, stack-based, hierarchical search method. It allows for a search
606      *  for a DICOM object with a given attribute within a given container,
607      *  hierarchically, from a starting position identified through a cursor stack.
608      *  @param xtag the DICOM attribute tag we are searching for
609      *  @param resultStack Depending on the search mode (see below), this parameter
610      *     either serves as an input and output parameter, or as an output parameter
611      *     only (the latter being the default). When used as an input parameter,
612      *     the cursor stack defines the start position for the search within a
613      *     hierarchical DICOM dataset. Upon successful return, the stack contains
614      *     the position of the element found, in the form of a pointer to each dataset,
615      *     sequence, item and element from the main dataset down to the found element.
616      *  @param mode search mode, controls how the search stack is handled.
617      *     In the default mode, ESM_fromHere, the stack is ignored on input, and
618      *     the search starts in the object for which this method is called.
619      *     In the other modes, the stack is used both as an input and an output
620      *     parameter and defines the starting point for the search.
621      *  @param searchIntoSub if true, the search will be performed hierarchically descending
622      *    into the sequences and items of the dataset. If false, only the current container
623      *    (sequence or item) will be traversed.
624      *  @return EC_Normal if found, EC_TagNotFound if not found, an error code is something went wrong.
625      */
626     virtual OFCondition search(const DcmTagKey &xtag,
627                                DcmStack &resultStack,
628                                E_SearchMode mode = ESM_fromHere,
629                                OFBool searchIntoSub = OFTrue);
630 
631     /** this method loads all attribute values maintained by this object and
632      *  all sub-objects (in case of a container such as DcmDataset) into memory.
633      *  After a call to this method, the file from which a dataset was read may safely
634      *  be deleted or replaced. For large files, this method may obviously allocate large
635      *  amounts of memory.
636      *  @return EC_Normal if successful, an error code otherwise
637      */
638     virtual OFCondition loadAllDataIntoMemory() = 0;
639 
640     /** return the current value of the Length field (which is different from the functionality
641      *  of the public getLength() method). Only needed for internal purposes and for checker tools
642      *  that verify values against the length field.
643      *  @return current value of length field
644      */
getLengthField()645     Uint32 getLengthField() const { return Length; }
646 
647  protected:
648 
649     /** print line indentation, e.g.\ a couple of spaces for each nesting level.
650      *  Depending on the value of 'flags' other visualizations are also possible.
651      *  @param out output stream
652      *  @param flags used to customize the output (see DCMTypes::PF_xxx)
653      *  @param level current level of nested items. Used for indentation.
654      */
655     void printNestingLevel(STD_NAMESPACE ostream &out,
656                            const size_t flags,
657                            const int level);
658 
659     /** print beginning of the info line.
660      *  The default output is tag and value representation, though other
661      *  visualizations are possible depending on the value of 'flags'.
662      *  @param out output stream
663      *  @param flags used to customize the output (see DCMTypes::PF_xxx)
664      *  @param level current level of nested items. Used for indentation.
665      *  @param tag optional tag used to print the data element information
666      */
667     void printInfoLineStart(STD_NAMESPACE ostream &out,
668                             const size_t flags,
669                             const int level,
670                             DcmTag *tag = NULL);
671 
672     /** print end of the info line.
673      *  The default output is length, value multiplicity and tag name, though
674      *  other visualizations are possible depending on the value of 'flags'.
675      *  @param out output stream
676      *  @param flags used to customize the output (see DCMTypes::PF_xxx)
677      *  @param printedLength number of characters printed after line start.
678      *    Used for padding purposes.
679      *  @param tag optional tag used to print the data element information
680      */
681     void printInfoLineEnd(STD_NAMESPACE ostream &out,
682                           const size_t flags,
683                           const unsigned long printedLength = 0xffffffff /*no padding*/,
684                           DcmTag *tag = NULL);
685 
686     /** print given text with element information.
687      *  Calls printInfoLineStart() and printInfoLineEnd() to frame the 'info' text.
688      *  @param out output stream
689      *  @param flags used to customize the output (see DCMTypes::PF_xxx)
690      *  @param level current level of nested items. Used for indentation.
691      *  @param info text to be printed
692      *  @param tag optional tag used to print the data element information
693      *  @param isInfo optional flag indicating whether this text is really given for
694      *    informational purposes only. Used to choose the correct output color.
695      */
696     virtual void printInfoLine(STD_NAMESPACE ostream &out,
697                                const size_t flags,
698                                const int level = 0,
699                                const char *info = NULL,
700                                DcmTag *tag = NULL,
701                                const OFBool isInfo = OFTrue);
702 
703     /** static helper function that writes a given attribute tag to a binary
704      *  output stream using the byte order indicated by the transfer syntax.
705      *  @param outStream output stream
706      *  @param tag tag to write to the stream
707      *  @param oxfer transfer syntax defining the byte order
708      *  @return EC_Normal if successful, an error code otherwise
709      */
710     static OFCondition writeTag(DcmOutputStream &outStream,
711                                 const DcmTag &tag,
712                                 const E_TransferSyntax oxfer);
713 
714     /** write tag, VR and length field to the given output stream
715      *  @param outStream output stream
716      *  @param oxfer transfer syntax for writing
717      *  @param writtenBytes number of bytes written to stream returned in this parameter
718      *  @return EC_Normal if successful, an error code otherwise
719      */
720     virtual OFCondition writeTagAndLength(DcmOutputStream &outStream,
721                                           const E_TransferSyntax oxfer, // in
722                                           Uint32 &writtenBytes) const;  // out
723 
724     /** return the number of bytes needed to serialize the
725      *  tag, VR and length information of the current object using the given
726      *  transfer syntax.
727      *  @param oxfer The transfer syntax used for encoding
728      *  @return number of bytes, may be 8 or 12 depending on VR and transfer syntax.
729      */
730     virtual Uint32 getTagAndLengthSize(const E_TransferSyntax oxfer) const;
731 
732     /** return the DICOM attribute tag name for this object. If not known yet, will
733      *  be looked up in the dictionary and cached. Therefore, method is not const.
734      *  @return tag name for this attribute
735      */
getTagName()736     const char *getTagName() { return Tag.getTagName(); }
737 
738     /** set the VR for this attribute
739      *  @param vr new VR for this attribute.
740      */
setTagVR(DcmEVR vr)741     void setTagVR(DcmEVR vr) { Tag.setVR(vr); }
742 
743     /** return the current transfer state of this object during serialization/deserialization
744      *  @return current transfer state of this object
745      */
getTransferState()746     E_TransferState getTransferState() const { return fTransferState; }
747 
748     /** set the current transfer state of this object during serialization/deserialization
749      *  @param newState new transfer state of this object
750      */
setTransferState(E_TransferState newState)751     void setTransferState(E_TransferState newState) { fTransferState = newState; }
752 
753     /** return the number of transferred bytes for this object during serialization/deserialization
754      *  @return number of transferred bytes
755      */
getTransferredBytes()756     Uint32 getTransferredBytes() const { return fTransferredBytes; }
757 
758     /** set the number of transferred bytes for this object during serialization/deserialization
759      *  @param val number of transferred bytes
760      */
setTransferredBytes(Uint32 val)761     void setTransferredBytes(Uint32 val) { fTransferredBytes = val; }
762 
763     /** add to the number of transferred bytes for this object during serialization/deserialization
764      *  @param val number of additional transferred bytes to add to existing value
765      */
incTransferredBytes(Uint32 val)766     void incTransferredBytes(Uint32 val) { fTransferredBytes += val; }
767 
768     /** set the current value of the Length field
769      *  @param val new value of the Length field
770      */
setLengthField(Uint32 val)771     void setLengthField(Uint32 val) { Length = val; }
772 
773  public:
774 
775     /** helper class to print a DcmObject to an ostream using operator<<
776      */
777     class DCMTK_DCMDATA_EXPORT PrintHelper
778     {
779       private:
780         /** Undefined assignment operator. This is needed to work around a
781          *  compiler warning on VC2008 with the highest warning level.
782          */
783         PrintHelper& operator=(PrintHelper &);
784 
785       public:
786         /** construct a PrintHelper
787          *  @param dcmobj DcmObject you want to print
788          *  @param flags flags to use for DcmObject::print()
789          *  @param level level to use for DcmObject::print()
790          */
791         explicit PrintHelper(DcmObject &dcmobj, size_t flags = 0, int level = 0)
dcmobj_(dcmobj)792           : dcmobj_(dcmobj), flags_(flags), level_(level)
793         {}
794 
795         DcmObject &dcmobj_;
796         const size_t flags_;
797         const int level_;
798     };
799 
800     /* member variables */
801 
802  protected:
803 
804     /// error flag for this object.
805     OFCondition errorFlag;
806 
807  private:
808 
809     /// the DICOM attribute tag and VR for this object
810     DcmTag Tag;
811 
812     /// the length of this attribute as read from stream, may be undefined length
813     Uint32 Length;
814 
815     /// transfer state during read and write operations
816     E_TransferState fTransferState;
817 
818     /// number of bytes already read/written during transfer
819     Uint32 fTransferredBytes;
820 
821     /// pointer to parent object if contained in a dataset/item (might be NULL)
822     DcmObject *Parent;
823  }; // class DcmObject
824 
825 /** Print a DcmObject::PrintHelper to an ostream.
826  *  @param stream stream to print to
827  *  @param obj object which will be print()ed
828  *  @return the stream argument
829  */
830 static inline STD_NAMESPACE ostream& operator<<(STD_NAMESPACE ostream &stream, DcmObject::PrintHelper obj)
831 {
832     obj.dcmobj_.print(stream, obj.flags_, obj.level_);
833     return stream;
834 }
835 
836 #endif // DCOBJECT_H
837