GCC Code Coverage Report


Directory: ./
File: pdcom5/src/msrproto/expat_wrapper_impl.h
Date: 2024-12-01 04:08:21
Exec Total Coverage
Lines: 39 44 88.6%
Branches: 20 52 38.5%

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 157 inline void XmlParserDeleter::operator()(XML_ParserStruct *s) noexcept
34 {
35
1/2
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
157 if (s)
36 157 XML_ParserFree(s);
37 157 }
38
39
40 template <typename Handler, bool useExpatBuffer>
41 struct ExpatWrapper<Handler, useExpatBuffer>::CallbackWrapper
42 {
43 // TODO(ighvh): use template<auto> when C++17 is mandatory (so in about 10
44 // years)
45 template <typename T, T, int = 0>
46 struct Impl;
47
48 // We use a partial specialisation of the struct above
49 // to extract the argument types (Args) from the Member function.
50 template <
51 typename... Args,
52 void (Handler::*callback)(Args...),
53 int level_change>
54 struct Impl<void (Handler::*)(Args...), callback, level_change>
55 {
56 5460 static void XMLCALL call(void *userdata, Args... args)
57 {
58 5460 auto &This =
59 *reinterpret_cast<ExpatWrapper<Handler, useExpatBuffer> *>(
60 userdata);
61 // increment (start handler only)
62 5460 This.level_ += level_change == 1;
63
3/4
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2650 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2809 times.
5460 if (This.pending_exception_)
64 1 return;
65 try {
66
3/4
✓ Branch 4 taken 2650 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 2808 times.
✓ Branch 11 taken 1 times.
5459 (static_cast<Handler &>(This).*callback)(args...);
67 }
68 2 catch (...) {
69 1 This.pending_exception_ = std::current_exception();
70
1/4
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 XML_StopParser(This.parser_.get(), false);
71 }
72 // decrement (end handler only)
73 5459 This.level_ -= level_change == -1;
74 }
75 };
76 };
77
78 template <typename Handler, bool useExpatBuffer>
79 158 inline ExpatWrapper<Handler, useExpatBuffer>::ExpatWrapper(const char *encoding)
80 {
81
1/2
✓ Branch 2 taken 158 times.
✗ Branch 3 not taken.
158 reset(encoding);
82 158 }
83
84 template <typename Handler, bool useExpatBuffer>
85 158 inline void ExpatWrapper<Handler, useExpatBuffer>::reset(const char *encoding)
86 {
87 158 pending_exception_ = nullptr;
88 158 level_ = 0;
89 158 parser_.reset(XML_ParserCreate(encoding));
90
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 158 times.
158 if (!parser_)
91 throw PdCom::Exception("Could not create XML parser");
92
93 #if (XML_MAJOR_VERSION == 2 && XML_MINOR_VERSION >= 6) \
94 || (XML_MAJOR_VERSION > 3)
95 if (XML_SetReparseDeferralEnabled(parser_.get(), XML_FALSE) != XML_TRUE)
96 throw PdCom::Exception("Could not set ReparseDeferralEnabled attribute "
97 "of XML parser.");
98 #endif
99
100 using W1 = typename CallbackWrapper::template Impl<
101 decltype(&Handler::startElement), &Handler::startElement, 1>;
102 using W2 = typename CallbackWrapper::template Impl<
103 decltype(&Handler::endElement), &Handler::endElement, -1>;
104
105 158 XML_SetUserData(parser_.get(), this);
106 158 XML_SetStartElementHandler(parser_.get(), &W1::call);
107 158 XML_SetEndElementHandler(parser_.get(), &W2::call);
108 158 }
109
110 template <typename Handler, bool useExpatBuffer>
111 template <typename T>
112 inline typename std::
113 enable_if<!useExpatBuffer && std::is_same<T, char>::value, bool>::type
114 ExpatWrapper<Handler, useExpatBuffer>::parse(
115 const T *s,
116 std::size_t n,
117 bool final)
118 {
119 if (XML_STATUS_OK == XML_Parse(parser_.get(), s, n, final))
120 return true;
121
122 const XML_Error err_code = XML_GetErrorCode(parser_.get());
123 if (err_code == XML_ERROR_ABORTED && pending_exception_) {
124 auto pe = pending_exception_;
125 pending_exception_ = nullptr;
126 std::rethrow_exception(pe);
127 }
128
129 static_cast<Handler *>(this)->xmlError(XML_ErrorString(err_code));
130 return false;
131 }
132
133
134 template <typename Handler, bool useExpatBuffer>
135 template <std::size_t bufsize>
136 1300 ExpatWrapper<Handler, useExpatBuffer>::ExpatBuffer<bufsize>::ExpatBuffer(
137 ExpatWrapper<Handler, useExpatBuffer> &wrapper)
138 {
139 static_assert(bufsize > 0, "Buffer size of 0 makes no sense.");
140 static_assert(useExpatBuffer, "Don't make a buffer when not using it");
141 1300 buffer_ = XML_GetBuffer(wrapper.parser_.get(), bufsize);
142
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1142 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 158 times.
1300 if (!buffer_)
143 throw std::bad_alloc();
144 1300 }
145
146 template <typename Handler, bool useExpatBuffer>
147 template <std::size_t bufsize>
148 inline typename std::enable_if<(useExpatBuffer && bufsize > 0), bool>::type
149 1282 ExpatWrapper<Handler, useExpatBuffer>::parse(
150 ExpatWrapper<Handler, useExpatBuffer>::ExpatBuffer<
151 bufsize> /* buffer */,
152 std::size_t n,
153 bool final)
154 {
155
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1124 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 158 times.
1282 if (n > bufsize)
156 throw PdCom::InvalidArgument(
157 "buffer overflow, wrote more bytes than buffer size.");
158
159
3/4
✓ Branch 3 taken 1123 times.
✓ Branch 4 taken 1 times.
✓ Branch 8 taken 158 times.
✗ Branch 9 not taken.
1282 if (XML_STATUS_OK == XML_ParseBuffer(parser_.get(), n, final))
160 1281 return true;
161
162 1 const XML_Error err_code = XML_GetErrorCode(parser_.get());
163
3/12
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
1 if (err_code == XML_ERROR_ABORTED && pending_exception_) {
164 2 auto pe = pending_exception_;
165 1 pending_exception_ = nullptr;
166 2 std::rethrow_exception(pe);
167 }
168
169 static_cast<Handler *>(this)->xmlError(XML_ErrorString(err_code));
170 return false;
171 }
172
173 }}} // namespace PdCom::impl::MsrProto
174
175 #endif // MSRPROTO_EXPAT_WRAPPER_H
176