1 /*
2  *
3  *  Copyright (C) 1994-2002, OFFIS
4  *
5  *  This software and supporting documentation were developed by
6  *
7  *    Kuratorium OFFIS e.V.
8  *    Healthcare Information and Communication Systems
9  *    Escherweg 2
10  *    D-26121 Oldenburg, Germany
11  *
12  *  THIS SOFTWARE IS MADE AVAILABLE,  AS IS,  AND OFFIS MAKES NO  WARRANTY
13  *  REGARDING  THE  SOFTWARE,  ITS  PERFORMANCE,  ITS  MERCHANTABILITY  OR
14  *  FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES  OR
15  *  ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
16  *  PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
17  *
18  *  Module:  dcmdata
19  *
20  *  Author:  Andrew Hewett
21  *
22  *  Purpose:
23  *  Definitions of "well known" DICOM Unique Indentifiers,
24  *  routines for finding and creating UIDs.
25  *
26  */
27 
28 #include "osconfig.h"    /* make sure OS specific configuration is included first */
29 
30 #ifdef HAVE_WINDOWS_H
31 #include <windows.h>     /* this includes either winsock.h or winsock2.h */
32 #else
33 #ifdef HAVE_WINSOCK_H
34 #include <winsock.h>     /* include winsock.h directly i.e. on MacOS */
35 #endif
36 #endif
37 
38 #ifdef _WIN32
39 #include <process.h>     /* needed for declaration of getpid() */
40 #endif
41 
42 #define INCLUDE_CSTDLIB
43 #define INCLUDE_CSTDIO
44 #define INCLUDE_CSTRING
45 #define INCLUDE_CTIME
46 #include "ofstdinc.h"
47 
48 BEGIN_EXTERN_C
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #ifdef HAVE_LIBC_H
53 #include <libc.h>
54 #endif
55 #ifndef _WIN32
56 #ifdef HAVE_SYS_TIME_H
57 #include <sys/time.h>
58 #endif
59 #ifdef HAVE_SYS_TYPES_H
60 #include <sys/types.h>
61 #endif
62 #ifdef HAVE_SYS_SOCKET_H
63 #ifndef DCOMPAT_SYS_SOCKET_H_
64 #define DCOMPAT_SYS_SOCKET_H_
65 /* some systems don't protect sys/socket.h (e.g. DEC Ultrix) */
66 #include <sys/socket.h>
67 #endif
68 #endif
69 #endif
70 #ifdef HAVE_NETINET_IN_H
71 #include <netinet/in.h>
72 #endif
73 #ifdef HAVE_ARPA_INET_H
74 #include <arpa/inet.h>
75 #endif
76 #ifdef HAVE_NETDB_H
77 #include <netdb.h>
78 #endif
79 END_EXTERN_C
80 
81 #include "ofstream.h"
82 #include "dcuid.h"
83 #include "ofthread.h"
84 #include "ofcrc32.h"
85 
86 struct UIDNameMap {
87     const char* uid;
88     const char* name;
89 };
90 
91 //
92 // It is very important that the names of the UIDs may not use the following
93 // characters: space  (  )  [  ], =  <  >
94 
95 static const UIDNameMap uidNameMap[] = {
96     { UID_StandardApplicationContext,                         "StandardApplicationContext" },
97     { UID_LittleEndianImplicitTransferSyntax,                 "LittleEndianImplicit" },
98     { UID_LittleEndianExplicitTransferSyntax,                 "LittleEndianExplicit" },
99     { UID_BigEndianExplicitTransferSyntax,                    "BigEndianExplicit" },
100     { UID_JPEGProcess1TransferSyntax,                         "JPEGBaseline" },
101     { UID_JPEGProcess2_4TransferSyntax,                       "JPEGExtended:Process2+4" },
102     { UID_JPEGProcess3_5TransferSyntax,                       "JPEGExtended:Process3+5" },
103     { UID_JPEGProcess6_8TransferSyntax,                       "JPEGSpectralSelection:Non-hierarchical:Process6+8" },
104     { UID_JPEGProcess7_9TransferSyntax,                       "JPEGSpectralSelection:Non-hierarchical:Process7+9" },
105     { UID_JPEGProcess10_12TransferSyntax,                     "JPEGFullProgression:Non-hierarchical:Process10+12" },
106     { UID_JPEGProcess11_13TransferSyntax,                     "JPEGFullProgression:Non-hierarchical:Process11+13" },
107     { UID_JPEGProcess14TransferSyntax,                        "JPEGLossless:Non-hierarchical:Process14" },
108     { UID_JPEGProcess15TransferSyntax,                        "JPEGLossless:Non-hierarchical:Process15" },
109     { UID_JPEGProcess16_18TransferSyntax,                     "JPEGExtended:Hierarchical:Process16+18" },
110     { UID_JPEGProcess17_19TransferSyntax,                     "JPEGExtended:Hierarchical:Process17+19" },
111     { UID_JPEGProcess20_22TransferSyntax,                     "JPEGSpectralSelection:Hierarchical:Process20+22" },
112     { UID_JPEGProcess21_23TransferSyntax,                     "JPEGSpectralSelection:Hierarchical:Process21+23" },
113     { UID_JPEGProcess24_26TransferSyntax,                     "JPEGFullProgression:Hierarchical:Process24+26" },
114     { UID_JPEGProcess25_27TransferSyntax,                     "JPEGFullProgression:Hierarchical:Process25+27" },
115     { UID_JPEGProcess28TransferSyntax,                        "JPEGLossless:Hierarchical:Process28" },
116     { UID_JPEGProcess29TransferSyntax,                        "JPEGLossless:Hierarchical:Process29" },
117     { UID_JPEGProcess14SV1TransferSyntax,                     "JPEGLossless:Non-hierarchical-1stOrderPrediction" },
118     { UID_JPEGLSLossless,                                     "JPEGLSLossless" },
119     { UID_JPEGLSLossy,                                        "JPEGLSLossy" },
120     { UID_RLELossless,                                        "RLELossless" },
121     { UID_DeflatedExplicitVRLittleEndianTransferSyntax,       "DeflatedLittleEndianExplicit" },
122     { UID_JPEG2000LosslessOnlyTransferSyntax,                 "JPEG2000LosslessOnly" },
123     { UID_JPEG2000TransferSyntax,                             "JPEG2000" },
124 
125     // Storage
126     { UID_AmbulatoryECGWaveformStorage,                       "AmbulatoryECGWaveformStorage" },
127     { UID_BasicTextSR,                                        "BasicTextSR" },
128     { UID_BasicVoiceAudioWaveformStorage,                     "BasicVoiceAudioWaveformStorage" },
129     { UID_CTImageStorage,                                     "CTImageStorage" },
130     { UID_CardiacElectrophysiologyWaveformStorage,            "CardiacElectrophysiologyWaveformStorage" },
131     { UID_ComprehensiveSR,                                    "ComprehensiveSR" },
132     { UID_ComputedRadiographyImageStorage,                    "ComputedRadiographyImageStorage" },
133     { UID_DigitalIntraOralXRayImageStorageForPresentation,    "DigitalIntraOralXRayImageStorageForPresentation" },
134     { UID_DigitalIntraOralXRayImageStorageForProcessing,      "DigitalIntraOralXRayImageStorageForProcessing" },
135     { UID_DigitalMammographyXRayImageStorageForPresentation,  "DigitalMammographyXRayImageStorageForPresentation" },
136     { UID_DigitalMammographyXRayImageStorageForProcessing,    "DigitalMammographyXRayImageStorageForProcessing" },
137     { UID_DigitalXRayImageStorageForPresentation,             "DigitalXRayImageStorageForPresentation" },
138     { UID_DigitalXRayImageStorageForProcessing,               "DigitalXRayImageStorageForProcessing" },
139     { UID_EnhancedMRImageStorage,                             "EnhancedMRImageStorage" },
140     { UID_EnhancedSR,                                         "EnhancedSR" },
141     { UID_GeneralECGWaveformStorage,                          "GeneralECGWaveformStorage" },
142     { UID_GrayscaleSoftcopyPresentationStateStorage,          "GrayscaleSoftcopyPresentationStateStorage" },
143     { UID_HardcopyColorImageStorage,                          "HardcopyColorImageStorage" },
144     { UID_HardcopyGrayscaleImageStorage,                      "HardcopyGrayscaleImageStorage" },
145     { UID_HemodynamicWaveformStorage,                         "HemodynamicWaveformStorage" },
146     { UID_KeyObjectSelectionDocument,                         "KeyObjectSelectionDocument" },
147     { UID_MRImageStorage,                                     "MRImageStorage" },
148     { UID_MRSpectroscopyStorage,                              "MRSpectroscopyStorage" },
149     { UID_MammographyCADSR,                                   "MammographyCADSR" },
150     { UID_MultiframeGrayscaleByteSecondaryCaptureImageStorage, "MultiframeGrayscaleByteSecondaryCaptureImageStorage" },
151     { UID_MultiframeGrayscaleWordSecondaryCaptureImageStorage, "MultiframeGrayscaleWordSecondaryCaptureImageStorage" },
152     { UID_MultiframeSingleBitSecondaryCaptureImageStorage,    "MultiframeSingleBitSecondaryCaptureImageStorage" },
153     { UID_MultiframeTrueColorSecondaryCaptureImageStorage,    "MultiframeTrueColorSecondaryCaptureImageStorage" },
154     { UID_NuclearMedicineImageStorage,                        "NuclearMedicineImageStorage" },
155     { UID_PETCurveStorage,                                    "PETCurveStorage" },
156     { UID_PETImageStorage,                                    "PETImageStorage" },
157     { UID_RETIRED_NuclearMedicineImageStorage,                "RETIRED_NuclearMedicineImageStorage" },
158     { UID_RETIRED_UltrasoundImageStorage,                     "RETIRED_UltrasoundImageStorage" },
159     { UID_RETIRED_UltrasoundMultiframeImageStorage,           "RETIRED_UltrasoundMultiframeImageStorage" },
160     { UID_RETIRED_VLImageStorage,                             "RETIRED_VLImageStorage" },
161     { UID_RETIRED_VLMultiFrameImageStorage,                   "RETIRED_VLMultiFrameImageStorage" },
162     { UID_RETIRED_XRayAngiographicBiPlaneImageStorage,        "RETIRED_XRayAngiographicBiPlaneImageStorage" },
163     { UID_RTBeamsTreatmentRecordStorage,                      "RTBeamsTreatmentRecordStorage" },
164     { UID_RTBrachyTreatmentRecordStorage,                     "RTBrachyTreatmentRecordStorage" },
165     { UID_RTDoseStorage,                                      "RTDoseStorage" },
166     { UID_RTImageStorage,                                     "RTImageStorage" },
167     { UID_RTPlanStorage,                                      "RTPlanStorage" },
168     { UID_RTStructureSetStorage,                              "RTStructureSetStorage" },
169     { UID_RTTreatmentSummaryRecordStorage,                    "RTTreatmentSummaryRecordStorage" },
170     { UID_RawDataStorage,                                     "RawDataStorage" },
171     { UID_SecondaryCaptureImageStorage,                       "SecondaryCaptureImageStorage" },
172     { UID_StandaloneCurveStorage,                             "StandaloneCurveStorage" },
173     { UID_StandaloneModalityLUTStorage,                       "StandaloneModalityLUTStorage" },
174     { UID_StandaloneOverlayStorage,                           "StandaloneOverlayStorage" },
175     { UID_StandaloneVOILUTStorage,                            "StandaloneVOILUTStorage" },
176     { UID_StoredPrintStorage,                                 "StoredPrintStorage" },
177     { UID_TwelveLeadECGWaveformStorage,                       "TwelveLeadECGWaveformStorage" },
178     { UID_UltrasoundImageStorage,                             "UltrasoundImageStorage" },
179     { UID_UltrasoundMultiframeImageStorage,                   "UltrasoundMultiframeImageStorage" },
180     { UID_VLEndoscopicImageStorage,                           "VLEndoscopicImageStorage" },
181     { UID_VLMicroscopicImageStorage,                          "VLMicroscopicImageStorage" },
182     { UID_VLPhotographicImageStorage,                         "VLPhotographicImageStorage" },
183     { UID_VLSlideCoordinatesMicroscopicImageStorage,          "VLSlideCoordinatesMicroscopicImageStorage" },
184     { UID_XRayAngiographicImageStorage,                       "XRayAngiographicImageStorage" },
185     { UID_XRayFluoroscopyImageStorage,                        "XRayFluoroscopyImageStorage" },
186 
187     // Query/Retrieve
188     { UID_FINDModalityWorklistInformationModel,               "FINDModalityWorklistInformationModel" },
189     { UID_FINDPatientRootQueryRetrieveInformationModel,       "FINDPatientRootQueryRetrieveInformationModel" },
190     { UID_FINDPatientStudyOnlyQueryRetrieveInformationModel,  "FINDPatientStudyOnlyQueryRetrieveInformationModel" },
191     { UID_FINDStudyRootQueryRetrieveInformationModel,         "FINDStudyRootQueryRetrieveInformationModel" },
192     { UID_GETPatientRootQueryRetrieveInformationModel,        "GETPatientRootQueryRetrieveInformationModel" },
193     { UID_GETPatientStudyOnlyQueryRetrieveInformationModel,   "GETPatientStudyOnlyQueryRetrieveInformationModel" },
194     { UID_GETStudyRootQueryRetrieveInformationModel,          "GETStudyRootQueryRetrieveInformationModel" },
195     { UID_MOVEPatientRootQueryRetrieveInformationModel,       "MOVEPatientRootQueryRetrieveInformationModel" },
196     { UID_MOVEPatientStudyOnlyQueryRetrieveInformationModel,  "MOVEPatientStudyOnlyQueryRetrieveInformationModel" },
197     { UID_MOVEStudyRootQueryRetrieveInformationModel,         "MOVEStudyRootQueryRetrieveInformationModel" },
198     { UID_FINDGeneralPurposeWorklistInformationModel,         "FINDGeneralPurposeWorklistInformationModel" },
199 
200     // Print
201     { UID_BasicAnnotationBoxSOPClass,                         "BasicAnnotationBoxSOPClass" },
202     { UID_BasicColorImageBoxSOPClass,                         "BasicColorImageBoxSOPClass" },
203     { UID_BasicColorPrintManagementMetaSOPClass,              "BasicColorPrintManagementMetaSOPClass" },
204     { UID_BasicFilmBoxSOPClass,                               "BasicFilmBoxSOPClass" },
205     { UID_BasicFilmSessionSOPClass,                           "BasicFilmSessionSOPClass" },
206     { UID_BasicGrayscaleImageBoxSOPClass,                     "BasicGrayscaleImageBoxSOPClass" },
207     { UID_BasicGrayscalePrintManagementMetaSOPClass,          "BasicGrayscalePrintManagementMetaSOPClass" },
208     { UID_BasicPrintImageOverlayBoxSOPClass,                  "BasicPrintImageOverlayBoxSOPClass" },
209     { UID_ImageOverlayBoxSOPClass,                            "ImageOverlayBoxSOPClass" },
210     { UID_PresentationLUTSOPClass,                            "PresentationLUTSOPClass" },
211     { UID_PrintJobSOPClass,                                   "PrintJobSOPClass" },
212     { UID_PrintQueueManagementSOPClass,                       "PrintQueueManagementSOPClass" },
213     { UID_PrintQueueSOPInstance,                              "PrintQueueSOPInstance" },
214     { UID_PrinterConfigurationRetrievalSOPClass,              "PrinterConfigurationRetrievalSOPClass" },
215     { UID_PrinterConfigurationRetrievalSOPInstance,           "PrinterConfigurationRetrievalSOPInstance" },
216     { UID_PrinterSOPClass,                                    "PrinterSOPClass" },
217     { UID_PrinterSOPInstance,                                 "PrinterSOPInstance" },
218     { UID_PullPrintRequestSOPClass,                           "PullPrintRequestSOPClass" },
219     { UID_PullStoredPrintManagementMetaSOPClass,              "PullStoredPrintManagementMetaSOPClass" },
220     { UID_RETIRED_ReferencedColorPrintManagementMetaSOPClass, "RETIRED_ReferencedColorPrintManagementMetaSOPClass" },
221     { UID_RETIRED_ReferencedGrayscalePrintManagementMetaSOPClass, "RETIRED_ReferencedGrayscalePrintManagementMetaSOPClass" },
222     { UID_RETIRED_ReferencedImageBoxSOPClass,                  "RETIRED_ReferencedImageBoxSOPClass" },
223     { UID_VOILUTBoxSOPClass,                                  "VOILUTBoxSOPClass" },
224 
225     // Storage Commitment
226     { UID_RETIRED_StorageCommitmentPullModelSOPClass,         "RETIRED_StorageCommitmentPullModelSOPClass" },
227     { UID_RETIRED_StorageCommitmentPullModelSOPInstance,      "RETIRED_StorageCommitmentPullModelSOPInstance" },
228     { UID_StorageCommitmentPushModelSOPClass,                 "StorageCommitmentPushModelSOPClass" },
229     { UID_StorageCommitmentPushModelSOPInstance,              "StorageCommitmentPushModelSOPInstance" },
230 
231     // MPPS
232     { UID_ModalityPerformedProcedureStepNotificationSOPClass, "ModalityPerformedProcedureStepNotificationSOPClass" },
233     { UID_ModalityPerformedProcedureStepRetrieveSOPClass,     "ModalityPerformedProcedureStepRetrieveSOPClass" },
234     { UID_ModalityPerformedProcedureStepSOPClass,             "ModalityPerformedProcedureStepSOPClass" },
235 
236     // Detached Management
237     { UID_DetachedInterpretationManagementSOPClass,           "DetachedInterpretationManagementSOPClass" },
238     { UID_DetachedPatientManagementMetaSOPClass,              "DetachedPatientManagementMetaSOPClass" },
239     { UID_DetachedPatientManagementSOPClass,                  "DetachedPatientManagementSOPClass" },
240     { UID_DetachedResultsManagementMetaSOPClass,              "DetachedResultsManagementMetaSOPClass" },
241     { UID_DetachedResultsManagementSOPClass,                  "DetachedResultsManagementSOPClass" },
242     { UID_DetachedStudyManagementMetaSOPClass,                "DetachedStudyManagementMetaSOPClass" },
243     { UID_DetachedStudyManagementSOPClass,                    "DetachedStudyManagementSOPClass" },
244     { UID_DetachedVisitManagementSOPClass,                    "DetachedVisitManagementSOPClass" },
245 
246     // General Purpose Worklist (Supplement 52 final text)
247     { UID_GeneralPurposeScheduledProcedureStepSOPClass,       "GeneralPurposeScheduledProcedureStepSOPClass" },
248     { UID_GeneralPurposePerformedProcedureStepSOPClass,       "GeneralPurposePerformedProcedureStepSOPClass" },
249     { UID_GeneralPurposeWorklistManagementMetaSOPClass,       "GeneralPurposeWorklistManagementMetaSOPClass" },
250 
251     // other
252     { UID_BasicDirectoryStorageSOPClass,                      "BasicDirectoryStorageSOPClass" },
253     { UID_BasicStudyContentNotificationSOPClass,              "BasicStudyContentNotificationSOPClass" },
254     { UID_StudyComponentManagementSOPClass,                   "StudyComponentManagementSOPClass" },
255     { UID_VerificationSOPClass,                               "VerificationSOPClass" },
256 
257     // DICOM Controlled Terminology
258     { UID_DICOMControlledTerminologyCodingScheme,             "DICOMControlledTerminologyCodingScheme" },
259 
260     // supplements
261     { UID_DRAFT_SRTextStorage,                                "DRAFT_SRTextStorage" },
262     { UID_DRAFT_SRAudioStorage,                               "DRAFT_SRAudioStorage" },
263     { UID_DRAFT_SRDetailStorage,                              "DRAFT_SRDetailStorage" },
264     { UID_DRAFT_SRComprehensiveStorage,                       "DRAFT_SRComprehensiveStorage" },
265     { UID_DRAFT_WaveformStorage,                              "DRAFT_WaveformStorage" },
266 
267     { NULL, NULL }
268 };
269 
270 static const int uidNameMap_size = ( sizeof(uidNameMap) / sizeof(UIDNameMap) );
271 
272 /*
273 ** The global variable dcmStorageSOPClassUIDs is an array of
274 ** string pointers containing the UIDs of all known Storage SOP
275 ** Classes.  The global variable numberOfDcmStorageSOPClassUIDs
276 ** defines the size of the array.
277 */
278 
279 const char* dcmStorageSOPClassUIDs[] = {
280     // basic directory storage is a special case - we cannot
281     // transmit a DICOMDIR by c-store because of the absolute
282     // file position offsets within the DICOMDIR.
283     // UID_BasicDirectoryStorageSOPClass,
284 
285     UID_AmbulatoryECGWaveformStorage,
286     UID_BasicTextSR,
287     UID_BasicVoiceAudioWaveformStorage,
288     UID_CTImageStorage,
289     UID_CardiacElectrophysiologyWaveformStorage,
290     UID_ComprehensiveSR,
291     UID_ComputedRadiographyImageStorage,
292 /* disabled draft storage SOP classes to keep the number of storage transfer
293  * syntaxes <= 64.  If we have more than 64 storage transfer syntaxes, tools
294  * such as storescu will fail because they attempt to negotiate two
295  * presentation contexts for each SOP class, and there is a total limit of
296  * 128 contexts for one association.
297  *
298     UID_DRAFT_SRAudioStorage,
299     UID_DRAFT_SRComprehensiveStorage,
300     UID_DRAFT_SRDetailStorage,
301     UID_DRAFT_SRTextStorage,
302     UID_DRAFT_WaveformStorage,
303  */
304     UID_DigitalIntraOralXRayImageStorageForPresentation,
305     UID_DigitalIntraOralXRayImageStorageForProcessing,
306     UID_DigitalMammographyXRayImageStorageForPresentation,
307     UID_DigitalMammographyXRayImageStorageForProcessing,
308     UID_DigitalXRayImageStorageForPresentation,
309     UID_DigitalXRayImageStorageForProcessing,
310     UID_EnhancedMRImageStorage,
311     UID_EnhancedSR,
312     UID_GeneralECGWaveformStorage,
313     UID_GrayscaleSoftcopyPresentationStateStorage,
314     UID_HardcopyColorImageStorage,
315     UID_HardcopyGrayscaleImageStorage,
316     UID_HemodynamicWaveformStorage,
317     UID_KeyObjectSelectionDocument,
318     UID_MRImageStorage,
319     UID_MRSpectroscopyStorage,
320     UID_MammographyCADSR,
321     UID_MultiframeGrayscaleByteSecondaryCaptureImageStorage,
322     UID_MultiframeGrayscaleWordSecondaryCaptureImageStorage,
323     UID_MultiframeSingleBitSecondaryCaptureImageStorage,
324     UID_MultiframeTrueColorSecondaryCaptureImageStorage,
325     UID_NuclearMedicineImageStorage,
326     UID_PETCurveStorage,
327     UID_PETImageStorage,
328     UID_RETIRED_NuclearMedicineImageStorage,
329     UID_RETIRED_UltrasoundImageStorage,
330     UID_RETIRED_UltrasoundMultiframeImageStorage,
331 /* disabled draft storage SOP classes to keep the number of storage transfer
332  * syntaxes <= 64.  If we have more than 64 storage transfer syntaxes, tools
333  * such as storescu will fail because they attempt to negotiate two
334  * presentation contexts for each SOP class, and there is a total limit of
335  * 128 contexts for one association.
336  *
337     UID_RETIRED_VLImageStorage,
338     UID_RETIRED_VLMultiFrameImageStorage,
339  */
340     UID_RETIRED_XRayAngiographicBiPlaneImageStorage,
341     UID_RTBeamsTreatmentRecordStorage,
342     UID_RTBrachyTreatmentRecordStorage,
343     UID_RTDoseStorage,
344     UID_RTImageStorage,
345     UID_RTPlanStorage,
346     UID_RTStructureSetStorage,
347     UID_RTTreatmentSummaryRecordStorage,
348     UID_RawDataStorage,
349     UID_SecondaryCaptureImageStorage,
350     UID_StandaloneCurveStorage,
351     UID_StandaloneModalityLUTStorage,
352     UID_StandaloneOverlayStorage,
353     UID_StandaloneVOILUTStorage,
354     UID_StoredPrintStorage,
355     UID_TwelveLeadECGWaveformStorage,
356     UID_UltrasoundImageStorage,
357     UID_UltrasoundMultiframeImageStorage,
358     UID_VLEndoscopicImageStorage,
359     UID_VLMicroscopicImageStorage,
360     UID_VLPhotographicImageStorage,
361     UID_VLSlideCoordinatesMicroscopicImageStorage,
362     UID_XRayAngiographicImageStorage,
363     UID_XRayFluoroscopyImageStorage,
364 
365     NULL
366 };
367 
368 const int numberOfDcmStorageSOPClassUIDs =
369     (sizeof(dcmStorageSOPClassUIDs) / sizeof(const char*)) - 1;
370 
371 
372 /*
373 ** The global variable dcmImageSOPClassUIDs is an array of
374 ** string pointers containing the UIDs of all known Image SOP
375 ** Classes.  The instances of SOP Classes in this list can be
376 ** referenced from DICOMDIR IMAGE records.
377 **
378 ** The dcmgpdir program uses this list to determine what kind of
379 ** objects can be referenced from IMAGE records.
380 ** Be _very_ careful when adding SOP Classes to this list!!
381 **
382 ** The global variable numberOfDcmImageSOPClassUIDs
383 ** defines the size of the array.
384 ** NOTE: this list represents a subset of the dcmStorageSOPClassUIDs list
385 */
386 
387 const char* dcmImageSOPClassUIDs[] = {
388     UID_CTImageStorage,
389     UID_ComputedRadiographyImageStorage,
390     UID_DigitalIntraOralXRayImageStorageForPresentation,
391     UID_DigitalIntraOralXRayImageStorageForProcessing,
392     UID_DigitalMammographyXRayImageStorageForPresentation,
393     UID_DigitalMammographyXRayImageStorageForProcessing,
394     UID_DigitalXRayImageStorageForPresentation,
395     UID_DigitalXRayImageStorageForProcessing,
396     UID_EnhancedMRImageStorage,
397     UID_HardcopyColorImageStorage,
398     UID_HardcopyGrayscaleImageStorage,
399     UID_MRImageStorage,
400     UID_NuclearMedicineImageStorage,
401     UID_PETCurveStorage,
402     UID_PETImageStorage,
403     UID_RETIRED_NuclearMedicineImageStorage,
404     UID_RETIRED_UltrasoundImageStorage,
405     UID_RETIRED_UltrasoundMultiframeImageStorage,
406     UID_RETIRED_VLImageStorage,
407     UID_RETIRED_VLMultiFrameImageStorage,
408     UID_RETIRED_XRayAngiographicBiPlaneImageStorage,
409     UID_RTImageStorage,
410     UID_SecondaryCaptureImageStorage,
411     UID_UltrasoundImageStorage,
412     UID_UltrasoundMultiframeImageStorage,
413     UID_VLEndoscopicImageStorage,
414     UID_VLMicroscopicImageStorage,
415     UID_VLPhotographicImageStorage,
416     UID_VLSlideCoordinatesMicroscopicImageStorage,
417     UID_XRayAngiographicImageStorage,
418     UID_XRayFluoroscopyImageStorage,
419     UID_MultiframeSingleBitSecondaryCaptureImageStorage,
420     UID_MultiframeGrayscaleByteSecondaryCaptureImageStorage,
421     UID_MultiframeGrayscaleWordSecondaryCaptureImageStorage,
422     UID_MultiframeTrueColorSecondaryCaptureImageStorage,
423 
424     NULL
425 };
426 
427 const int numberOfDcmImageSOPClassUIDs =
428     (sizeof(dcmImageSOPClassUIDs) / sizeof(const char*)) - 1;
429 
430 
431 typedef struct {
432     const char *sopClass;
433     const char *modality;
434     unsigned long averageSize;  /* can be way, way out */
435 } DcmModalityTable;
436 
437 /*
438 ** The modalities table defines a short character code for each
439 ** Storage SOP Class for use in filenames.
440 ** It also gives a typical size for each SOP Instance.  This will
441 ** ususally be way out, but is useful in user interfaces to give an
442 ** idea of progress when receiving an image (C-STORE does not indicate
443 ** the size of an image being transmitted).
444 */
445 static const DcmModalityTable modalities[] = {
446     { UID_AmbulatoryECGWaveformStorage,                        "ECA", 4096 },
447     { UID_BasicTextSR,                                         "SRt", 4096 },
448     { UID_BasicVoiceAudioWaveformStorage,                      "AUV", 4096 },
449     { UID_CTImageStorage,                                      "CT",  2 *  512 *  512 },
450     { UID_CardiacElectrophysiologyWaveformStorage,             "WVc", 4096 },
451     { UID_ComprehensiveSR,                                     "SRc", 4096 },
452     { UID_ComputedRadiographyImageStorage,                     "CR",  2 * 2048 * 2048 },
453     { UID_DRAFT_SRAudioStorage,                                "SRw", 4096 },
454     { UID_DRAFT_SRComprehensiveStorage,                        "SRx", 4096 },
455     { UID_DRAFT_SRDetailStorage,                               "SRy", 4096 },
456     { UID_DRAFT_SRTextStorage,                                 "SRz", 4096 },
457     { UID_DRAFT_WaveformStorage,                               "WVd", 4096 },
458     { UID_DigitalIntraOralXRayImageStorageForPresentation,     "DXo", 2 * 1024 * 1024 },
459     { UID_DigitalIntraOralXRayImageStorageForProcessing,       "DPo", 2 * 1024 * 1024 },
460     { UID_DigitalMammographyXRayImageStorageForPresentation,   "DXm", 2 * 4096 * 4096 },
461     { UID_DigitalMammographyXRayImageStorageForProcessing,     "DPm", 2 * 4096 * 4096 },
462     { UID_DigitalXRayImageStorageForPresentation,              "DX",  2 * 2048 * 2048 },
463     { UID_DigitalXRayImageStorageForProcessing,                "DP",  2 * 2048 * 2048 },
464     { UID_EnhancedMRImageStorage,                              "MRe", 512 * 512 * 256 },
465     { UID_EnhancedSR,                                          "SRe", 4096 },
466     { UID_GeneralECGWaveformStorage,                           "ECG", 4096 },
467     { UID_GrayscaleSoftcopyPresentationStateStorage,           "PSg", 4096 },
468     { UID_HardcopyColorImageStorage,                           "HC",  4096 },
469     { UID_HardcopyGrayscaleImageStorage,                       "HG",  4096 },
470     { UID_HemodynamicWaveformStorage,                          "WVh", 4096 },
471     { UID_KeyObjectSelectionDocument,                          "SRk", 4096 },
472     { UID_MRImageStorage,                                      "MR",  2 * 256 * 256 },
473     { UID_MRSpectroscopyStorage,                               "MRs", 512 * 512 * 256 },
474     { UID_MammographyCADSR,                                    "SRm", 4096 },
475     { UID_MultiframeGrayscaleByteSecondaryCaptureImageStorage, "SCb",  1 * 512 * 512 },
476     { UID_MultiframeGrayscaleWordSecondaryCaptureImageStorage, "SCw",  2 * 512 * 512 },
477     { UID_MultiframeSingleBitSecondaryCaptureImageStorage,     "SCs",  1024 * 1024 },  /* roughly an A4 300dpi scan */
478     { UID_MultiframeTrueColorSecondaryCaptureImageStorage,     "SCc",  3 * 512 * 512 },
479     { UID_NuclearMedicineImageStorage,                         "NM",  2 * 64 * 64 },
480     { UID_PETCurveStorage,                                     "PC",  4096 },
481     { UID_PETImageStorage,                                     "PI",  512*512*2 },
482     { UID_RETIRED_NuclearMedicineImageStorage,                 "NMr", 2 * 64 * 64 },
483     { UID_RETIRED_UltrasoundImageStorage,                      "USr", 1 * 512 * 512 },
484     { UID_RETIRED_UltrasoundMultiframeImageStorage,            "USr", 1 * 512 * 512 },
485     { UID_RETIRED_VLImageStorage,                              "VLr", 768 * 576 * 3 },
486     { UID_RETIRED_VLMultiFrameImageStorage,                    "VMr", 768 * 576 * 3 },
487     { UID_RETIRED_XRayAngiographicBiPlaneImageStorage,         "XB",  2 * 512 * 512 },
488     { UID_RTBeamsTreatmentRecordStorage,                       "RTb", 4096 },
489     { UID_RTBrachyTreatmentRecordStorage,                      "RTr", 4096 },
490     { UID_RTDoseStorage,                                       "RD",  4096 },
491     { UID_RTImageStorage,                                      "RI",  4096 },
492     { UID_RTPlanStorage,                                       "RP" , 4096 },
493     { UID_RTStructureSetStorage,                               "RS",  4096 },
494     { UID_RTTreatmentSummaryRecordStorage,                     "RTs", 4096 },
495     { UID_RawDataStorage,                                      "RAW", 512 * 512 * 256 },
496     { UID_SecondaryCaptureImageStorage,                        "SC",  2 * 512 * 512 },
497     { UID_StandaloneCurveStorage,                              "CV",  4096 },
498     { UID_StandaloneModalityLUTStorage,                        "ML",  4096*2 },
499     { UID_StandaloneOverlayStorage,                            "OV",  512 * 512 },
500     { UID_StandaloneVOILUTStorage,                             "VO",  4096*2 },
501     { UID_StoredPrintStorage,                                  "SP",  4096 },
502     { UID_TwelveLeadECGWaveformStorage,                        "TLE", 4096 },
503     { UID_UltrasoundImageStorage,                              "US",  1 * 512 * 512 },
504     { UID_UltrasoundMultiframeImageStorage,                    "US",  1 * 512 * 512 },
505     { UID_VLEndoscopicImageStorage,                            "VLe", 768 * 576 * 3 },
506     { UID_VLMicroscopicImageStorage,                           "VLm", 768 * 576 * 3 },
507     { UID_VLPhotographicImageStorage,                          "VLp", 768 * 576 * 3 },
508     { UID_VLSlideCoordinatesMicroscopicImageStorage,           "VMs", 768 * 576 * 3 },
509     { UID_XRayAngiographicImageStorage,                        "XA",  2 * 512 * 512 },
510     { UID_XRayFluoroscopyImageStorage,                         "RF",  2 * 512 * 512 }
511 };
512 
513 static const int numberOfDcmModalityTableEntries =
514     (sizeof(modalities) / sizeof(DcmModalityTable));
515 
516 
517 /*
518  * Public Function Prototypes
519  */
520 
521 
dcmSOPClassUIDToModality(const char * sopClassUID)522 const char *dcmSOPClassUIDToModality(const char *sopClassUID)
523 {
524     if (sopClassUID == NULL) return NULL;
525     for (int i = 0; i < numberOfDcmModalityTableEntries; i++)
526     {
527       if (strcmp(modalities[i].sopClass, sopClassUID) == 0) return modalities[i].modality;
528     }
529     return NULL;
530 }
531 
dcmGuessModalityBytes(const char * sopClassUID)532 unsigned long dcmGuessModalityBytes(const char *sopClassUID)
533 {
534     unsigned long nbytes = 1048576; /* default: 1 MByte */
535 
536     if (sopClassUID == NULL) return nbytes;
537 
538     int found=0;
539     for (int i = 0; (!found && (i < numberOfDcmModalityTableEntries)); i++)
540     {
541     found = (strcmp(modalities[i].sopClass, sopClassUID) == 0);
542     if (found) nbytes = modalities[i].averageSize;
543     }
544 
545     return nbytes;
546 }
547 
548 
549 /*
550 ** dcmFindNameOfUID(const char* uid)
551 ** Return the name of a UID.
552 ** Performs a table lookup and returns a pointer to a read-only string.
553 ** Returns NULL of the UID is not known.
554 */
555 
556 const char*
dcmFindNameOfUID(const char * uid)557 dcmFindNameOfUID(const char* uid)
558 {
559     int i = 0;
560     if (uid == NULL) return NULL;
561     for (i=0; i<uidNameMap_size; i++) {
562         if (uidNameMap[i].uid != NULL && strcmp(uid, uidNameMap[i].uid) == 0) {
563             return uidNameMap[i].name;
564         }
565     }
566     return NULL;
567 }
568 
569 //
570 // dcmFindUIDFromName(const char* name)
571 // Return the UID of a name.
572 // Performs a table lookup and returns a pointer to a read-only string.
573 // Returns NULL of the name is not known.
574 //
575 
576 const char *
dcmFindUIDFromName(const char * name)577 dcmFindUIDFromName(const char * name)
578 {
579     if (name == NULL) return NULL;
580     for (int i = 0; i < uidNameMap_size; i++)
581     {
582         if (uidNameMap[i].name != NULL && strcmp(name, uidNameMap[i].name) == 0)
583             return uidNameMap[i].uid;
584     }
585     return NULL;
586 }
587 
588 
589 /*
590 ** dcmIsaStorageSOPClassUID(const char* uid)
591 ** Returns true if the uid is one of the Storage SOP Classes.
592 ** Performs a table lookup in the dcmStorageSOPClassUIDs table.
593 */
594 OFBool
dcmIsaStorageSOPClassUID(const char * uid)595 dcmIsaStorageSOPClassUID(const char* uid)
596 {
597     int i = 0;
598     if (uid == NULL) return OFFalse;
599     for (i=0; i<numberOfDcmStorageSOPClassUIDs; i++) {
600         if (dcmStorageSOPClassUIDs[i] != NULL
601         && strcmp(uid, dcmStorageSOPClassUIDs[i]) == 0) {
602             return OFTrue;
603         }
604     }
605     return OFFalse;
606 }
607 
608 // ********************************
609 
610 #ifndef HAVE_GETHOSTID
611 #ifdef HAVE_SYSINFO
612 
613 #include <sys/systeminfo.h>
gethostid(void)614 static long gethostid(void)
615 {
616     char buf[128];
617     if (sysinfo(SI_HW_SERIAL, buf, 128) == -1) {
618        ofConsole.lockCerr() << "sysinfo: " << strerror(errno) << endl;
619        ofConsole.unlockCerr();
620        exit(1);
621     }
622 #ifdef HAVE_STRTOUL
623     return(strtoul(buf, NULL, 0));
624 #else
625     long result;
626     sscanf(buf, "%ld", &result);
627     return result;
628 #endif
629 }
630 
631 #else // !HAVE_SYSINFO
632 
633 /*
634 ** There is no implementation of gethostid() and we cannot implement it in
635 ** terms of sysinfo() so define a workaround.
636 */
637 #if (defined(HAVE_GETHOSTNAME) && defined(HAVE_GETHOSTBYNAME)) || defined(HAVE_WINDOWS_H)
638 
639 // 16K should be large enough to handle everything pointed to by a struct hostent
640 #define GETHOSTBYNAME_R_BUFSIZE 16384
641 
642 /* on Windows systems specify a routine to determine the MAC address of the Ethernet adapter */
643 #ifdef HAVE_WINDOWS_H
644 
645 #include <snmp.h>
646 
647 typedef int(WINAPI *pSnmpUtilOidCpy) (
648         OUT AsnObjectIdentifier *pOidDst,
649         IN AsnObjectIdentifier *pOidSrc);
650 
651 typedef int(WINAPI *pSnmpUtilOidNCmp) (
652         IN AsnObjectIdentifier *pOid1,
653         IN AsnObjectIdentifier *pOid2,
654         IN UINT nSubIds);
655 
656 typedef void(WINAPI *pSnmpUtilVarBindFree) (
657         IN OUT SnmpVarBind *pVb);
658 
659 typedef bool(WINAPI *pSnmpExtensionInit) (
660         IN DWORD dwTimeZeroReference,
661         OUT HANDLE *hPollForTrapEvent,
662         OUT AsnObjectIdentifier *supportedView);
663 
664 typedef bool(WINAPI *pSnmpExtensionTrap) (
665         OUT AsnObjectIdentifier *enterprise,
666         OUT AsnInteger32 *genericTrap,
667         OUT AsnInteger32 *specificTrap,
668         OUT AsnTimeticks *timeStamp,
669         OUT SnmpVarBindList *variableBindings);
670 
671 typedef bool(WINAPI *pSnmpExtensionQuery) (
672         IN BYTE requestType,
673         IN OUT SnmpVarBindList *variableBindings,
674         OUT AsnInteger32 *errorStatus,
675         OUT AsnInteger32 *errorIndex);
676 
677 typedef bool(WINAPI *pSnmpExtensionInitEx) (
678         OUT AsnObjectIdentifier *supportedView);
679 
680 typedef struct _ASTAT_
681 {
682     ADAPTER_STATUS adapt;
683     NAME_BUFFER    NameBuff[30];
684 } ASTAT, *PASTAT;
685 
686 /* get the MAC address of the (first) Ethernet adapter (6 bytes) */
getMACAddress(unsigned char buffer[6])687 static unsigned char *getMACAddress(unsigned char buffer[6])
688 {
689     OFBool success = OFFalse;
690     /* init return variable */
691     memset(buffer, 0, sizeof(buffer));
692     NCB ncb;
693     memset(&ncb, 0, sizeof(ncb));
694     /* reset the LAN adapter */
695     ncb.ncb_command = NCBRESET;
696     /* it is considered bad practice to hardcode the LANA number (should enumerate
697        adapters first), but at least this approach also works on Windows 9x */
698     ncb.ncb_lana_num = 0;
699     if (Netbios(&ncb) == NRC_GOODRET)
700     {
701         ASTAT Adapter;
702         /* prepare to get the adapter status block */
703         memset(&ncb, 0, sizeof(ncb));
704         ncb.ncb_command = NCBASTAT;
705         /* it is considered bad practice to hardcode the LANA number (should enumerate
706            adapters first), but at least this approach also works on Windows 9x */
707         ncb.ncb_lana_num = 0;
708         strcpy((char *)ncb.ncb_callname, "*");
709         ncb.ncb_buffer = (unsigned char *)&Adapter;
710         ncb.ncb_length = sizeof(Adapter);
711         /* get the adapter's info */
712         if (Netbios(&ncb) == 0)
713         {
714             /* store the MAC address */
715             buffer[0] = Adapter.adapt.adapter_address[0];
716             buffer[1] = Adapter.adapt.adapter_address[1];
717             buffer[2] = Adapter.adapt.adapter_address[2];
718             buffer[3] = Adapter.adapt.adapter_address[3];
719             buffer[4] = Adapter.adapt.adapter_address[4];
720             buffer[5] = Adapter.adapt.adapter_address[5];
721             success = OFTrue;
722         }
723     }
724     /* check whether NetBIOS routines succeeded, if not try the SNMP approach */
725     if (!success)
726     {
727         HINSTANCE m_hInst1, m_hInst2;
728         /* load the "SNMP Utility Library" dll and get the addresses of the functions necessary */
729         m_hInst1 = LoadLibrary("snmpapi.dll");
730         if (m_hInst1 >= (HINSTANCE)HINSTANCE_ERROR)
731         {
732             pSnmpUtilOidCpy m_Copy = (pSnmpUtilOidCpy)GetProcAddress(m_hInst1, "SnmpUtilOidCpy");
733             pSnmpUtilOidNCmp m_Compare = (pSnmpUtilOidNCmp)GetProcAddress(m_hInst1, "SnmpUtilOidNCmp");
734             pSnmpUtilVarBindFree m_BindFree = (pSnmpUtilVarBindFree)GetProcAddress(m_hInst1, "SnmpUtilVarBindFree");
735             /* load the "SNMP Internet MIB" dll and get the addresses of the functions necessary */
736             m_hInst2 = LoadLibrary("inetmib1.dll");
737             if (m_hInst2 >= (HINSTANCE)HINSTANCE_ERROR)
738             {
739                 HANDLE PollForTrapEvent;
740                 AsnObjectIdentifier SupportedView;
741                 UINT OID_ifEntryType[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 3};
742                 UINT OID_ifEntryNum[] = {1, 3, 6, 1, 2, 1, 2, 1};
743                 UINT OID_ipMACEntAddr[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 6};
744                 AsnObjectIdentifier MIB_ifMACEntAddr = {sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr};
745                 AsnObjectIdentifier MIB_ifEntryType = {sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType};
746                 AsnObjectIdentifier MIB_ifEntryNum = {sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum};
747                 SnmpVarBindList varBindList;
748                 SnmpVarBind varBind[2];
749                 AsnInteger32 errorStatus;
750                 AsnInteger32 errorIndex;
751                 AsnObjectIdentifier MIB_NULL = {0, 0};
752                 int ret;
753                 int dtmp;
754                 int i = 0, j = 0;
755                 bool found = false;
756                 pSnmpExtensionInit m_Init = (pSnmpExtensionInit)GetProcAddress(m_hInst2, "SnmpExtensionInit");
757                 pSnmpExtensionInitEx m_InitEx = (pSnmpExtensionInitEx)GetProcAddress(m_hInst2, "SnmpExtensionInitEx");
758                 pSnmpExtensionQuery m_Query = (pSnmpExtensionQuery)GetProcAddress(m_hInst2, "SnmpExtensionQuery");
759                 pSnmpExtensionTrap m_Trap = (pSnmpExtensionTrap)GetProcAddress(m_hInst2, "SnmpExtensionTrap");
760                 m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView);
761                 /* initialize the variable list to be retrieved by m_Query */
762                 varBindList.list = varBind;
763                 varBind[0].name = MIB_NULL;
764                 varBind[1].name = MIB_NULL;
765                 /* copy in the OID to find the number of entries in the interface table */
766                 varBindList.len = 1;        /* only retrieving one item */
767                 m_Copy(&varBind[0].name, &MIB_ifEntryNum);
768                 ret = m_Query(SNMP_PDU_GETNEXT, &varBindList, &errorStatus, &errorIndex);
769                 varBindList.len = 2;
770                 /* copy in the OID of ifType, the type of interface */
771                 m_Copy(&varBind[0].name, &MIB_ifEntryType);
772                 /* copy in the OID of ifPhysAddress, the address */
773                 m_Copy(&varBind[1].name, &MIB_ifMACEntAddr);
774                 do {
775                     /* Submit the query.  Responses will be loaded into varBindList.
776                        We can expect this call to succeed a # of times corresponding
777                        to the # of adapters reported to be in the system */
778                     ret = m_Query(SNMP_PDU_GETNEXT, &varBindList, &errorStatus, &errorIndex);
779                     if (!ret)
780                         ret = 1;
781                     else
782                     {
783                         /* confirm that the proper type has been returned */
784                         ret = m_Compare(&varBind[0].name, &MIB_ifEntryType, MIB_ifEntryType.idLength);
785                     }
786                     if (!ret)
787                     {
788                         j++;
789                         dtmp = varBind[0].value.asnValue.number;
790                         /* type 6 describes ethernet interfaces */
791                         if (dtmp == 6)
792                         {
793                             /* confirm that we have an address here */
794                             ret = m_Compare(&varBind[1].name, &MIB_ifMACEntAddr,MIB_ifMACEntAddr.idLength);
795                             if ((!ret) && (varBind[1].value.asnValue.address.stream != NULL))
796                             {
797                                 if ((varBind[1].value.asnValue.address.stream[0] == 0x44) &&
798                                     (varBind[1].value.asnValue.address.stream[1] == 0x45) &&
799                                     (varBind[1].value.asnValue.address.stream[2] == 0x53) &&
800                                     (varBind[1].value.asnValue.address.stream[3] == 0x54) &&
801                                     (varBind[1].value.asnValue.address.stream[4] == 0x00))
802                                 {
803                                     /* ignore all dial-up networking adapters */
804                                     continue;
805                                 }
806                                 if ((varBind[1].value.asnValue.address.stream[0] == 0x00) &&
807                                     (varBind[1].value.asnValue.address.stream[1] == 0x00) &&
808                                     (varBind[1].value.asnValue.address.stream[2] == 0x00) &&
809                                     (varBind[1].value.asnValue.address.stream[3] == 0x00) &&
810                                     (varBind[1].value.asnValue.address.stream[4] == 0x00) &&
811                                     (varBind[1].value.asnValue.address.stream[5] == 0x00))
812                                 {
813                                     /* ignore NULL addresses returned by other network interfaces */
814                                     continue;
815                                 }
816                                 /* store the MAC address */
817                                 buffer[0] = varBind[1].value.asnValue.address.stream[0];
818                                 buffer[1] = varBind[1].value.asnValue.address.stream[1];
819                                 buffer[2] = varBind[1].value.asnValue.address.stream[2];
820                                 buffer[3] = varBind[1].value.asnValue.address.stream[3];
821                                 buffer[4] = varBind[1].value.asnValue.address.stream[4];
822                                 buffer[5] = varBind[1].value.asnValue.address.stream[5];
823                                 ret = 1;    // we found an address -> exit
824                             }
825                         }
826                     }
827                 } while (!ret);  /* Stop only on an error. An error will occur when we
828                                     go exhaust the list of interfaces to be examined */
829                 FreeLibrary(m_hInst2);
830                 /* free the bindings */
831                 m_BindFree(&varBind[0]);
832                 m_BindFree(&varBind[1]);
833             }
834             FreeLibrary(m_hInst1);
835         }
836     }
837     return buffer;
838 }
839 #endif
840 
841 #ifdef HAVE_PROTOTYPE_GETHOSTID
842 /* CW10 has a prototype but no implementation (gethostid() is already declared extern */
gethostid(void)843 long gethostid(void)
844 #else
845 static long gethostid(void)
846 #endif
847 {
848     long result = 0;
849 #if defined(HAVE_GETHOSTNAME) && defined(HAVE_GETHOSTBYNAME)
850     char name[1024];
851     struct hostent *hent = NULL;
852     char **p = NULL;
853     struct in_addr in;
854 #ifdef HAVE_WINSOCK_H
855     WSAData winSockData;
856     /* we need at least version 1.1 */
857     WORD winSockVersionNeeded = MAKEWORD(1, 1);
858     WSAStartup(winSockVersionNeeded, &winSockData);
859 #endif
860     /*
861     ** Define the hostid to be the system's main TCP/IP address.
862     ** This is not perfect but it is better than nothing (i.e. using zero)
863     */
864     if (gethostname(name, 1024) == 0)
865     {
866 #if defined(_REENTRANT) && !defined(_WIN32) && !defined(__CYGWIN__)
867         // use gethostbyname_r instead of gethostbyname
868         int h_errnop=0;
869         struct hostent theHostent;
870         char buffer[GETHOSTBYNAME_R_BUFSIZE];
871         if ((hent = gethostbyname_r(name, &theHostent, buffer, GETHOSTBYNAME_R_BUFSIZE, &h_errnop)) != NULL)
872 #else
873         if ((hent = gethostbyname(name)) != NULL)
874 #endif
875         {
876             p = hent->h_addr_list;
877             if (p && *p)
878             {
879                 (void) memcpy(&in.s_addr, *p, sizeof(in.s_addr));
880                 result = (long)in.s_addr;
881             }
882         }
883     }
884 #ifdef HAVE_WINSOCK_H
885     WSACleanup();
886 #endif
887 #endif /* defined(HAVE_GETHOSTNAME) && defined(HAVE_GETHOSTBYNAME) */
888 /* on Windows systems determine some system specific information (e.g. MAC address) */
889 #ifdef HAVE_WINDOWS_H
890     OFCRC32 crc;
891     /* get some processor specific information in addition to the MAC address */
892     SYSTEM_INFO systemInfo;
893     GetSystemInfo(&systemInfo);
894     /* get volume information of the system drive */
895     char systemDrive[MAX_PATH];
896     DWORD serialNumber = 0;
897     if (GetSystemDirectory(systemDrive, sizeof(systemDrive)) >= 0)
898     {
899         /* check for proper pathname */
900         if ((strlen(systemDrive) >= 3) && (systemDrive[1] == ':') && (systemDrive[2] == '\\'))
901         {
902             /* truncate the pathname directly after the drive specification */
903             systemDrive[3] = 0;
904             if (!GetVolumeInformation(systemDrive, NULL, 0, &serialNumber, NULL, NULL, NULL, 0))
905                 serialNumber = 0;
906         }
907     }
908     unsigned char buffer[6];
909     /* concatenate the host specific elements and compute a 32-bit checksum */
910     crc.addBlock(&result /*ip address*/, sizeof(result));
911     crc.addBlock(getMACAddress(buffer), sizeof(buffer));
912     crc.addBlock(&serialNumber, sizeof(serialNumber));
913     crc.addBlock(&systemInfo.wProcessorLevel, sizeof(systemInfo.wProcessorLevel));
914     crc.addBlock(&systemInfo.wProcessorRevision, sizeof(systemInfo.wProcessorRevision));
915     crc.addBlock(&systemInfo.dwProcessorType, sizeof(systemInfo.dwProcessorType));
916     result = (long)crc.getCRC32();
917 #endif
918     /* 'artificial' hostid: on Windows system a CRC32 checksum over some host specific
919        information (e.g. MAC address), the 4 bytes TCP/IP address otherwise.
920     */
921     return result;
922 }
923 
924 #else // !(defined(HAVE_GETHOSTNAME) && defined(HAVE_GETHOSTBYNAME))
925 /*
926 ** last chance workaround if there is no other way
927 */
928 #ifdef HAVE_PROTOTYPE_GETHOSTID
929 /* CW10 has a prototype but no implementation (gethostid() is already declared extern */
gethostid(void)930 long gethostid(void) { return 0; }
931 #else
gethostid(void)932 static long gethostid(void) { return 0; }
933 #endif
934 #endif // !(defined(HAVE_GETHOSTNAME) && defined(HAVE_GETHOSTBYNAME))
935 
936 #endif // !HAVE_SYSINFO
937 #else // HAVE_GETHOSTID
938 #ifndef HAVE_PROTOTYPE_GETHOSTID
939 extern "C" {
940 long gethostid(void);
941 }
942 #endif // !HAVE_PROTOTYPE_GETHOSTID
943 #endif // HAVE_GETHOSTID
944 
945 #ifndef HAVE_GETPID
getpid(void)946 static int getpid(void) { return 0; }   // workaround for MAC
947 #endif // !HAVE_GETPID
948 
949 // ********************************
950 
951 /*
952  * Global variable storing the return value of gethostid().
953  * Since the variable is not declared in the header file it can only be used
954  * within this source file. Any access to or modification of its value is
955  * protected by a mutex (see dcmGenerateUniqueIdentifier()).
956  */
957 
958 static unsigned long hostIdentifier = 0;
959 
960 
961 /*
962 ** char* generateUniqueIdentifer(char* buf)
963 ** Creates a Unique Identifer in buf and returns buf.
964 ** buf must be at least 65 bytes.
965 */
966 
967 
968 #ifdef _REENTRANT
969 static OFMutex uidCounterMutex;  // mutex protecting access to counterOfCurrentUID and hostIdentifier
970 #endif
971 
972 static unsigned int counterOfCurrentUID = 1;
973 
974 static const int maxUIDLen = 64;    /* A UID may be 64 chars or less */
975 
976 static char*
stripTrailing(char * s,char c)977 stripTrailing(char* s, char c)
978 {
979     int i, n;
980 
981     if (s == NULL) return s;
982 
983     n = strlen(s);
984     for (i = n - 1; (i >= 0) && (s[i] == c); i--)
985         s[i] = '\0';
986     return s;
987 }
988 
989 static void
addUIDComponent(char * uid,const char * s)990 addUIDComponent(char* uid, const char* s)
991 {
992     int charsLeft = maxUIDLen - strlen(uid);
993 
994     if (charsLeft > 0) {
995         /* copy into uid as much of the contents of s as possible */
996         int slen = strlen(s);
997         int use = charsLeft;
998         if (slen < charsLeft) use = slen;
999             strncat(uid, s, use);
1000     }
1001 
1002     stripTrailing(uid, '.');
1003 }
1004 
1005 inline static unsigned long
forcePositive(long i)1006 forcePositive(long i)
1007 {
1008     return (i < 0) ? (unsigned long)-i : (unsigned long)i;
1009 }
1010 
dcmGenerateUniqueIdentifier(char * uid,const char * prefix)1011 char* dcmGenerateUniqueIdentifier(char* uid, const char* prefix)
1012 {
1013     char buf[128]; /* be very safe */
1014 
1015     uid[0] = '\0'; /* initialise */
1016 
1017 #ifdef _REENTRANT
1018     uidCounterMutex.lock();
1019 #endif
1020     if (hostIdentifier == 0)
1021         hostIdentifier = (unsigned long)gethostid();
1022     unsigned int counter = counterOfCurrentUID++;
1023 #ifdef _REENTRANT
1024     uidCounterMutex.unlock();
1025 #endif
1026 
1027     if (prefix != NULL ) {
1028         addUIDComponent(uid, prefix);
1029     } else {
1030         addUIDComponent(uid, SITE_INSTANCE_UID_ROOT);
1031     }
1032 
1033     sprintf(buf, ".%lu", hostIdentifier);
1034     addUIDComponent(uid, buf);
1035 
1036     sprintf(buf, ".%lu", forcePositive(getpid()));
1037     addUIDComponent(uid, buf);
1038 
1039     sprintf(buf, ".%lu", forcePositive(long(time(NULL))));
1040     addUIDComponent(uid, buf);
1041 
1042     sprintf(buf, ".%u", counter);
1043 
1044     addUIDComponent(uid, buf);
1045 
1046     return uid;
1047 }
1048