GCC Code Coverage Report


Directory: ./
File: src/msrproto/expat_wrapper_impl.h
Date: 2024-06-11 13:26:06
Exec Total Coverage
Lines: 44 55 80.0%
Branches: 24 62 38.7%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * Copyright (C) 2021 Bjarne von Horn (vh at igh dot de)
4 *
5 * This file is part of the PdCom library.
6 *
7 * The PdCom library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * The PdCom library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with the PdCom library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 *****************************************************************************/
21
22 #ifndef MSRPROTO_EXPAT_WRAPPER_IMPL_H
23 #define MSRPROTO_EXPAT_WRAPPER_IMPL_H
24
25 #include "expat_wrapper.h"
26
27 #include <expat.h>
28 #include <expat_external.h>
29 #include <pdcom5/Exception.h>
30 #include <stdexcept>
31
32 namespace PdCom { namespace impl { namespace MsrProto {
33 136 inline void XmlParserDeleter::operator()(XML_ParserStruct *s) noexcept
34 {
35
1/2
✓ Branch 0 taken 136 times.
✗ Branch 1 not taken.
136 if (s)
36 136 XML_ParserFree(s);
37 136 }
38
39
40 template <typename Handler, bool useExpatBuffer, bool setReparseDeferralEnabled>
41 struct ExpatWrapper<Handler, useExpatBuffer, setReparseDeferralEnabled>::
42 CallbackWrapper
43 {
44 // TODO(ighvh): use template<auto> when C++17 is mandatory (so in about 10
45 // years)
46 template <typename T, T, int = 0>
47 struct Impl;
48
49 // We use a partial specialisation of the struct above
50 // to extract the argument types (Args) from the Member function.
51 template <
52 typename... Args,
53 void (Handler::*callback)(Args...),
54 int level_change>
55 struct Impl<void (Handler::*)(Args...), callback, level_change>
56 {
57 1684 static void XMLCALL call(void *userdata, Args... args)
58 {
59 1684 auto &This = *reinterpret_cast<ExpatWrapper<
60 Handler, useExpatBuffer, setReparseDeferralEnabled> *>(
61 userdata);
62 // increment (start handler only)
63 1684 This.level_ += level_change == 1;
64
3/4
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 610 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1072 times.
1684 if (This.pending_exception_)
65 2 return;
66 try {
67
3/4
✓ Branch 4 taken 610 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 1070 times.
✓ Branch 11 taken 2 times.
1682 (static_cast<Handler &>(This).*callback)(args...);
68 }
69 4 catch (...) {
70 2 This.pending_exception_ = std::current_exception();
71
1/4
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
2 XML_StopParser(This.parser_.get(), false);
72 }
73 // decrement (end handler only)
74 1682 This.level_ -= level_change == -1;
75 }
76 };
77 };
78
79 template <typename Handler, bool useExpatBuffer, bool setReparseDeferralEnabled>
80 128 inline ExpatWrapper<Handler, useExpatBuffer, setReparseDeferralEnabled>::
81 128 ExpatWrapper(const char *encoding)
82 {
83
1/2
✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
128 reset(encoding);
84 128 }
85
86 template <typename Handler, bool useExpatBuffer, bool setReparseDeferralEnabled>
87 inline void
88 136 ExpatWrapper<Handler, useExpatBuffer, setReparseDeferralEnabled>::reset(
89 const char *encoding)
90 {
91 136 pending_exception_ = nullptr;
92 136 level_ = 0;
93 136 parser_.reset(XML_ParserCreate(encoding));
94
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 136 times.
136 if (!parser_)
95 throw PdCom::Exception("Could not create XML parser");
96
97 #if (XML_MAJOR_VERSION == 2 && XML_MINOR_VERSION >= 6) \
98 || (XML_MAJOR_VERSION > 3)
99 if (XML_SetReparseDeferralEnabled(
100 parser_.get(), setReparseDeferralEnabled ? XML_TRUE : XML_FALSE)
101 != XML_TRUE)
102 throw PdCom::Exception("Could not set ReparseDeferralEnabled attribute "
103 "of XML parser.");
104 #endif
105
106 using W1 = typename CallbackWrapper::template Impl<
107 decltype(&Handler::startElement), &Handler::startElement, 1>;
108 using W2 = typename CallbackWrapper::template Impl<
109 decltype(&Handler::endElement), &Handler::endElement, -1>;
110
111 136 XML_SetUserData(parser_.get(), this);
112 136 XML_SetStartElementHandler(parser_.get(), &W1::call);
113 136 XML_SetEndElementHandler(parser_.get(), &W2::call);
114 136 }
115
116 template <typename Handler, bool useExpatBuffer, bool setReparseDeferralEnabled>
117 template <typename T>
118 inline typename std::
119 enable_if<!useExpatBuffer && std::is_same<T, char>::value, bool>::type
120 6974 ExpatWrapper<Handler, useExpatBuffer, setReparseDeferralEnabled>::parse(
121 const T *s,
122 std::size_t n,
123 bool final)
124 {
125
1/2
✓ Branch 3 taken 6974 times.
✗ Branch 4 not taken.
6974 if (XML_STATUS_OK == XML_Parse(parser_.get(), s, n, final))
126 6974 return true;
127
128 const XML_Error err_code = XML_GetErrorCode(parser_.get());
129 if (err_code == XML_ERROR_ABORTED && pending_exception_) {
130 auto pe = pending_exception_;
131 pending_exception_ = nullptr;
132 std::rethrow_exception(pe);
133 }
134
135 static_cast<Handler *>(this)->xmlError(XML_ErrorString(err_code));
136 return false;
137 }
138
139
140 template <typename Handler, bool useExpatBuffer, bool setReparseDeferralEnabled>
141 template <std::size_t bufsize>
142 436 ExpatWrapper<Handler, useExpatBuffer, setReparseDeferralEnabled>::
143 ExpatBuffer<bufsize>::ExpatBuffer(
144 ExpatWrapper<Handler, useExpatBuffer, setReparseDeferralEnabled>
145 &wrapper)
146 {
147 static_assert(bufsize > 0, "Buffer size of 0 makes no sense.");
148 static_assert(useExpatBuffer, "Don't make a buffer when not using it");
149 436 buffer_ = XML_GetBuffer(wrapper.parser_.get(), bufsize);
150
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 369 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
436 if (!buffer_)
151 throw std::bad_alloc();
152 436 }
153
154 template <typename Handler, bool useExpatBuffer, bool setReparseDeferralEnabled>
155 template <std::size_t bufsize>
156 inline typename std::enable_if<(useExpatBuffer && bufsize > 0), bool>::type
157 425 ExpatWrapper<Handler, useExpatBuffer, setReparseDeferralEnabled>::parse(
158 ExpatWrapper<Handler, useExpatBuffer, setReparseDeferralEnabled>::
159 ExpatBuffer<bufsize> /* buffer */,
160 std::size_t n,
161 bool final)
162 {
163
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
425 if (n > bufsize)
164 throw PdCom::InvalidArgument(
165 "buffer overflow, wrote more bytes than buffer size.");
166
167
3/4
✓ Branch 3 taken 355 times.
✓ Branch 4 taken 3 times.
✓ Branch 8 taken 67 times.
✗ Branch 9 not taken.
425 if (XML_STATUS_OK == XML_ParseBuffer(parser_.get(), n, final))
168 422 return true;
169
170 3 const XML_Error err_code = XML_GetErrorCode(parser_.get());
171
5/12
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
3 if (err_code == XML_ERROR_ABORTED && pending_exception_) {
172 4 auto pe = pending_exception_;
173 2 pending_exception_ = nullptr;
174 4 std::rethrow_exception(pe);
175 }
176
177
1/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
1 static_cast<Handler *>(this)->xmlError(XML_ErrorString(err_code));
178 return false;
179 }
180
181 }}} // namespace PdCom::impl::MsrProto
182
183 #endif // MSRPROTO_EXPAT_WRAPPER_H
184