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