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