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: Implementation of class DcmDirectoryRecord
19 *
20 */
21
22
23 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
24
25 #define INCLUDE_CSTDLIB
26 #define INCLUDE_CSTDIO
27 #define INCLUDE_CSTRING
28 #define INCLUDE_CCTYPE
29 #define INCLUDE_LIBC
30 #define INCLUDE_UNISTD
31 #include "dcmtk/ofstd/ofstdinc.h"
32
33 #include "dcmtk/ofstd/ofstream.h"
34 #include "dcmtk/ofstd/ofcast.h"
35 #include "dcmtk/ofstd/ofstd.h"
36
37 #include "dcmtk/dcmdata/dcdirrec.h"
38 #include "dcmtk/dcmdata/dctk.h"
39 #include "dcmtk/dcmdata/dcxfer.h"
40 #include "dcmtk/dcmdata/dcvr.h"
41 #include "dcmtk/dcmdata/dcvrus.h"
42 #include "dcmtk/dcmdata/dcspchrs.h"
43
44 #ifdef HAVE_UNIX_H
45 #if defined(macintosh) && defined (HAVE_WINSOCK_H)
46 /* unix.h defines timeval incompatible with winsock.h */
47 #define timeval _UNWANTED_timeval
48 #endif
49 #include <unix.h> /* for unlink() under Metrowerks C++ (Macintosh) */
50 #undef timeval
51 #endif
52
53
54 // ********************************
55
56
57 static const char *DRTypeNames[] =
58 {
59 "root",
60 "CURVE",
61 "FILM BOX",
62 "FILM SESSION",
63 "IMAGE",
64 "IMAGE BOX",
65 "INTERPRETATION",
66 "MODALITY LUT",
67 "MRDR",
68 "OVERLAY",
69 "PATIENT",
70 "PRINT QUEUE",
71 "PRIVATE",
72 "RESULTS",
73 "SERIES",
74 "STUDY",
75 "STUDY COMPONENT",
76 "TOPIC",
77 "VISIT",
78 "VOI LUT",
79 "SR DOCUMENT", /* was "STRUCT REPORT" in old frozen draft */
80 "PRESENTATION",
81 "WAVEFORM",
82 "RT DOSE",
83 "RT STRUCTURE SET",
84 "RT PLAN",
85 "RT TREAT RECORD",
86 "STORED PRINT",
87 "KEY OBJECT DOC",
88 "REGISTRATION",
89 "FIDUCIAL",
90 "RAW DATA",
91 "SPECTROSCOPY",
92 "ENCAP DOC",
93 "VALUE MAP",
94 "HANGING PROTOCOL",
95 "STEREOMETRIC",
96 "HL7 STRUC DOC",
97 "PALETTE",
98 "SURFACE",
99 "MEASUREMENT",
100 "IMPLANT",
101 "IMPLANT GROUP",
102 "IMPLANT ASSY",
103 "PLAN",
104 "SURFACE SCAN",
105 "TRACT",
106 "ASSESSMENT",
107 "RADIOTHERAPY"
108 };
109
110 static const short DIM_OF_DRTypeNames = OFstatic_cast(short, (sizeof(DRTypeNames) / sizeof(DRTypeNames[0])));
111
112
113 // ********************************
114
115
DcmDirectoryRecord()116 DcmDirectoryRecord::DcmDirectoryRecord()
117 : DcmItem(DCM_ItemTag),
118 recordsOriginFile(),
119 lowerLevelList(new DcmSequenceOfItems(DCM_DirectoryRecordSequence)),
120 DirRecordType(ERT_Private),
121 referencedMRDR(NULL),
122 numberOfReferences(0),
123 offsetInFile(0)
124 {
125 }
126
127
128 // ********************************
129
130
DcmDirectoryRecord(const DcmTag & tag,const Uint32 len)131 DcmDirectoryRecord::DcmDirectoryRecord(const DcmTag &tag,
132 const Uint32 len)
133 : DcmItem(tag, len),
134 recordsOriginFile(),
135 lowerLevelList(new DcmSequenceOfItems(DCM_DirectoryRecordSequence)),
136 DirRecordType(ERT_Private),
137 referencedMRDR(NULL),
138 numberOfReferences(0),
139 offsetInFile(0)
140 {
141 }
142
143
144 // ********************************
145
146
DcmDirectoryRecord(const E_DirRecType recordType,const char * referencedFileID,const OFFilename & sourceFilename,DcmFileFormat * fileFormat)147 DcmDirectoryRecord::DcmDirectoryRecord(const E_DirRecType recordType,
148 const char *referencedFileID,
149 const OFFilename &sourceFilename,
150 DcmFileFormat *fileFormat)
151 : DcmItem(DCM_ItemTag),
152 recordsOriginFile(),
153 lowerLevelList(new DcmSequenceOfItems(DCM_DirectoryRecordSequence)),
154 DirRecordType(recordType),
155 referencedMRDR(NULL),
156 numberOfReferences(0),
157 offsetInFile(0)
158 {
159 setRecordsOriginFile(sourceFilename);
160
161 if (DirRecordType != ERT_root)
162 errorFlag = fillElementsAndReadSOP(referencedFileID, sourceFilename, fileFormat);
163 }
164
165
166 // ********************************
167
168
DcmDirectoryRecord(const char * recordTypeName,const char * referencedFileID,const OFFilename & sourceFilename,DcmFileFormat * fileFormat)169 DcmDirectoryRecord::DcmDirectoryRecord(const char *recordTypeName,
170 const char *referencedFileID,
171 const OFFilename &sourceFilename,
172 DcmFileFormat *fileFormat)
173 : DcmItem(DCM_ItemTag),
174 recordsOriginFile(),
175 lowerLevelList(new DcmSequenceOfItems(DCM_DirectoryRecordSequence)),
176 DirRecordType(ERT_Private),
177 referencedMRDR(NULL),
178 numberOfReferences(0),
179 offsetInFile(0)
180 {
181 DirRecordType = recordNameToType(recordTypeName);
182 setRecordsOriginFile(sourceFilename);
183
184 if (DirRecordType != ERT_root)
185 errorFlag = fillElementsAndReadSOP(referencedFileID, sourceFilename, fileFormat);
186 }
187
188
189 // ********************************
190
191
DcmDirectoryRecord(const DcmDirectoryRecord & old)192 DcmDirectoryRecord::DcmDirectoryRecord(const DcmDirectoryRecord &old)
193 : DcmItem(old),
194 recordsOriginFile(old.recordsOriginFile),
195 lowerLevelList(new DcmSequenceOfItems(*old.lowerLevelList)),
196 DirRecordType(old.DirRecordType),
197 referencedMRDR(old.referencedMRDR), // copies a pointer!
198 numberOfReferences(old.numberOfReferences),
199 offsetInFile(old.offsetInFile)
200 {
201 }
202
203
204 // ********************************
205
206
operator =(const DcmDirectoryRecord & obj)207 DcmDirectoryRecord& DcmDirectoryRecord::operator=(const DcmDirectoryRecord& obj)
208 {
209 if (this != &obj)
210 {
211 // copy parent's member variables
212 DcmItem::operator=(obj);
213 // copy DcmDirectoryRecords' member variables
214 recordsOriginFile = obj.recordsOriginFile;
215 lowerLevelList = new DcmSequenceOfItems(*obj.lowerLevelList);
216 DirRecordType = obj.DirRecordType;
217 referencedMRDR = obj.referencedMRDR; // copies a pointer!
218 numberOfReferences = obj.numberOfReferences;
219 offsetInFile = obj.offsetInFile;
220 }
221 return *this;
222 }
223
224
225 // ********************************
226
227
copyFrom(const DcmObject & rhs)228 OFCondition DcmDirectoryRecord::copyFrom(const DcmObject& rhs)
229 {
230 if (this != &rhs)
231 {
232 if (rhs.ident() != ident()) return EC_IllegalCall;
233 *this = OFstatic_cast(const DcmDirectoryRecord &, rhs);
234 }
235 return EC_Normal;
236 }
237
238
239 // ********************************
240
241
~DcmDirectoryRecord()242 DcmDirectoryRecord::~DcmDirectoryRecord()
243 {
244 delete lowerLevelList;
245 }
246
247
248 // ********************************
249
250
recordNameToType(const char * recordTypeName)251 E_DirRecType DcmDirectoryRecord::recordNameToType(const char *recordTypeName)
252 {
253 E_DirRecType recType = ERT_Private;
254 if (recordTypeName != NULL)
255 {
256 short i = 0;
257 while (i < DIM_OF_DRTypeNames && strcmp(DRTypeNames[i], recordTypeName) != 0)
258 i++;
259
260 if (i < DIM_OF_DRTypeNames && strcmp(DRTypeNames[i], recordTypeName) == 0)
261 recType = OFstatic_cast(E_DirRecType, i);
262 else if (strcmp(recordTypeName,"STRUCT REPORT") == 0)
263 recType = ERT_SRDocument; // we recognize the old name as well
264 DCMDATA_TRACE("DcmDirectoryRecord::recordNameToType() input char*=\"" << recordTypeName
265 << "\" output enum=" << recType);
266 }
267 return recType;
268 }
269
270
271 // ********************************
272
273
buildFileName(const char * origName,char * destName,size_t len) const274 char *DcmDirectoryRecord::buildFileName(const char *origName,
275 char *destName,
276 size_t len) const
277 {
278 const char *from = origName;
279 char *to = destName;
280 char c;
281 char lastchar = '\0';
282 while ((c = *from++) != 0)
283 {
284 if (c == '\\')
285 {
286 if (lastchar != '\\') // eliminate double '\\'
287 *to++ = PATH_SEPARATOR;
288 } else {
289 *to++ = c;
290 }
291 lastchar = c;
292 }
293 *to = '\0';
294
295 /*
296 ** Some OS's append a '.' to the filename of a ISO9660 filesystem.
297 ** If the filename does not exist then try appending a '.'
298 */
299 FILE* f = NULL;
300 if ((f = fopen(destName, "rb")) != NULL)
301 {
302 fclose(f);
303 } else {
304 size_t buflen = strlen(destName) + 2;
305 char* newname = new char[buflen];
306 OFStandard::strlcpy(newname, destName, buflen);
307 OFStandard::strlcat(newname, ".", buflen);
308 if ((f = fopen(newname, "rb")) != NULL)
309 {
310 fclose(f);
311 OFStandard::strlcpy(destName, newname, len);
312 } else {
313 /* we cannot find the file. let the caller deal with this */
314 }
315 delete[] newname;
316 }
317 return destName;
318 }
319
320
321 // ********************************
322
323
checkHierarchy(const E_DirRecType upperRecord,const E_DirRecType lowerRecord)324 OFCondition DcmDirectoryRecord::checkHierarchy(const E_DirRecType upperRecord,
325 const E_DirRecType lowerRecord)
326 {
327 OFCondition l_error = EC_IllegalCall;
328 switch (upperRecord)
329 {
330 case ERT_root:
331 switch (lowerRecord)
332 {
333 case ERT_Patient:
334 case ERT_PrintQueue:
335 case ERT_Topic:
336 case ERT_HangingProtocol:
337 case ERT_Palette:
338 case ERT_Implant:
339 case ERT_ImplantGroup:
340 case ERT_ImplantAssy:
341 case ERT_Private:
342 l_error = EC_Normal;
343 break;
344 default:
345 l_error = EC_IllegalCall;
346 break;
347 }
348 break;
349 case ERT_FilmBox: // retired
350 switch (lowerRecord)
351 {
352 case ERT_ImageBox:
353 case ERT_Private:
354 l_error = EC_Normal;
355 break;
356 default:
357 l_error = EC_IllegalCall;
358 break;
359 }
360 break;
361 case ERT_FilmSession: // retired
362 switch (lowerRecord)
363 {
364 case ERT_FilmBox:
365 case ERT_Private:
366 l_error = EC_Normal;
367 break;
368 default:
369 l_error = EC_IllegalCall;
370 break;
371 }
372 break;
373 case ERT_Patient:
374 switch (lowerRecord)
375 {
376 case ERT_Study:
377 case ERT_HL7StrucDoc: // retired
378 case ERT_Private:
379 l_error = EC_Normal;
380 break;
381 default:
382 l_error = EC_IllegalCall;
383 break;
384 }
385 break;
386 case ERT_PrintQueue: // retired
387 switch (lowerRecord)
388 {
389 case ERT_FilmSession:
390 case ERT_Private:
391 l_error = EC_Normal;
392 break;
393 default:
394 l_error = EC_IllegalCall;
395 break;
396 }
397 break;
398 case ERT_Results: // retired
399 switch (lowerRecord)
400 {
401 case ERT_Interpretation:
402 case ERT_Private:
403 l_error = EC_Normal;
404 break;
405 default:
406 l_error = EC_IllegalCall;
407 break;
408 }
409 break;
410 case ERT_Series:
411 switch (lowerRecord)
412 {
413 case ERT_Curve:
414 case ERT_Image:
415 case ERT_ModalityLut:
416 case ERT_Overlay:
417 case ERT_VoiLut:
418 case ERT_SRDocument:
419 case ERT_Presentation:
420 case ERT_Waveform:
421 case ERT_RTDose:
422 case ERT_RTStructureSet:
423 case ERT_RTPlan:
424 case ERT_RTTreatRecord:
425 case ERT_StoredPrint:
426 case ERT_KeyObjectDoc:
427 case ERT_Registration:
428 case ERT_Fiducial:
429 case ERT_RawData:
430 case ERT_Spectroscopy:
431 case ERT_EncapDoc:
432 case ERT_ValueMap:
433 case ERT_Stereometric:
434 case ERT_Surface:
435 case ERT_Measurement:
436 case ERT_Plan:
437 case ERT_SurfaceScan:
438 case ERT_Tract:
439 case ERT_Assessment:
440 case ERT_Radiotherapy:
441 case ERT_Private:
442 l_error = EC_Normal;
443 break;
444 default:
445 l_error = EC_IllegalCall;
446 break;
447 }
448 break;
449 case ERT_Study:
450 switch (lowerRecord)
451 {
452 case ERT_FilmSession:
453 case ERT_Results:
454 case ERT_Series:
455 case ERT_StudyComponent:
456 case ERT_Visit:
457 case ERT_Private:
458 l_error = EC_Normal;
459 break;
460 default:
461 l_error = EC_IllegalCall;
462 break;
463 }
464 break;
465 case ERT_Topic: // retired
466 switch (lowerRecord)
467 {
468 case ERT_Curve:
469 case ERT_FilmSession:
470 case ERT_Image:
471 case ERT_ModalityLut:
472 case ERT_Overlay:
473 case ERT_Series:
474 case ERT_Study:
475 case ERT_VoiLut:
476 case ERT_SRDocument:
477 case ERT_Presentation:
478 case ERT_Waveform:
479 case ERT_RTDose:
480 case ERT_RTStructureSet:
481 case ERT_RTPlan:
482 case ERT_RTTreatRecord:
483 case ERT_StoredPrint:
484 case ERT_KeyObjectDoc:
485 case ERT_Registration:
486 case ERT_Fiducial:
487 case ERT_RawData:
488 case ERT_Spectroscopy:
489 case ERT_Private:
490 l_error = EC_Normal;
491 break;
492 default:
493 l_error = EC_IllegalCall;
494 break;
495 }
496 break;
497 case ERT_Mrdr: // retired
498 l_error = EC_IllegalCall;
499 break;
500 case ERT_Curve:
501 case ERT_Image:
502 case ERT_ImageBox:
503 case ERT_Interpretation:
504 case ERT_ModalityLut:
505 case ERT_Overlay:
506 case ERT_StudyComponent:
507 case ERT_Visit:
508 case ERT_VoiLut:
509 case ERT_SRDocument:
510 case ERT_Presentation:
511 case ERT_Waveform:
512 case ERT_RTDose:
513 case ERT_RTStructureSet:
514 case ERT_RTPlan:
515 case ERT_RTTreatRecord:
516 case ERT_StoredPrint:
517 case ERT_KeyObjectDoc:
518 case ERT_Registration:
519 case ERT_Fiducial:
520 case ERT_RawData:
521 case ERT_Spectroscopy:
522 case ERT_EncapDoc:
523 case ERT_ValueMap:
524 case ERT_HangingProtocol:
525 case ERT_Stereometric:
526 case ERT_HL7StrucDoc: // retired
527 case ERT_Palette:
528 case ERT_Surface:
529 case ERT_Measurement:
530 case ERT_Implant:
531 case ERT_ImplantGroup:
532 case ERT_ImplantAssy:
533 case ERT_Plan:
534 case ERT_SurfaceScan:
535 case ERT_Tract:
536 case ERT_Assessment:
537 case ERT_Radiotherapy:
538 case ERT_Private:
539 switch (lowerRecord)
540 {
541 case ERT_Private:
542 l_error = EC_Normal;
543 break;
544 default:
545 l_error = EC_IllegalCall;
546 break;
547 }
548 break;
549 default:
550 l_error = EC_Normal;
551 break;
552 }
553 return l_error;
554 }
555
556
557 // ********************************
558
559
setRecordType(E_DirRecType newType)560 OFCondition DcmDirectoryRecord::setRecordType(E_DirRecType newType)
561 {
562 OFCondition l_error = EC_Normal;
563
564 DcmTag dirRecTag(DCM_DirectoryRecordType);
565 DcmCodeString *csP = new DcmCodeString(dirRecTag);
566 csP->putString(DRTypeNames[newType]);
567 insert(csP, OFTrue);
568
569 return l_error;
570 }
571
572
573 // ********************************
574
575
576
lookForRecordType()577 E_DirRecType DcmDirectoryRecord::lookForRecordType()
578 {
579 E_DirRecType localType = ERT_Private;
580 if (!elementList->empty())
581 {
582 DcmStack stack;
583 if (search(DCM_DirectoryRecordType, stack, ESM_fromHere, OFFalse).good())
584 {
585 if (stack.top()->ident() == EVR_CS)
586 {
587 char *recName = NULL;
588 DcmCodeString *recType = OFstatic_cast(DcmCodeString *, stack.top());
589 recType->verify(OFTrue); // force dealignment
590 recType->getString(recName);
591 localType = recordNameToType(recName);
592
593 DCMDATA_TRACE("DcmDirectoryRecord::lookForRecordType() RecordType Element "
594 << recType->getTag() << " Type = " << DRTypeNames[DirRecordType]);
595 }
596 }
597 }
598 return localType;
599 }
600
601
602 // ********************************
603
hostToDicomFilename(char * fname)604 static void hostToDicomFilename(char *fname)
605 {
606 /*
607 ** Massage filename into DICOM format.
608 ** Eliminate any invalid characters.
609 ** Most commonly there is a '.' at the end of a filename.
610 */
611 size_t len = strlen(fname);
612 int k = 0;
613 unsigned char c = '\0';
614 for (size_t i = 0; i < len; ++i)
615 {
616 c = OFstatic_cast(unsigned char, fname[i]);
617 /* the PATH_SEPARATOR depends on the OS (see <osconfig.h>) */
618 if (c == PATH_SEPARATOR)
619 {
620 fname[k++] = '\\';
621 } else if (isalpha(c) || isdigit(c) || (c == '_') || (c == '\\')) {
622 /* filenames in DICOM must always be in uppercase */
623 fname[k++] = OFstatic_cast(char, toupper(c));
624 }
625 }
626 fname[k] = '\0';
627 }
628
629
setReferencedFileID(const char * referencedFileID)630 OFCondition DcmDirectoryRecord::setReferencedFileID(const char *referencedFileID)
631 {
632 OFCondition l_error = EC_Normal;
633
634 size_t bufsize = strlen(referencedFileID) + 1;
635 char* newFname = new char[bufsize];
636 OFStandard::strlcpy(newFname, referencedFileID, bufsize);
637 hostToDicomFilename(newFname);
638
639 DcmTag refFileTag(DCM_ReferencedFileID);
640 DcmCodeString *csP = new DcmCodeString(refFileTag);
641 if (referencedFileID != NULL)
642 csP->putString(newFname);
643 insert(csP, OFTrue);
644
645 delete[] newFname;
646 return l_error;
647 }
648
649
650 // ********************************
651
652
lookForReferencedFileID()653 const char *DcmDirectoryRecord::lookForReferencedFileID()
654 {
655 char *localFile = NULL;
656 if (!elementList->empty())
657 {
658 DcmStack stack;
659 if (search(DCM_ReferencedFileID, stack, ESM_fromHere, OFFalse).good())
660 {
661 if (stack.top()->ident() == EVR_CS)
662 {
663 DcmCodeString *refFile = OFstatic_cast(DcmCodeString *, stack.top());
664 refFile->verify(OFTrue); // force dealignment
665 refFile->getString(localFile);
666 if (localFile != NULL && *localFile == '\0')
667 localFile = NULL;
668 }
669 }
670 }
671 DCMDATA_TRACE("DcmDirectoryRecord::lookForReferencedFileID() ReferencedFileID = "
672 << ((localFile) ? localFile : ""));
673
674 return localFile;
675 }
676
677
678 // ********************************
679
680
lookForReferencedMRDR()681 DcmDirectoryRecord *DcmDirectoryRecord::lookForReferencedMRDR()
682 {
683 DcmDirectoryRecord *localMRDR = NULL;
684 if (!elementList->empty())
685 {
686 DcmStack stack;
687 if (search(DCM_RETIRED_MRDRDirectoryRecordOffset, stack, ESM_fromHere, OFFalse).good())
688 {
689 if (stack.top()->ident() == EVR_up)
690 {
691 DcmUnsignedLongOffset *offElem;
692 offElem = OFstatic_cast(DcmUnsignedLongOffset *, stack.top());
693 localMRDR = OFstatic_cast(DcmDirectoryRecord *, offElem->getNextRecord());
694 #ifdef DEBUG
695 Uint32 l_uint = 0;
696 offElem->getUint32(l_uint);
697 DCMDATA_TRACE("DcmDirectoryRecord::lookForReferencedMRDR() MRDR Offset Element "
698 << offElem->getTag() << " offs=0x"
699 << STD_NAMESPACE hex << STD_NAMESPACE setfill('0')
700 << STD_NAMESPACE setw(8) << l_uint
701 << " p=" << OFstatic_cast(void *, offElem)
702 << " n=" << OFstatic_cast(void *, localMRDR));
703 #endif
704 }
705 }
706 }
707 if (localMRDR == NULL)
708 DCMDATA_TRACE("DcmDirectoryRecord::lookForReferencedMRDR() no ReferencedMRDR found");
709
710 return localMRDR;
711 }
712
713
714 // ********************************
715
716
getReferencedFileName()717 const char *DcmDirectoryRecord::getReferencedFileName()
718 {
719 const char *localFile = NULL;
720 if (referencedMRDR != NULL)
721 localFile = referencedMRDR->lookForReferencedFileID();
722 else
723 localFile = lookForReferencedFileID();
724 return localFile;
725 }
726
727
728 // ********************************
729
730
setRecordInUseFlag(const Uint16 newFlag)731 OFCondition DcmDirectoryRecord::setRecordInUseFlag(const Uint16 newFlag)
732 {
733 OFCondition l_error = EC_Normal;
734
735 DcmTag recInUseTag(DCM_RecordInUseFlag);
736 DcmUnsignedShort *usP = new DcmUnsignedShort(recInUseTag);
737 usP->putUint16(newFlag);
738 insert(usP, OFTrue);
739
740 return l_error;
741 }
742
743
744 // ********************************
745
746
lookForRecordInUseFlag()747 Uint16 DcmDirectoryRecord::lookForRecordInUseFlag()
748 {
749 Uint16 localFlag = Uint16(0xffff); // default value: record is in use
750 if (!elementList->empty())
751 {
752 DcmStack stack;
753 if (search(DCM_RecordInUseFlag, stack, ESM_fromHere, OFFalse).good())
754 {
755 if (stack.top()->ident() == EVR_US)
756 errorFlag = OFstatic_cast(DcmUnsignedShort *, stack.top())->getUint16(localFlag);
757 }
758 }
759 return localFlag;
760 }
761
762
763 // ********************************
764
765
getFileOffset() const766 Uint32 DcmDirectoryRecord::getFileOffset() const
767 {
768 return offsetInFile;
769 }
770
771
772 // ********************************
773
774
setFileOffset(Uint32 position)775 Uint32 DcmDirectoryRecord::setFileOffset(Uint32 position)
776 {
777 offsetInFile = position;
778 return position;
779 }
780
781
782 // ********************************
783
784
setNumberOfReferences(Uint32 newRefNum)785 OFCondition DcmDirectoryRecord::setNumberOfReferences(Uint32 newRefNum)
786 {
787 OFCondition l_error = EC_Normal;
788 if (DirRecordType == ERT_Mrdr)
789 {
790 // insert new value
791 DcmTag numRefTag(DCM_RETIRED_NumberOfReferences);
792 DcmUnsignedLong *newUL = new DcmUnsignedLong(numRefTag);
793 newUL->putUint32(newRefNum);
794 insert(newUL, OFTrue);
795 } else {
796 errorFlag = EC_IllegalCall;
797 DCMDATA_ERROR("illegal usage of DcmDirectoryRecord::setNumberOfReferences() - RecordType must be MRDR");
798 }
799 return l_error;
800 }
801
802
803 // ********************************
804
805
lookForNumberOfReferences()806 Uint32 DcmDirectoryRecord::lookForNumberOfReferences()
807 {
808 Uint32 localRefNum = 0L;
809 if (!elementList->empty())
810 {
811 DcmStack stack;
812 if (search(DCM_RETIRED_NumberOfReferences, stack, ESM_fromHere, OFFalse).good())
813 {
814 if (stack.top()->ident() == EVR_UL)
815 errorFlag = OFstatic_cast(DcmUnsignedLong *, stack.top())->getUint32(localRefNum);
816 }
817 }
818 return localRefNum;
819 }
820
821
822 // ********************************
823
824
increaseRefNum()825 Uint32 DcmDirectoryRecord::increaseRefNum()
826 {
827 if (DirRecordType == ERT_Mrdr)
828 {
829 if (numberOfReferences == 0L)
830 setRecordInUseFlag(0xffff); // activate record
831 numberOfReferences++;
832 errorFlag = setNumberOfReferences(numberOfReferences);
833 } else {
834 errorFlag = EC_IllegalCall;
835 DCMDATA_ERROR("illegal usage of DcmDirectoryRecord::increaseRefNum() - RecordType must be MRDR");
836 }
837 return numberOfReferences;
838 }
839
840
841 // ********************************
842
843
decreaseRefNum()844 Uint32 DcmDirectoryRecord::decreaseRefNum()
845 {
846 if (DirRecordType == ERT_Mrdr)
847 {
848 if (numberOfReferences > 0)
849 {
850 numberOfReferences--;
851 if (numberOfReferences == 0L)
852 setRecordInUseFlag(0x0000); // deactivate record
853 errorFlag = setNumberOfReferences(numberOfReferences);
854 } else {
855 errorFlag = EC_IllegalCall;
856 DCMDATA_WARN("DcmDirectoryRecord::decreaseRefNum() attempt to decrease value lower than zero");
857 }
858 } else {
859 errorFlag = EC_IllegalCall;
860 DCMDATA_ERROR("illegal usage of DcmDirectoryRecord::decreaseRefNum() - RecordType must be MRDR");
861 }
862 return numberOfReferences;
863 }
864
865
866
867 // ********************************
868
869 // --- IGNORE THE FOLLOWING GERMAN COMMENT ---
870 //
871 // Es werden alle Datenelemente gemaess Tabelle B.3.2.2-1 DICOM part 10
872 // erzeugt.
873 // Wird ein gueltiger Dateiname (referencedFileID) fuer eine SOP-Instanz
874 // uebergeben, so werden alle benoetigten keys aus dieser Datei ausgelesen:
875 // Das Datenelement MRDRDirectoryRecordOffset entfaellt.
876 // directFromFile == OFTrue
877 //
878 // Ist referencedFileID ein NULL-Zeiger, so wird versucht, die keys indirekt
879 // ueber den referenzierten MRDR zu besorgen.
880 // Das Datenelement ReferencedFileID bekommt die Laenge 0.
881 // indirectViaMRDR == OFTrue
882 //
883 // Existiert kein Verweis auf einen MRDR, so wird davon ausgegangen, das auch
884 // keine SOP-Instanz mit dem aktuellen Directory Record verknuepft werden soll:
885 // Die Datenelemente ReferencedFileID, MRDRDirectoryRecordOffset,
886 // ReferencedSOPClassUIDinFile und ReferencedSOPInstanceUIDinFile entfallen.
887 // !directFromFile && !indirectViaMRDR
888 //
889
fillElementsAndReadSOP(const char * referencedFileID,const OFFilename & sourceFileName,DcmFileFormat * fileFormat)890 OFCondition DcmDirectoryRecord::fillElementsAndReadSOP(const char *referencedFileID,
891 const OFFilename &sourceFileName,
892 DcmFileFormat *fileFormat)
893 {
894 OFCondition l_error = EC_Normal;
895 OFFilename fileName;
896 DcmFileFormat *refFile = NULL;
897 /* This variable is only set if we created our own DcmFileFormat instance */
898 DcmFileFormat *ownFile = NULL;
899
900 if (fileFormat != NULL && sourceFileName.isEmpty())
901 return EC_IllegalCall;
902
903 OFBool directFromFile = OFFalse;
904 OFBool indirectViaMRDR = OFFalse;
905 if (referencedFileID != NULL && *referencedFileID != '\0')
906 directFromFile = OFTrue;
907 else if (DirRecordType != ERT_Mrdr && referencedMRDR != NULL) // illegal for MRDR
908 {
909 indirectViaMRDR = OFTrue;
910 referencedFileID = referencedMRDR->lookForReferencedFileID();
911 }
912
913 if (referencedFileID != NULL && *referencedFileID != '\0')
914 {
915 if (sourceFileName.isEmpty())
916 {
917 /* create a new source filename */
918 size_t bufsize = strlen(referencedFileID) + 2;
919 char *newname = new char[bufsize];
920 buildFileName(referencedFileID, newname, bufsize);
921 fileName.set(newname);
922 delete[] newname;
923 } else {
924 /* just copy the source filename */
925 fileName = sourceFileName;
926 }
927
928 if (DirRecordType != ERT_Mrdr)
929 {
930 if (fileFormat)
931 {
932 DCMDATA_TRACE("DcmDirectoryRecord::fillElementsAndReadSOP(): Using existing file format for \"" << fileName << "\".");
933 refFile = fileFormat;
934 } else {
935 DCMDATA_TRACE("DcmDirectoryRecord::fillElementsAndReadSOP(): Load file \"" << fileName << "\" because our caller didn't do so.");
936 ownFile = new DcmFileFormat();
937 l_error = ownFile->loadFile(fileName);
938 refFile = ownFile;
939 if (l_error.bad())
940 {
941 DCMDATA_ERROR("DcmDirectoryRecord::fillElementsAndReadSOP(): DicomFile \""
942 << fileName << "\" not found");
943 directFromFile = OFFalse;
944 indirectViaMRDR = OFFalse;
945 }
946 }
947 }
948 } else {
949 directFromFile = OFFalse;
950 indirectViaMRDR = OFFalse;
951 }
952
953 DcmStack stack;
954 DcmUnsignedLongOffset *uloP;
955 DcmUniqueIdentifier *uiP;
956
957 DcmTag nextOffTag(DCM_OffsetOfTheNextDirectoryRecord); // (0004,1400)
958 uloP = new DcmUnsignedLongOffset(nextOffTag);
959 uloP->putUint32(Uint32(0));
960 if (insert(uloP, OFFalse).bad())
961 delete uloP;
962
963 setRecordInUseFlag(0xffff); // (0004,1410)
964
965 DcmTag lowerOffTag(DCM_OffsetOfReferencedLowerLevelDirectoryEntity);
966 uloP = new DcmUnsignedLongOffset(lowerOffTag); // (0004,1420)
967 uloP->putUint32(Uint32(0));
968 if (insert(uloP, OFFalse).bad())
969 delete uloP;
970
971 setRecordType(DirRecordType); // (0004,1430)
972
973 DcmTag privRecTag(DCM_PrivateRecordUID); // (0004,1432)
974 if (DirRecordType == ERT_Private)
975 {
976 uiP = new DcmUniqueIdentifier(privRecTag);
977 if (insert(uiP, OFFalse).bad())
978 delete uiP;
979 } else
980 delete remove(privRecTag);
981
982 if (directFromFile) // (0004,1500)
983 setReferencedFileID(referencedFileID);
984 else
985 {
986 DcmTag refFileTag(DCM_ReferencedFileID);
987 delete remove(refFileTag);
988 }
989
990 DcmTag mrdrOffTag(DCM_RETIRED_MRDRDirectoryRecordOffset); // (0004,1504)
991 if (indirectViaMRDR)
992 {
993 // create pointer attribute to MRDR
994 DcmUnsignedLongOffset *uloP2 = new DcmUnsignedLongOffset(mrdrOffTag);
995 uloP2->putUint32(Uint32(0));
996 uloP2->setNextRecord(referencedMRDR);
997 insert(uloP2, OFTrue);
998 } else
999 delete remove(mrdrOffTag);
1000
1001 DcmTag refSOPClassTag(DCM_ReferencedSOPClassUIDInFile);
1002 DcmTag refSOPInstTag(DCM_ReferencedSOPInstanceUIDInFile);
1003 DcmTag refFileXferTag(DCM_ReferencedTransferSyntaxUIDInFile);
1004
1005 if (DirRecordType != ERT_Mrdr && (directFromFile || indirectViaMRDR))
1006 {
1007 if (refFile == NULL)
1008 {
1009 DCMDATA_ERROR("Internal ERROR in DcmDirectoryRecord::fillElementsAndReadSOP()");
1010 }
1011 uiP = new DcmUniqueIdentifier(refSOPClassTag); // (0004,1510)
1012 if (refFile->search(DCM_SOPClassUID, stack).good())
1013 {
1014 char *uid = NULL;
1015 OFstatic_cast(DcmUniqueIdentifier *, stack.top())->getString(uid);
1016 uiP->putString(uid);
1017 } else {
1018 DCMDATA_ERROR("DcmDirectoryRecord::fillElementsAndReadSOP(): "
1019 << "can't find SOPClassUID in Dataset: " << fileName);
1020 l_error = EC_CorruptedData;
1021 }
1022 insert(uiP, OFTrue);
1023
1024 uiP = new DcmUniqueIdentifier(refSOPInstTag); // (0004,1511)
1025 if (refFile->search(DCM_SOPInstanceUID, stack).good() || refFile->search(DCM_MediaStorageSOPInstanceUID, stack).good())
1026 {
1027 char *uid = NULL;
1028 OFstatic_cast(DcmUniqueIdentifier *, stack.top())->getString(uid);
1029 uiP->putString(uid);
1030 } else {
1031 DCMDATA_ERROR("DcmDirectoryRecord::fillElementsAndReadSOP(): "
1032 << "can't find SOPInstanceUID neither in Dataset or MetaInfo of file: " << fileName);
1033 l_error = EC_CorruptedData;
1034 }
1035 insert(uiP, OFTrue);
1036
1037 uiP = new DcmUniqueIdentifier(refFileXferTag); // (0004,1512)
1038 if (refFile->search(DCM_TransferSyntaxUID, stack).good())
1039 {
1040 char *uid = NULL;
1041 OFstatic_cast(DcmUniqueIdentifier *, stack.top())->getString(uid);
1042 uiP->putString(uid);
1043 } else {
1044 DCMDATA_ERROR("DcmDirectoryRecord::fillElementsAndReadSOP(): "
1045 << "can't find TransferSyntaxUID in MetaInfo of file: " << fileName);
1046 l_error = EC_CorruptedData;
1047 }
1048 insert(uiP, OFTrue);
1049 }
1050 else // not only in this case: if (DirRecordType == ERT_Mrdr)
1051 {
1052 // remove SOP UIDs from Directory Record
1053 delete remove(refSOPClassTag);
1054 delete remove(refSOPInstTag);
1055 delete remove(refFileXferTag);
1056 }
1057
1058 delete ownFile;
1059
1060 return l_error;
1061 }
1062
1063
1064 // ********************************
1065
1066
masterInsertSub(DcmDirectoryRecord * dirRec,const unsigned long where)1067 OFCondition DcmDirectoryRecord::masterInsertSub(DcmDirectoryRecord *dirRec,
1068 const unsigned long where)
1069 {
1070 // insert without type check
1071 errorFlag = lowerLevelList->insert(dirRec, where);
1072 return errorFlag;
1073 }
1074
1075
1076 // ********************************
1077
1078
purgeReferencedFile()1079 OFCondition DcmDirectoryRecord::purgeReferencedFile()
1080 {
1081 OFCondition l_error = EC_Normal;
1082 if (DirRecordType != ERT_root)
1083 {
1084 char *localFileName = NULL;
1085
1086 // remove filename from directory record
1087 const char *fileName = lookForReferencedFileID();
1088 if (fileName != NULL)
1089 {
1090 size_t buflen = strlen(fileName) + 2;
1091 localFileName = new char[buflen];
1092 buildFileName(fileName, localFileName, buflen);
1093 setReferencedFileID(NULL);
1094 }
1095
1096 DCMDATA_DEBUG("DcmDirectoryRecord::purgeReferencedFile() trying to purge file "
1097 << localFileName << " from file system");
1098
1099 if (localFileName != NULL)
1100 { // filename exists
1101 if (unlink(localFileName) != 0)
1102 {
1103 OFString buffer = OFStandard::getLastSystemErrorCode().message();
1104 errorFlag = makeOFCondition(OFM_dcmdata, 19, OF_error, buffer.c_str());
1105 }
1106 delete[] localFileName;
1107 } else { // no referenced file exists
1108 // do nothing
1109 }
1110 } else
1111 l_error = EC_IllegalCall;
1112
1113 return l_error;
1114 }
1115
1116
1117 // ********************************
1118 // ******** public methods ********
1119 // ********************************
1120
1121
ident() const1122 DcmEVR DcmDirectoryRecord::ident() const
1123 {
1124 return EVR_dirRecord;
1125 }
1126
1127
1128 // ********************************
1129
1130
convertCharacterSet(const OFString & fromCharset,const OFString & toCharset,const size_t flags,const OFBool updateCharset)1131 OFCondition DcmDirectoryRecord::convertCharacterSet(const OFString &fromCharset,
1132 const OFString &toCharset,
1133 const size_t flags,
1134 const OFBool updateCharset)
1135 {
1136 // call the method of the base class; this method is only needed to avoid a compiler warning
1137 return DcmItem::convertCharacterSet(fromCharset, toCharset, flags, updateCharset);
1138 }
1139
1140
convertCharacterSet(const OFString & toCharset,const size_t flags,const OFBool ignoreCharset)1141 OFCondition DcmDirectoryRecord::convertCharacterSet(const OFString &toCharset,
1142 const size_t flags,
1143 const OFBool ignoreCharset)
1144 {
1145 // call the method of the base class; this method is only needed to avoid a compiler warning
1146 return DcmItem::convertCharacterSet(toCharset, flags, ignoreCharset);
1147 }
1148
1149
convertCharacterSet(DcmSpecificCharacterSet & converter)1150 OFCondition DcmDirectoryRecord::convertCharacterSet(DcmSpecificCharacterSet &converter)
1151 {
1152 DCMDATA_DEBUG("DcmDirectoryRecord::convertCharacterSet() processing directory record with offset "
1153 << getFileOffset());
1154 // handle special case of DICOMDIR: the Specific Character Set (0008,0005)
1155 // can be specified individually for each directory record (i.e. item)
1156 OFCondition status = EC_Normal;
1157 OFString fromCharset;
1158 const OFString toCharset = converter.getDestinationCharacterSet();
1159 // determine value of Specific Character Set (0008,0005) if present in this item
1160 if (findAndGetOFStringArray(DCM_SpecificCharacterSet, fromCharset, OFFalse /*searchIntoSub*/).good() &&
1161 (fromCharset != converter.getSourceCharacterSet()))
1162 {
1163 DcmSpecificCharacterSet newConverter;
1164 // create a new character set converter
1165 DCMDATA_DEBUG("DcmDirectoryRecord::convertCharacterSet() creating a new character set converter for '"
1166 << fromCharset << "'" << (fromCharset.empty() ? " (ASCII)" : "") << " to '"
1167 << toCharset << "'" << (toCharset.empty() ? " (ASCII)" : ""));
1168 // select source and destination character set, use same transliteration mode
1169 status = newConverter.selectCharacterSet(fromCharset, toCharset);
1170 if (status.good())
1171 {
1172 const unsigned cflags = converter.getConversionFlags();
1173 if (cflags > 0)
1174 status = newConverter.setConversionFlags(cflags);
1175 if (status.good())
1176 {
1177 // convert all affected element values in the item with the new converter
1178 status = DcmItem::convertCharacterSet(newConverter);
1179 // update the Specific Character Set (0008,0005) element
1180 updateSpecificCharacterSet(status, newConverter);
1181 }
1182 }
1183 } else {
1184 // no Specific Character Set attribute or the same character set,
1185 // so proceed with the given converter
1186 status = DcmItem::convertCharacterSet(converter);
1187 }
1188 return status;
1189 }
1190
1191
1192 // ********************************
1193
1194
print(STD_NAMESPACE ostream & out,const size_t flags,const int level,const char * pixelFileName,size_t * pixelCounter)1195 void DcmDirectoryRecord::print(STD_NAMESPACE ostream &out,
1196 const size_t flags,
1197 const int level,
1198 const char *pixelFileName,
1199 size_t *pixelCounter)
1200 {
1201 if (flags & DCMTypes::PF_showTreeStructure)
1202 {
1203 /* print record line */
1204 OFOStringStream oss;
1205 oss << "\"Directory Record\" (offset=$"
1206 << getFileOffset() << ")" << OFStringStream_ends;
1207 OFSTRINGSTREAM_GETSTR(oss, tmpString)
1208 printInfoLine(out, flags, level, tmpString);
1209 OFSTRINGSTREAM_FREESTR(tmpString)
1210 /* print item content */
1211 if (!elementList->empty())
1212 {
1213 DcmObject *dO;
1214 elementList->seek(ELP_first);
1215 do {
1216 dO = elementList->get();
1217 dO->print(out, flags, level + 1, pixelFileName, pixelCounter);
1218 } while (elementList->seek(ELP_next));
1219 }
1220 if (lowerLevelList->card() > 0)
1221 lowerLevelList->print(out, flags, level + 1);
1222 } else {
1223 /* print record start line */
1224 OFOStringStream oss;
1225 oss << "\"Directory Record\" " << DRTypeNames[DirRecordType]
1226 << " #=" << card() << OFStringStream_ends;
1227 OFSTRINGSTREAM_GETSTR(oss, tmpString)
1228 printInfoLine(out, flags, level, tmpString);
1229 OFSTRINGSTREAM_FREESTR(tmpString)
1230 /* print record comment line */
1231 if (flags & DCMTypes::PF_useANSIEscapeCodes)
1232 out << DCMDATA_ANSI_ESCAPE_CODE_INFO;
1233 printNestingLevel(out, flags, level);
1234 out << "# offset=$" << getFileOffset();
1235 if (referencedMRDR != NULL)
1236 out << " refMRDR=$" << referencedMRDR->getFileOffset();
1237 if (DirRecordType == ERT_Mrdr)
1238 out << " refCount=" << numberOfReferences;
1239 const char *refFile = getReferencedFileName();
1240 if (refFile != NULL)
1241 out << " refFileID=\"" << refFile << "\"";
1242 if (flags & DCMTypes::PF_useANSIEscapeCodes)
1243 out << DCMDATA_ANSI_ESCAPE_CODE_RESET;
1244 out << OFendl;
1245 /* print item content */
1246 if (!elementList->empty())
1247 {
1248 DcmObject *dO;
1249 elementList->seek(ELP_first);
1250 do {
1251 dO = elementList->get();
1252 dO->print(out, flags, level + 1, pixelFileName, pixelCounter);
1253 } while (elementList->seek(ELP_next));
1254 }
1255 if (lowerLevelList->card() > 0)
1256 lowerLevelList->print(out, flags, level + 1);
1257 /* print record end line */
1258 DcmTag delimItemTag(DCM_ItemDelimitationItemTag);
1259 if (getLengthField() == DCM_UndefinedLength)
1260 printInfoLine(out, flags, level, "\"ItemDelimitationItem\"", &delimItemTag);
1261 else
1262 printInfoLine(out, flags, level, "\"ItemDelimitationItem for re-encoding\"", &delimItemTag);
1263 }
1264 }
1265
1266
1267 // ********************************
1268
1269
writeXML(STD_NAMESPACE ostream & out,const size_t flags)1270 OFCondition DcmDirectoryRecord::writeXML(STD_NAMESPACE ostream &out,
1271 const size_t flags)
1272 {
1273 OFCondition l_error = EC_Normal;
1274 if (flags & DCMTypes::XF_useNativeModel)
1275 {
1276 /* in Native DICOM Model, there is no concept of a DICOMDIR */
1277 l_error = makeOFCondition(OFM_dcmdata, EC_CODE_CannotConvertToXML, OF_error,
1278 "Cannot convert Directory Record to Native DICOM Model");
1279 } else {
1280 /* XML start tag for "item" */
1281 out << "<item";
1282 /* cardinality (number of attributes) = 1..n */
1283 out << " card=\"" << card() << "\"";
1284 /* value length in bytes = 0..max (if not undefined) */
1285 if (getLengthField() != DCM_UndefinedLength)
1286 out << " len=\"" << getLengthField() << "\"";
1287 /* byte offset of the record */
1288 out << " offset=\"" << getFileOffset() << "\"";
1289 out << ">" << OFendl;
1290 /* write item content */
1291 if (!elementList->empty())
1292 {
1293 /* write content of all children */
1294 DcmObject *dO;
1295 elementList->seek(ELP_first);
1296 do {
1297 dO = elementList->get();
1298 l_error = dO->writeXML(out, flags);
1299 } while (l_error.good() && elementList->seek(ELP_next));
1300 }
1301 if (l_error.good())
1302 {
1303 if (lowerLevelList->card() > 0)
1304 lowerLevelList->writeXML(out, flags);
1305 /* XML end tag for "item" */
1306 out << "</item>" << OFendl;
1307 }
1308 }
1309 return l_error;
1310 }
1311
1312
1313 // ********************************
1314
1315
read(DcmInputStream & inStream,const E_TransferSyntax xfer,const E_GrpLenEncoding glenc,const Uint32 maxReadLength)1316 OFCondition DcmDirectoryRecord::read(DcmInputStream &inStream,
1317 const E_TransferSyntax xfer,
1318 const E_GrpLenEncoding glenc,
1319 const Uint32 maxReadLength)
1320 {
1321 if (getTransferState() == ERW_notInitialized)
1322 errorFlag = EC_IllegalCall;
1323 else
1324 {
1325 if (getTransferState() != ERW_ready)
1326 {
1327 DcmXfer xferSyn(xfer);
1328 errorFlag = DcmItem::read(inStream, xfer, glenc, maxReadLength);
1329 /*
1330 ** Remember the actual file offset for this Directory Record.
1331 ** Compute by subtracting the Item header (tag & length fields)
1332 ** from the start position of data within the Item (fStartPosition).
1333 ** fStartPosition is set in DcmItem::read(...)
1334 ** offsetInFile is used in the print(...) method.
1335 */
1336 offsetInFile = OFstatic_cast(Uint32, fStartPosition) - xferSyn.sizeofTagHeader(getTag().getEVR());
1337 }
1338
1339 if (getTransferState() == ERW_ready && DirRecordType == ERT_Private) // minimizes multiple evaluation
1340 {
1341 DirRecordType = lookForRecordType();
1342 if (DirRecordType == ERT_Mrdr)
1343 numberOfReferences = lookForNumberOfReferences();
1344 }
1345 }
1346 return errorFlag;
1347 }
1348
1349
1350 // ********************************
1351
1352
verify(const OFBool autocorrect)1353 OFCondition DcmDirectoryRecord::verify(const OFBool autocorrect)
1354 {
1355 OFCondition err1 = EC_Normal;
1356 OFCondition err2 = EC_Normal;
1357 errorFlag = EC_Normal;
1358 if (autocorrect == OFTrue && DirRecordType != ERT_root)
1359 errorFlag = fillElementsAndReadSOP(getReferencedFileName(), "");
1360
1361 err1 = DcmItem::verify(autocorrect);
1362 err2 = lowerLevelList->verify(autocorrect);
1363 if (errorFlag.good() && (err1.bad() || err2.bad()))
1364 errorFlag = EC_CorruptedData;
1365 return errorFlag;
1366 }
1367
1368
1369 // ********************************
1370
1371
search(const DcmTagKey & tag,DcmStack & resultStack,E_SearchMode mode,OFBool searchIntoSub)1372 OFCondition DcmDirectoryRecord::search(const DcmTagKey &tag,
1373 DcmStack &resultStack,
1374 E_SearchMode mode,
1375 OFBool searchIntoSub)
1376 {
1377 OFCondition l_error = DcmItem::search(tag, resultStack, mode, searchIntoSub);
1378 if (l_error.bad())
1379 {
1380 if (mode != ESM_afterStackTop || resultStack.top() == this)
1381 resultStack.push(lowerLevelList);
1382 l_error = lowerLevelList->search(tag, resultStack, mode, searchIntoSub);
1383 if (l_error.bad())
1384 resultStack.pop();
1385 }
1386 return l_error;
1387 }
1388
1389
1390 // ********************************
1391
1392
getRecordType()1393 E_DirRecType DcmDirectoryRecord::getRecordType()
1394 {
1395 return DirRecordType;
1396 }
1397
1398
1399 // ********************************
1400
1401
getReferencedMRDR()1402 DcmDirectoryRecord* DcmDirectoryRecord::getReferencedMRDR()
1403 {
1404 return referencedMRDR;
1405 }
1406
1407
1408 // ********************************
1409
1410
assignToSOPFile(const char * referencedFileID,const OFFilename & sourceFileName)1411 OFCondition DcmDirectoryRecord::assignToSOPFile(const char *referencedFileID,
1412 const OFFilename &sourceFileName)
1413 {
1414 errorFlag = EC_Normal;
1415
1416 if (DirRecordType != ERT_root)
1417 {
1418 DCMDATA_DEBUG("DcmDirectoryRecord::assignToSOPFile() old Referenced File ID was "
1419 << getReferencedFileName());
1420 DCMDATA_DEBUG("new Referenced File ID is " << referencedFileID);
1421
1422 // update against the old reference counter
1423 if (referencedMRDR != NULL)
1424 referencedMRDR->decreaseRefNum();
1425 referencedMRDR = NULL;
1426
1427 errorFlag = fillElementsAndReadSOP(referencedFileID, sourceFileName);
1428 } else
1429 errorFlag = EC_IllegalCall;
1430 return errorFlag;
1431 }
1432
1433
1434 // ********************************
1435
1436
assignToMRDR(DcmDirectoryRecord * mrdr)1437 OFCondition DcmDirectoryRecord::assignToMRDR(DcmDirectoryRecord *mrdr)
1438 {
1439 errorFlag = EC_Normal;
1440 if (DirRecordType != ERT_root
1441 && mrdr != NULL // new MRDR available
1442 && mrdr != referencedMRDR // old MRDR != new MRDR
1443 )
1444 {
1445 DCMDATA_DEBUG("DcmDirectoryRecord::assignToMRDR() old Referenced File ID was "
1446 << getReferencedFileName());
1447 DCMDATA_DEBUG("new Referenced File ID is " << mrdr->lookForReferencedFileID());
1448
1449 // set internal pointer to mrdr and update against the old value
1450 if (referencedMRDR != NULL)
1451 referencedMRDR->decreaseRefNum();
1452 referencedMRDR = mrdr;
1453
1454 // increase reference counter in referencedMRDR by one
1455 referencedMRDR->increaseRefNum();
1456
1457 // set length of Referenced File ID to zero and fill data elements
1458 errorFlag = fillElementsAndReadSOP(NULL, "");
1459 } else
1460 errorFlag = EC_IllegalCall;
1461
1462 return errorFlag;
1463 }
1464
1465
1466 // ********************************
1467
1468
cardSub() const1469 unsigned long DcmDirectoryRecord::cardSub() const
1470 {
1471 return lowerLevelList->card();
1472 }
1473
1474
1475 // ********************************
1476
1477
insertSub(DcmDirectoryRecord * dirRec,unsigned long where,OFBool before)1478 OFCondition DcmDirectoryRecord::insertSub(DcmDirectoryRecord *dirRec,
1479 unsigned long where,
1480 OFBool before)
1481 {
1482 if (dirRec != NULL)
1483 {
1484 if (checkHierarchy(DirRecordType, dirRec->DirRecordType).good())
1485 errorFlag = lowerLevelList->insert(dirRec, where, before);
1486 else
1487 {
1488 errorFlag = EC_IllegalCall;
1489 DCMDATA_DEBUG("DcmDirectoryRecord::insertSub() dcdirrec: ("
1490 << DRTypeNames[getRecordType()] << " -> "
1491 << DRTypeNames[dirRec->getRecordType()] << ") hierarchy not allowed");
1492 }
1493 }
1494 return errorFlag;
1495 }
1496
1497
1498 // ********************************
1499
1500
insertSubAtCurrentPos(DcmDirectoryRecord * dirRec,OFBool before)1501 OFCondition DcmDirectoryRecord::insertSubAtCurrentPos(DcmDirectoryRecord *dirRec,
1502 OFBool before)
1503 {
1504 if (dirRec != NULL)
1505 {
1506 if (checkHierarchy(DirRecordType, dirRec->DirRecordType).good())
1507 errorFlag = lowerLevelList->insertAtCurrentPos(dirRec, before);
1508 else {
1509 errorFlag = EC_IllegalCall;
1510 DCMDATA_DEBUG("DcmDirectoryRecord::insertSubAtCurrentPos() dcdirrec: ("
1511 << DRTypeNames[getRecordType()] << " -> " << DRTypeNames[dirRec->getRecordType()]
1512 << ") hierarchy not allowed");
1513 }
1514 }
1515 return errorFlag;
1516 }
1517
1518
1519 // ********************************
1520
1521
getSub(const unsigned long num)1522 DcmDirectoryRecord *DcmDirectoryRecord::getSub(const unsigned long num)
1523 {
1524 DcmDirectoryRecord *retRec = OFstatic_cast(DcmDirectoryRecord *, lowerLevelList->getItem(num));
1525 errorFlag = lowerLevelList->error();
1526 return retRec;
1527 }
1528
1529
1530 // ********************************
1531
1532
nextSub(const DcmDirectoryRecord * dirRec)1533 DcmDirectoryRecord *DcmDirectoryRecord::nextSub(const DcmDirectoryRecord *dirRec)
1534 {
1535 DcmDirectoryRecord *retRec = OFstatic_cast(DcmDirectoryRecord *, lowerLevelList->nextInContainer(dirRec));
1536 errorFlag = lowerLevelList->error();
1537 return retRec;
1538 }
1539
1540
1541 // ********************************
1542
1543
removeSub(const unsigned long num)1544 DcmDirectoryRecord* DcmDirectoryRecord::removeSub(const unsigned long num)
1545 {
1546 DcmDirectoryRecord *retRec = OFstatic_cast(DcmDirectoryRecord *, lowerLevelList->remove(num));
1547 errorFlag = lowerLevelList->error();
1548 return retRec;
1549 }
1550
1551
1552 // ********************************
1553
1554
removeSub(DcmDirectoryRecord * dirRec)1555 DcmDirectoryRecord* DcmDirectoryRecord::removeSub(DcmDirectoryRecord *dirRec)
1556 {
1557 DcmDirectoryRecord *retRec = OFstatic_cast(DcmDirectoryRecord *, lowerLevelList->remove(dirRec));
1558 errorFlag = lowerLevelList->error();
1559 return retRec;
1560 }
1561
1562
1563 // ********************************
1564
1565
deleteSubAndPurgeFile(const unsigned long num)1566 OFCondition DcmDirectoryRecord::deleteSubAndPurgeFile(const unsigned long num)
1567 {
1568 DcmDirectoryRecord *subDirRec = OFstatic_cast(DcmDirectoryRecord *, lowerLevelList->remove(num));
1569 errorFlag = lowerLevelList->error();
1570 if (subDirRec != NULL)
1571 {
1572 DcmDirectoryRecord *localSubRefMRDR = subDirRec->getReferencedMRDR();
1573
1574 if (localSubRefMRDR != NULL)
1575 { // file is referenced (indirect)
1576 localSubRefMRDR->decreaseRefNum();
1577 } else // remove file directly
1578 errorFlag = subDirRec->purgeReferencedFile();
1579
1580 DCMDATA_DEBUG("DcmDirectoryRecord::deleteSubAndPurgeFile() now purging lower records:");
1581
1582 while (subDirRec->cardSub() > 0) // remove all sub sub records
1583 subDirRec->deleteSubAndPurgeFile(OFstatic_cast(unsigned long, 0));
1584 delete subDirRec; // remove sub directory record
1585 }
1586 return errorFlag;
1587 }
1588
1589
1590 // ********************************
1591
1592
deleteSubAndPurgeFile(DcmDirectoryRecord * dirRec)1593 OFCondition DcmDirectoryRecord::deleteSubAndPurgeFile(DcmDirectoryRecord *dirRec)
1594 {
1595 DcmDirectoryRecord *subDirRec = OFstatic_cast(DcmDirectoryRecord *, lowerLevelList->remove(dirRec));
1596 errorFlag = lowerLevelList->error();
1597 if (subDirRec != NULL)
1598 {
1599 DcmDirectoryRecord *localSubRefMRDR = subDirRec->getReferencedMRDR();
1600
1601 if (localSubRefMRDR != NULL)
1602 { // file is referenced (indirect)
1603 localSubRefMRDR->decreaseRefNum();
1604 } else // remove file directly
1605 errorFlag = subDirRec->purgeReferencedFile();
1606
1607 DCMDATA_DEBUG("DcmDirectoryRecord::deleteSubAndPurgeFile() now purging lower records:");
1608
1609 while (subDirRec->cardSub() > 0) // remove all sub sub records
1610 subDirRec->deleteSubAndPurgeFile(OFstatic_cast(unsigned long, 0));
1611 delete subDirRec; // remove sub directory record
1612 }
1613 return errorFlag;
1614 }
1615
1616
clearSub()1617 OFCondition DcmDirectoryRecord::clearSub()
1618 {
1619 errorFlag = lowerLevelList->clear();
1620 return errorFlag;
1621 }
1622
1623
setRecordsOriginFile(const OFFilename & fname)1624 void DcmDirectoryRecord::setRecordsOriginFile(const OFFilename &fname)
1625 {
1626 recordsOriginFile = fname;
1627 }
1628
getRecordsOriginFile()1629 const OFFilename &DcmDirectoryRecord::getRecordsOriginFile()
1630 {
1631 return recordsOriginFile;
1632 }
1633