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