1 /*
2  *
3  *  Copyright (C) 2000-2020, 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: DSRTypes
20  *
21  */
22 
23 
24 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
25 
26 #include "dcmtk/dcmsr/dsrtypes.h"
27 #include "dcmtk/dcmsr/dsrtextn.h"
28 #include "dcmtk/dcmsr/dsrcodtn.h"
29 #include "dcmtk/dcmsr/dsrnumtn.h"
30 #include "dcmtk/dcmsr/dsrdtitn.h"
31 #include "dcmtk/dcmsr/dsrdattn.h"
32 #include "dcmtk/dcmsr/dsrtimtn.h"
33 #include "dcmtk/dcmsr/dsruidtn.h"
34 #include "dcmtk/dcmsr/dsrpnmtn.h"
35 #include "dcmtk/dcmsr/dsrscotn.h"
36 #include "dcmtk/dcmsr/dsrsc3tn.h"
37 #include "dcmtk/dcmsr/dsrtcotn.h"
38 #include "dcmtk/dcmsr/dsrcomtn.h"
39 #include "dcmtk/dcmsr/dsrimgtn.h"
40 #include "dcmtk/dcmsr/dsrwavtn.h"
41 #include "dcmtk/dcmsr/dsrcontn.h"
42 #include "dcmtk/dcmsr/dsrreftn.h"
43 #include "dcmtk/dcmsr/dsrbascc.h"
44 #include "dcmtk/dcmsr/dsrenhcc.h"
45 #include "dcmtk/dcmsr/dsrcomcc.h"
46 #include "dcmtk/dcmsr/dsrkeycc.h"
47 #include "dcmtk/dcmsr/dsrmamcc.h"
48 #include "dcmtk/dcmsr/dsrchecc.h"
49 #include "dcmtk/dcmsr/dsrcolcc.h"
50 #include "dcmtk/dcmsr/dsrprocc.h"
51 #include "dcmtk/dcmsr/dsrxrdcc.h"
52 #include "dcmtk/dcmsr/dsrspecc.h"
53 #include "dcmtk/dcmsr/dsrmaccc.h"
54 #include "dcmtk/dcmsr/dsrimpcc.h"
55 #include "dcmtk/dcmsr/dsrc3dcc.h"
56 #include "dcmtk/dcmsr/dsrrrdcc.h"
57 #include "dcmtk/dcmsr/dsracqcc.h"
58 #include "dcmtk/dcmsr/dsrsaecc.h"
59 #include "dcmtk/dcmsr/dsrprdcc.h"
60 #include "dcmtk/dcmsr/dsrpficc.h"
61 #include "dcmtk/dcmsr/dsrplicc.h"
62 #include "dcmtk/dcmsr/dsrrsdcc.h"
63 
64 #include "dcmtk/dcmdata/dcuid.h"
65 #include "dcmtk/dcmdata/dcvrda.h"
66 #include "dcmtk/dcmdata/dcvrdt.h"
67 #include "dcmtk/dcmdata/dcvrpn.h"
68 #include "dcmtk/dcmdata/dcvrtm.h"
69 
70 #include "dcmtk/ofstd/ofstd.h"
71 
72 #define INCLUDE_CSTDIO
73 #define INCLUDE_CCTYPE
74 #include "dcmtk/ofstd/ofstdinc.h"
75 
76 
77 /*---------------------------------*
78  *  constant definitions (part 1)  *
79  *---------------------------------*/
80 
81 /* read flags */
82 const size_t DSRTypes::RF_readDigitalSignatures             = 1 <<  0;
83 const size_t DSRTypes::RF_acceptUnknownRelationshipType     = 1 <<  1;
84 const size_t DSRTypes::RF_acceptInvalidContentItemValue     = 1 <<  2;
85 const size_t DSRTypes::RF_ignoreRelationshipConstraints     = 1 <<  3;
86 const size_t DSRTypes::RF_ignoreContentItemErrors           = 1 <<  4;
87 const size_t DSRTypes::RF_skipInvalidContentItems           = 1 <<  5;
88 const size_t DSRTypes::RF_showCurrentlyProcessedItem        = 1 <<  6;
89 
90 /* renderHTML flags */
91 const size_t DSRTypes::HF_neverExpandChildrenInline         = 1 <<  0;
92 const size_t DSRTypes::HF_alwaysExpandChildrenInline        = 1 <<  1;
93 const size_t DSRTypes::HF_renderInlineCodes                 = 1 <<  2;
94 const size_t DSRTypes::HF_useCodeDetailsTooltip             = 1 <<  3;
95 const size_t DSRTypes::HF_renderConceptNameCodes            = 1 <<  4;
96 const size_t DSRTypes::HF_renderNumericUnitCodes            = 1 <<  5;
97 const size_t DSRTypes::HF_useCodeMeaningAsUnit              = 1 <<  6;
98 const size_t DSRTypes::HF_renderPatientTitle                = 1 <<  7;
99 const size_t DSRTypes::HF_renderNoDocumentHeader            = 1 <<  8;
100 const size_t DSRTypes::HF_renderDcmtkFootnote               = 1 <<  9;
101 const size_t DSRTypes::HF_renderFullData                    = 1 << 10;
102 const size_t DSRTypes::HF_renderSectionTitlesInline         = 1 << 11;
103 const size_t DSRTypes::HF_copyStyleSheetContent             = 1 << 12;
104 const size_t DSRTypes::HF_HTML32Compatibility               = 1 << 13;
105 const size_t DSRTypes::HF_XHTML11Compatibility              = 1 << 14;
106 const size_t DSRTypes::HF_addDocumentTypeReference          = 1 << 15;
107 const size_t DSRTypes::HF_omitGeneratorMetaElement          = 1 << 16;
108 /* internal */
109 const size_t DSRTypes::HF_renderItemsSeparately             = 1 << 17;
110 const size_t DSRTypes::HF_renderItemInline                  = 1 << 18;
111 const size_t DSRTypes::HF_currentlyInsideAnnex              = 1 << 19;
112 const size_t DSRTypes::HF_createFootnoteReferences          = 1 << 20;
113 const size_t DSRTypes::HF_convertNonASCIICharacters         = 1 << 21;
114 /* shortcuts */
115 const size_t DSRTypes::HF_renderAllCodes                    = DSRTypes::HF_renderInlineCodes |
116                                                               DSRTypes::HF_renderConceptNameCodes |
117                                                               DSRTypes::HF_renderNumericUnitCodes;
118 const size_t DSRTypes::HF_internalUseOnly                   = DSRTypes::HF_renderItemsSeparately |
119                                                               DSRTypes::HF_renderItemInline |
120                                                               DSRTypes::HF_currentlyInsideAnnex |
121                                                               DSRTypes::HF_createFootnoteReferences |
122                                                               DSRTypes::HF_convertNonASCIICharacters;
123 
124 /* read/writeXML flags */
125 const size_t DSRTypes::XF_writeEmptyTags                    = 1 << 0;
126 const size_t DSRTypes::XF_writeTemplateIdentification       = 1 << 1;
127 const size_t DSRTypes::XF_alwaysWriteItemIdentifier         = 1 << 2;
128 const size_t DSRTypes::XF_codeComponentsAsAttribute         = 1 << 3;
129 const size_t DSRTypes::XF_relationshipTypeAsAttribute       = 1 << 4;
130 const size_t DSRTypes::XF_valueTypeAsAttribute              = 1 << 5;
131 const size_t DSRTypes::XF_templateIdentifierAsAttribute     = 1 << 6;
132 const size_t DSRTypes::XF_useDcmsrNamespace                 = 1 << 7;
133 const size_t DSRTypes::XF_addSchemaReference                = 1 << 8;
134 const size_t DSRTypes::XF_validateSchema                    = 1 << 9;
135 const size_t DSRTypes::XF_templateElementEnclosesItems      = 1 << 10;
136 const size_t DSRTypes::XF_addCommentsForIncludedTemplate    = 1 << 11;
137 const size_t DSRTypes::XF_acceptEmptyStudySeriesInstanceUID = 1 << 12;
138 /* shortcuts */
139 const size_t DSRTypes::XF_encodeEverythingAsAttribute       = DSRTypes::XF_codeComponentsAsAttribute |
140                                                               DSRTypes::XF_relationshipTypeAsAttribute |
141                                                               DSRTypes::XF_valueTypeAsAttribute |
142                                                               DSRTypes::XF_templateIdentifierAsAttribute;
143 
144 /* print flags */
145 const size_t DSRTypes::PF_printItemPosition                 = 1 << 0;
146 const size_t DSRTypes::PF_shortenLongItemValues             = 1 << 1;
147 const size_t DSRTypes::PF_printSOPInstanceUID               = 1 << 2;
148 const size_t DSRTypes::PF_printConceptNameCodes             = 1 << 3;
149 const size_t DSRTypes::PF_printNoDocumentHeader             = 1 << 4;
150 const size_t DSRTypes::PF_printTemplateIdentification       = 1 << 5;
151 const size_t DSRTypes::PF_useANSIEscapeCodes                = 1 << 6;
152 const size_t DSRTypes::PF_printLongSOPClassName             = 1 << 7;
153 const size_t DSRTypes::PF_printSOPClassUID                  = 1 << 8;
154 const size_t DSRTypes::PF_printInvalidCodes                 = 1 << 9;
155 const size_t DSRTypes::PF_printNodeID                       = 1 << 10;
156 const size_t DSRTypes::PF_indicateEnhancedEncodingMode      = 1 << 11;
157 const size_t DSRTypes::PF_printAnnotation                   = 1 << 12;
158 const size_t DSRTypes::PF_hideIncludedTemplateNodes         = 1 << 13;
159 const size_t DSRTypes::PF_dontCountIncludedTemplateNodes    = 1 << 14;
160 const size_t DSRTypes::PF_printEmptyCodes                   = 1 << 15;
161 /* shortcuts */
162 const size_t DSRTypes::PF_printAllCodes                     = DSRTypes::PF_printConceptNameCodes;
163 
164 /* checkByReferenceRelationships modes */
165 const size_t DSRTypes::CM_updatePositionString              = 1 << 0;
166 const size_t DSRTypes::CM_updateNodeID                      = 1 << 1;
167 const size_t DSRTypes::CM_resetReferenceTargetFlag          = 1 << 2;
168 
169 /* checkByReferenceRelationships bit masks (avoid conflicts!) */
170 const size_t DSRTypes::CB_maskPrintFlags                    = DSRTypes::PF_dontCountIncludedTemplateNodes;
171 const size_t DSRTypes::CB_maskReadFlags                     = DSRTypes::RF_acceptUnknownRelationshipType |
172                                                               DSRTypes::RF_ignoreRelationshipConstraints |
173                                                               DSRTypes::RF_showCurrentlyProcessedItem;
174 
175 
176 /*---------------------*
177  *  type declarations  *
178  *---------------------*/
179 
180 struct S_DocumentTypeNameMap
181 {
182     DSRTypes::E_DocumentType Type;
183     const char *SOPClassUID;
184     size_t ExtendedModules;
185     const char *Modality;
186     const char *ReadableName;
187 };
188 
189 
190 struct S_RelationshipTypeNameMap
191 {
192     DSRTypes::E_RelationshipType Type;
193     const char *DefinedTerm;
194     const char *ReadableName;
195 };
196 
197 
198 struct S_ValueTypeNameMap
199 {
200     DSRTypes::E_ValueType Type;
201     const char *DefinedTerm;
202     const char *XMLTagName;
203     const char *ReadableName;
204 };
205 
206 
207 struct S_PresentationStateTypeNameMap
208 {
209     DSRTypes::E_PresentationStateType Type;
210     const char *SOPClassUID;
211     const char *ShortName;
212 };
213 
214 
215 struct S_GraphicTypeNameMap
216 {
217     DSRTypes::E_GraphicType Type;
218     const char *EnumeratedValue;
219     const char *ReadableName;
220 };
221 
222 
223 struct S_GraphicType3DNameMap
224 {
225     DSRTypes::E_GraphicType3D Type;
226     const char *EnumeratedValue;
227     const char *ReadableName;
228 };
229 
230 
231 struct S_TemporalRangeTypeNameMap
232 {
233     DSRTypes::E_TemporalRangeType Type;
234     const char *EnumeratedValue;
235     const char *ReadableName;
236 };
237 
238 
239 struct S_ContinuityOfContentNameMap
240 {
241     DSRTypes::E_ContinuityOfContent Type;
242     const char *EnumeratedValue;
243 };
244 
245 
246 struct S_PreliminaryFlagNameMap
247 {
248     DSRTypes::E_PreliminaryFlag Type;
249     const char *EnumeratedValue;
250 };
251 
252 
253 struct S_CompletionFlagNameMap
254 {
255     DSRTypes::E_CompletionFlag Type;
256     const char *EnumeratedValue;
257 };
258 
259 
260 struct S_VerificationFlagNameMap
261 {
262     DSRTypes::E_VerificationFlag Type;
263     const char *EnumeratedValue;
264 };
265 
266 
267 struct S_CharacterSetNameMap
268 {
269     DSRTypes::E_CharacterSet Type;
270     const char *DefinedTerm;
271     const char *HTMLName;
272     const char *XMLName;
273 };
274 
275 
276 /*---------------------------------*
277  *  constant definitions (part 2)  *
278  *---------------------------------*/
279 
280 // conditions
281 makeOFConditionConst(SR_EC_UnknownDocumentType,                 OFM_dcmsr,  1, OF_error, "Unknown Document Type");
282 makeOFConditionConst(SR_EC_InvalidDocument,                     OFM_dcmsr,  2, OF_error, "Invalid Document");
283 makeOFConditionConst(SR_EC_InvalidDocumentTree,                 OFM_dcmsr,  3, OF_error, "Invalid Document Tree");
284 makeOFConditionConst(SR_EC_MandatoryAttributeMissing,           OFM_dcmsr,  4, OF_error, "Mandatory Attribute missing");
285 makeOFConditionConst(SR_EC_InvalidValue,                        OFM_dcmsr,  5, OF_error, "Invalid Value");
286 makeOFConditionConst(SR_EC_UnsupportedValue,                    OFM_dcmsr,  6, OF_error, "Unsupported Value");
287 makeOFConditionConst(SR_EC_UnknownValueType,                    OFM_dcmsr,  7, OF_error, "Unknown Value Type");
288 makeOFConditionConst(SR_EC_UnknownRelationshipType,             OFM_dcmsr,  8, OF_error, "Unknown Relationship Type");
289 makeOFConditionConst(SR_EC_InvalidByValueRelationship,          OFM_dcmsr,  9, OF_error, "Invalid by-value Relationship");
290 makeOFConditionConst(SR_EC_InvalidByReferenceRelationship,      OFM_dcmsr, 10, OF_error, "Invalid by-reference Relationship");
291 makeOFConditionConst(SR_EC_SOPInstanceNotFound,                 OFM_dcmsr, 11, OF_error, "SOP Instance not found");
292 makeOFConditionConst(SR_EC_DifferentSOPClassesForAnInstance,    OFM_dcmsr, 12, OF_error, "Different SOP Classes for an Instance");
293 makeOFConditionConst(SR_EC_CodingSchemeNotFound,                OFM_dcmsr, 13, OF_error, "Coding Scheme Designator not found");
294 makeOFConditionConst(SR_EC_CorruptedXMLStructure,               OFM_dcmsr, 14, OF_error, "Corrupted XML structure");
295 makeOFConditionConst(SR_EC_RepresentationNotAvailable,          OFM_dcmsr, 15, OF_error, "Representation not available");
296 makeOFConditionConst(SR_EC_CannotCreateIconImage,               OFM_dcmsr, 16, OF_error, "Cannot create Icon Image");
297 makeOFConditionConst(SR_EC_CannotAddContentItem,                OFM_dcmsr, 17, OF_error, "Cannot add Content Item");
298 makeOFConditionConst(SR_EC_InvalidConceptName,                  OFM_dcmsr, 18, OF_error, "Invalid Concept Name");
299 makeOFConditionConst(SR_EC_CannotInsertSubTree,                 OFM_dcmsr, 19, OF_error, "Cannot insert Subtree");
300 makeOFConditionConst(SR_EC_CannotChangeRelationshipType,        OFM_dcmsr, 20, OF_error, "Cannot change Relationship Type");
301 makeOFConditionConst(SR_EC_IncompatibleDocumentTree,            OFM_dcmsr, 21, OF_error, "Incompatible Document Tree");
302 makeOFConditionConst(SR_EC_ContentItemNotFound,                 OFM_dcmsr, 22, OF_error, "Content Item not found");
303 makeOFConditionConst(SR_EC_CannotRemoveSubTree,                 OFM_dcmsr, 23, OF_error, "Cannot remove Subtree");
304 makeOFConditionConst(SR_EC_EmptyDocumentTree,                   OFM_dcmsr, 24, OF_error, "Empty Document Tree");
305 makeOFConditionConst(SR_EC_InvalidContentItem,                  OFM_dcmsr, 25, OF_error, "Invalid Content Item");
306 makeOFConditionConst(SR_EC_CannotUseTemplateIdentification,     OFM_dcmsr, 26, OF_error, "Cannot use Template Identification");
307 makeOFConditionConst(SR_EC_NonExtensibleTemplate,               OFM_dcmsr, 27, OF_error, "Non-extensible Template");
308 makeOFConditionConst(SR_EC_NonExtensibleContextGroup,           OFM_dcmsr, 28, OF_error, "Non-extensible Context Group");
309 makeOFConditionConst(SR_EC_CodedEntryNotInContextGroup,         OFM_dcmsr, 29, OF_error, "Coded Entry not in Context Group");
310 makeOFConditionConst(SR_EC_CodedEntryInStandardContextGroup,    OFM_dcmsr, 30, OF_ok,    "Coded Entry in Context Group (Standard)");
311 makeOFConditionConst(SR_EC_CodedEntryIsExtensionOfContextGroup, OFM_dcmsr, 31, OF_ok,    "Coded Entry in Context Group (Extension)");
312 makeOFConditionConst(SR_EC_ValueSetConstraintViolated,          OFM_dcmsr, 32, OF_error, "Value Set Constraint violated");
313 makeOFConditionConst(SR_EC_InvalidTemplateStructure,            OFM_dcmsr, 33, OF_error, "Invalid Template Structure");
314 makeOFConditionConst(SR_EC_CannotProcessIncludedTemplates,      OFM_dcmsr, 34, OF_error, "Cannot process Document Tree with included Templates");
315 
316 // NOTE:
317 // error codes 1000 and above are reserved for the submodule "cmr"
318 
319 
320 /* extended IOD modules (only used internally) */
321 const size_t EM_EnhancedEquipment = 1 << 0;
322 const size_t EM_Timezone          = 1 << 1;
323 const size_t EM_Synchronization   = 1 << 2;
324 const size_t EM_KeyObjectDocument = 1 << 3;
325 
326 static const S_DocumentTypeNameMap DocumentTypeNameMap[] =
327 {
328     {DSRTypes::DT_invalid,                               "",                                                  0,                                                                "",   "invalid document type"},
329     {DSRTypes::DT_BasicTextSR,                           UID_BasicTextSRStorage,                              0,                                                                "SR", "Basic Text SR"},
330     {DSRTypes::DT_EnhancedSR,                            UID_EnhancedSRStorage,                               0,                                                                "SR", "Enhanced SR"},
331     {DSRTypes::DT_ComprehensiveSR,                       UID_ComprehensiveSRStorage,                          0,                                                                "SR", "Comprehensive SR"},
332     {DSRTypes::DT_KeyObjectSelectionDocument,            UID_KeyObjectSelectionDocumentStorage,               EM_KeyObjectDocument,                                             "KO", "Key Object Selection Document"},
333     {DSRTypes::DT_MammographyCadSR,                      UID_MammographyCADSRStorage,                         0,                                                                "SR", "Mammography CAD SR"},
334     {DSRTypes::DT_ChestCadSR,                            UID_ChestCADSRStorage,                               0,                                                                "SR", "Chest CAD SR"},
335     {DSRTypes::DT_ColonCadSR,                            UID_ColonCADSRStorage,                               EM_EnhancedEquipment,                                             "SR", "Colon CAD SR"},
336     {DSRTypes::DT_ProcedureLog,                          UID_ProcedureLogStorage,                             EM_Synchronization,                                               "SR", "Procedure Log"},
337     {DSRTypes::DT_XRayRadiationDoseSR,                   UID_XRayRadiationDoseSRStorage,                      EM_EnhancedEquipment,                                             "SR", "X-Ray Radiation Dose SR"},
338     {DSRTypes::DT_SpectaclePrescriptionReport,           UID_SpectaclePrescriptionReportStorage,              EM_EnhancedEquipment,                                             "SR", "Spectacle Prescription Report"},
339     {DSRTypes::DT_MacularGridThicknessAndVolumeReport,   UID_MacularGridThicknessAndVolumeReportStorage,      EM_EnhancedEquipment,                                             "SR", "Macular Grid Thickness and Volume Report"},
340     {DSRTypes::DT_ImplantationPlanSRDocument,            UID_ImplantationPlanSRDocumentStorage,               EM_EnhancedEquipment,                                             "SR", "Implantation Plan SR Document"},
341     {DSRTypes::DT_Comprehensive3DSR,                     UID_Comprehensive3DSRStorage,                        0,                                                                "SR", "Comprehensive 3D SR"},
342     {DSRTypes::DT_RadiopharmaceuticalRadiationDoseSR,    UID_RadiopharmaceuticalRadiationDoseSRStorage,       EM_EnhancedEquipment,                                             "SR", "Radiopharmaceutical Radiation Dose SR"},
343     {DSRTypes::DT_ExtensibleSR,                          UID_ExtensibleSRStorage,                             EM_EnhancedEquipment,                                             "SR", "Extensible SR"},
344     {DSRTypes::DT_AcquisitionContextSR,                  UID_AcquisitionContextSRStorage,                     EM_EnhancedEquipment,                                             "SR", "Acquisition Context SR"},
345     {DSRTypes::DT_SimplifiedAdultEchoSR,                 UID_SimplifiedAdultEchoSRStorage,                    EM_EnhancedEquipment | EM_Timezone,                               "SR", "Simplified Adult Echo SR"},
346     {DSRTypes::DT_PatientRadiationDoseSR,                UID_PatientRadiationDoseSRStorage,                   EM_EnhancedEquipment,                                             "SR", "Patient Radiation Dose SR"},
347     {DSRTypes::DT_PerformedImagingAgentAdministrationSR, UID_PerformedImagingAgentAdministrationSRStorage,    EM_EnhancedEquipment | EM_Synchronization,                        "SR", "Performed Imaging Agent Administration SR"},
348     {DSRTypes::DT_PlannedImagingAgentAdministrationSR,   UID_PlannedImagingAgentAdministrationSRStorage,      EM_EnhancedEquipment,                                             "SR", "Planned Imaging Agent Administration SR"},
349     {DSRTypes::DT_RenditionSelectionDocument,            UID_RenditionSelectionDocumentRealTimeCommunication, EM_EnhancedEquipment | EM_Synchronization | EM_KeyObjectDocument, "KO", "Rendition Selection Document"}
350 };
351 
352 
353 static const S_RelationshipTypeNameMap RelationshipTypeNameMap[] =
354 {
355     {DSRTypes::RT_invalid,       "",                "invalid relationship type"},
356     {DSRTypes::RT_unknown,       "",                "unknown relationship type"},
357     {DSRTypes::RT_isRoot,        "",                "(is root)"},
358     {DSRTypes::RT_contains,      "CONTAINS",        "contains"},
359     {DSRTypes::RT_hasObsContext, "HAS OBS CONTEXT", "has obs context"},
360     {DSRTypes::RT_hasAcqContext, "HAS ACQ CONTEXT", "has acq context"},
361     {DSRTypes::RT_hasConceptMod, "HAS CONCEPT MOD", "has concept mod"},
362     {DSRTypes::RT_hasProperties, "HAS PROPERTIES",  "has properties"},
363     {DSRTypes::RT_inferredFrom,  "INFERRED FROM",   "inferred from"},
364     {DSRTypes::RT_selectedFrom,  "SELECTED FROM",   "selected from"}
365 };
366 
367 
368 static const S_ValueTypeNameMap ValueTypeNameMap[] =
369 {
370     {DSRTypes::VT_invalid,          "",                "item",       "invalid/unknown value type"},
371     {DSRTypes::VT_Text,             "TEXT",            "text",       "Text"},
372     {DSRTypes::VT_Code,             "CODE",            "code",       "Code"},
373     {DSRTypes::VT_Num,              "NUM",             "num",        "Number"},
374     {DSRTypes::VT_DateTime,         "DATETIME",        "datetime",   "Date/Time"},
375     {DSRTypes::VT_Date,             "DATE",            "date",       "Date"},
376     {DSRTypes::VT_Time,             "TIME",            "time",       "Time"},
377     {DSRTypes::VT_UIDRef,           "UIDREF",          "uidref",     "UID Reference"},
378     {DSRTypes::VT_PName,            "PNAME",           "pname",      "Person Name"},
379     {DSRTypes::VT_SCoord,           "SCOORD",          "scoord",     "Spatial Coordinates"},
380     {DSRTypes::VT_SCoord3D,         "SCOORD3D",        "scoord3d",   "Spatial Coordinates (3D)"},
381     {DSRTypes::VT_TCoord,           "TCOORD",          "tcoord",     "Temporal Coordinates"},
382     {DSRTypes::VT_Composite,        "COMPOSITE",       "composite",  "Composite Object"},
383     {DSRTypes::VT_Image,            "IMAGE",           "image",      "Image"},
384     {DSRTypes::VT_Waveform,         "WAVEFORM",        "waveform",   "Waveform"},
385     {DSRTypes::VT_Container,        "CONTAINER",       "container",  "Container"},
386     {DSRTypes::VT_byReference,      "(by-reference)",  "reference",  "(by-reference)"},
387     {DSRTypes::VT_includedTemplate, "(incl-template)", "INCL-TEMPL", "(included template)"}     // the XML name should never be used!
388 };
389 
390 
391 static const S_PresentationStateTypeNameMap PresentationStateTypeNameMap[] =
392 {
393     {DSRTypes::PT_invalid,                  "",                                                             "invalid/unknown presentation state type"},
394     {DSRTypes::PT_Grayscale,                UID_GrayscaleSoftcopyPresentationStateStorage,                  "GSPS"},
395     {DSRTypes::PT_Color,                    UID_ColorSoftcopyPresentationStateStorage,                      "CSPS"},
396     {DSRTypes::PT_PseudoColor,              UID_PseudoColorSoftcopyPresentationStateStorage,                "PCSPS"},
397     {DSRTypes::PT_Blending,                 UID_BlendingSoftcopyPresentationStateStorage,                   "BSPS"},
398     {DSRTypes::PT_XAXRFGrayscale,           UID_XAXRFGrayscaleSoftcopyPresentationStateStorage,             "XGSPS"},
399     {DSRTypes::PT_GrayscalePlanarMPR,       UID_GrayscalePlanarMPRVolumetricPresentationStateStorage,       "GP-VPS"},
400     {DSRTypes::PT_CompositingPlanarMPR,     UID_CompositingPlanarMPRVolumetricPresentationStateStorage,     "CP-VPS"},
401     {DSRTypes::PT_AdvancedBlending,         UID_AdvancedBlendingPresentationStateStorage,                   "ABPS"},
402     {DSRTypes::PT_VolumeRendering,          UID_VolumeRenderingVolumetricPresentationStateStorage,          "VR-VPS"},
403     {DSRTypes::PT_SegmentedVolumeRendering, UID_SegmentedVolumeRenderingVolumetricPresentationStateStorage, "SVR-VPS"},
404     {DSRTypes::PT_MultipleVolumeRendering,  UID_MultipleVolumeRenderingVolumetricPresentationStateStorage,  "MVR-VPS"}
405 };
406 
407 
408 static const S_GraphicTypeNameMap GraphicTypeNameMap[] =
409 {
410     {DSRTypes::GT_invalid,    "",           "invalid/unknown graphic type"},
411     {DSRTypes::GT_Point,      "POINT",      "Point"},
412     {DSRTypes::GT_Multipoint, "MULTIPOINT", "Multiple Points"},
413     {DSRTypes::GT_Polyline,   "POLYLINE",   "Polyline"},
414     {DSRTypes::GT_Circle,     "CIRCLE",     "Circle"},
415     {DSRTypes::GT_Ellipse,    "ELLIPSE",    "Ellipse"}
416 };
417 
418 
419 static const S_GraphicType3DNameMap GraphicType3DNameMap[] =
420 {
421     {DSRTypes::GT3_invalid,    "",           "invalid/unknown graphic type"},
422     {DSRTypes::GT3_Point,      "POINT",      "Point"},
423     {DSRTypes::GT3_Multipoint, "MULTIPOINT", "Multiple Points"},
424     {DSRTypes::GT3_Polyline,   "POLYLINE",   "Polyline"},
425     {DSRTypes::GT3_Polygon ,   "POLYGON",    "Polygon"},
426     {DSRTypes::GT3_Ellipse,    "ELLIPSE",    "Ellipse"},
427     {DSRTypes::GT3_Ellipsoid,  "ELLIPSOID",  "Ellipsoid"}
428 };
429 
430 
431 static const S_TemporalRangeTypeNameMap TemporalRangeTypeNameMap[] =
432 {
433     {DSRTypes::TRT_invalid,      "",             "invalid/unknown temporal range type"},
434     {DSRTypes::TRT_Point,        "POINT",        "Point"},
435     {DSRTypes::TRT_Multipoint,   "MULTIPOINT",   "Multiple Points"},
436     {DSRTypes::TRT_Segment,      "SEGMENT",      "Segment"},
437     {DSRTypes::TRT_Multisegment, "MULTISEGMENT", "Multiple Segments"},
438     {DSRTypes::TRT_Begin,        "BEGIN",        "Begin"},
439     {DSRTypes::TRT_End,          "END",          "End"}
440 };
441 
442 
443 static const S_ContinuityOfContentNameMap ContinuityOfContentNameMap[] =
444 {
445     {DSRTypes::COC_invalid,    ""},
446     {DSRTypes::COC_Separate,   "SEPARATE"},
447     {DSRTypes::COC_Continuous, "CONTINUOUS"}
448 };
449 
450 
451 static const S_PreliminaryFlagNameMap PreliminaryFlagNameMap[] =
452 {
453     {DSRTypes::PF_invalid,      ""},
454     {DSRTypes::PF_Preliminary,  "PRELIMINARY"},
455     {DSRTypes::PF_Final,        "FINAL"}
456 };
457 
458 
459 static const S_CompletionFlagNameMap CompletionFlagNameMap[] =
460 {
461     {DSRTypes::CF_invalid,  ""},
462     {DSRTypes::CF_Partial,  "PARTIAL"},
463     {DSRTypes::CF_Complete, "COMPLETE"}
464 };
465 
466 
467 static const S_VerificationFlagNameMap VerificationFlagNameMap[] =
468 {
469     {DSRTypes::VF_invalid,    ""},
470     {DSRTypes::VF_Unverified, "UNVERIFIED"},
471     {DSRTypes::VF_Verified,   "VERIFIED"}
472 };
473 
474 
475 static const S_CharacterSetNameMap CharacterSetNameMap[] =
476 {
477     // columns: enum, DICOM, HTML, XML (if "?" a warning is reported).
478     // This mapping is based on Table D-1 in DICOM PS 3.18 Annex D.
479     {DSRTypes::CS_invalid,        "",                               "",            ""},
480     {DSRTypes::CS_ASCII,          "ISO_IR 6",                       "",            "UTF-8"},   /* "ISO_IR 6" is only used for reading */
481     {DSRTypes::CS_Latin1,         "ISO_IR 100",                     "ISO-8859-1",  "ISO-8859-1"},
482     {DSRTypes::CS_Latin2,         "ISO_IR 101",                     "ISO-8859-2",  "ISO-8859-2"},
483     {DSRTypes::CS_Latin3,         "ISO_IR 109",                     "ISO-8859-3",  "ISO-8859-3"},
484     {DSRTypes::CS_Latin4,         "ISO_IR 110",                     "ISO-8859-4",  "ISO-8859-4"},
485     {DSRTypes::CS_Cyrillic,       "ISO_IR 144",                     "ISO-8859-5",  "ISO-8859-5"},
486     {DSRTypes::CS_Arabic,         "ISO_IR 127",                     "ISO-8859-6",  "ISO-8859-6"},
487     {DSRTypes::CS_Greek,          "ISO_IR 126",                     "ISO-8859-7",  "ISO-8859-7"},
488     {DSRTypes::CS_Hebrew,         "ISO_IR 138",                     "ISO-8859-8",  "ISO-8859-8"},
489     {DSRTypes::CS_Latin5,         "ISO_IR 148",                     "ISO-8859-9",  "ISO-8859-9"},
490     {DSRTypes::CS_Thai,           "ISO_IR 166",                     "TIS-620",     "TIS-620"},
491     {DSRTypes::CS_Japanese,       "ISO 2022 IR 13\\ISO 2022 IR 87", "ISO-2022-JP", "ISO-2022-JP"},
492     {DSRTypes::CS_Korean,         "ISO 2022 IR 6\\ISO 2022 IR 149", "ISO-2022-KR", "ISO-2022-KR"},
493     {DSRTypes::CS_ChineseISO,     "ISO 2022 IR 6\\ISO 2022 IR 58",  "ISO-2022-CN", "ISO-2022-CN"},
494     {DSRTypes::CS_ChineseGB18030, "GB18030",                        "GB18030",     "GB18030"},
495     {DSRTypes::CS_ChineseGBK,     "GBK",                            "GBK",         "GBK"},
496     {DSRTypes::CS_UTF8,           "ISO_IR 192",                     "UTF-8",       "UTF-8"}
497 };
498 
499 
500 /*--------------------*
501  *  global variables  *
502  *--------------------*/
503 
504 OFLogger DCM_dcmsrLogger = OFLog::getLogger("dcmtk.dcmsr");
505 
506 
507 /*------------------*
508  *  implementation  *
509  *------------------*/
510 
~DSRTypes()511 DSRTypes::~DSRTypes()
512 {
513 }
514 
515 
documentTypeToSOPClassUID(const E_DocumentType documentType)516 const char *DSRTypes::documentTypeToSOPClassUID(const E_DocumentType documentType)
517 {
518     const S_DocumentTypeNameMap *iterator = DocumentTypeNameMap;
519     while ((iterator->Type != DT_last) && (iterator->Type != documentType))
520         iterator++;
521     return iterator->SOPClassUID;
522 }
523 
524 
documentTypeToModality(const E_DocumentType documentType)525 const char *DSRTypes::documentTypeToModality(const E_DocumentType documentType)
526 {
527     const S_DocumentTypeNameMap *iterator = DocumentTypeNameMap;
528     while ((iterator->Type != DT_last) && (iterator->Type != documentType))
529         iterator++;
530     return iterator->Modality;
531 }
532 
533 
documentTypeToReadableName(const E_DocumentType documentType)534 const char *DSRTypes::documentTypeToReadableName(const E_DocumentType documentType)
535 {
536     const S_DocumentTypeNameMap *iterator = DocumentTypeNameMap;
537     while ((iterator->Type != DT_last) && (iterator->Type != documentType))
538         iterator++;
539     return iterator->ReadableName;
540 }
541 
542 
documentTypeToDocumentTitle(const E_DocumentType documentType,OFString & documentTitle)543 const char *DSRTypes::documentTypeToDocumentTitle(const E_DocumentType documentType,
544                                                   OFString &documentTitle)
545 {
546     if (documentType != DT_invalid)
547     {
548         documentTitle = documentTypeToReadableName(documentType);
549         // avoid doubling of term "Document" and/or "Report"
550         if (!documentTitle.empty() && (documentTitle.find("Document") == OFString_npos) &&
551                                       (documentTitle.find("Report") == OFString_npos))
552         {
553             documentTitle += " Document";
554         }
555     } else {
556         // return empty string in case of invalid document
557         documentTitle.clear();
558     }
559     return documentTitle.c_str();
560 }
561 
562 
requiresEnhancedEquipmentModule(const E_DocumentType documentType)563 OFBool DSRTypes::requiresEnhancedEquipmentModule(const E_DocumentType documentType)
564 {
565     const S_DocumentTypeNameMap *iterator = DocumentTypeNameMap;
566     while ((iterator->Type != DT_last) && (iterator->Type != documentType))
567         iterator++;
568     return (iterator->ExtendedModules & EM_EnhancedEquipment) > 0;
569 }
570 
571 
requiresTimezoneModule(const E_DocumentType documentType)572 OFBool DSRTypes::requiresTimezoneModule(const E_DocumentType documentType)
573 {
574     const S_DocumentTypeNameMap *iterator = DocumentTypeNameMap;
575     while ((iterator->Type != DT_last) && (iterator->Type != documentType))
576         iterator++;
577     return (iterator->ExtendedModules & EM_Timezone) > 0;
578 }
579 
580 
requiresSynchronizationModule(const E_DocumentType documentType)581 OFBool DSRTypes::requiresSynchronizationModule(const E_DocumentType documentType)
582 {
583     const S_DocumentTypeNameMap *iterator = DocumentTypeNameMap;
584     while ((iterator->Type != DT_last) && (iterator->Type != documentType))
585         iterator++;
586     return (iterator->ExtendedModules & EM_Synchronization) > 0;
587 }
588 
589 
usesSRDocumentSeriesModule(const E_DocumentType documentType)590 OFBool DSRTypes::usesSRDocumentSeriesModule(const E_DocumentType documentType)
591 {
592     /* SR Document Series Module and Key Object Document Series Module are mutually exclusive */
593     return !usesKeyObjectDocumentSeriesModule(documentType);
594 }
595 
596 
usesKeyObjectDocumentSeriesModule(const E_DocumentType documentType)597 OFBool DSRTypes::usesKeyObjectDocumentSeriesModule(const E_DocumentType documentType)
598 {
599     /* Key Object Document Series Module is used if (and only if) Key Object Document Module is used */
600     return usesKeyObjectDocumentModule(documentType);
601 }
602 
603 
usesSRDocumentGeneralModule(const E_DocumentType documentType)604 OFBool DSRTypes::usesSRDocumentGeneralModule(const E_DocumentType documentType)
605 {
606     /* SR Document Module and Key Object Document Module are mutually exclusive */
607     return !usesKeyObjectDocumentModule(documentType);
608 }
609 
610 
usesKeyObjectDocumentModule(const E_DocumentType documentType)611 OFBool DSRTypes::usesKeyObjectDocumentModule(const E_DocumentType documentType)
612 {
613     const S_DocumentTypeNameMap *iterator = DocumentTypeNameMap;
614     while ((iterator->Type != DT_last) && (iterator->Type != documentType))
615         iterator++;
616     return (iterator->ExtendedModules & EM_KeyObjectDocument) > 0;
617 }
618 
619 
relationshipTypeToDefinedTerm(const E_RelationshipType relationshipType)620 const char *DSRTypes::relationshipTypeToDefinedTerm(const E_RelationshipType relationshipType)
621 {
622     const S_RelationshipTypeNameMap *iterator = RelationshipTypeNameMap;
623     while ((iterator->Type != RT_last) && (iterator->Type != relationshipType))
624         iterator++;
625     return iterator->DefinedTerm;
626 }
627 
628 
relationshipTypeToReadableName(const E_RelationshipType relationshipType)629 const char *DSRTypes::relationshipTypeToReadableName(const E_RelationshipType relationshipType)
630 {
631     const S_RelationshipTypeNameMap *iterator = RelationshipTypeNameMap;
632     while ((iterator->Type != RT_last) && (iterator->Type != relationshipType))
633         iterator++;
634     return iterator->ReadableName;
635 }
636 
637 
valueTypeToDefinedTerm(const E_ValueType valueType)638 const char *DSRTypes::valueTypeToDefinedTerm(const E_ValueType valueType)
639 {
640     const S_ValueTypeNameMap *iterator = ValueTypeNameMap;
641     while ((iterator->Type != VT_last) && (iterator->Type != valueType))
642         iterator++;
643     return iterator->DefinedTerm;
644 }
645 
646 
valueTypeToXMLTagName(const E_ValueType valueType)647 const char *DSRTypes::valueTypeToXMLTagName(const E_ValueType valueType)
648 {
649     const S_ValueTypeNameMap *iterator = ValueTypeNameMap;
650     while ((iterator->Type != VT_last) && (iterator->Type != valueType))
651         iterator++;
652     return iterator->XMLTagName;
653 }
654 
655 
valueTypeToReadableName(const E_ValueType valueType)656 const char *DSRTypes::valueTypeToReadableName(const E_ValueType valueType)
657 {
658     const S_ValueTypeNameMap *iterator = ValueTypeNameMap;
659     while ((iterator->Type != VT_last) && (iterator->Type != valueType))
660         iterator++;
661     return iterator->ReadableName;
662 }
663 
664 
presentationStateTypeToShortName(const E_PresentationStateType pstateType)665 const char *DSRTypes::presentationStateTypeToShortName(const E_PresentationStateType pstateType)
666 {
667     const S_PresentationStateTypeNameMap *iterator = PresentationStateTypeNameMap;
668     while ((iterator->Type != PT_last) && (iterator->Type != pstateType))
669         iterator++;
670     return iterator->ShortName;
671 }
672 
673 
graphicTypeToEnumeratedValue(const E_GraphicType graphicType)674 const char *DSRTypes::graphicTypeToEnumeratedValue(const E_GraphicType graphicType)
675 {
676     const S_GraphicTypeNameMap *iterator = GraphicTypeNameMap;
677     while ((iterator->Type != GT_last) && (iterator->Type != graphicType))
678         iterator++;
679     return iterator->EnumeratedValue;
680 }
681 
682 
graphicTypeToReadableName(const E_GraphicType graphicType)683 const char *DSRTypes::graphicTypeToReadableName(const E_GraphicType graphicType)
684 {
685     const S_GraphicTypeNameMap *iterator = GraphicTypeNameMap;
686     while ((iterator->Type != GT_last) && (iterator->Type != graphicType))
687         iterator++;
688     return iterator->ReadableName;
689 }
690 
691 
graphicType3DToEnumeratedValue(const E_GraphicType3D graphicType)692 const char *DSRTypes::graphicType3DToEnumeratedValue(const E_GraphicType3D graphicType)
693 {
694     const S_GraphicType3DNameMap *iterator = GraphicType3DNameMap;
695     while ((iterator->Type != GT3_last) && (iterator->Type != graphicType))
696         iterator++;
697     return iterator->EnumeratedValue;
698 }
699 
700 
graphicType3DToReadableName(const E_GraphicType3D graphicType)701 const char *DSRTypes::graphicType3DToReadableName(const E_GraphicType3D graphicType)
702 {
703     const S_GraphicType3DNameMap *iterator = GraphicType3DNameMap;
704     while ((iterator->Type != GT3_last) && (iterator->Type != graphicType))
705         iterator++;
706     return iterator->ReadableName;
707 }
708 
709 
temporalRangeTypeToEnumeratedValue(const E_TemporalRangeType temporalRangeType)710 const char *DSRTypes::temporalRangeTypeToEnumeratedValue(const E_TemporalRangeType temporalRangeType)
711 {
712     const S_TemporalRangeTypeNameMap *iterator = TemporalRangeTypeNameMap;
713     while ((iterator->Type != TRT_last) && (iterator->Type != temporalRangeType))
714         iterator++;
715     return iterator->EnumeratedValue;
716 }
717 
718 
temporalRangeTypeToReadableName(const E_TemporalRangeType temporalRangeType)719 const char *DSRTypes::temporalRangeTypeToReadableName(const E_TemporalRangeType temporalRangeType)
720 {
721     const S_TemporalRangeTypeNameMap *iterator = TemporalRangeTypeNameMap;
722     while ((iterator->Type != TRT_last) && (iterator->Type != temporalRangeType))
723         iterator++;
724     return iterator->ReadableName;
725 }
726 
727 
continuityOfContentToEnumeratedValue(const E_ContinuityOfContent continuityOfContent)728 const char *DSRTypes::continuityOfContentToEnumeratedValue(const E_ContinuityOfContent continuityOfContent)
729 {
730     const S_ContinuityOfContentNameMap *iterator = ContinuityOfContentNameMap;
731     while ((iterator->Type != COC_last) && (iterator->Type != continuityOfContent))
732         iterator++;
733     return iterator->EnumeratedValue;
734 }
735 
736 
preliminaryFlagToEnumeratedValue(const E_PreliminaryFlag preliminaryFlag)737 const char *DSRTypes::preliminaryFlagToEnumeratedValue(const E_PreliminaryFlag preliminaryFlag)
738 {
739     const S_PreliminaryFlagNameMap *iterator = PreliminaryFlagNameMap;
740     while ((iterator->Type != PF_last) && (iterator->Type != preliminaryFlag))
741         iterator++;
742     return iterator->EnumeratedValue;
743 }
744 
745 
completionFlagToEnumeratedValue(const E_CompletionFlag completionFlag)746 const char *DSRTypes::completionFlagToEnumeratedValue(const E_CompletionFlag completionFlag)
747 {
748     const S_CompletionFlagNameMap *iterator = CompletionFlagNameMap;
749     while ((iterator->Type != CF_last) && (iterator->Type != completionFlag))
750         iterator++;
751     return iterator->EnumeratedValue;
752 }
753 
754 
verificationFlagToEnumeratedValue(const E_VerificationFlag verificationFlag)755 const char *DSRTypes::verificationFlagToEnumeratedValue(const E_VerificationFlag verificationFlag)
756 {
757     const S_VerificationFlagNameMap *iterator = VerificationFlagNameMap;
758     while ((iterator->Type != VF_last) && (iterator->Type != verificationFlag))
759         iterator++;
760     return iterator->EnumeratedValue;
761 }
762 
763 
characterSetToDefinedTerm(const E_CharacterSet characterSet)764 const char *DSRTypes::characterSetToDefinedTerm(const E_CharacterSet characterSet)
765 {
766     const S_CharacterSetNameMap *iterator = CharacterSetNameMap;
767     /* make sure that we never return "ISO_IR 6", but an empty string instead */
768     if (characterSet != CS_ASCII)
769     {
770         while ((iterator->Type != CS_last) && (iterator->Type != characterSet))
771             iterator++;
772     }
773     return iterator->DefinedTerm;
774 }
775 
776 
characterSetToHTMLName(const E_CharacterSet characterSet)777 const char *DSRTypes::characterSetToHTMLName(const E_CharacterSet characterSet)
778 {
779     const S_CharacterSetNameMap *iterator = CharacterSetNameMap;
780     while ((iterator->Type != CS_last) && (iterator->Type != characterSet))
781         iterator++;
782     return iterator->HTMLName;
783 }
784 
785 
characterSetToXMLName(const E_CharacterSet characterSet)786 const char *DSRTypes::characterSetToXMLName(const E_CharacterSet characterSet)
787 {
788     const S_CharacterSetNameMap *iterator = CharacterSetNameMap;
789     while ((iterator->Type != CS_last) && (iterator->Type != characterSet))
790         iterator++;
791     return iterator->XMLName;
792 }
793 
794 
sopClassUIDToDocumentType(const OFString & sopClassUID)795 DSRTypes::E_DocumentType DSRTypes::sopClassUIDToDocumentType(const OFString &sopClassUID)
796 {
797     E_DocumentType type = DT_invalid;
798     const S_DocumentTypeNameMap *iterator = DocumentTypeNameMap;
799     while ((iterator->Type != DT_last) && (sopClassUID != iterator->SOPClassUID))
800         iterator++;
801     if (sopClassUID == iterator->SOPClassUID)
802         type = iterator->Type;
803     return type;
804 }
805 
806 
definedTermToRelationshipType(const OFString & definedTerm)807 DSRTypes::E_RelationshipType DSRTypes::definedTermToRelationshipType(const OFString &definedTerm)
808 {
809     E_RelationshipType type = RT_invalid;
810     const S_RelationshipTypeNameMap *iterator = RelationshipTypeNameMap;
811     while ((iterator->Type != RT_last) && (definedTerm != iterator->DefinedTerm))
812         iterator++;
813     if (definedTerm == iterator->DefinedTerm)
814         type = iterator->Type;
815     return type;
816 }
817 
818 
definedTermToValueType(const OFString & definedTerm)819 DSRTypes::E_ValueType DSRTypes::definedTermToValueType(const OFString &definedTerm)
820 {
821     E_ValueType type = VT_invalid;
822     const S_ValueTypeNameMap *iterator = ValueTypeNameMap;
823     while ((iterator->Type != VT_last) && (definedTerm != iterator->DefinedTerm))
824         iterator++;
825     if (definedTerm == iterator->DefinedTerm)
826         type = iterator->Type;
827     return type;
828 }
829 
830 
sopClassUIDToPresentationStateType(const OFString & sopClassUID)831 DSRTypes::E_PresentationStateType DSRTypes::sopClassUIDToPresentationStateType(const OFString &sopClassUID)
832 {
833     E_PresentationStateType type = PT_invalid;
834     const S_PresentationStateTypeNameMap *iterator = PresentationStateTypeNameMap;
835     while ((iterator->Type != PT_last) && (sopClassUID != iterator->SOPClassUID))
836         iterator++;
837     if (sopClassUID == iterator->SOPClassUID)
838         type = iterator->Type;
839     return type;
840 }
841 
842 
xmlTagNameToValueType(const OFString & xmlTagName)843 DSRTypes::E_ValueType DSRTypes::xmlTagNameToValueType(const OFString &xmlTagName)
844 {
845     E_ValueType type = VT_invalid;
846     const S_ValueTypeNameMap *iterator = ValueTypeNameMap;
847     while ((iterator->Type != VT_last) && (xmlTagName != iterator->XMLTagName))
848         iterator++;
849     if (xmlTagName == iterator->XMLTagName)
850         type = iterator->Type;
851     return type;
852 }
853 
854 
enumeratedValueToGraphicType(const OFString & enumeratedValue)855 DSRTypes::E_GraphicType DSRTypes::enumeratedValueToGraphicType(const OFString &enumeratedValue)
856 {
857     E_GraphicType type = GT_invalid;
858     const S_GraphicTypeNameMap *iterator = GraphicTypeNameMap;
859     while ((iterator->Type != GT_last) && (enumeratedValue != iterator->EnumeratedValue))
860         iterator++;
861     if (enumeratedValue == iterator->EnumeratedValue)
862         type = iterator->Type;
863     return type;
864 }
865 
866 
enumeratedValueToGraphicType3D(const OFString & enumeratedValue)867 DSRTypes::E_GraphicType3D DSRTypes::enumeratedValueToGraphicType3D(const OFString &enumeratedValue)
868 {
869     E_GraphicType3D type = GT3_invalid;
870     const S_GraphicType3DNameMap *iterator = GraphicType3DNameMap;
871     while ((iterator->Type != GT3_last) && (enumeratedValue != iterator->EnumeratedValue))
872         iterator++;
873     if (enumeratedValue == iterator->EnumeratedValue)
874         type = iterator->Type;
875     return type;
876 }
877 
878 
enumeratedValueToTemporalRangeType(const OFString & enumeratedValue)879 DSRTypes::E_TemporalRangeType DSRTypes::enumeratedValueToTemporalRangeType(const OFString &enumeratedValue)
880 {
881     E_TemporalRangeType type = TRT_invalid;
882     const S_TemporalRangeTypeNameMap *iterator = TemporalRangeTypeNameMap;
883     while ((iterator->Type != TRT_last) && (enumeratedValue != iterator->EnumeratedValue))
884         iterator++;
885     if (enumeratedValue == iterator->EnumeratedValue)
886         type = iterator->Type;
887     return type;
888 }
889 
890 
enumeratedValueToContinuityOfContent(const OFString & enumeratedValue)891 DSRTypes::E_ContinuityOfContent DSRTypes::enumeratedValueToContinuityOfContent(const OFString &enumeratedValue)
892 {
893     E_ContinuityOfContent type = COC_invalid;
894     const S_ContinuityOfContentNameMap *iterator = ContinuityOfContentNameMap;
895     while ((iterator->Type != COC_last) && (enumeratedValue != iterator->EnumeratedValue))
896         iterator++;
897     if (enumeratedValue == iterator->EnumeratedValue)
898         type = iterator->Type;
899     return type;
900 }
901 
902 
enumeratedValueToPreliminaryFlag(const OFString & enumeratedValue)903 DSRTypes::E_PreliminaryFlag DSRTypes::enumeratedValueToPreliminaryFlag(const OFString &enumeratedValue)
904 {
905     E_PreliminaryFlag type = PF_invalid;
906     const S_PreliminaryFlagNameMap *iterator = PreliminaryFlagNameMap;
907     while ((iterator->Type != PF_last) && (enumeratedValue != iterator->EnumeratedValue))
908         iterator++;
909     if (enumeratedValue == iterator->EnumeratedValue)
910         type = iterator->Type;
911     return type;
912 }
913 
914 
enumeratedValueToCompletionFlag(const OFString & enumeratedValue)915 DSRTypes::E_CompletionFlag DSRTypes::enumeratedValueToCompletionFlag(const OFString &enumeratedValue)
916 {
917     E_CompletionFlag type = CF_invalid;
918     const S_CompletionFlagNameMap *iterator = CompletionFlagNameMap;
919     while ((iterator->Type != CF_last) && (enumeratedValue != iterator->EnumeratedValue))
920         iterator++;
921     if (enumeratedValue == iterator->EnumeratedValue)
922         type = iterator->Type;
923     return type;
924 }
925 
926 
enumeratedValueToVerificationFlag(const OFString & enumeratedValue)927 DSRTypes::E_VerificationFlag DSRTypes::enumeratedValueToVerificationFlag(const OFString &enumeratedValue)
928 {
929     E_VerificationFlag type = VF_invalid;
930     const S_VerificationFlagNameMap *iterator = VerificationFlagNameMap;
931     while ((iterator->Type != VF_last) && (enumeratedValue != iterator->EnumeratedValue))
932         iterator++;
933     if (enumeratedValue == iterator->EnumeratedValue)
934         type = iterator->Type;
935     return type;
936 }
937 
938 
definedTermToCharacterSet(const OFString & definedTerm)939 DSRTypes::E_CharacterSet DSRTypes::definedTermToCharacterSet(const OFString &definedTerm)
940 {
941     E_CharacterSet type = CS_default;
942     /* empty defined term means default */
943     if (!definedTerm.empty())
944     {
945         const S_CharacterSetNameMap *iterator = CharacterSetNameMap;
946         while ((iterator->Type != CS_last) && (definedTerm != iterator->DefinedTerm))
947             iterator++;
948         if (definedTerm == iterator->DefinedTerm)
949             type = iterator->Type;
950         else
951             type = CS_invalid;
952     }
953     return type;
954 }
955 
956 
isDocumentTypeSupported(const E_DocumentType documentType)957 OFBool DSRTypes::isDocumentTypeSupported(const E_DocumentType documentType)
958 {
959     return (documentType != DT_invalid) && (documentType != DT_ExtensibleSR);
960 }
961 
962 
addElementToDataset(OFCondition & result,DcmItem & dataset,DcmElement * delem,const OFString & vm,const OFString & type,const char * moduleName)963 OFCondition DSRTypes::addElementToDataset(OFCondition &result,
964                                           DcmItem &dataset,
965                                           DcmElement *delem,
966                                           const OFString &vm,
967                                           const OFString &type,
968                                           const char *moduleName)
969 {
970     if (delem != NULL)
971     {
972         OFBool triedToInsert = OFFalse;
973         if (result.good())
974         {
975             if ((type == "2") || !delem->isEmpty())
976             {
977                 triedToInsert = OFTrue;
978                 /* insert non-empty element or empty "type 2" element */
979                 result = dataset.insert(delem, OFTrue /*replaceOld*/);
980                 if (DCM_dcmsrLogger.isEnabledFor(OFLogger::WARN_LOG_LEVEL))
981                     checkElementValue(*delem, vm, type, result, moduleName);
982             }
983             else if (type == "1")
984             {
985                 /* empty element value not allowed for "type 1" */
986                 result = SR_EC_InvalidValue;
987                 if (DCM_dcmsrLogger.isEnabledFor(OFLogger::WARN_LOG_LEVEL))
988                     checkElementValue(*delem, vm, type, result, moduleName);
989             }
990         }
991         /* delete element if not inserted into the dataset */
992         if (result.bad() || !triedToInsert)
993             delete delem;
994     } else
995         result = EC_MemoryExhausted;
996     return result;
997 }
998 
999 
removeAttributeFromSequence(DcmSequenceOfItems & sequence,const DcmTagKey & tagKey)1000 void DSRTypes::removeAttributeFromSequence(DcmSequenceOfItems &sequence,
1001                                            const DcmTagKey &tagKey)
1002 {
1003     /* iterate over all sequence items */
1004     DcmObject *dobj = NULL;
1005     while ((dobj = sequence.nextInContainer(dobj)) != NULL)
1006     {
1007         DcmItem *ditem = OFstatic_cast(DcmItem *, dobj);
1008         /* remove specified data elements (on all nesting levels) */
1009         ditem->findAndDeleteElement(tagKey, OFTrue /*allOccurrences*/);
1010     }
1011 }
1012 
1013 
getElementFromDataset(DcmItem & dataset,DcmElement & delem)1014 OFCondition DSRTypes::getElementFromDataset(DcmItem &dataset,
1015                                             DcmElement &delem)
1016 {
1017     DcmStack stack;
1018     OFCondition result = dataset.search(delem.getTag(), stack, ESM_fromHere, OFFalse /*searchIntoSub*/);
1019     if (result.good())
1020     {
1021         /* copy object from search stack */
1022         result = delem.copyFrom(*stack.top());
1023     }
1024     return result;
1025 }
1026 
1027 
getStringValueFromElement(const DcmElement & delem)1028 const char *DSRTypes::getStringValueFromElement(const DcmElement &delem)
1029 {
1030     char *stringValue = NULL;
1031     if (OFconst_cast(DcmElement &, delem).getString(stringValue).bad())
1032         stringValue = NULL;
1033     return stringValue;
1034 }
1035 
1036 
getStringValueFromElement(const DcmElement & delem,OFString & stringValue)1037 const OFString &DSRTypes::getStringValueFromElement(const DcmElement &delem,
1038                                                     OFString &stringValue)
1039 {
1040     if (OFconst_cast(DcmElement &, delem).getOFString(stringValue, 0).bad())
1041         stringValue.clear();
1042     return stringValue;
1043 }
1044 
1045 
getStringValueFromElement(const DcmElement & delem,OFString & stringValue,const signed long pos)1046 OFCondition DSRTypes::getStringValueFromElement(const DcmElement &delem,
1047                                                 OFString &stringValue,
1048                                                 const signed long pos)
1049 {
1050     OFCondition result = EC_Normal;
1051     if (pos < 0)
1052         result = OFconst_cast(DcmElement &, delem).getOFStringArray(stringValue);
1053     else
1054         result = OFconst_cast(DcmElement &, delem).getOFString(stringValue, OFstatic_cast(unsigned long, pos));
1055     if (result.bad())
1056         stringValue.clear();
1057     return result;
1058 }
1059 
1060 
getPrintStringFromElement(const DcmElement & delem,OFString & stringValue)1061 const OFString &DSRTypes::getPrintStringFromElement(const DcmElement &delem,
1062                                                     OFString &stringValue)
1063 {
1064     OFString tempString;
1065     return convertToPrintString(getStringValueFromElement(delem, tempString), stringValue);
1066 }
1067 
1068 
getMarkupStringFromElement(const DcmElement & delem,OFString & stringValue,const OFBool convertNonASCII)1069 const OFString &DSRTypes::getMarkupStringFromElement(const DcmElement &delem,
1070                                                      OFString &stringValue,
1071                                                      const OFBool convertNonASCII)
1072 {
1073     OFString tempString;
1074     return OFStandard::convertToMarkupString(getStringValueFromElement(delem, tempString), stringValue, convertNonASCII);
1075 }
1076 
1077 
getStringValueFromDataset(DcmItem & dataset,const DcmTagKey & tagKey,OFString & stringValue,const signed long pos)1078 OFCondition DSRTypes::getStringValueFromDataset(DcmItem &dataset,
1079                                                 const DcmTagKey &tagKey,
1080                                                 OFString &stringValue,
1081                                                 const signed long pos)
1082 {
1083     OFCondition result = EC_Normal;
1084     if (pos < 0)
1085         result = dataset.findAndGetOFStringArray(tagKey, stringValue, OFFalse /*searchIntoSub*/);
1086     else
1087         result = dataset.findAndGetOFString(tagKey, stringValue, OFstatic_cast(unsigned long, pos), OFFalse /*searchIntoSub*/);
1088     return result;
1089 }
1090 
1091 
putStringValueToDataset(DcmItem & dataset,const DcmTag & tag,const OFString & stringValue,const OFBool allowEmpty)1092 OFCondition DSRTypes::putStringValueToDataset(DcmItem &dataset,
1093                                               const DcmTag &tag,
1094                                               const OFString &stringValue,
1095                                               const OFBool allowEmpty)
1096 {
1097     OFCondition result = EC_Normal;
1098     if (allowEmpty || !stringValue.empty())
1099         result = dataset.putAndInsertOFStringArray(tag, stringValue, OFTrue /*replaceOld*/);
1100     return result;
1101 }
1102 
1103 
checkElementValue(DcmElement * delem,const DcmTagKey & tagKey,const OFString & vm,const OFString & type,const OFCondition & searchCond,const char * moduleName,const OFBool acceptViolation)1104 OFBool DSRTypes::checkElementValue(DcmElement *delem,
1105                                    const DcmTagKey &tagKey,
1106                                    const OFString &vm,
1107                                    const OFString &type,
1108                                    const OFCondition &searchCond,
1109                                    const char *moduleName,
1110                                    const OFBool acceptViolation)
1111 {
1112     OFBool result = OFTrue;
1113     const OFString tagName = DcmTag(tagKey).getTagName();
1114     const OFString module = (moduleName == NULL) ? "SR document" : moduleName;
1115     /* NB: type 1C and 2C cannot be checked, assuming to be optional */
1116     if (((type == "1") || (type == "2")) && searchCond.bad())
1117     {
1118         DCMSR_WARN(tagName << " " << tagKey << " absent in " << module << " (type " << type << ")");
1119         result = OFFalse;
1120     }
1121     else if ((delem == NULL) || delem->isEmpty(OFTrue /*normalize*/))
1122     {
1123         /* however, type 1C should never be present with empty value */
1124         if (((type == "1") || (type == "1C")) && searchCond.good())
1125         {
1126             DCMSR_WARN(tagName << " " << tagKey << " empty in " << module << " (type " << type << ")");
1127             result = OFFalse;
1128         }
1129     } else {
1130         const OFCondition checkResult = delem->checkValue(vm, OFTrue /*oldFormat*/);
1131         if (checkResult == EC_InvalidCharacter)
1132         {
1133             DCMSR_WARN(tagName << " " << tagKey << " contains invalid character(s) in " << module);
1134             result = acceptViolation;
1135         }
1136         else if (checkResult == EC_ValueRepresentationViolated)
1137         {
1138             DCMSR_WARN(tagName << " " << tagKey << " violates VR definition in " << module);
1139             result = acceptViolation;
1140         }
1141         else if (checkResult == EC_ValueMultiplicityViolated)
1142         {
1143             const OFString vmText = (delem->getVR() == EVR_SQ) ? " #items" : " VM";
1144             DCMSR_WARN(tagName << " " << tagKey << vmText << " != " << vm << " in " << module);
1145             result = acceptViolation;
1146         }
1147         else if (checkResult == EC_MaximumLengthViolated)
1148         {
1149             DCMSR_WARN(tagName << " " << tagKey << " violates maximum VR length in " << module);
1150             result = acceptViolation;
1151         }
1152         else if (checkResult.bad())
1153         {
1154             DCMSR_DEBUG("INTERNAL ERROR while checking value of " << tagName << " " << tagKey << " in " << module);
1155         }
1156     }
1157     return result;
1158 }
1159 
1160 
checkElementValue(DcmElement & delem,const OFString & vm,const OFString & type,const OFCondition & searchCond,const char * moduleName,const OFBool acceptViolation)1161 OFBool DSRTypes::checkElementValue(DcmElement &delem,
1162                                    const OFString &vm,
1163                                    const OFString &type,
1164                                    const OFCondition &searchCond,
1165                                    const char *moduleName,
1166                                    const OFBool acceptViolation)
1167 {
1168     /* call the real function */
1169     return checkElementValue(&delem, delem.getTag(), vm, type, searchCond, moduleName, acceptViolation);
1170 }
1171 
1172 
getAndCheckElementFromDataset(DcmItem & dataset,DcmElement & delem,const OFString & vm,const OFString & type,const char * moduleName,const OFBool acceptViolation)1173 OFCondition DSRTypes::getAndCheckElementFromDataset(DcmItem &dataset,
1174                                                     DcmElement &delem,
1175                                                     const OFString &vm,
1176                                                     const OFString &type,
1177                                                     const char *moduleName,
1178                                                     const OFBool acceptViolation)
1179 {
1180     DcmStack stack;
1181     const DcmTagKey tagKey = delem.getTag();
1182     OFCondition result = dataset.search(tagKey, stack, ESM_fromHere, OFFalse /*searchIntoSub*/);
1183     if (result.good())
1184     {
1185         /* copy object from search stack */
1186         result = delem.copyFrom(*stack.top());
1187         /* we need a reference to the original element in order to determine the SpecificCharacterSet */
1188         if (!checkElementValue(OFstatic_cast(DcmElement *, stack.top()), tagKey, vm, type, result, moduleName, acceptViolation))
1189             result = SR_EC_InvalidValue;
1190     }
1191     /* the element could not be found in the dataset */
1192     else if (!checkElementValue(delem, vm, type, result, moduleName, acceptViolation))
1193         result = SR_EC_InvalidValue;
1194     return result;
1195 }
1196 
1197 
getAndCheckStringValueFromDataset(DcmItem & dataset,const DcmTagKey & tagKey,OFString & stringValue,const OFString & vm,const OFString & type,const char * moduleName,const OFBool acceptViolation)1198 OFCondition DSRTypes::getAndCheckStringValueFromDataset(DcmItem &dataset,
1199                                                         const DcmTagKey &tagKey,
1200                                                         OFString &stringValue,
1201                                                         const OFString &vm,
1202                                                         const OFString &type,
1203                                                         const char *moduleName,
1204                                                         const OFBool acceptViolation)
1205 {
1206     DcmStack stack;
1207     OFCondition result = dataset.search(tagKey, stack, ESM_fromHere, OFFalse /*searchIntoSub*/);
1208     if (result.good())
1209     {
1210         DcmElement *delem = OFstatic_cast(DcmElement *, stack.top());
1211         /* we need a reference to the original element in order to determine the SpecificCharacterSet */
1212         if (!checkElementValue(delem, tagKey, vm, type, result, moduleName, acceptViolation))
1213             result = SR_EC_InvalidValue;
1214         delem->getOFString(stringValue, 0);
1215     } else {
1216         if ((type == "1") || (type == "2"))
1217         {
1218             const OFString tagName = DcmTag(tagKey).getTagName();
1219             const OFString module = (moduleName == NULL) ? "SR document" : moduleName;
1220             DCMSR_WARN(tagName << " " << tagKey << " absent in " << module << " (type " << type << ")");
1221         }
1222     }
1223     /* clear return parameter if an error occurred, but not in case of invalid value */
1224     if (result.bad() && (result != SR_EC_InvalidValue))
1225         stringValue.clear();
1226     return result;
1227 }
1228 
1229 
1230 // --- misc helper functions ---
1231 
currentDate(OFString & dateString)1232 const OFString &DSRTypes::currentDate(OFString &dateString)
1233 {
1234     DcmDate::getCurrentDate(dateString);
1235     return dateString;
1236 }
1237 
1238 
currentTime(OFString & timeString)1239 const OFString &DSRTypes::currentTime(OFString &timeString)
1240 {
1241     DcmTime::getCurrentTime(timeString, OFTrue /*seconds*/, OFFalse /*fraction*/);
1242     return timeString;
1243 }
1244 
1245 
currentDateTime(OFString & dateTimeString)1246 const OFString &DSRTypes::currentDateTime(OFString &dateTimeString)
1247 {
1248     DcmDateTime::getCurrentDateTime(dateTimeString, OFTrue /*seconds*/, OFFalse /*fraction*/, OFFalse /*timeZone*/);
1249     return dateTimeString;
1250 }
1251 
1252 
localTimezone(OFString & timezoneString)1253 const OFString &DSRTypes::localTimezone(OFString &timezoneString)
1254 {
1255     OFString dateTimeString;
1256     DcmDateTime::getCurrentDateTime(dateTimeString, OFFalse /*seconds*/, OFFalse /*fraction*/, OFTrue /*timeZone*/);
1257     timezoneString.assign(dateTimeString.substr(8 /* YYYYMMDD */ + 4 /* HHMM */, 5 /* &ZZZZ */));
1258     return timezoneString;
1259 }
1260 
1261 
dicomToReadableDate(const OFString & dicomDate,OFString & readableDate)1262 const OFString &DSRTypes::dicomToReadableDate(const OFString &dicomDate,
1263                                               OFString &readableDate)
1264 {
1265     DcmDate::getISOFormattedDateFromString(dicomDate, readableDate);
1266     return readableDate;
1267 }
1268 
1269 
dicomToReadableTime(const OFString & dicomTime,OFString & readableTime)1270 const OFString &DSRTypes::dicomToReadableTime(const OFString &dicomTime,
1271                                               OFString &readableTime)
1272 {
1273     DcmTime::getISOFormattedTimeFromString(dicomTime, readableTime, OFTrue /*seconds*/, OFFalse /*fraction*/, OFFalse /*createMissingPart*/);
1274     return readableTime;
1275 }
1276 
1277 
dicomToReadableDateTime(const OFString & dicomDateTime,OFString & readableDateTime)1278 const OFString &DSRTypes::dicomToReadableDateTime(const OFString &dicomDateTime,
1279                                                   OFString &readableDateTime)
1280 {
1281     DcmDateTime::getISOFormattedDateTimeFromString(dicomDateTime, readableDateTime, OFTrue /*seconds*/, OFFalse /*fraction*/, OFTrue /*timeZone*/, OFFalse /*createMissingPart*/);
1282     return readableDateTime;
1283 }
1284 
1285 
dicomToReadablePersonName(const OFString & dicomPersonName,OFString & readablePersonName)1286 const OFString &DSRTypes::dicomToReadablePersonName(const OFString &dicomPersonName,
1287                                                     OFString &readablePersonName)
1288 {
1289     if (DcmPersonName::getFormattedNameFromString(dicomPersonName, readablePersonName, 0 /*componentGroup*/).bad())
1290         readablePersonName = dicomPersonName;
1291     return readablePersonName;
1292 }
1293 
1294 
dicomToXMLPersonName(const OFString & dicomPersonName,OFString & xmlPersonName,const OFBool writeEmptyValue)1295 const OFString &DSRTypes::dicomToXMLPersonName(const OFString &dicomPersonName,
1296                                                OFString &xmlPersonName,
1297                                                const OFBool writeEmptyValue)
1298 {
1299     OFString str1, str2, str3, str4, str5;
1300     if (DcmPersonName::getNameComponentsFromString(dicomPersonName, str1, str2, str3, str4, str5, 0 /*componentGroup*/).good())
1301     {
1302         OFBool newLine = OFFalse;
1303         OFString xmlString;
1304         xmlPersonName.clear();
1305         /* prefix */
1306         if (writeEmptyValue || !str4.empty())
1307         {
1308             xmlPersonName += "<prefix>";
1309             xmlPersonName += convertToXMLString(str4, xmlString);
1310             xmlPersonName += "</prefix>";
1311             newLine = OFTrue;
1312         }
1313         /* first name */
1314         if (writeEmptyValue || !str2.empty())
1315         {
1316             if (newLine)
1317             {
1318                 xmlPersonName += '\n';
1319                 newLine = OFFalse;
1320             }
1321             xmlPersonName += "<first>";
1322             xmlPersonName += convertToXMLString(str2, xmlString);
1323             xmlPersonName += "</first>";
1324             newLine = OFTrue;
1325         }
1326         /* middle name */
1327         if (writeEmptyValue || !str3.empty())
1328         {
1329             if (newLine)
1330             {
1331                 xmlPersonName += '\n';
1332                 newLine = OFFalse;
1333             }
1334             xmlPersonName += "<middle>";
1335             xmlPersonName += convertToXMLString(str3, xmlString);
1336             xmlPersonName += "</middle>";
1337             newLine = OFTrue;
1338         }
1339         /* last name */
1340         if (writeEmptyValue || !str1.empty())
1341         {
1342             if (newLine)
1343             {
1344                 xmlPersonName += '\n';
1345                 newLine = OFFalse;
1346             }
1347             xmlPersonName += "<last>";
1348             xmlPersonName += convertToXMLString(str1, xmlString);
1349             xmlPersonName += "</last>";
1350             newLine = OFTrue;
1351         }
1352         /* suffix */
1353         if (writeEmptyValue || !str5.empty())
1354         {
1355             if (newLine)
1356             {
1357                 xmlPersonName += '\n';
1358                 newLine = OFFalse;
1359             }
1360             xmlPersonName += "<suffix>";
1361             xmlPersonName += convertToXMLString(str5, xmlString);
1362             xmlPersonName += "</suffix>";
1363             newLine = OFTrue;
1364         }
1365     } else
1366         xmlPersonName = dicomPersonName;
1367     return xmlPersonName;
1368 }
1369 
1370 
numberToString(const size_t number,char * stringValue)1371 const char *DSRTypes::numberToString(const size_t number,
1372                                      char *stringValue)
1373 {
1374     if (stringValue != NULL)
1375     {
1376         /* unsigned long */
1377         sprintf(stringValue, "%lu", OFstatic_cast(unsigned long, number));
1378     }
1379     return stringValue;
1380 }
1381 
1382 
stringToNumber(const char * stringValue)1383 size_t DSRTypes::stringToNumber(const char *stringValue)
1384 {
1385     size_t result = 0;
1386     if (stringValue != NULL)
1387     {
1388         unsigned long lu_value = 0;
1389         /* unsigned long */
1390         if (sscanf(stringValue, "%lu", &lu_value) == 1)
1391             result = OFstatic_cast(size_t, lu_value);
1392     }
1393     return result;
1394 }
1395 
1396 
convertToPrintString(const OFString & sourceString,OFString & printString)1397 const OFString &DSRTypes::convertToPrintString(const OFString &sourceString,
1398                                                OFString &printString)
1399 {
1400     /* char ptr allows fastest access to the string */
1401     const char *str = sourceString.c_str();
1402     const size_t count = strlen(str);
1403     /* start with empty string */
1404     printString.clear();
1405     /* avoid to resize the string too often */
1406     printString.reserve(count);
1407     for (size_t i = 0; i < count; i++)
1408     {
1409         /* newline: depends on OS */
1410         if (*str == '\n')
1411             printString += "\\n";
1412         /* line feed: LF */
1413         else if (*str == '\012')
1414             printString += "\\012";
1415         /* return: CR */
1416         else if (*str == '\r')
1417             printString += "\\r";
1418         /* other character: just append */
1419         else
1420             printString += *str;
1421         str++;
1422     }
1423     return printString;
1424 }
1425 
1426 
convertToHTMLString(const OFString & sourceString,OFString & markupString,const size_t flags,const OFBool newlineAllowed)1427 const OFString &DSRTypes::convertToHTMLString(const OFString &sourceString,
1428                                               OFString &markupString,
1429                                               const size_t flags,
1430                                               const OFBool newlineAllowed)
1431 {
1432     const OFBool convertNonASCII = (flags & HF_convertNonASCIICharacters) > 0;
1433     const OFStandard::E_MarkupMode markupMode = (flags & HF_XHTML11Compatibility) ? OFStandard::MM_XHTML : (flags & HF_HTML32Compatibility) ? OFStandard::MM_HTML32 : OFStandard::MM_HTML;
1434     /* call the real function */
1435     return OFStandard::convertToMarkupString(sourceString, markupString, convertNonASCII, markupMode, newlineAllowed);
1436 }
1437 
1438 
convertToXMLString(const OFString & sourceString,OFString & markupString)1439 const OFString &DSRTypes::convertToXMLString(const OFString &sourceString,
1440                                              OFString &markupString)
1441 {
1442     /* call the real function */
1443     return OFStandard::convertToMarkupString(sourceString, markupString, OFFalse /*convertNonASCII*/, OFStandard::MM_XML, OFFalse /*newlineAllowed*/);
1444 }
1445 
1446 
checkForValidReference(const OFString & stringValue)1447 OFBool DSRTypes::checkForValidReference(const OFString &stringValue)
1448 {
1449     OFBool result = OFFalse;
1450     /* empty strings are invalid */
1451     if (!stringValue.empty())
1452     {
1453         const unsigned char *p = OFreinterpret_cast(const unsigned char *, stringValue.c_str());
1454         if (p != NULL)
1455         {
1456             /* check for leading number */
1457             while (isdigit(*p))
1458             {
1459                 /* disallow leading 0 */
1460                 if (!result && (*p == '0'))
1461                     break;
1462                 result = OFTrue;
1463                 p++;
1464             }
1465             /* check for separator */
1466             while ((*p == '.') && result)
1467             {
1468                 /* trailing '.' is invalid */
1469                 result = OFFalse;
1470                 p++;
1471                 /* check for trailing number */
1472                 while (isdigit(*p))
1473                 {
1474                     /* disallow leading 0 */
1475                     if (!result && (*p == '0'))
1476                         break;
1477                     result = OFTrue;
1478                     p++;
1479                 }
1480             }
1481             /* all characters checked? */
1482             if (*p != 0)
1483                 result = OFFalse;
1484         }
1485     }
1486     return result;
1487 }
1488 
1489 
createIODConstraintChecker(const E_DocumentType documentType)1490 DSRIODConstraintChecker *DSRTypes::createIODConstraintChecker(const E_DocumentType documentType)
1491 {
1492     DSRIODConstraintChecker *checker = NULL;
1493     switch (documentType)
1494     {
1495         case DT_BasicTextSR:
1496             checker = new DSRBasicTextSRConstraintChecker();
1497             break;
1498         case DT_EnhancedSR:
1499             checker = new DSREnhancedSRConstraintChecker();
1500             break;
1501         case DT_ComprehensiveSR:
1502             checker = new DSRComprehensiveSRConstraintChecker();
1503             break;
1504         case DT_KeyObjectSelectionDocument:
1505             checker = new DSRKeyObjectSelectionDocumentConstraintChecker();
1506             break;
1507         case DT_MammographyCadSR:
1508             checker = new DSRMammographyCadSRConstraintChecker();
1509             break;
1510         case DT_ChestCadSR:
1511             checker = new DSRChestCadSRConstraintChecker();
1512             break;
1513         case DT_ColonCadSR:
1514             checker = new DSRColonCadSRConstraintChecker();
1515             break;
1516         case DT_ProcedureLog:
1517             checker = new DSRProcedureLogConstraintChecker();
1518             break;
1519         case DT_XRayRadiationDoseSR:
1520             checker = new DSRXRayRadiationDoseSRConstraintChecker();
1521             break;
1522         case DT_SpectaclePrescriptionReport:
1523             checker = new DSRSpectaclePrescriptionReportConstraintChecker();
1524             break;
1525         case DT_MacularGridThicknessAndVolumeReport:
1526             checker = new DSRMacularGridThicknessAndVolumeReportConstraintChecker();
1527             break;
1528         case DT_ImplantationPlanSRDocument:
1529             checker = new DSRImplantationPlanSRDocumentConstraintChecker();
1530             break;
1531         case DT_Comprehensive3DSR:
1532             checker = new DSRComprehensive3DSRConstraintChecker();
1533             break;
1534         case DT_RadiopharmaceuticalRadiationDoseSR:
1535             checker = new DSRRadiopharmaceuticalRadiationDoseSRConstraintChecker();
1536             break;
1537         case DT_ExtensibleSR:
1538             /* not yet supported */
1539             break;
1540         case DT_AcquisitionContextSR:
1541             checker = new DSRAcquisitionContextSRConstraintChecker();
1542             break;
1543         case DT_SimplifiedAdultEchoSR:
1544             checker = new DSRSimplifiedAdultEchoSRConstraintChecker();
1545             break;
1546         case DT_PatientRadiationDoseSR:
1547             checker = new DSRPatientRadiationDoseSRConstraintChecker();
1548             break;
1549         case DT_PerformedImagingAgentAdministrationSR:
1550             checker = new DSRPerformedImagingAgentAdministrationSRConstraintChecker();
1551             break;
1552         case DT_PlannedImagingAgentAdministrationSR:
1553             checker = new DSRPlannedImagingAgentAdministrationSRConstraintChecker();
1554             break;
1555         case DT_RenditionSelectionDocument:
1556             checker = new DSRRenditionSelectionDocumentConstraintChecker();
1557             break;
1558         case DT_invalid:
1559             /* nothing to do */
1560             break;
1561     }
1562     return checker;
1563 }
1564 
1565 
createDocumentTreeNode(const E_RelationshipType relationshipType,const E_ValueType valueType)1566 DSRDocumentTreeNode *DSRTypes::createDocumentTreeNode(const E_RelationshipType relationshipType,
1567                                                       const E_ValueType valueType)
1568 {
1569     DSRDocumentTreeNode *node = NULL;
1570     switch (valueType)
1571     {
1572         case VT_Text:
1573             node = new DSRTextTreeNode(relationshipType);
1574             break;
1575         case VT_Code:
1576             node = new DSRCodeTreeNode(relationshipType);
1577             break;
1578         case VT_Num:
1579             node = new DSRNumTreeNode(relationshipType);
1580             break;
1581         case VT_DateTime:
1582             node = new DSRDateTimeTreeNode(relationshipType);
1583             break;
1584         case VT_Date:
1585             node = new DSRDateTreeNode(relationshipType);
1586             break;
1587         case VT_Time:
1588             node = new DSRTimeTreeNode(relationshipType);
1589             break;
1590         case VT_UIDRef:
1591             node = new DSRUIDRefTreeNode(relationshipType);
1592             break;
1593         case VT_PName:
1594             node = new DSRPNameTreeNode(relationshipType);
1595             break;
1596         case VT_SCoord:
1597             node = new DSRSCoordTreeNode(relationshipType);
1598             break;
1599         case VT_SCoord3D:
1600             node = new DSRSCoord3DTreeNode(relationshipType);
1601             break;
1602         case VT_TCoord:
1603             node = new DSRTCoordTreeNode(relationshipType);
1604             break;
1605         case VT_Composite:
1606             node = new DSRCompositeTreeNode(relationshipType);
1607             break;
1608         case VT_Image:
1609             node = new DSRImageTreeNode(relationshipType);
1610             break;
1611         case VT_Waveform:
1612             node = new DSRWaveformTreeNode(relationshipType);
1613             break;
1614         case VT_Container:
1615             node = new DSRContainerTreeNode(relationshipType);
1616             break;
1617         case VT_byReference:
1618             node = new DSRByReferenceTreeNode(relationshipType);
1619             break;
1620         default:
1621             break;
1622     }
1623     return node;
1624 }
1625 
1626 
printInvalidContentItemMessage(const char * action,const DSRDocumentTreeNode * node,const char * location)1627 void DSRTypes::printInvalidContentItemMessage(const char *action,
1628                                               const DSRDocumentTreeNode *node,
1629                                               const char *location)
1630 {
1631     OFString message;
1632     if (action != NULL)
1633         message += action;
1634     else
1635         message += "Processing";
1636     message += " invalid/incomplete content item";
1637     if (node != NULL)
1638     {
1639         message += " ";
1640         message += valueTypeToDefinedTerm(node->getValueType());
1641     }
1642     if (location != NULL)
1643     {
1644         message += " \"";
1645         message += location;
1646         message += "\"";
1647     }
1648     DCMSR_WARN(message);
1649 }
1650 
1651 
printContentItemErrorMessage(const char * action,const OFCondition & result,const DSRDocumentTreeNode * node,const char * location)1652 void DSRTypes::printContentItemErrorMessage(const char *action,
1653                                             const OFCondition &result,
1654                                             const DSRDocumentTreeNode *node,
1655                                             const char *location)
1656 {
1657     if (result.bad())
1658     {
1659         OFString message;
1660         if (action != NULL)
1661             message += action;
1662         else
1663             message += "Processing";
1664         message += " content item";
1665         if (node != NULL)
1666         {
1667             message += " ";
1668             message += valueTypeToDefinedTerm(node->getValueType());
1669         }
1670         if (location != NULL)
1671         {
1672             message += " \"";
1673             message += location;
1674             message += "\"";
1675         }
1676         message += " (";
1677         message += result.text();
1678         message += ")";
1679         DCMSR_ERROR(message);
1680     }
1681 }
1682 
1683 
printUnknownValueWarningMessage(const char * valueName,const char * readValue,const char * action)1684 void DSRTypes::printUnknownValueWarningMessage(const char *valueName,
1685                                                const char *readValue,
1686                                                const char *action)
1687 {
1688     if (valueName != NULL)
1689     {
1690         OFString message;
1691         if (action != NULL)
1692             message += action;
1693         else
1694             message += "Processing";
1695         message += " unknown/unsupported ";
1696         message += valueName;
1697         if ((readValue != NULL) && (strlen(readValue) > 0))
1698         {
1699             message += " (";
1700             message += readValue;
1701             message += ")";
1702         }
1703         DCMSR_WARN(message);
1704     }
1705 }
1706 
1707 
writeStringValueToXML(STD_NAMESPACE ostream & stream,const OFString & stringValue,const OFString & tagName,const OFBool writeEmptyValue)1708 OFBool DSRTypes::writeStringValueToXML(STD_NAMESPACE ostream &stream,
1709                                        const OFString &stringValue,
1710                                        const OFString &tagName,
1711                                        const OFBool writeEmptyValue)
1712 {
1713     OFBool result = OFFalse;
1714     if (writeEmptyValue || !stringValue.empty())
1715     {
1716         stream << "<" << tagName << ">";
1717         OFStandard::convertToMarkupStream(stream, stringValue, OFFalse /*convertNonASCII*/, OFStandard::MM_XML, OFFalse /*newlineAllowed*/);
1718         stream << "</" << tagName << ">" << OFendl;
1719         result = OFTrue;
1720     }
1721     return result;
1722 }
1723 
1724 
writeStringFromElementToXML(STD_NAMESPACE ostream & stream,DcmElement & delem,const OFString & tagName,const OFBool writeEmptyValue)1725 OFBool DSRTypes::writeStringFromElementToXML(STD_NAMESPACE ostream &stream,
1726                                              DcmElement &delem,
1727                                              const OFString &tagName,
1728                                              const OFBool writeEmptyValue)
1729 {
1730     OFBool result = OFFalse;
1731     if (writeEmptyValue || !delem.isEmpty())
1732     {
1733         OFString tempString;
1734         stream << "<" << tagName << ">";
1735         /* special formatting for person names */
1736         if (delem.getVR() == EVR_PN)
1737         {
1738             OFString xmlString;
1739             /* use first element value only */
1740             stream << OFendl << dicomToXMLPersonName(getStringValueFromElement(delem, tempString), xmlString, writeEmptyValue) << OFendl;
1741         } else {
1742             /* use all element values (1-n) */
1743             getStringValueFromElement(delem, tempString, -1 /* all components */);
1744             OFStandard::convertToMarkupStream(stream, tempString, OFFalse /*convertNonASCII*/);
1745         }
1746         stream << "</" << tagName << ">" << OFendl;
1747         result = OFTrue;
1748     }
1749     return result;
1750 }
1751 
1752 
createHTMLAnnexEntry(STD_NAMESPACE ostream & docStream,STD_NAMESPACE ostream & annexStream,const OFString & referenceText,size_t & annexNumber,const size_t flags)1753 size_t DSRTypes::createHTMLAnnexEntry(STD_NAMESPACE ostream &docStream,
1754                                       STD_NAMESPACE ostream &annexStream,
1755                                       const OFString &referenceText,
1756                                       size_t &annexNumber,
1757                                       const size_t flags)
1758 {
1759     /* hyperlink to corresponding annex */
1760     const char *attrName = (flags & DSRTypes::HF_XHTML11Compatibility) ? "id" : "name";
1761     docStream << "[";
1762     if (!referenceText.empty())
1763         docStream << referenceText << " ";
1764     docStream << "<a " << attrName << "=\"annex_src_" << annexNumber << "\" href=\"#annex_dst_" << annexNumber << "\">Annex " << annexNumber << "</a>]" << OFendl;
1765     /* create new annex */
1766     annexStream << "<h2><a " << attrName << "=\"annex_dst_" << annexNumber << "\" href=\"#annex_src_" << annexNumber << "\">Annex " << annexNumber << "</a></h2>" << OFendl;
1767     /* increase annex number, return previous number */
1768     return annexNumber++;
1769 }
1770 
1771 
createHTMLFootnote(STD_NAMESPACE ostream & docStream,STD_NAMESPACE ostream & footnoteStream,size_t & footnoteNumber,const size_t nodeID,const size_t flags)1772 size_t DSRTypes::createHTMLFootnote(STD_NAMESPACE ostream &docStream,
1773                                     STD_NAMESPACE ostream &footnoteStream,
1774                                     size_t &footnoteNumber,
1775                                     const size_t nodeID,
1776                                     const size_t flags)
1777 {
1778     /* hyperlink to corresponding footnote */
1779     const char *attrName = (flags & DSRTypes::HF_XHTML11Compatibility) ? "id" : "name";
1780     if (flags & HF_XHTML11Compatibility)
1781         docStream << "<span class=\"super\">";
1782     else
1783         docStream << "<small><sup>";
1784     docStream << "<a " << attrName << "=\"footnote_src_" << nodeID << "_" << footnoteNumber << "\" ";
1785     docStream << "href=\"#footnote_dst_" << nodeID << "_" << footnoteNumber << "\">" << footnoteNumber << "</a>";
1786     if (flags & HF_XHTML11Compatibility)
1787         docStream << "</span>" << OFendl;
1788     else
1789         docStream << "</sup></small>" << OFendl;
1790     /* create new footnote */
1791     footnoteStream << "<b><a " << attrName << "=\"footnote_dst_" << nodeID << "_" << footnoteNumber << "\" ";
1792     footnoteStream << "href=\"#footnote_src_" << nodeID << "_" << footnoteNumber << "\">Footnote " << footnoteNumber << "</a></b>" << OFendl;
1793     /* increase footnote number, return previous number */
1794     return footnoteNumber++;
1795 }
1796 
1797 
appendStream(STD_NAMESPACE ostream & mainStream,OFOStringStream & tempStream,const char * heading)1798 OFCondition DSRTypes::appendStream(STD_NAMESPACE ostream &mainStream,
1799                                    OFOStringStream &tempStream,
1800                                    const char *heading)
1801 {
1802     OFCondition result = EC_InvalidStream;
1803     /* add final 0 byte (if required) */
1804     tempStream << OFStringStream_ends;
1805     /* freeze/get string (now we have full control over the array) */
1806     OFSTRINGSTREAM_GETSTR(tempStream, tempString)
1807     /* should never be NULL */
1808     if (tempString != NULL)
1809     {
1810         if (strlen(tempString) > 0)
1811         {
1812             /* append optional heading */
1813             if (heading != NULL)
1814                 mainStream << heading << OFendl;
1815             /* append temporal document to main document */
1816             mainStream << tempString;
1817         }
1818         /* very important! since we have full control we are responsible for deleting the array */
1819         OFSTRINGSTREAM_FREESTR(tempString)
1820         result = EC_Normal;
1821     }
1822     return result;
1823 }
1824