1 /* 2 * 3 * Copyright (C) 1994-2019, 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, Andreas Barth 17 * 18 * Purpose: Interface of class DcmDirectoryRecord 19 * 20 */ 21 22 #ifndef DCDIRREC_H 23 #define DCDIRREC_H 24 25 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ 26 27 #include "dcmtk/dcmdata/dcitem.h" 28 #include "dcmtk/dcmdata/dcsequen.h" 29 #include "dcmtk/dcmdata/dcfilefo.h" 30 31 32 /// types of directory records in a DICOMDIR 33 typedef enum { 34 /// root 35 ERT_root = 0, 36 /// curve (retired) 37 ERT_Curve = 1, 38 /// film box (retired) 39 ERT_FilmBox = 2, 40 /// film session (retired) 41 ERT_FilmSession = 3, 42 /// image 43 ERT_Image = 4, 44 /// image box (retired) 45 ERT_ImageBox = 5, 46 /// interpretation (retired) 47 ERT_Interpretation = 6, 48 /// modality LUT (retired) 49 ERT_ModalityLut = 7, 50 /// MRDR (retired) 51 ERT_Mrdr = 8, 52 /// overlay (retired) 53 ERT_Overlay = 9, 54 /// patient 55 ERT_Patient = 10, 56 /// print queue (retired) 57 ERT_PrintQueue = 11, 58 /// private 59 ERT_Private = 12, 60 /// results 61 ERT_Results = 13, 62 /// series 63 ERT_Series = 14, 64 /// study 65 ERT_Study = 15, 66 /// study component (retired) 67 ERT_StudyComponent = 16, 68 /// topic (retired) 69 ERT_Topic = 17, 70 /// visit (retired) 71 ERT_Visit = 18, 72 /// VOI LUT (retired) 73 ERT_VoiLut = 19, 74 /// SR document 75 ERT_SRDocument = 20, 76 /// presentation state 77 ERT_Presentation = 21, 78 /// waveform 79 ERT_Waveform = 22, 80 /// RT dose 81 ERT_RTDose = 23, 82 /// RT structure set 83 ERT_RTStructureSet = 24, 84 /// RT plan 85 ERT_RTPlan = 25, 86 /// RT treatment record 87 ERT_RTTreatRecord = 26, 88 /// stored print (retired) 89 ERT_StoredPrint = 27, 90 /// key object selection document 91 ERT_KeyObjectDoc = 28, 92 /// registration 93 ERT_Registration = 29, 94 /// fiducial 95 ERT_Fiducial = 30, 96 /// raw data 97 ERT_RawData = 31, 98 /// spectroscopy 99 ERT_Spectroscopy = 32, 100 /// encapsulated document 101 ERT_EncapDoc = 33, 102 /// value map 103 ERT_ValueMap = 34, 104 /// hanging protocol 105 ERT_HangingProtocol = 35, 106 /// stereometric relationships 107 ERT_Stereometric = 36, 108 /// HL7 structured document (retired) 109 ERT_HL7StrucDoc = 37, 110 /// palette 111 ERT_Palette = 38, 112 /// surface 113 ERT_Surface = 39, 114 /// measurement 115 ERT_Measurement = 40, 116 /// implant 117 ERT_Implant = 41, 118 /// implant group 119 ERT_ImplantGroup = 42, 120 /// implant assembly 121 ERT_ImplantAssy = 43, 122 /// plan 123 ERT_Plan = 44, 124 /// surface scan 125 ERT_SurfaceScan = 45, 126 /// tractography 127 ERT_Tract = 46, 128 /// assessment 129 ERT_Assessment = 47, 130 /// radiotherapy 131 ERT_Radiotherapy = 48 132 } E_DirRecType; 133 134 135 class DcmDicomDir; 136 137 /** a class representing a directory record dataset in a DICOMDIR. 138 */ 139 class DCMTK_DCMDATA_EXPORT DcmDirectoryRecord : public DcmItem 140 { 141 142 friend class DcmDicomDir; 143 144 public: 145 /// default constructor 146 DcmDirectoryRecord(); 147 148 /** constructor. 149 * Create new element from given tag and length. 150 * @param tag attribute tag 151 * @param len length of the attribute value 152 */ 153 DcmDirectoryRecord(const DcmTag &tag, 154 const Uint32 len); 155 156 /** constructor 157 * @param recordType record type 158 * @param referencedFileID referenced file ID in DICOM format 159 * @param sourceFileName path to referenced file in operating system specific format 160 * @param fileFormat fileFormat for sourceFileName, can be NULL 161 */ 162 DcmDirectoryRecord(const E_DirRecType recordType, 163 const char *referencedFileID, // DICOM format with '\\' 164 const OFFilename &sourceFileName, // OS format 165 DcmFileFormat* fileFormat = NULL); 166 167 /** constructor 168 * @param recordTypeName record type as string 169 * @param referencedFileID referenced file ID in DICOM format 170 * @param sourceFileName path to referenced file in operating system specific format 171 * @param fileFormat fileFormat for sourceFileName, can be NULL 172 */ 173 DcmDirectoryRecord(const char *recordTypeName, 174 const char *referencedFileID, // DICOM format with '\\' 175 const OFFilename &sourceFileName, // OS format 176 DcmFileFormat* fileFormat = NULL); 177 178 /** copy constructor 179 * @param oldDirRec element to be copied 180 */ 181 DcmDirectoryRecord(const DcmDirectoryRecord &oldDirRec); 182 183 /** assignment operator 184 * @param obj the directory record to be copied 185 */ 186 DcmDirectoryRecord &operator=(const DcmDirectoryRecord &obj); 187 188 /// destructor 189 virtual ~DcmDirectoryRecord(); 190 191 /** clone method 192 * @return deep copy of this object 193 */ clone()194 virtual DcmObject *clone() const 195 { 196 return new DcmDirectoryRecord(*this); 197 } 198 199 /** Virtual object copying. This method can be used for DcmObject 200 * and derived classes to get a deep copy of an object. Internally 201 * the assignment operator is called if the given DcmObject parameter 202 * is of the same type as "this" object instance. If not, an error 203 * is returned. This function permits copying an object by value 204 * in a virtual way which therefore is different to just calling the 205 * assignment operator of DcmElement which could result in slicing 206 * the object. 207 * @param rhs - [in] The instance to copy from. Has to be of the same 208 * class type as "this" object 209 * @return EC_Normal if copying was successful, error otherwise 210 */ 211 virtual OFCondition copyFrom(const DcmObject& rhs); 212 213 /** return identifier for this class. Every class derived from this class 214 * returns a unique value of type enum DcmEVR for this call. This is used 215 * as a "poor man's RTTI" to correctly identify instances derived from 216 * this class even on compilers not supporting RTTI. 217 * @return type identifier of this class 218 */ 219 virtual DcmEVR ident() const; 220 221 /// returns current status flag error()222 inline OFCondition error() const { return errorFlag; } 223 224 /** mode specifying whether the SpecificCharacterSet (0008,0005) element should be 225 * checked by convertCharacterSet() or not, i.e.\ whether this element might be 226 * present on this dataset-level. 227 * @return always returns OFTrue, i.e.\ SpecificCharacterSet should be checked 228 */ checkForSpecificCharacterSet()229 virtual OFBool checkForSpecificCharacterSet() const { return OFTrue; } 230 231 /** convert all element values that are contained in this record and that are 232 * affected by SpecificCharacterSet from the given source character set to the given 233 * destination character set. The defined terms for a particular character set can 234 * be found in the DICOM standard, e.g. "ISO_IR 100" for ISO 8859-1 (Latin 1) or 235 * "ISO_IR 192" for Unicode in UTF-8. An empty string denotes the default character 236 * repertoire, which is ASCII (7-bit). If multiple values are given for 'fromCharset' 237 * (separated by a backslash) code extension techniques are used and escape sequences 238 * may be encountered in the source string to switch between the specified character 239 * sets. 240 * @param fromCharset name of the source character set(s) used for the conversion 241 * @param toCharset name of the destination character set used for the conversion. 242 * Only a single value is permitted (i.e. no code extensions). 243 * @param flags optional flag used to customize the conversion (see DCMTypes::CF_xxx) 244 * @param updateCharset if OFTrue, the SpecificCharacterSet (0008,0005) element is 245 * updated, i.e.\ the current value is either replaced or a new element is inserted 246 * or the existing element is deleted. If OFFalse the SpecificCharacterSet element 247 * remains unchanged. 248 * @return status, EC_Normal if successful, an error code otherwise 249 */ 250 virtual OFCondition convertCharacterSet(const OFString &fromCharset, 251 const OFString &toCharset, 252 const size_t flags = 0, 253 const OFBool updateCharset = OFFalse); 254 255 /** convert all element values that are contained in this record and that are 256 * affected by SpecificCharacterSet to the given destination character set. If not 257 * disabled, the source character set is determined automatically from the value of 258 * the SpecificCharacterSet (0008,0005) element. The defined terms for the 259 * destination character set can be found in the DICOM standard, e.g. "ISO_IR 100" 260 * for ISO 8859-1 (Latin 1) or "ISO_IR 192" for Unicode in UTF-8. An empty string 261 * denotes the default character repertoire, which is ASCII (7-bit). 262 * @param toCharset name of the destination character set used for the conversion. 263 * Only a single value is permitted (i.e. no code extensions). 264 * @param flags optional flag used to customize the conversion (see DCMTypes::CF_xxx) 265 * @param ignoreCharset if OFTrue, the value of SpecificCharacterSet is ignored. 266 * Also see checkForSpecificCharacterSet(). 267 * @return status, EC_Normal if successful, an error code otherwise 268 */ 269 virtual OFCondition convertCharacterSet(const OFString &toCharset, 270 const size_t flags = 0, 271 const OFBool ignoreCharset = OFFalse); 272 273 /** convert all element values that are contained in this record and that are 274 * affected by SpecificCharacterSet from the currently selected source character 275 * set to the currently selected destination character set. Since the Basic 276 * Directory IOD, which specifies the structure and content of a DICOMDIR, does not 277 * contain the SpecificCharacterSet (0008,0005) element in the main dataset but in 278 * each directory record, this method also checks for this element and creates a new 279 * character set converter for the contained data elements (if needed). 280 * @param converter character set converter to be used to convert the element values 281 * @return status, EC_Normal if successful, an error code otherwise 282 */ 283 virtual OFCondition convertCharacterSet(DcmSpecificCharacterSet &converter); 284 285 /** print all elements of the item to a stream 286 * @param out output stream 287 * @param flags optional flag used to customize the output (see DCMTypes::PF_xxx) 288 * @param level current level of nested items. Used for indentation. 289 * @param pixelFileName not used 290 * @param pixelCounter not used 291 */ 292 virtual void print(STD_NAMESPACE ostream &out, 293 const size_t flags = 0, 294 const int level = 0, 295 const char *pixelFileName = NULL, 296 size_t *pixelCounter = NULL); 297 298 /** This function reads the information of all attributes which 299 * are captured in the input stream and captures this information 300 * in elementList. Each attribute is represented as an element 301 * in this list. If not all information for an attribute could be 302 * read from the stream, the function returns EC_StreamNotifyClient. 303 * @param inStream The stream which contains the information. 304 * @param xfer The transfer syntax which was used to encode 305 * the information in inStream. 306 * @param glenc Encoding type for group length; specifies 307 * what will be done with group length tags. 308 * @param maxReadLength Maximum read length for reading an attribute value. 309 * @return status, EC_Normal if successful, an error code otherwise 310 */ 311 virtual OFCondition read(DcmInputStream &inStream, 312 const E_TransferSyntax xfer, 313 const E_GrpLenEncoding glenc = EGL_noChange, 314 const Uint32 maxReadLength = DCM_MaxReadLength); 315 316 /** write object in XML format 317 * @param out output stream to which the XML document is written 318 * @param flags optional flag used to customize the output (see DCMTypes::XF_xxx) 319 * @return status, EC_Normal if successful, an error code otherwise 320 */ 321 virtual OFCondition writeXML(STD_NAMESPACE ostream &out, 322 const size_t flags = 0); 323 324 325 /** check the currently stored element value 326 * @param autocorrect correct value length if OFTrue 327 * @return status, EC_Normal if value length is correct, an error code otherwise 328 */ 329 virtual OFCondition verify(const OFBool autocorrect = OFFalse); 330 331 /** a complex, stack-based, hierarchical search method. It allows for a search 332 * for a DICOM object with a given attribute within a given container, 333 * hierarchically, from a starting position identified through a cursor stack. 334 * @param xtag the DICOM attribute tag we are searching for 335 * @param resultStack depending on the search mode (see below), this parameter 336 * either serves as an input and output parameter, or as an output parameter 337 * only (the latter being the default). When used as an input parameter, 338 * the cursor stack defines the start position for the search within a 339 * hierarchical DICOM dataset. Upon successful return, the stack contains 340 * the position of the element found, in the form of a pointer to each dataset, 341 * sequence, item and element from the main dataset down to the found element. 342 * @param mode search mode, controls how the search stack is handled. 343 * In the default mode, ESM_fromHere, the stack is ignored on input, and 344 * the search starts in the object for which this method is called. 345 * In the other modes, the stack is used both as an input and an output 346 * parameter and defines the starting point for the search. 347 * @param searchIntoSub if true, the search will be performed hierarchically descending 348 * into the sequences and items of the dataset. If false, only the current container 349 * (sequence or item) will be traversed. 350 * @return EC_Normal if found, EC_TagNotFound if not found, an error code is something went wrong. 351 */ 352 virtual OFCondition search(const DcmTagKey &xtag, // in 353 DcmStack &resultStack, // inout 354 E_SearchMode mode = ESM_fromHere, // in 355 OFBool searchIntoSub = OFTrue); // in 356 357 /// get record type of this directory record 358 virtual E_DirRecType getRecordType(); 359 360 /** if this directory record references an MRDR (multi-reference directory record), 361 * return pointer to the MRDR referenced by this object. 362 * @return pointer to MRDR referenced by this object or NULL of no MRDR referenced 363 */ 364 virtual DcmDirectoryRecord* getReferencedMRDR(); 365 366 /** create a reference from this record to an MRDR 367 * @param mrdr pointer to MRDR 368 * @return EC_Normal upon success, an error code otherwise 369 */ 370 virtual OFCondition assignToMRDR(DcmDirectoryRecord *mrdr ); // in 371 372 /** open a DICOM file and make this directory record into a directory 373 * record for that DICOM file. The most relevant record keys 374 * (SOP Class UID, SOP instance UID, Transfer Syntax UID) are inserted 375 * into the directory record. 376 * @param referencedFileID referenced file ID in DICOM format 377 * @param sourceFileName path to file in operating system specific format 378 * @return EC_Normal upon success, an error code otherwise 379 */ 380 virtual OFCondition assignToSOPFile(const char *referencedFileID, 381 const OFFilename &sourceFileName); 382 383 /// return number of directory records that are child record of this one 384 virtual unsigned long cardSub() const; 385 386 /** insert a child directory record 387 * @param dirRec directory record to be inserted. Must be allocated on heap, ownership is 388 * transferred to this object 389 * @param where index where to insert object 390 * @param before flag indicating whether to insert the record before or after the element 391 * identified by where 392 * @return EC_Normal upon success, an error code otherwise 393 */ 394 virtual OFCondition insertSub(DcmDirectoryRecord* dirRec, 395 unsigned long where = DCM_EndOfListIndex, 396 OFBool before = OFFalse); 397 398 /** insert new directory child record at the current position. 399 * The current position is stored internally in the 'lowerLevelList' member variable. 400 * @param dirRec new child record to be inserted 401 * @param before flag indicating whether to insert the record before (OFFalse) or 402 * after (OFTrue) the current position 403 * @return status, EC_Normal upon success, an error code otherwise 404 */ 405 virtual OFCondition insertSubAtCurrentPos(DcmDirectoryRecord *dirRec, 406 OFBool before = OFFalse); 407 408 /** access child directory record. Returns a pointer to the object maintained 409 * as a child, not a copy. 410 * @param num index, must be < cardSub() 411 * @return pointer to child directory record or NULL if not found 412 */ 413 virtual DcmDirectoryRecord* getSub(const unsigned long num); 414 415 /** get next directory child record starting at a given record 416 * @param dirRec record to start from (goto first record if NULL) 417 * @return pointer to next record if successful, NULL otherwise 418 */ 419 virtual DcmDirectoryRecord* nextSub(const DcmDirectoryRecord *dirRec); 420 421 /** remove child directory record. If found, the record is not deleted but 422 * returned to the caller who is responsible for further management of the 423 * DcmDirectoryRecord object. 424 * @param num index number of element, must be < cardSub() 425 * @return pointer to DcmDirectoryRecord if found, NULL otherwise 426 */ 427 virtual DcmDirectoryRecord* removeSub(const unsigned long num); 428 429 /** remove child directory record. If found, the record is not deleted but 430 * returned to the caller who is responsible for further management of the 431 * DcmDirectoryRecord object. 432 * @param dirRec pointer to element to be removed from list 433 * @return pointer to element if found, NULL otherwise 434 */ 435 virtual DcmDirectoryRecord* removeSub(DcmDirectoryRecord *dirRec); 436 437 /** remove child directory record and delete file referenced by that record, if any 438 * @param num index number of element, must be < cardSub() 439 * @return status, EC_Normal upon success, an error code otherwise 440 */ 441 virtual OFCondition deleteSubAndPurgeFile(const unsigned long num); 442 443 /** remove child directory record and delete file referenced by that record, if any 444 * @param dirRec pointer to element to be removed from list 445 * @return status, EC_Normal upon success, an error code otherwise 446 */ 447 virtual OFCondition deleteSubAndPurgeFile(DcmDirectoryRecord *dirRec); 448 449 /// revert the list of child directory records to default constructed (empty) state 450 virtual OFCondition clearSub(); 451 452 /** store the filename from which this directory record was read from 453 * @param fname filename, must not be empty 454 */ 455 virtual void setRecordsOriginFile(const OFFilename &fname); 456 457 /// get the filename from which this directory record was read from, empty if not set 458 virtual const OFFilename &getRecordsOriginFile(); 459 460 /// get the offset in file of this directory record 461 Uint32 getFileOffset() const; 462 463 protected: 464 465 // side-effect-free conversion routines: 466 E_DirRecType recordNameToType(const char *recordTypeName); 467 char* buildFileName(const char *origName, char *destName, size_t len) const; 468 OFCondition checkHierarchy(const E_DirRecType upperRecord, 469 const E_DirRecType lowerRecord); 470 471 // access to data elements within the Directory Records: 472 OFCondition setRecordType(E_DirRecType newType); 473 E_DirRecType lookForRecordType(); 474 OFCondition setReferencedFileID( const char *referencedFileID); 475 const char* lookForReferencedFileID(); 476 DcmDirectoryRecord* lookForReferencedMRDR(); 477 const char* getReferencedFileName(); // local or in MRDR 478 OFCondition setRecordInUseFlag(const Uint16 newFlag); 479 Uint16 lookForRecordInUseFlag(); 480 Uint32 setFileOffset(Uint32 position); 481 482 // access to MRDR data element: 483 OFCondition setNumberOfReferences(Uint32 newRefNum); 484 Uint32 lookForNumberOfReferences(); 485 Uint32 increaseRefNum(); 486 Uint32 decreaseRefNum(); 487 488 // misc: 489 /** Load all necessary info for this directory record. 490 * @param referencedFileID file ID that is being referenced, may be NULL 491 * @param sourceFileName filename for the DICOM file, may be empty (unspecified) 492 * @param fileFormat If not NULL, then this should be the result of loading 493 * sourceFileName. May only be non-NULL if sourceFileName isn't empty. 494 */ 495 OFCondition fillElementsAndReadSOP(const char *referencedFileID, 496 const OFFilename &sourceFileName, 497 DcmFileFormat *fileFormat = NULL); 498 OFCondition masterInsertSub(DcmDirectoryRecord *dirRec, 499 const unsigned long where = DCM_EndOfListIndex); 500 OFCondition purgeReferencedFile(); 501 502 private: 503 504 /// filename (path) of the file from which this directory record was read 505 OFFilename recordsOriginFile; 506 507 /// list of child directory records, kept in a sequence of items 508 DcmSequenceOfItems *lowerLevelList; 509 510 /// directory record type of this record 511 E_DirRecType DirRecordType; 512 513 /// pointer to multi-referenced directory record (MRDR) if this record refers to one, NULL otherwise 514 DcmDirectoryRecord *referencedMRDR; 515 516 /// number of other directory records referring to this one; used for MRDR records 517 Uint32 numberOfReferences; 518 519 /// byte offset at which the start of this directory record resides in the file from which it was read 520 Uint32 offsetInFile; 521 522 }; 523 524 525 #endif // DCDIRREC_H 526