1 /*
2 *
3 * Copyright (C) 1994-2002, OFFIS
4 *
5 * This software and supporting documentation were developed by
6 *
7 * Kuratorium OFFIS e.V.
8 * Healthcare Information and Communication Systems
9 * Escherweg 2
10 * D-26121 Oldenburg, Germany
11 *
12 * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY
13 * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR
14 * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR
15 * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
16 * PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
17 *
18 * Module: dcmdata
19 *
20 * Author: Gerd Ehlers, Andreas Barth
21 *
22 * Purpose: Implementation of class DcmSequenceOfItems
23 *
24 */
25
26
27 #include "osconfig.h" /* make sure OS specific configuration is included first */
28
29 #define INCLUDE_CSTDLIB
30 #define INCLUDE_CSTDIO
31 #include "ofstdinc.h"
32
33 #include "ofstream.h"
34 #include "ofstd.h"
35
36 #include "dcsequen.h"
37 #include "dcitem.h"
38 #include "dcdirrec.h"
39 #include "dcvr.h"
40 #include "dcpxitem.h"
41 #include "dcswap.h"
42 #include "dcdebug.h"
43 #include "dcmetinf.h"
44 #include "dcdeftag.h"
45 #include "dcistrma.h" /* for class DcmInputStream */
46 #include "dcostrma.h" /* for class DcmOutputStream */
47
48
49 // ********************************
50
51
DcmSequenceOfItems(const DcmTag & tag,const Uint32 len)52 DcmSequenceOfItems::DcmSequenceOfItems(const DcmTag &tag,
53 const Uint32 len)
54 : DcmElement(tag, len),
55 itemList(NULL),
56 lastItemComplete(OFTrue),
57 fStartPosition(0)
58 {
59 itemList = new DcmList;
60 }
61
62
63 // ********************************
64
65
DcmSequenceOfItems(const DcmSequenceOfItems & old)66 DcmSequenceOfItems::DcmSequenceOfItems(const DcmSequenceOfItems &old)
67 : DcmElement(old),
68 itemList(NULL),
69 lastItemComplete(OFTrue),
70 fStartPosition(old.fStartPosition)
71 {
72 itemList = new DcmList;
73
74 switch (old.ident())
75 {
76 case EVR_SQ:
77 case EVR_pixelSQ:
78 case EVR_fileFormat:
79 if (!old.itemList->empty())
80 {
81 DcmObject *oldDO;
82 DcmObject *newDO;
83 itemList->seek(ELP_first);
84 old.itemList->seek(ELP_first);
85 do {
86 oldDO = old.itemList->get();
87 switch (oldDO->ident())
88 {
89 case EVR_item:
90 newDO = new DcmItem(*(DcmItem*)oldDO);
91 break;
92 case EVR_pixelItem:
93 newDO = new DcmPixelItem(*(DcmPixelItem*)oldDO);
94 break;
95 case EVR_metainfo:
96 newDO = new DcmMetaInfo(*(DcmMetaInfo*)oldDO);
97 break;
98 case EVR_dataset:
99 newDO = new DcmDataset(*(DcmDataset*)oldDO);
100 break;
101 default:
102 newDO = new DcmItem(oldDO->getTag());
103 ofConsole.lockCerr() << "Error: DcmSequenceOfItems(): Element("
104 << hex << setfill('0')
105 << setw(4) << oldDO->getGTag() << ","
106 << setw(4) << oldDO->getETag()
107 << dec << setfill(' ')
108 << ") found, which was not an Item" << endl;
109 ofConsole.unlockCerr();
110 break;
111 }
112
113 itemList->insert(newDO, ELP_next);
114 } while (old.itemList->seek(ELP_next));
115 }
116 break;
117 default:
118 // wrong use of copy constructor, should never happen
119 break;
120 }
121 }
122
123
124 // ********************************
125
126
~DcmSequenceOfItems()127 DcmSequenceOfItems::~DcmSequenceOfItems()
128 {
129 DcmObject *dO;
130 itemList->seek(ELP_first);
131 while (!itemList->empty())
132 {
133 dO = itemList->remove();
134 if (dO != (DcmObject*)NULL)
135 delete dO;
136 }
137 delete itemList;
138 }
139
140
141 // ********************************
142
143
operator =(const DcmSequenceOfItems & obj)144 DcmSequenceOfItems &DcmSequenceOfItems::operator=(const DcmSequenceOfItems &obj)
145 {
146 DcmElement::operator=(obj);
147 lastItemComplete = obj.lastItemComplete;
148 fStartPosition = obj.fStartPosition;
149
150 DcmList *newList = new DcmList; // DcmList has no copy constructor. Need to copy ourselves.
151 if (newList)
152 {
153 switch (obj.ident())
154 {
155 case EVR_SQ:
156 case EVR_pixelSQ:
157 case EVR_fileFormat:
158 if (!obj.itemList->empty())
159 {
160 DcmObject *oldDO;
161 DcmObject *newDO;
162 newList->seek(ELP_first);
163 obj.itemList->seek(ELP_first);
164 do {
165 oldDO = obj.itemList->get();
166 switch (oldDO->ident())
167 {
168 case EVR_item:
169 newDO = new DcmItem(*(DcmItem*)oldDO);
170 break;
171 case EVR_pixelItem:
172 newDO = new DcmPixelItem(*(DcmPixelItem*)oldDO);
173 break;
174 case EVR_metainfo:
175 newDO = new DcmMetaInfo(*(DcmMetaInfo*)oldDO);
176 break;
177 case EVR_dataset:
178 newDO = new DcmDataset(*(DcmDataset*)oldDO);
179 break;
180 default:
181 newDO = new DcmItem(oldDO->getTag());
182 ofConsole.lockCerr() << "Error: DcmSequenceOfItems(): Element("
183 << hex << oldDO->getGTag() << "," << oldDO->getETag()
184 << dec << ") found, which was not an Item" << endl;
185 ofConsole.unlockCerr();
186 break;
187 }
188 newList->insert(newDO, ELP_next);
189 } while (obj.itemList->seek(ELP_next));
190 }
191 break;
192 default:
193 // wrong use of assignment operator, should never happen
194 break;
195 }
196 }
197 delete itemList;
198 itemList = newList;
199
200 return *this;
201 }
202
203
204 // ********************************
205
206
print(ostream & out,const size_t flags,const int level,const char * pixelFileName,size_t * pixelCounter)207 void DcmSequenceOfItems::print(ostream &out,
208 const size_t flags,
209 const int level,
210 const char *pixelFileName,
211 size_t *pixelCounter)
212 {
213 /* print sequence start line */
214 if (flags & DCMTypes::PF_showTreeStructure)
215 {
216 /* empty text */
217 printInfoLine(out, flags, level);
218 /* print sequence content */
219 if (!itemList->empty())
220 {
221 /* reset internal flags */
222 const size_t newFlags = flags & ~DCMTypes::PF_lastEntry;
223 /* print all items contained in the sequence */
224 DcmObject *dO;
225 itemList->seek(ELP_first);
226 do {
227 dO = itemList->get();
228 dO->print(out, newFlags, level + 1, pixelFileName, pixelCounter);
229 } while (itemList->seek(ELP_next));
230 }
231 } else {
232 OFOStringStream oss;
233 oss << "(Sequence ";
234 if (Length == DCM_UndefinedLength)
235 oss << "undefined";
236 else
237 oss << "explicit";
238 oss << " length #=" << card() << ")" << OFStringStream_ends;
239 OFSTRINGSTREAM_GETSTR(oss, tmpString)
240 printInfoLine(out, flags, level, tmpString);
241 OFSTRINGSTREAM_FREESTR(tmpString)
242 /* print sequence content */
243 if (!itemList->empty())
244 {
245 DcmObject *dO;
246 itemList->seek(ELP_first);
247 do {
248 dO = itemList->get();
249 dO->print(out, flags, level + 1, pixelFileName, pixelCounter);
250 } while (itemList->seek(ELP_next));
251 }
252 /* print sequence end line */
253 DcmTag delimItemTag(DCM_SequenceDelimitationItem);
254 if (Length == DCM_UndefinedLength)
255 printInfoLine(out, flags, level, "(SequenceDelimitationItem)", &delimItemTag);
256 else
257 printInfoLine(out, flags, level, "(SequenceDelimitationItem for re-encod.)", &delimItemTag);
258 }
259 }
260
261
262 // ********************************
263
264
writeXML(ostream & out,const size_t flags)265 OFCondition DcmSequenceOfItems::writeXML(ostream &out,
266 const size_t flags)
267 {
268 OFString xmlString;
269 DcmVR vr(Tag.getVR());
270 /* XML start tag for "sequence" */
271 out << "<sequence";
272 /* attribute tag = (gggg,eeee) */
273 out << " tag=\"";
274 out << hex << setfill('0')
275 << setw(4) << Tag.getGTag() << ","
276 << setw(4) << Tag.getETag() << "\""
277 << dec << setfill(' ');
278 /* value representation = VR */
279 out << " vr=\"" << vr.getVRName() << "\"";
280 /* cardinality (number of items) = 1..n */
281 out << " card=\"" << card() << "\"";
282 /* value length in bytes = 0..max (if not undefined) */
283 if (Length != DCM_UndefinedLength)
284 out << " len=\"" << Length << "\"";
285 /* tag name (if known) */
286 out << " name=\"" << OFStandard::convertToMarkupString(Tag.getTagName(), xmlString) << "\"";
287 out << ">" << endl;
288 /* write sequence content */
289 if (!itemList->empty())
290 {
291 /* write content of all children */
292 DcmObject *dO;
293 itemList->seek(ELP_first);
294 do
295 {
296 dO = itemList->get();
297 dO->writeXML(out, flags);
298 } while (itemList->seek(ELP_next));
299 }
300 /* XML end tag for "sequence" */
301 out << "</sequence>" << endl;
302 /* always report success */
303 return EC_Normal;
304 }
305
306
307 // ********************************
308
309
canWriteXfer(const E_TransferSyntax newXfer,const E_TransferSyntax oldXfer)310 OFBool DcmSequenceOfItems::canWriteXfer(const E_TransferSyntax newXfer,
311 const E_TransferSyntax oldXfer)
312 {
313 OFBool canWrite = OFTrue;
314
315 if (newXfer == EXS_Unknown)
316 canWrite = OFFalse;
317 else if (!itemList->empty())
318 {
319 DcmObject *dO;
320 itemList->seek(ELP_first);
321 do
322 {
323 dO = itemList->get();
324 canWrite = dO -> canWriteXfer(newXfer, oldXfer);
325 } while (itemList->seek(ELP_next) && canWrite);
326 }
327
328 return canWrite;
329 }
330
331
332 // ********************************
333
334
calcElementLength(const E_TransferSyntax xfer,const E_EncodingType enctype)335 Uint32 DcmSequenceOfItems::calcElementLength(const E_TransferSyntax xfer,
336 const E_EncodingType enctype)
337 {
338 Uint32 seqlen = DcmElement::calcElementLength(xfer, enctype);
339 if (enctype == EET_UndefinedLength)
340 seqlen += 8; // for Sequence Delimitation Tag
341 return seqlen;
342 }
343
344
345 // ********************************
346
347
getLength(const E_TransferSyntax xfer,const E_EncodingType enctype)348 Uint32 DcmSequenceOfItems::getLength(const E_TransferSyntax xfer,
349 const E_EncodingType enctype)
350 {
351 Uint32 seqlen = 0;
352 if (!itemList->empty())
353 {
354 DcmItem *dI;
355 itemList->seek(ELP_first);
356 do {
357 dI = (DcmItem*)(itemList->get());
358 seqlen += dI->calcElementLength(xfer, enctype);
359 } while (itemList->seek(ELP_next));
360 }
361 return seqlen;
362 }
363
364
365 // ********************************
366
367
computeGroupLengthAndPadding(const E_GrpLenEncoding glenc,const E_PaddingEncoding padenc,const E_TransferSyntax xfer,const E_EncodingType enctype,const Uint32 padlen,const Uint32 subPadlen,Uint32 instanceLength)368 OFCondition DcmSequenceOfItems::computeGroupLengthAndPadding(const E_GrpLenEncoding glenc,
369 const E_PaddingEncoding padenc,
370 const E_TransferSyntax xfer,
371 const E_EncodingType enctype,
372 const Uint32 padlen,
373 const Uint32 subPadlen,
374 Uint32 instanceLength)
375 {
376 OFCondition l_error = EC_Normal;
377
378 if (!itemList->empty())
379 {
380 itemList->seek(ELP_first);
381 do {
382 DcmItem *dO = (DcmItem*)itemList->get();
383 l_error = dO->computeGroupLengthAndPadding
384 (glenc, padenc, xfer, enctype, padlen,
385 subPadlen, instanceLength);
386 } while (itemList->seek(ELP_next));
387 }
388 return l_error;
389 }
390
391
392 // ********************************
393
394
makeSubObject(DcmObject * & subObject,const DcmTag & newTag,const Uint32 newLength)395 OFCondition DcmSequenceOfItems::makeSubObject(DcmObject *&subObject,
396 const DcmTag &newTag,
397 const Uint32 newLength)
398 {
399 OFCondition l_error = EC_Normal;
400 DcmItem *subItem = NULL;
401
402 switch (newTag.getEVR())
403 {
404 case EVR_na:
405 if (newTag.getXTag() == DCM_Item)
406 {
407 if (getTag().getXTag() == DCM_DirectoryRecordSequence)
408 subItem = new DcmDirectoryRecord(newTag, newLength);
409 else
410 subItem = new DcmItem(newTag, newLength);
411 }
412 else if (newTag.getXTag() == DCM_SequenceDelimitationItem)
413 l_error = EC_SequEnd;
414 else if (newTag.getXTag() == DCM_ItemDelimitationItem)
415 l_error = EC_ItemEnd;
416 else
417 l_error = EC_InvalidTag;
418 break;
419
420 default:
421 subItem = new DcmItem(newTag, newLength);
422 l_error = EC_CorruptedData;
423 break;
424 }
425 subObject = subItem;
426 return l_error;
427 }
428
429
430 // ********************************
431
432
readTagAndLength(DcmInputStream & inStream,const E_TransferSyntax xfer,DcmTag & tag,Uint32 & length)433 OFCondition DcmSequenceOfItems::readTagAndLength(DcmInputStream &inStream,
434 const E_TransferSyntax xfer,
435 DcmTag &tag,
436 Uint32 &length)
437 {
438 Uint16 groupTag = 0xffff;
439 Uint16 elementTag = 0xffff;
440
441 OFCondition l_error = EC_Normal;
442 if (inStream.avail() < 8)
443 l_error = EC_StreamNotifyClient;
444
445 if (l_error.good())
446 {
447 DcmXfer iXfer(xfer);
448 const E_ByteOrder iByteOrder = iXfer.getByteOrder();
449 if (iByteOrder == EBO_unknown)
450 return EC_IllegalCall;
451 inStream.mark();
452 inStream.read(&groupTag, 2);
453 inStream.read(&elementTag, 2);
454 swapIfNecessary(gLocalByteOrder, iByteOrder, &groupTag, 2, 2);
455 swapIfNecessary(gLocalByteOrder, iByteOrder, &elementTag, 2, 2);
456 // Tag ist gelesen
457
458 DcmTag newTag(groupTag, elementTag);
459
460 Uint32 valueLength = 0;
461 inStream.read(&valueLength, 4);
462 swapIfNecessary(gLocalByteOrder, iByteOrder, &valueLength, 4, 4);
463 if ((valueLength & 1)&&(valueLength != (Uint32) -1))
464 {
465 ofConsole.lockCerr() << "Warning: parse error in DICOM object: length of item in sequence " << Tag << " is odd" << endl;
466 ofConsole.unlockCerr();
467 }
468 length = valueLength;
469 tag = newTag; // return value: assignment-operator
470 }
471
472 debug(4, ("in Sequ.readTag errorFlag = %s", l_error.text()));
473 return l_error;
474 }
475
476
477 // ********************************
478
479
readSubItem(DcmInputStream & inStream,const DcmTag & newTag,const Uint32 newLength,const E_TransferSyntax xfer,const E_GrpLenEncoding glenc,const Uint32 maxReadLength)480 OFCondition DcmSequenceOfItems::readSubItem(DcmInputStream &inStream,
481 const DcmTag &newTag,
482 const Uint32 newLength,
483 const E_TransferSyntax xfer,
484 const E_GrpLenEncoding glenc,
485 const Uint32 maxReadLength)
486 {
487 // For DcmSequenceOfItems, subObject is always inherited from DcmItem
488 // For DcmPixelSequence, subObject is always inherited from DcmPixelItem
489 DcmObject * subObject = NULL;
490 OFCondition l_error = makeSubObject(subObject, newTag, newLength);
491 if (l_error.good() && subObject != NULL)
492 {
493 // inStream.UnsetPutbackMark(); // not needed anymore with new stream architecture
494 itemList->insert(subObject, ELP_next);
495 l_error = subObject->read(inStream, xfer, glenc, maxReadLength); // read sub-item
496 return l_error; // prevent subObject from getting deleted
497 }
498 else if (l_error == EC_InvalidTag) // try to recover parsing
499 {
500 inStream.putback();
501 ofConsole.lockCerr() << "Warning: DcmSequenceOfItems::readSubItem(): parse error occurred: " << newTag << endl;
502 ofConsole.unlockCerr();
503 debug(1, ("Warning: DcmSequenceOfItems::readSubItem(): parse error occurred:"
504 " (0x%4.4hx,0x%4.4hx)", newTag.getGTag(), newTag.getETag()));
505 }
506 else if (l_error != EC_SequEnd)
507 {
508 // inStream.UnsetPutbackMark(); // not needed anymore with new stream architecture
509 ofConsole.lockCerr() << "Error: DcmSequenceOfItems::readSubItem(): cannot create SubItem " << newTag << endl;
510 ofConsole.unlockCerr();
511 debug(1, ("Error: DcmSequenceOfItems::readSubItem(): cannot create SubItem"
512 " (0x%4.4hx,0x%4.4hx)", newTag.getGTag(), newTag.getETag()));
513 } else {
514 // inStream.UnsetPutbackMark(); // not needed anymore with new stream architecture
515 }
516
517 if (subObject) delete subObject; // only executed if makeSubObject() has returned an error
518 return l_error;
519 }
520
521
522 // ********************************
523
524
read(DcmInputStream & inStream,const E_TransferSyntax xfer,const E_GrpLenEncoding glenc,const Uint32 maxReadLength)525 OFCondition DcmSequenceOfItems::read(DcmInputStream &inStream,
526 const E_TransferSyntax xfer,
527 const E_GrpLenEncoding glenc,
528 const Uint32 maxReadLength)
529 {
530 if (fTransferState == ERW_notInitialized)
531 errorFlag = EC_IllegalCall;
532 else
533 {
534 errorFlag = inStream.status();
535
536 if (errorFlag.good() && inStream.eos())
537 errorFlag = EC_EndOfStream;
538 else if (errorFlag.good() && fTransferState != ERW_ready)
539 {
540 if (fTransferState == ERW_init)
541 {
542 fStartPosition = inStream.tell(); // Position Sequence-Value
543 fTransferState = ERW_inWork;
544 }
545
546 itemList->seek(ELP_last); // append data at end
547 while (inStream.good() && (fTransferredBytes < Length || !lastItemComplete))
548 {
549 DcmTag newTag;
550 Uint32 newValueLength = 0;
551
552 if (lastItemComplete)
553 {
554 errorFlag = readTagAndLength(inStream, xfer, newTag, newValueLength);
555
556 if (errorFlag.bad())
557 break; // finish while loop
558 else
559 fTransferredBytes += 8;
560
561 lastItemComplete = OFFalse;
562 errorFlag = readSubItem(inStream, newTag, newValueLength,
563 xfer, glenc, maxReadLength);
564 if (errorFlag.good())
565 lastItemComplete = OFTrue;
566 }
567 else
568 {
569 errorFlag = itemList->get()->read(inStream, xfer, glenc,
570 maxReadLength);
571 if (errorFlag.good())
572 lastItemComplete = OFTrue;
573 }
574 fTransferredBytes = inStream.tell() - fStartPosition;
575
576 if (errorFlag.bad())
577 break;
578 } //while
579 if ((fTransferredBytes < Length || !lastItemComplete) && errorFlag.good())
580 errorFlag = EC_StreamNotifyClient;
581 } // else errorFlag
582
583 if (errorFlag == EC_SequEnd)
584 errorFlag = EC_Normal;
585 if (errorFlag.good())
586 fTransferState = ERW_ready; // sequence is complete
587 }
588 return errorFlag;
589 }
590
591
592 // ********************************
593
594
write(DcmOutputStream & outStream,const E_TransferSyntax oxfer,const E_EncodingType enctype)595 OFCondition DcmSequenceOfItems::write(DcmOutputStream & outStream,
596 const E_TransferSyntax oxfer,
597 const E_EncodingType enctype)
598 {
599 if (fTransferState == ERW_notInitialized)
600 errorFlag = EC_IllegalCall;
601 else
602 {
603 errorFlag = outStream.status();
604 if (errorFlag.good() && fTransferState != ERW_ready)
605 {
606 if (fTransferState == ERW_init)
607 {
608 if (outStream.avail() >= DCM_TagInfoLength) // header might be smaller than this
609 {
610 if (enctype == EET_ExplicitLength)
611 Length = getLength(oxfer, enctype);
612 else
613 Length = DCM_UndefinedLength;
614 Uint32 written_bytes = 0;
615 errorFlag = writeTagAndLength(outStream, oxfer, written_bytes);
616 if (errorFlag.good())
617 {
618 fTransferState = ERW_inWork;
619 itemList->seek(ELP_first);
620 }
621 } else
622 errorFlag = EC_StreamNotifyClient;
623 }
624 if (fTransferState == ERW_inWork)
625 {
626 // itemList->get() can be NULL if buffer was full after
627 // writing the last item but before writing the sequence delimitation.
628 if (!itemList->empty() && (itemList->get() != NULL))
629 {
630 DcmObject *dO;
631 do
632 {
633 dO = itemList->get();
634 if (dO->transferState() != ERW_ready)
635 errorFlag = dO->write(outStream, oxfer, enctype);
636 } while (errorFlag.good() && itemList->seek(ELP_next));
637 }
638 if (errorFlag.good())
639 {
640 fTransferState = ERW_ready;
641 if (Length == DCM_UndefinedLength)
642 {
643 if (outStream.avail() >= 8)
644 {
645 // write sequence delimitation item
646 DcmTag delim(DCM_SequenceDelimitationItem);
647 errorFlag = writeTag(outStream, delim, oxfer);
648 Uint32 delimLen = 0L;
649 outStream.write(&delimLen, 4); // 4 bytes length
650 } else {
651 // the complete sequence is written but it
652 // is not possible to write the delimination item into the buffer.
653 errorFlag = EC_StreamNotifyClient;
654 fTransferState = ERW_inWork;
655 }
656 }
657 }
658 }
659 }
660 }
661 return errorFlag;
662 }
663
664 // ********************************
665
666
writeTagAndVR(DcmOutputStream & outStream,const DcmTag & tag,DcmEVR vr,const E_TransferSyntax oxfer)667 OFCondition DcmSequenceOfItems::writeTagAndVR(DcmOutputStream &outStream,
668 const DcmTag &tag,
669 DcmEVR vr,
670 const E_TransferSyntax oxfer)
671 {
672 OFCondition l_error = outStream.status();
673 if (l_error.good())
674 {
675 /* write the tag information (a total of 4 bytes, group number and element */
676 /* number) to the stream. Mind the transfer syntax's byte ordering. */
677 l_error = writeTag(outStream, tag, oxfer);
678 /* create an object which represents the transfer syntax */
679 DcmXfer oxferSyn(oxfer);
680 /* if the transfer syntax is one with explicit value representation */
681 /* this value's data type also has to be written to the stream. Do so */
682 /* and also write the length information to the stream. */
683 if (oxferSyn.isExplicitVR())
684 {
685 /* Create an object that represents this object's data type */
686 DcmVR myvr(vr);
687 /* get name of data type */
688 const char *vrname = myvr.getValidVRName();
689 /* write data type name to the stream (a total of 2 bytes) */
690 outStream.write(vrname, 2);
691 /* create another data type object on the basis of the above created object */
692 DcmVR outvr(myvr.getValidEVR());
693 /* in case we are dealing with a transfer syntax with explicit VR (see if above) */
694 /* and the actual VR uses extended length encoding (see DICOM standard (year 2000) */
695 /* part 5, section 7.1.2) (or the corresponding section in a later version of the */
696 /* standard) we have to add 2 reserved bytes (set to a value of 00H) to the data */
697 /* type field and the actual length field is 4 bytes wide. Write the corresponding */
698 /* information to the stream. */
699 if (outvr.usesExtendedLengthEncoding())
700 {
701 Uint16 reserved = 0;
702 outStream.write(&reserved, 2); // write 2 reserved bytes to stream
703 }
704 }
705 }
706 /* return result */
707 return l_error;
708 }
709
710
writeSignatureFormat(DcmOutputStream & outStream,const E_TransferSyntax oxfer,const E_EncodingType enctype)711 OFCondition DcmSequenceOfItems::writeSignatureFormat(DcmOutputStream &outStream,
712 const E_TransferSyntax oxfer,
713 const E_EncodingType enctype)
714 {
715 if (fTransferState == ERW_notInitialized)
716 errorFlag = EC_IllegalCall;
717 else
718 {
719 errorFlag = outStream.status();
720 if (errorFlag.good() && fTransferState != ERW_ready)
721 {
722 if (fTransferState == ERW_init)
723 {
724 if (outStream.avail() >= DCM_TagInfoLength) // header might be smaller than this
725 {
726 if (enctype == EET_ExplicitLength)
727 Length = getLength(oxfer, enctype);
728 else
729 Length = DCM_UndefinedLength;
730 errorFlag = writeTagAndVR(outStream, Tag, getVR(), oxfer);
731 /* we don't write the sequence length */
732 if (errorFlag.good())
733 {
734 fTransferState = ERW_inWork;
735 itemList->seek(ELP_first);
736 }
737 } else
738 errorFlag = EC_StreamNotifyClient;
739 }
740 if (fTransferState == ERW_inWork)
741 {
742 // itemList->get() can be NULL if buffer was full after
743 // writing the last item but before writing the sequence delimitation.
744 if (!itemList->empty() && (itemList->get() != NULL))
745 {
746 DcmObject *dO;
747 do {
748 dO = itemList->get();
749 if (dO->transferState() != ERW_ready)
750 errorFlag = dO->writeSignatureFormat(outStream, oxfer, enctype);
751 } while (errorFlag.good() && itemList->seek(ELP_next));
752 }
753 if (errorFlag.good())
754 {
755 fTransferState = ERW_ready;
756 /* we always write a sequence delimitation item tag, but no length */
757 if (outStream.avail() >= 4)
758 {
759 // write sequence delimitation item
760 DcmTag delim(DCM_SequenceDelimitationItem);
761 errorFlag = writeTag(outStream, delim, oxfer);
762 } else {
763 // Every subelement of the item was written but it
764 // is not possible to write the delimination item
765 // into the buffer.
766 fTransferState = ERW_inWork;
767 errorFlag = EC_StreamNotifyClient;
768 }
769 }
770 }
771 }
772 }
773 return errorFlag;
774 }
775
776
777 // ********************************
778
779
transferInit()780 void DcmSequenceOfItems::transferInit()
781 {
782 DcmObject::transferInit();
783 fStartPosition = 0;
784 lastItemComplete = OFTrue;
785 if (!itemList->empty())
786 {
787 itemList->seek(ELP_first);
788 do {
789 itemList->get()->transferInit();
790 } while (itemList->seek(ELP_next));
791 }
792 }
793
794
795 // ********************************
796
797
transferEnd()798 void DcmSequenceOfItems::transferEnd()
799 {
800 DcmObject::transferEnd();
801 if (!itemList->empty())
802 {
803 itemList->seek(ELP_first);
804 do {
805 itemList->get()->transferEnd();
806 } while (itemList->seek(ELP_next));
807 }
808 }
809
810
811 // ********************************
812
813
card()814 unsigned long DcmSequenceOfItems::card()
815 {
816 return itemList->card();
817 }
818
819
820 // ********************************
821
822
prepend(DcmItem * item)823 OFCondition DcmSequenceOfItems::prepend(DcmItem *item)
824 {
825 errorFlag = EC_Normal;
826 if (item != (DcmItem*)NULL)
827 itemList->prepend(item);
828 else
829 errorFlag = EC_IllegalCall;
830
831 return errorFlag;
832 }
833
834 // ********************************
835
836
insert(DcmItem * item,unsigned long where,OFBool before)837 OFCondition DcmSequenceOfItems::insert(DcmItem *item,
838 unsigned long where,
839 OFBool before)
840 {
841 errorFlag = EC_Normal;
842 if (item != (DcmItem*)NULL)
843 {
844 itemList->seek_to(where);
845 // insert before or after "where"
846 E_ListPos whichSide = (before) ? (ELP_prev) : (ELP_next);
847 itemList->insert(item, whichSide);
848 if (before)
849 {
850 debug(3, ("DcmSequenceOfItems::insert() item inserted before position %d", where));
851 } else {
852 debug(3, ("DcmSequenceOfItems::insert() item inserted after position %d", where));
853 }
854 } else
855 errorFlag = EC_IllegalCall;
856 return errorFlag;
857 }
858
859
860 // ********************************
861
862
append(DcmItem * item)863 OFCondition DcmSequenceOfItems::append(DcmItem *item)
864 {
865 errorFlag = EC_Normal;
866 if (item != (DcmItem*)NULL)
867 itemList->append(item);
868 else
869 errorFlag = EC_IllegalCall;
870 return errorFlag;
871 }
872
873
874 // ********************************
875
876
getItem(const unsigned long num)877 DcmItem* DcmSequenceOfItems::getItem(const unsigned long num)
878 {
879 errorFlag = EC_Normal;
880 DcmItem *item;
881 item = (DcmItem*)(itemList->seek_to(num)); // read item from list
882 if (item == (DcmItem*)NULL)
883 errorFlag = EC_IllegalCall;
884 return item;
885 }
886
887
888 // ********************************
889
890
nextInContainer(const DcmObject * obj)891 DcmObject *DcmSequenceOfItems::nextInContainer(const DcmObject *obj)
892 {
893 if (!obj)
894 return itemList->get(ELP_first);
895 else
896 {
897 if (itemList->get() != obj)
898 {
899 for (DcmObject *search_obj = itemList -> seek(ELP_first);
900 search_obj && search_obj != obj;
901 search_obj = itemList -> seek(ELP_next)
902 )
903 { /* do nothing */ }
904 }
905 return itemList -> seek(ELP_next);
906 }
907 }
908
909
910 // ********************************
911
912
nextObject(DcmStack & stack,const OFBool intoSub)913 OFCondition DcmSequenceOfItems::nextObject(DcmStack &stack,
914 const OFBool intoSub)
915 {
916 OFCondition l_error = EC_Normal;
917 DcmObject *container = NULL;
918 DcmObject *obj = NULL;
919 DcmObject *result = NULL;
920 OFBool examSub = intoSub;
921
922 if (stack.empty())
923 {
924 stack.push(this);
925 examSub = OFTrue;
926 }
927
928 obj = stack.top();
929 if (obj->isLeaf() || !intoSub)
930 {
931 stack.pop();
932 if (stack.card() > 0)
933 {
934 container = stack.top();
935 result = container -> nextInContainer(obj);
936 }
937 } else if (examSub)
938 result = obj -> nextInContainer(NULL);
939
940 if (result)
941 stack.push(result);
942 else if (intoSub)
943 l_error = nextUp(stack);
944 else
945 l_error = EC_SequEnd;
946
947 return l_error;
948 }
949
950
951 // ********************************
952
953
remove(const unsigned long num)954 DcmItem *DcmSequenceOfItems::remove(const unsigned long num)
955 {
956 errorFlag = EC_Normal;
957 DcmItem *item;
958 item = (DcmItem*)(itemList->seek_to(num)); // read item from list
959 if (item != (DcmItem*)NULL)
960 itemList->remove();
961 else
962 errorFlag = EC_IllegalCall;
963 return item;
964 }
965
966
967 // ********************************
968
969
remove(DcmItem * item)970 DcmItem *DcmSequenceOfItems::remove(DcmItem *item)
971 {
972 DcmItem *retItem = (DcmItem*)NULL;
973 errorFlag = EC_IllegalCall;
974 if (!itemList->empty() && item != (DcmItem*)NULL)
975 {
976 DcmObject *dO;
977 itemList->seek(ELP_first);
978 do {
979 dO = itemList->get();
980 if (dO == item)
981 {
982 itemList->remove(); // removes element from list but does not delete it
983 errorFlag = EC_Normal;
984 break;
985 }
986 } while (itemList->seek(ELP_next));
987 }
988 if (errorFlag == EC_IllegalCall)
989 retItem = (DcmItem*)NULL;
990 else
991 retItem = item;
992 return retItem;
993 }
994
995
996 // ********************************
997
998
clear()999 OFCondition DcmSequenceOfItems::clear()
1000 {
1001 errorFlag = EC_Normal;
1002 DcmObject *dO;
1003 itemList->seek(ELP_first);
1004 while (!itemList->empty())
1005 {
1006 dO = itemList->remove();
1007 if (dO != (DcmObject*)NULL)
1008 {
1009 delete dO;
1010 dO = (DcmObject*)NULL;
1011 }
1012 }
1013 Length = 0;
1014 return errorFlag;
1015 }
1016
1017
1018 // ********************************
1019
1020
verify(const OFBool autocorrect)1021 OFCondition DcmSequenceOfItems::verify(const OFBool autocorrect)
1022 {
1023 errorFlag = EC_Normal;
1024 if (!itemList->empty())
1025 {
1026 DcmObject *dO;
1027 itemList->seek(ELP_first);
1028 do {
1029 dO = itemList->get();
1030 if (dO->verify(autocorrect).bad())
1031 errorFlag = EC_CorruptedData;
1032 } while (itemList->seek(ELP_next));
1033 }
1034 if (autocorrect == OFTrue)
1035 Length = getLength();
1036
1037 return errorFlag;
1038 }
1039
1040
1041 /*
1042 * precondition: itemList not empty.
1043 * result:
1044 * - element pointer on resultStack if return value is EC_Normal
1045 * - unmodified resultStack if return value is EC_TagNotFound
1046 * continue search: push pointer to sub-element onto resultStack and start sub-search
1047 */
1048
searchSubFromHere(const DcmTagKey & tag,DcmStack & resultStack,const OFBool searchIntoSub)1049 OFCondition DcmSequenceOfItems::searchSubFromHere(const DcmTagKey &tag,
1050 DcmStack &resultStack,
1051 const OFBool searchIntoSub)
1052 {
1053 DcmObject *dO;
1054 OFCondition l_error = EC_TagNotFound;
1055 if (!itemList->empty())
1056 {
1057 itemList->seek(ELP_first);
1058 do {
1059 dO = itemList->get();
1060 if (searchIntoSub)
1061 {
1062 resultStack.push(dO);
1063 if (tag == dO->getTag())
1064 l_error = EC_Normal;
1065 else
1066 l_error = dO->search(tag, resultStack, ESM_fromStackTop, OFTrue);
1067 if (l_error.bad())
1068 resultStack.pop();
1069 } else {
1070 if (tag == dO->getTag())
1071 {
1072 resultStack.push(dO);
1073 l_error = EC_Normal;
1074 }
1075 }
1076 } while (l_error.bad() && itemList->seek(ELP_next));
1077 }
1078 return l_error;
1079 }
1080
1081
1082 // ********************************
1083
1084
search(const DcmTagKey & tag,DcmStack & resultStack,E_SearchMode mode,OFBool searchIntoSub)1085 OFCondition DcmSequenceOfItems::search(const DcmTagKey &tag,
1086 DcmStack &resultStack,
1087 E_SearchMode mode,
1088 OFBool searchIntoSub)
1089 {
1090 DcmObject *dO = (DcmObject*)NULL;
1091 OFCondition l_error = EC_TagNotFound;
1092 if (mode == ESM_afterStackTop && resultStack.top() == this)
1093 {
1094 l_error = searchSubFromHere(tag, resultStack, searchIntoSub);
1095 }
1096 else if (!itemList->empty())
1097 {
1098 if (mode == ESM_fromHere || resultStack.empty())
1099 {
1100 resultStack.clear();
1101 l_error = searchSubFromHere(tag, resultStack, searchIntoSub);
1102 }
1103 else if (mode == ESM_fromStackTop)
1104 {
1105 dO = resultStack.top();
1106 if (dO == this)
1107 l_error = searchSubFromHere(tag, resultStack, searchIntoSub);
1108 else
1109 { // continue directly in sub-tree
1110 l_error = dO->search(tag, resultStack, mode, searchIntoSub);
1111 // The next two lines destroy the stack, delete them
1112 // if (l_error.bad()) // raeumt nur die oberste Stackebene
1113 // resultStack.pop(); // ab; der Rest ist unveraendert
1114 }
1115 }
1116 else if (mode == ESM_afterStackTop && searchIntoSub)
1117 {
1118 // resultStack enthaelt Zielinformationen:
1119 // - stelle Zustand der letzen Suche in den einzelnen Suchroutinen
1120 // wieder her
1121 // - finde Position von dO in Baum-Struktur
1122 // 1. suche eigenen Stack-Eintrag
1123 // - bei Fehlschlag Suche beenden
1124 // 2. nehme naechsthoeheren Eintrag dnO
1125 // 3. stelle eigene Liste auf Position von dnO
1126 // 4. starte Suche ab dnO
1127
1128 unsigned long i = resultStack.card();
1129 while (i > 0 && (dO = resultStack.elem(i-1)) != this)
1130 {
1131 i--;
1132 }
1133 if (dO != this && resultStack.card() > 0)
1134 { // highest level is never in resultStack
1135 i = resultStack.card()+1;// now points to highest level +1
1136 dO = this; // match in highest level
1137 }
1138 if (dO == this)
1139 {
1140 if (i == 1) // resultStack.top() found
1141 l_error = EC_TagNotFound; // don't mark as match, see above
1142 else
1143 {
1144 E_SearchMode submode = mode;
1145 OFBool searchNode = OFTrue;
1146 DcmObject *dnO;
1147 dnO = resultStack.elem(i-2); // node of next level
1148 itemList->seek(ELP_first);
1149 do {
1150 dO = itemList->get();
1151 searchNode = searchNode ? (dO != dnO) : OFFalse;
1152 if (!searchNode)
1153 { // continue search
1154 if (submode == ESM_fromStackTop)
1155 resultStack.push(dO); // update stack
1156 if (submode == ESM_fromStackTop && tag == dO->getTag())
1157 l_error = EC_Normal;
1158 else
1159 l_error = dO->search(tag, resultStack, submode, OFTrue);
1160 if (l_error.bad())
1161 resultStack.pop();
1162 else
1163 break;
1164 submode = ESM_fromStackTop; // normal search from here
1165 }
1166 } while (itemList->seek(ELP_next));
1167 }
1168 } else // probably never reached
1169 l_error = EC_IllegalCall;
1170 } // (mode == ESM_afterStackTop
1171 else
1172 l_error = EC_IllegalCall;
1173 }
1174 return l_error;
1175 }
1176
1177
1178 // ********************************
1179
1180
searchErrors(DcmStack & resultStack)1181 OFCondition DcmSequenceOfItems::searchErrors(DcmStack &resultStack)
1182 {
1183 OFCondition l_error = errorFlag;
1184 DcmObject *dO = (DcmObject*)NULL;
1185 if (errorFlag.bad())
1186 resultStack.push(this);
1187 if (!itemList->empty())
1188 {
1189 itemList->seek(ELP_first);
1190 do {
1191 OFCondition err = EC_Normal;
1192 dO = itemList->get();
1193 if ((err = dO->searchErrors(resultStack)).bad())
1194 l_error = err;
1195 } while (itemList->seek(ELP_next));
1196 }
1197 return l_error;
1198 }
1199
1200
1201 // ********************************
1202
1203
loadAllDataIntoMemory()1204 OFCondition DcmSequenceOfItems::loadAllDataIntoMemory()
1205 {
1206 OFCondition l_error = EC_Normal;
1207 if (!itemList->empty())
1208 {
1209 itemList->seek(ELP_first);
1210 do {
1211 OFCondition err = EC_Normal;
1212 DcmObject *dO = itemList->get();
1213 if ((err = dO->loadAllDataIntoMemory()).bad())
1214 l_error = err;
1215 } while (itemList->seek(ELP_next));
1216 }
1217 return l_error;
1218 }
1219
1220
1221 // ********************************
1222
1223
isSignable() const1224 OFBool DcmSequenceOfItems::isSignable() const
1225 {
1226 // a sequence is signable if the tag and VR doesn't prevent signing
1227 // and if none of the items contains a UN element
1228 return (DcmElement::isSignable() && (! containsUnknownVR()));
1229 }
1230
1231
containsUnknownVR() const1232 OFBool DcmSequenceOfItems::containsUnknownVR() const
1233 {
1234 if (!itemList->empty())
1235 {
1236 itemList->seek(ELP_first);
1237 do {
1238 if (itemList->get()->containsUnknownVR())
1239 return OFTrue;
1240 } while (itemList->seek(ELP_next));
1241 }
1242 return OFFalse;
1243 }
1244