1 /*
2  *
3  *  Copyright (C) 2000-2017, 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: dcmsr
15  *
16  *  Author: Joerg Riesmeier
17  *
18  *  Purpose:
19  *    classes: DSRDocumentTreeNode
20  *
21  */
22 
23 
24 #ifndef DSRDOCTN_H
25 #define DSRDOCTN_H
26 
27 #include "dcmtk/config/osconfig.h"   /* make sure OS specific configuration is included first */
28 
29 #include "dcmtk/dcmsr/dsrtree.h"
30 #include "dcmtk/dcmsr/dsrcodvl.h"
31 
32 
33 /*-----------------------*
34  *  forward declaration  *
35  *-----------------------*/
36 
37 class DSRIODConstraintChecker;
38 
39 
40 /*---------------------*
41  *  class declaration  *
42  *---------------------*/
43 
44 /** Base class for content items
45  */
46 class DCMTK_DCMSR_EXPORT DSRDocumentTreeNode
47   : public DSRTreeNode
48 {
49     // allow direct access to protected methods
50     friend class DSRTree<DSRDocumentTreeNode>;
51     friend class DSRTreeNodeCursor<DSRDocumentTreeNode>;
52     // also for the derived cursor classes
53     friend class DSRDocumentTreeNodeCursor;
54     friend class DSRIncludedTemplateNodeCursor;
55 
56     // allow access to getConceptNamePtr()
57     friend class DSRContentItem;
58 
59   public:
60 
61     /** constructor.
62      *  The 'valueType' can never be changed after the tree node has been created
63      *  (therefore, the corresponding member variable is declared "const").
64      ** @param  relationshipType  type of relationship to the parent tree node.  Should
65      *                            not be DSRTypes::RT_invalid, and DSRTypes::RT_isRoot
66      *                            only for the root node.
67      *  @param  valueType         value type of the associated content item.  Should not
68      *                            be DSRTypes::VT_invalid.
69      */
70     DSRDocumentTreeNode(const E_RelationshipType relationshipType,
71                         const E_ValueType valueType);
72 
73     /** copy constructor.
74      *  Please note that the member variables of the base class DSRTreeNode are not copied
75      *  because the new tree node is not (yet) part of a document tree.  Furthermore, the
76      *  following member variables of this class are also not copied but initialized with
77      *  their respective default values:
78      *  - ReferenceTarget
79      *  - MACParameters
80      *  - DigitalSignatures
81      *
82      ** @param  node  tree node to be copied
83      */
84     DSRDocumentTreeNode(const DSRDocumentTreeNode &node);
85 
86     /** destructor
87      */
88     virtual ~DSRDocumentTreeNode();
89 
90     /** comparison operator "equal".
91      *  Two tree nodes are regarded as equal if the relationship type, the value type and the
92      *  concept name are equal.  Other information is not used unless implemented in a derived
93      *  class.
94      ** @param  node  tree node that should be compared to the current one
95      ** @return OFTrue if both tree nodes are equal, OFFalse otherwise
96      */
97     virtual OFBool operator==(const DSRDocumentTreeNode &node) const;
98 
99     /** comparison operator "not equal".
100      *  Two tree nodes are regarded as not equal if either the relationship type or the value
101      *  type or the concept name are not equal.  Other information is not used unless implemented
102      *  in a derived class.
103      ** @param  node  tree node that should be compared to the current one
104      ** @return OFTrue if both tree nodes are not equal, OFFalse otherwise
105      */
106     virtual OFBool operator!=(const DSRDocumentTreeNode &node) const;
107 
108     /** clone this tree node (abstract).
109      *  Internally, the copy constructor is used, so the corresponding comments apply.
110      ** @return copy of this tree node
111      */
112     virtual DSRDocumentTreeNode *clone() const = 0;
113 
114     /** clear all member variables.
115      *  This does not apply to the relationship and value type since they are never changed.
116      */
117     virtual void clear();
118 
119     /** check whether the content item is valid.
120      *  The content item is valid if the relationship type and the value type are both not invalid.
121      ** @return OFTrue if tree node is valid, OFFalse otherwise
122      */
123     virtual OFBool isValid() const;
124 
125     /** check whether the value of the content item is valid.  See derived classes for details.
126      ** @return OFTrue if the value is valid, OFFalse otherwise
127      */
128     virtual OFBool hasValidValue() const;
129 
130     /** check whether the content is short.
131      *  This method is used to check whether the rendered output of this content item can be
132      *  expanded inline or not (used for renderHTML()).  This base class always returns OFTrue.
133      ** @param  flags  flag used to customize the output (see DSRTypes::HF_xxx)
134      ** @return OFTrue if the content is short, OFFalse otherwise
135      */
136     virtual OFBool isShort(const size_t flags) const;
137 
138     /** check whether template identification is set
139      ** @return OFTrue if template identification is set, OFFalse otherwise
140      */
141     virtual OFBool hasTemplateIdentification() const;
142 
143     /** print content item.
144      *  The output of a content item depends on its value type.  This general method prints
145      *  only those parts which all derived classes (= value types) do have in common, i.e. the
146      *  type of relationship, the value type and the (optional) concept name.
147      *  A typical output looks like this: has concept mod CODE: (,,"Concept")
148      ** @param  stream  output stream to which the content item should be printed
149      *  @param  flags   flag used to customize the output (see DSRTypes::PF_xxx)
150      ** @return status, EC_Normal if successful, an error code otherwise
151      */
152     virtual OFCondition print(STD_NAMESPACE ostream &stream,
153                               const size_t flags) const;
154 
155     /** print extended information on the content item.
156      *  The following details are printed (if present and output is enabled): observation
157      *  date/time (in curly brackets), annotation text (in quotation marks) and template
158      *  identification (after a hash mark).  This method is intended to be called after
159      *  the general print() method, e.g. like it is done by DSRDocumentSubTree::print().
160      ** @param  stream  output stream to which the extended information should be printed
161      *  @param  flags   flag used to customize the output (see DSRTypes::PF_xxx)
162      ** @return status, EC_Normal if successful, an error code otherwise
163      */
164     virtual OFCondition printExtended(STD_NAMESPACE ostream &stream,
165                                       const size_t flags) const;
166 
167     /** read content item from dataset.
168      *  A number of readXXX() methods are called (see "protected" part) in order to retrieve all
169      *  possibly nested content items from the dataset.
170      ** @param  dataset            DICOM dataset from which the content item should be read
171      *  @param  constraintChecker  checks relationship content constraints of the associated IOD
172      *  @param  flags              flag used to customize the reading process (see DSRTypes::RF_xxx)
173      ** @return status, EC_Normal if successful, an error code otherwise
174      */
175     virtual OFCondition read(DcmItem &dataset,
176                              const DSRIODConstraintChecker *constraintChecker,
177                              const size_t flags);
178 
179     /** write content item to dataset.
180      *  A number of writeXXX() methods are called (see "protected" part) in order to write all
181      *  possibly nested content items to the dataset.
182      ** @param  dataset      DICOM dataset to which the content item should be written
183      *  @param  markedItems  optional stack where pointers to all 'marked' content items
184      *                       (DICOM datasets/items) are added to during the write process.
185      *                       Can be used to digitally sign parts of the document tree.
186      ** @return status, EC_Normal if successful, an error code otherwise
187      */
188     virtual OFCondition write(DcmItem &dataset,
189                               DcmStack *markedItems = NULL);
190 
191     /** read general XML document tree node data
192      ** @param  doc           document containing the XML file content
193      *  @param  cursor        cursor pointing to the starting node
194      *  @param  documentType  type of the document to be read (used for debug output only)
195      *  @param  flags         flag used to customize the reading process (see DSRTypes::XF_xxx)
196      ** @return status, EC_Normal if successful, an error code otherwise
197      */
198     virtual OFCondition readXML(const DSRXMLDocument &doc,
199                                 DSRXMLCursor cursor,
200                                 const E_DocumentType documentType,
201                                 const size_t flags);
202 
203     /** write content item in XML format
204      ** @param  stream  output stream to which the XML document is written
205      *  @param  flags   flag used to customize the output (see DSRTypes::XF_xxx)
206      ** @return status, EC_Normal if successful, an error code otherwise
207      */
208     virtual OFCondition writeXML(STD_NAMESPACE ostream &stream,
209                                  const size_t flags) const;
210 
211     /** render content item in HTML/XHTML format.
212      *  After rendering the current content item all child nodes (if any) are also rendered (see
213      *  renderHTMLChildNodes() for details).
214      ** @param  docStream     output stream to which the main HTML/XHTML document is written
215      *  @param  annexStream   output stream to which the HTML/XHTML document annex is written
216      *  @param  nestingLevel  current nesting level.  Used to render section headings.
217      *  @param  annexNumber   reference to the variable where the current annex number is stored.
218      *                        Value is increased automatically by 1 after a new entry has been added.
219      *  @param  flags         flag used to customize the output (see DSRTypes::HF_xxx)
220      ** @return status, EC_Normal if successful, an error code otherwise
221      */
222     virtual OFCondition renderHTML(STD_NAMESPACE ostream &docStream,
223                                    STD_NAMESPACE ostream &annexStream,
224                                    const size_t nestingLevel,
225                                    size_t &annexNumber,
226                                    const size_t flags) const;
227 
228     /** check whether content item is digitally signed.
229      *  A content item is signed if the DigitalSignaturesSequence exists.  This sequence is read
230      *  from the dataset if present and the 'signature' flag for the 'read' method is turned on.
231      ** @return OFTrue if content item is signed, OFFalse otherwise
232      */
isSigned()233     inline OFBool isSigned()
234     {
235         return !DigitalSignatures.isEmpty();
236     }
237 
238     /** check whether content item is marked.
239      *  Use method setMark() to mark and unmark the current content item.
240      *  Pointers to the DICOM dataset/item of marked content items are added to the optional
241      *  stack when calling the DSRDocument::write() method.  This mechanism can e.g. be used
242      *  to digitally sign particular content items.
243      ** @return OFTrue if content item is marked, OFFalse otherwise
244      */
isMarked()245     inline OFBool isMarked() const
246     {
247         return MarkFlag;
248     }
249 
250     /** mark/unmark the current content item.
251      *  See explanation for method isMarked() for details.
252      *  @param  flag  mark item if OFTrue, unmark otherwise
253      */
setMark(const OFBool flag)254     inline void setMark(const OFBool flag)
255     {
256         MarkFlag = flag;
257     }
258 
259     /** check whether the current content item is target of a by-reference relationship
260      ** @return OFTrue if the content item is target, OFFalse otherwise
261      */
isReferenceTarget()262     inline OFBool isReferenceTarget() const
263     {
264         return ReferenceTarget;
265     }
266 
267     /** specify whether the current content item is target of a by-reference relationship
268      ** @param  isTarget  OFTrue if the content item is target (default), OFFalse otherwise
269      */
270     inline void setReferenceTarget(const OFBool isTarget = OFTrue)
271     {
272         ReferenceTarget = isTarget;
273     }
274 
275     /** check whether the current content item has any children
276      ** @return OFTrue if there are any child nodes, OFFalse otherwise
277      */
hasChildNodes()278     inline OFBool hasChildNodes() const
279     {
280         return (getDown() != NULL);
281     }
282 
283     /** check whether the current content item has any siblings
284      ** @return OFTrue if there are any sibling nodes, OFFalse otherwise
285      */
hasSiblingNodes()286     inline OFBool hasSiblingNodes() const
287     {
288         return (getPrev() != NULL) || (getNext() != NULL);
289     }
290 
291     /** get ID of the current tree node
292      ** @return ID of the current tree node (should never be 0)
293      */
getNodeID()294     inline size_t getNodeID() const
295     {
296         return getIdent();
297     }
298 
299     /** get relationship type of the current content item
300      ** @return relationship type of the current content item (might be DSRTypes::RT_invalid)
301      */
getRelationshipType()302     inline E_RelationshipType getRelationshipType() const
303     {
304         return RelationshipType;
305     }
306 
307     /** set relationship type of the current content item (if previously unknown).
308      *  Please note that changing the relationship type (which was originally passed to the
309      *  constructor of this class) only works if the current value is DSRTypes::RT_unknown.
310      *  This is needed for inserting document subtrees where the top-level nodes might have an
311      *  "unknown" relationship to the parent node (see DSRDocumentSubTree::insertSubTree()).
312      ** @param  relationshipType  type of relationship to the parent tree node.  Should not be
313      *                            DSRTypes::RT_invalid or DSRTypes::RT_unknown.  Be careful
314      *                            with DSRTypes::RT_isRoot, use it for root nodes only.
315      ** @return status, EC_Normal if successful, an error code otherwise
316      */
317     virtual OFCondition setRelationshipType(const E_RelationshipType relationshipType);
318 
319     /** get value type of the current content item
320      ** @return value type of the current content item (might be DSRTypes::VT_invalid)
321      */
getValueType()322     inline E_ValueType getValueType() const
323     {
324         return ValueType;
325     }
326 
327     /** get reference to the concept name
328      ** @return reference to the concept name (code, might be empty/invalid)
329      */
getConceptName()330     inline const DSRCodedEntryValue &getConceptName() const
331     {
332         return ConceptName;
333     }
334 
335     /** get copy of the concept name.
336      *  Code describing the concept represented by this content item.  Also conveys the value
337      *  of document title and section headings in documents.
338      ** @param  conceptName  reference to a variable where the code should be stored
339      ** @return status, EC_Normal if successful, an error code otherwise
340      */
341     virtual OFCondition getConceptName(DSRCodedEntryValue &conceptName) const;
342 
343     /** set the concept name.
344      *  Code describing the concept represented by this content item.  Also conveys the value
345      *  of document title and section headings in documents.
346      *  If the new code is invalid the current one is not replaced.  An empty code can
347      *  be used to clear the current concept name.
348      ** @param  conceptName  code to be set as the new concept name (checked before set)
349      *  @param  check        check 'conceptName' for validity if enabled.  See
350      *                       DSRCodedEntryValue::checkCode() for details.
351      ** @return status, EC_Normal if successful, an error code otherwise
352      */
353     virtual OFCondition setConceptName(const DSRCodedEntryValue &conceptName,
354                                        const OFBool check = OFTrue);
355 
356     /** get observation date/time.
357      *  This is the date and time on which this content item was completed.  Might be empty
358      *  if the date and time do not differ from the content date and time, see DSRDocument.
359      ** @return observation date/time of current content item (might be empty/invalid)
360      */
getObservationDateTime()361     inline const OFString &getObservationDateTime() const
362     {
363         return ObservationDateTime;
364     }
365 
366     /** set observation date/time.
367      *  This is the date and time on which this content item was completed.  Might be empty
368      *  if the date and time do not differ from the content date and time, see DSRDocument.
369      ** @param  observationDateTime  value to be set (might be an empty string)
370      *  @param  check                check 'observationDateTime' for conformance with VR (DT)
371      *                               and VM (1) if enabled
372      ** @return status, EC_Normal if successful, an error code otherwise
373      */
374     virtual OFCondition setObservationDateTime(const OFString &observationDateTime,
375                                                const OFBool check = OFTrue);
376 
377     /** set observation date/time from element.
378      *  This is the date and time on which this content item was completed.  Might be empty
379      *  if the date and time do not differ from the content date and time, see DSRDocument.
380      ** @param  delem  DICOM element from which the date/time value should be retrieved
381      *  @param  pos    index of the value in case of multi-valued elements (0..vm-1)
382      *  @param  check  check date/time value for conformance with VR (DT) and VM (1) if
383      *                 enabled
384      ** @return status, EC_Normal if successful, an error code otherwise
385      */
386     virtual OFCondition setObservationDateTime(const DcmElement &delem,
387                                                const unsigned long pos = 0,
388                                                const OFBool check = OFTrue);
389 
390     /** set observation date/time from dataset.
391      *  This is the date and time on which this content item was completed.  Might be empty
392      *  if the date and time do not differ from the content date and time, see DSRDocument.
393      ** @param  dataset  DICOM dataset from which the date/time value should be retrieved
394      *  @param  tagKey   DICOM tag specifying the attribute from which the value should be
395      *                   retrieved.  The search is limited to the top-level of the dataset.
396      *  @param  pos      index of the value in case of multi-valued elements (0..vm-1)
397      *  @param  check    check date/time value for conformance with VR (DT) and VM (1) if
398      *                   enabled
399      ** @return status, EC_Normal if successful, an error code otherwise
400      */
401     virtual OFCondition setObservationDateTime(DcmItem &dataset,
402                                                const DcmTagKey &tagKey,
403                                                const unsigned long pos = 0,
404                                                const OFBool check = OFTrue);
405 
406     /** get observation unique identifier.
407      *  The UID represents the semantic content of the observation; an encoding of the same
408      *  observation with the same context into another representation may use the same UID.
409      ** @return observation unique identifier of current content item (might be empty/invalid)
410      */
getObservationUID()411     inline const OFString &getObservationUID() const
412     {
413         return ObservationUID;
414     }
415 
416     /** set observation unique identifier.
417      *  The UID represents the semantic content of the observation; an encoding of the same
418      *  observation with the same context into another representation may use the same UID.
419      ** @param  observationUID  value to be set (might be an empty string)
420      *  @param  check           check 'observationUID' for conformance with VR (UI) and VM (1)
421      *                          if enabled
422      ** @return status, EC_Normal if successful, an error code otherwise
423      */
424     virtual OFCondition setObservationUID(const OFString &observationUID,
425                                           const OFBool check = OFTrue);
426 
427     /** compare template identification with given values
428      ** @param  templateIdentifier  template identifier to compare with
429      *  @param  mappingResource     mapping resource that defines the template
430      *  @param  mappingResourceUID  uniquely identifies the mapping resource (optional).
431      *                              Not used for comparison if the value is empty.
432      ** @result OFTrue if template identification is identical, OFFalse otherwise
433      */
434     virtual OFBool compareTemplateIdentification(const OFString &templateIdentifier,
435                                                  const OFString &mappingResource,
436                                                  const OFString &mappingResourceUID = "") const;
437 
438     /** get template identifier and mapping resource.
439      *  This value pair identifies the template that was used to create this content item
440      *  (and its children).  According to the DICOM standard, it is "required if a template
441      *  was used to define the content of this Item, and the template consists of a single
442      *  CONTAINER with nested content, and it is the outermost invocation of a set of
443      *  nested templates that start with the same CONTAINER."  The identification is valid
444      *  if both values are either present (non-empty) or absent (empty).
445      ** @param  templateIdentifier  identifier of the template (might be empty)
446      *  @param  mappingResource     mapping resource that defines the template (might be empty)
447      ** @return status, EC_Normal if successful, an error code otherwise
448      */
449     virtual OFCondition getTemplateIdentification(OFString &templateIdentifier,
450                                                   OFString &mappingResource) const;
451 
452     /** get template identifier, mapping resource and optional mapping resource UID.
453      *  This value triple identifies the template that was used to create this content item
454      *  (and its children).  According to the DICOM standard, it is "required if a template
455      *  was used to define the content of this Item, and the template consists of a single
456      *  CONTAINER with nested content, and it is the outermost invocation of a set of
457      *  nested templates that start with the same CONTAINER."  The identification is valid
458      *  if the first two values are either present (non-empty) or all three are absent (empty).
459      ** @param  templateIdentifier  identifier of the template (might be empty)
460      *  @param  mappingResource     mapping resource that defines the template (might be empty)
461      *  @param  mappingResourceUID  uniquely identifies the mapping resource (might be empty)
462      ** @return status, EC_Normal if successful, an error code otherwise
463      */
464     virtual OFCondition getTemplateIdentification(OFString &templateIdentifier,
465                                                   OFString &mappingResource,
466                                                   OFString &mappingResourceUID) const;
467 
468     /** set template identifier and mapping resource.
469      *  The identification is valid if the first two values are either present (non-empty) or
470      *  all three values are absent (empty).  See getTemplateIdentification() for details.
471      *  A warning message is reported to the logger if a template identification is specified
472      *  for a content item that is not a CONTAINER.
473      ** @param  templateIdentifier  identifier of the template to be set
474      *  @param  mappingResource     mapping resource that defines the template
475      *  @param  mappingResourceUID  uniquely identifies the mapping resource (optional)
476      *  @param  check               check 'templateIdentifier', 'mappingResource' and
477      *                              'mappingResourceUID' for conformance with VR (CS,UI) and
478      *                              VM (1) if enabled
479      ** @return status, EC_Normal if successful, an error code otherwise
480      */
481     virtual OFCondition setTemplateIdentification(const OFString &templateIdentifier,
482                                                   const OFString &mappingResource,
483                                                   const OFString &mappingResourceUID = "",
484                                                   const OFBool check = OFTrue);
485 
486     /** remove digital signatures from content item.
487      *  This method clears the MACParametersSequence and the DigitalSignaturesSequence for
488      *  the current content item which have been filled during reading.
489      */
490     void removeSignatures();
491 
492 
493   protected:
494 
495     /** get pointer to the concept name
496      ** @return pointer to the concept name (never NULL)
497      */
getConceptNamePtr()498     inline DSRCodedEntryValue *getConceptNamePtr()
499     {
500         return &ConceptName;
501     }
502 
503     /** get pointer to previous tree node
504      ** @return pointer to previous tree node (might be NULL)
505      */
getPrev()506     inline DSRDocumentTreeNode *getPrev() const
507     {
508         return OFstatic_cast(DSRDocumentTreeNode *, DSRTreeNode::getPrev());
509     }
510 
511     /** get pointer to next tree node
512      ** @return pointer to next tree node (might be NULL)
513      */
getNext()514     inline DSRDocumentTreeNode *getNext() const
515     {
516         return OFstatic_cast(DSRDocumentTreeNode *, DSRTreeNode::getNext());
517     }
518 
519     /** get pointer to first child node
520      ** @return pointer to first child node (might be NULL)
521      */
getDown()522     inline DSRDocumentTreeNode *getDown() const
523     {
524         return OFstatic_cast(DSRDocumentTreeNode *, DSRTreeNode::getDown());
525     }
526 
527     /** get unique identifier of this node
528      ** @return unique identifier of this node
529      */
getIdent()530     inline size_t getIdent() const
531     {
532         return DSRTreeNode::getIdent();
533     }
534 
535     /** create a new node and append it to the current one
536      ** @param  previousNode       reference to the pointer to the previous node (sibling).
537      *                             Used to decide whether the new node is a child (value=NULL)
538      *                             or a sibling (!=NULL).  NB: The value might be modified
539      *                             inside this method (to store a reference to the previous node).
540      *  @param  relationshipType   relationship type of the new node with regard to the
541      *                             current one
542      *  @param  valueType          value type of node to be added
543      *  @param  constraintChecker  checks relationship content constraints of the associated IOD
544      ** @return status, EC_Normal if successful, an error code otherwise
545      */
546     OFCondition createAndAppendNewNode(DSRDocumentTreeNode *&previousNode,
547                                        const E_RelationshipType relationshipType,
548                                        const E_ValueType valueType,
549                                        const DSRIODConstraintChecker *constraintChecker = NULL);
550 
551     /** read content item (value) from dataset.
552      *  This method does nothing for this base class, but derived classes overwrite it to read
553      *  the contents according to their value type.
554      ** @param  dataset  DICOM dataset from which the content item should be read
555      *  @param  flags    flag used to customize the reading process (see DSRTypes::RF_xxx)
556      ** @return status, EC_Normal if successful, an error code otherwise
557      */
558     virtual OFCondition readContentItem(DcmItem &dataset,
559                                         const size_t flags);
560 
561     /** write content item (value) to dataset.
562      *  This method does nothing for this base class, but derived classes overwrite it to write
563      *  the contents according to their value type.
564      ** @param  dataset  DICOM dataset to which the content item should be written
565      ** @return status, EC_Normal if successful, an error code otherwise
566      */
567     virtual OFCondition writeContentItem(DcmItem &dataset) const;
568 
569     /** read content item specific XML data.
570      *  This method does nothing for this base class, but derived classes overwrite it to read
571      *  the contents according to their value type.
572      ** @param  doc     document containing the XML file content
573      *  @param  cursor  cursor pointing to the starting node
574      *  @param  flags   flag used to customize the output (see DSRTypes::XF_xxx)
575      ** @return status, EC_Normal if successful, an error code otherwise
576      */
577     virtual OFCondition readXMLContentItem(const DSRXMLDocument &doc,
578                                            DSRXMLCursor cursor,
579                                            const size_t flags);
580 
581     /** render content item (value) in HTML/XHTML format.
582      *  This method does nothing for this base class, but derived classes overwrite it to render
583      *  the contents according to their value type.
584      ** @param  docStream     output stream to which the main HTML/XHTML document is written
585      *  @param  annexStream   output stream to which the HTML/XHTML document annex is written
586      *  @param  nestingLevel  current nesting level.  Used to render section headings.
587      *  @param  annexNumber   reference to the variable where the current annex number is stored.
588      *                        Value is increased automatically by 1 after a new entry has been added.
589      *  @param  flags         flag used to customize the output (see DSRTypes::HF_xxx)
590      ** @return status, EC_Normal if successful, an error code otherwise
591      */
592     virtual OFCondition renderHTMLContentItem(STD_NAMESPACE ostream &docStream,
593                                               STD_NAMESPACE ostream &annexStream,
594                                               const size_t nestingLevel,
595                                               size_t &annexNumber,
596                                               const size_t flags) const;
597 
598     /** write common item start (XML tag)
599      ** @param  stream          output stream to which the XML document is written
600      *  @param  flags           flag used to customize the output (see DSRTypes::XF_xxx)
601      *  @param  closingBracket  write closing bracket of XML start tag if OFTrue, otherwise the
602      *                          bracket has to be closed in the calling method
603      */
604     void writeXMLItemStart(STD_NAMESPACE ostream &stream,
605                            const size_t flags,
606                            const OFBool closingBracket = OFTrue) const;
607 
608     /** write common item start (XML tag)
609      ** @param  stream  output stream to which the XML document is written
610      *  @param  flags   flag used to customize the output (see DSRTypes::XF_xxx)
611      */
612     void writeXMLItemEnd(STD_NAMESPACE ostream &stream,
613                          const size_t flags) const;
614 
615     /** read SR document content module
616      ** @param  dataset            DICOM dataset from which the data should be read
617      *  @param  constraintChecker  checks relationship content constraints of the associated IOD
618      *  @param  flags              flag used to customize the reading process (see DSRTypes::RF_xxx)
619      ** @return status, EC_Normal if successful, an error code otherwise
620      */
621     OFCondition readSRDocumentContentModule(DcmItem &dataset,
622                                             const DSRIODConstraintChecker *constraintChecker,
623                                             const size_t flags);
624 
625     /** write SR document content module
626      ** @param  dataset      DICOM dataset to which the data should be written
627      *  @param  markedItems  optional stack where pointers to all 'marked' content items
628      *                       (DICOM datasets/items) are added to during the write process.
629      ** @return status, EC_Normal if successful, an error code otherwise
630      */
631     OFCondition writeSRDocumentContentModule(DcmItem &dataset,
632                                              DcmStack *markedItems);
633 
634     /** read document relationship macro
635      ** @param  dataset            DICOM dataset from which the data should be read
636      *  @param  constraintChecker  checks relationship content constraints of the associated IOD
637      *  @param  posString          location of the current content item (e.g.\ "1.2.3")
638      *  @param  flags              flag used to customize the reading process (see DSRTypes::RF_xxx)
639      ** @return status, EC_Normal if successful, an error code otherwise
640      */
641     OFCondition readDocumentRelationshipMacro(DcmItem &dataset,
642                                               const DSRIODConstraintChecker *constraintChecker,
643                                               const OFString &posString,
644                                               const size_t flags);
645 
646     /** write document relationship macro
647      ** @param  dataset      DICOM dataset to which the data should be written
648      *  @param  markedItems  optional stack where pointers to all 'marked' content items
649      *                       (DICOM datasets/items) are added to during the write process.
650      ** @return status, EC_Normal if successful, an error code otherwise
651      */
652     OFCondition writeDocumentRelationshipMacro(DcmItem &dataset,
653                                                DcmStack *markedItems);
654 
655     /** read document content macro
656      ** @param  dataset    DICOM dataset from which the data should be read
657      *  @param  posString  location of the current content item (e.g.\ "1.2.3")
658      *  @param  flags      flag used to customize the reading process (see DSRTypes::RF_xxx)
659      ** @return status, EC_Normal if successful, an error code otherwise
660      */
661     OFCondition readDocumentContentMacro(DcmItem &dataset,
662                                          const OFString &posString,
663                                          const size_t flags);
664 
665     /** write document content macro
666      ** @param  dataset  DICOM dataset to which the data should be written
667      ** @return status, EC_Normal if successful, an error code otherwise
668      */
669     OFCondition writeDocumentContentMacro(DcmItem &dataset) const;
670 
671     /** read content sequence
672      ** @param  dataset            DICOM dataset from which the data should be read
673      *  @param  constraintChecker  checks relationship content constraints of the associated IOD
674      *  @param  posString          location of the current content item (e.g.\ "1.2.3")
675      *  @param  flags              flag used to customize the reading process (see DSRTypes::RF_xxx)
676      ** @return status, EC_Normal if successful, an error code otherwise
677      */
678     OFCondition readContentSequence(DcmItem &dataset,
679                                     const DSRIODConstraintChecker *constraintChecker,
680                                     const OFString &posString,
681                                     const size_t flags);
682 
683     /** write content sequence
684      ** @param  dataset      DICOM dataset to which the data should be written
685      *  @param  markedItems  optional stack where pointers to all 'marked' content items
686      *                       (DICOM datasets/items) are added to during the write process.
687      ** @return status, EC_Normal if successful, an error code otherwise
688      */
689     OFCondition writeContentSequence(DcmItem &dataset,
690                                      DcmStack *markedItems) const;
691 
692     /** render concept name in HTML/XHTML format.
693      *  If the optional observation date/time field is non-empty, it is also rendered.
694      ** @param  docStream  output stream to which the main HTML/XHTML document is written
695      *  @param  flags      flag used to customize the output (see DSRTypes::HF_xxx)
696      ** @return status, EC_Normal if successful, an error code otherwise
697      */
698     OFCondition renderHTMLConceptName(STD_NAMESPACE ostream &docStream,
699                                       const size_t flags) const;
700 
701     /** render child nodes in HTML/XHTML format
702      ** @param  docStream     output stream to which the main HTML/XHTML document is written
703      *  @param  annexStream   output stream to which the HTML/XHTML document annex is written
704      *  @param  nestingLevel  current nesting level.  Used to render section headings.
705      *  @param  annexNumber   reference to the variable where the current annex number is stored.
706      *                        Value is increased automatically by 1 after a new entry has been added.
707      *  @param  flags         flag used to customize the output (see DSRTypes::HF_xxx)
708      ** @return status, EC_Normal if successful, an error code otherwise
709      */
710     OFCondition renderHTMLChildNodes(STD_NAMESPACE ostream &docStream,
711                                      STD_NAMESPACE ostream &annexStream,
712                                      const size_t nestingLevel,
713                                      size_t &annexNumber,
714                                      const size_t flags) const;
715 
716   // --- static function ---
717 
718     /** convert relationship type into a text used for HTML rendering
719      ** @param  relationshipType  type of relationship to be converted
720      *  @param  relationshipText  reference to string variable where the resulting text should be
721      *                            stored.  Value is cleared if 'relationshipType' is invalid or not
722      *                            supported.
723      *  @param  flags             flag used to customize the output (see DSRTypes::HF_xxx)
724      ** @return reference to the 'relationshipText' string (might be empty)
725      */
726     static const OFString &getRelationshipText(const E_RelationshipType relationshipType,
727                                                OFString &relationshipText,
728                                                const size_t flags);
729 
730     /** check the specified template identification values for validity.
731      *  The identification is valid if the first two values are either present (non-empty) or
732      *  absent (empty).  In the latter case, the third (optional) parameter also has to be empty.
733      ** @param  templateIdentifier  identifier of the template
734      *  @param  mappingResource     mapping resource that defines the template
735      *  @param  mappingResourceUID  uniquely identifies the mapping resource (optional)
736      ** @return OFTrue if template identification is valid, OFFalse otherwise
737      */
738     static OFBool checkTemplateIdentification(const OFString &templateIdentifier,
739                                               const OFString &mappingResource,
740                                               const OFString &mappingResourceUID);
741 
742 
743   private:
744 
745     /// flag indicating whether the content item is marked (e.g.\ used for digital signatures).
746     /// The default value is OFFalse.
747     OFBool             MarkFlag;
748     /// flag indicating whether the content item is referenced (by-reference relationship).
749     /// The default value is OFFalse.
750     OFBool             ReferenceTarget;
751 
752     /// relationship type to the parent node (associated DICOM VR=CS, mandatory)
753     E_RelationshipType RelationshipType;
754     /// value type (associated DICOM VR=CS, mandatory)
755     const E_ValueType  ValueType;
756 
757     /// concept name (VR=SQ, conditional)
758     DSRCodedEntryValue ConceptName;
759     /// observation date/time (VR=DT, conditional)
760     OFString           ObservationDateTime;
761     /// observation unique identifier (VR=UI, optional)
762     OFString           ObservationUID;
763 
764     /// template identifier (VR=CS, mandatory in ContentTemplateSequence)
765     OFString           TemplateIdentifier;
766     /// mapping resource (VR=CS, mandatory in ContentTemplateSequence)
767     OFString           MappingResource;
768     /// mapping resource UID (VR=UI, optional in ContentTemplateSequence)
769     OFString           MappingResourceUID;
770 
771     /// MAC parameters sequence (VR=SQ, optional)
772     DcmSequenceOfItems MACParameters;
773     /// digital signatures sequence (VR=SQ, optional)
774     DcmSequenceOfItems DigitalSignatures;
775 
776  // --- declaration of default constructor and assignment operator
777 
778     DSRDocumentTreeNode();
779     DSRDocumentTreeNode &operator=(const DSRDocumentTreeNode &);
780 };
781 
782 
783 #endif
784