G4OCCT 0.1.0
Geant4 interface to Open CASCADE Technology (OCCT) geometry definitions
Loading...
Searching...
No Matches
G4OCCTSensitiveDetectorMapReader.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-2.1-or-later
2// Copyright (C) 2026 G4OCCT Contributors
3
6
8
9// Xerces — provided transitively by Geant4::G4gdml.
10// G4GDMLRead.hh already includes the Xerces DOM headers; we repeat them here
11// for clarity and to document the direct dependency.
12#include <xercesc/dom/DOM.hpp>
13#include <xercesc/parsers/XercesDOMParser.hpp>
14#include <xercesc/util/PlatformUtils.hpp>
15#include <xercesc/util/XMLString.hpp>
16
17// Geant4
18#include <G4Exception.hh>
19#include <G4SDManager.hh>
20
21namespace {
22// Convert a Xerces XMLCh* string to G4String. Releases the transcoded buffer
23// immediately so callers do not need to manage it.
24G4String Transcode(const XMLCh* const str) {
25 char* buf = xercesc::XMLString::transcode(str);
26 G4String result(buf);
27 xercesc::XMLString::release(&buf);
28 return result;
29}
30} // namespace
31
33 // Xerces initialization is ref-counted; safe to call multiple times.
34 xercesc::XMLPlatformUtils::Initialize();
35
37
38 // Pre-parse fatal errors (SDReader003–007) are saved here and reported
39 // after the parser is destroyed and Terminate() has been called. Calling
40 // Terminate() inside the parser's {} scope and then returning through the
41 // scope exit would invoke XercesDOMParser::~XercesDOMParser() after
42 // Terminate() — a SEGFAULT if a non-aborting G4VExceptionHandler allows
43 // execution to continue past G4Exception().
44 G4String preFatalCode;
45 G4String preFatalMsg;
46
47 // IIFE: contains the XercesDOMParser so it is destroyed before Terminate().
48 // Early 'return' from the lambda exits the lambda scope cleanly, ensuring
49 // the parser destructor runs before Terminate() is called below.
50 [&]() {
51 xercesc::XercesDOMParser parser;
52 parser.setDoNamespaces(false);
53 parser.setDoSchema(false);
54 parser.setCreateEntityReferenceNodes(false);
55
56 try {
57 parser.parse(path.c_str());
58 } catch (const xercesc::XMLException& e) {
59 preFatalCode = "G4OCCT_SDReader003";
60 preFatalMsg = "XML error parsing '" + path + "': " + Transcode(e.getMessage());
61 return;
62 } catch (const xercesc::DOMException& e) {
63 preFatalCode = "G4OCCT_SDReader004";
64 preFatalMsg = "DOM error parsing '" + path + "': " + Transcode(e.getMessage());
65 return;
66 }
67
68 const xercesc::DOMDocument* const doc = parser.getDocument();
69 if (!doc) {
70 preFatalCode = "G4OCCT_SDReader005";
71 preFatalMsg = "Cannot open document: " + path;
72 return;
73 }
74
75 const xercesc::DOMElement* const root = doc->getDocumentElement();
76 if (!root) {
77 preFatalCode = "G4OCCT_SDReader006";
78 preFatalMsg = "Empty document: " + path;
79 return;
80 }
81
82 const G4String rootTag = Transcode(root->getTagName());
83 if (rootTag != "sensitive_detector_map") {
84 preFatalCode = "G4OCCT_SDReader007";
85 preFatalMsg =
86 "Root element must be <sensitive_detector_map>, got <" + rootTag + "> in '" + path + "'";
87 return;
88 }
89
90 for (xercesc::DOMNode* node = root->getFirstChild(); node != nullptr;
91 node = node->getNextSibling()) {
92 if (node->getNodeType() != xercesc::DOMNode::ELEMENT_NODE) {
93 continue;
94 }
95 const auto* child = dynamic_cast<const xercesc::DOMElement*>(node);
96 if (!child) {
97 continue;
98 }
99 if (Transcode(child->getTagName()) != "volume") {
100 continue;
101 }
102
103 G4String volumeName;
104 G4String sdName;
105 const xercesc::DOMNamedNodeMap* attrs = child->getAttributes();
106 for (XMLSize_t i = 0; i < attrs->getLength(); ++i) {
107 const auto* attr = dynamic_cast<const xercesc::DOMAttr*>(attrs->item(i));
108 if (!attr) {
109 continue;
110 }
111 const G4String aName = Transcode(attr->getName());
112 const G4String aValue = Transcode(attr->getValue());
113 if (aName == "name") {
114 volumeName = aValue;
115 } else if (aName == "sensDet") {
116 sdName = aValue;
117 }
118 }
119
120 if (volumeName.empty()) {
121 G4Exception("G4OCCTSensitiveDetectorMapReader::ReadFile", "G4OCCT_SDReader000",
122 FatalException,
123 ("<volume> element in '" + path + "' is missing the required 'name' attribute.")
124 .c_str());
125 continue;
126 }
127
128 if (sdName.empty()) {
129 G4Exception("G4OCCTSensitiveDetectorMapReader::ReadFile", "G4OCCT_SDReader001",
130 FatalException,
131 ("<volume name=\"" + volumeName + "\"> in '" + path +
132 "' is missing the required 'sensDet' attribute.")
133 .c_str());
134 continue;
135 }
136
137 G4VSensitiveDetector* sd =
138 G4SDManager::GetSDMpointer()->FindSensitiveDetector(sdName, /*warning=*/false);
139 if (!sd) {
140 G4Exception("G4OCCTSensitiveDetectorMapReader::ReadFile", "G4OCCT_SDReader002",
141 FatalException,
142 ("Sensitive detector '" + sdName + "' (volume pattern '" + volumeName +
143 "') not found in G4SDManager. Ensure all SDs are registered before "
144 "calling ReadFile().")
145 .c_str());
146 continue;
147 }
148
149 result.Add(volumeName, sd);
150 }
151 }(); // XercesDOMParser destroyed here
152
153 xercesc::XMLPlatformUtils::Terminate();
154
155 if (!preFatalCode.empty()) {
156 G4Exception("G4OCCTSensitiveDetectorMapReader::ReadFile", preFatalCode.c_str(), FatalException,
157 preFatalMsg.c_str());
158 // Normally unreachable: FatalException aborts. If a non-aborting handler
159 // is installed (e.g. G4OCCTFatalCatcher in tests), return an empty map so
160 // callers get a predictable, safe value.
161 return result;
162 }
163
164 return result;
165}
Declaration of G4OCCTSensitiveDetectorMapReader.
G4OCCTSensitiveDetectorMap ReadFile(const G4String &path)
Maps volume name patterns to Geant4 G4VSensitiveDetector objects.
void Add(const G4String &pattern, G4VSensitiveDetector *sd)