GCC Code Coverage Report


Directory: ./
File: pdserv/src/msrproto/XmlElement.cpp
Date: 2026-05-03 04:12:26
Exec Total Coverage
Lines: 100 101 99.0%
Branches: 49 71 69.0%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * Copyright 2010 Richard Hacker (lerichi at gmx dot net)
4 *
5 * This file is part of the pdserv library.
6 *
7 * The pdserv 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
9 * by the Free Software Foundation, either version 3 of the License, or (at
10 * your option) any later version.
11 *
12 * The pdserv 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 pdserv library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22 #include "XmlElement.h"
23 #include "Variable.h"
24 #include "../Debug.h"
25
26 #include <sstream>
27 #include <iomanip>
28 #include <algorithm>
29 #include <cstring> // strpbrk()
30
31 using namespace MsrProto;
32
33 /////////////////////////////////////////////////////////////////////////////
34 // XmlElement
35 /////////////////////////////////////////////////////////////////////////////
36 2415 XmlElement::XmlElement(const char *name, std::ostream &os,
37 2415 size_t level, std::string *id):
38 2415 level(level), id(id), os(os), name(name)
39 {
40
4/8
✓ Branch 6 taken 2415 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 2415 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2415 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2415 times.
✗ Branch 17 not taken.
2415 this->os << std::string(level,' ') << '<' << name;
41 2415 printed = false;
42 2415 }
43
44 /////////////////////////////////////////////////////////////////////////////
45 4830 XmlElement::~XmlElement()
46 {
47
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2415 times.
✓ Branch 3 taken 388 times.
✓ Branch 4 taken 2027 times.
2415 if (printed)
48 388 os << std::string(level, ' ') << "</" << name;
49 else {
50
6/6
✓ Branch 1 taken 967 times.
✓ Branch 2 taken 1060 times.
✓ Branch 7 taken 108 times.
✓ Branch 8 taken 859 times.
✓ Branch 9 taken 108 times.
✓ Branch 10 taken 1919 times.
2027 if (id and !id->empty())
51 108 Attribute(*this,"id").setEscaped(*id);
52 2027 os << '/';
53 }
54
55 2415 os << ">\r\n";
56 2415 }
57
58 /////////////////////////////////////////////////////////////////////////////
59 1060 XmlElement XmlElement::createChild(const char* name)
60 {
61
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1060 times.
✓ Branch 3 taken 388 times.
✓ Branch 4 taken 672 times.
1060 if (!printed) {
62
5/6
✓ Branch 1 taken 388 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 383 times.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 383 times.
388 if (id and !id->empty())
63
1/2
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
5 Attribute(*this,"id").setEscaped(*id);
64
65 388 os << ">\r\n";
66 }
67
68 1060 printed = 1;
69
70 1060 return XmlElement(name, os, level+1, 0);
71 }
72
73 /////////////////////////////////////////////////////////////////////////////
74 // XmlElement::Attribute
75 /////////////////////////////////////////////////////////////////////////////
76 7334 XmlElement::Attribute::Attribute(XmlElement& el, const char *name):
77 7334 os(el.os)
78 {
79 7334 os << ' ' << name << "=\"";
80 7334 }
81
82 /////////////////////////////////////////////////////////////////////////////
83 14668 XmlElement::Attribute::~Attribute()
84 {
85 7334 os << '"';
86 7334 }
87
88 /////////////////////////////////////////////////////////////////////////////
89 939 std::ostream& XmlElement::Attribute::operator<<(const char *s)
90 {
91 939 os << s;
92 939 return os;
93 }
94
95 /////////////////////////////////////////////////////////////////////////////
96 1047 std::ostream& XmlElement::Attribute::operator <<( struct timespec const& ts)
97 {
98
1/2
✓ Branch 2 taken 1047 times.
✗ Branch 3 not taken.
2094 std::ostringstream time;
99
1/2
✓ Branch 3 taken 1047 times.
✗ Branch 4 not taken.
1047 time << ts.tv_sec << '.'
100
4/8
✓ Branch 2 taken 1047 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1047 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1047 times.
✗ Branch 11 not taken.
✓ Branch 17 taken 1047 times.
✗ Branch 18 not taken.
1047 << std::setfill('0') << std::setw(6) << ts.tv_nsec / 1000;
101
102
2/4
✓ Branch 4 taken 1047 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1047 times.
✗ Branch 9 not taken.
1047 os << time.str();
103 2094 return os;
104 }
105
106 /////////////////////////////////////////////////////////////////////////////
107 945 void XmlElement::Attribute::setEscaped( const std::string& str)
108 {
109 945 const char *escape = "<>&\"'";
110 945 size_t start = 0, pos;
111
112
2/2
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 945 times.
1125 while (std::string::npos != (pos = str.find_first_of(escape, start))) {
113
1/2
✓ Branch 6 taken 90 times.
✗ Branch 7 not taken.
90 os << str.substr(start, pos - start);
114
5/6
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
90 switch (str[pos]) {
115 18 case '<':
116 18 os << "&lt;";
117 18 break;
118
119 18 case '>':
120 18 os << "&gt;";
121 18 break;
122
123 18 case '&':
124 18 os << "&amp;";
125 18 break;
126
127 18 case '"':
128 18 os << "&quot;";
129 18 break;
130
131 18 case '\'':
132 18 os << "&apos;";
133 18 break;
134 }
135
136 90 start = pos + 1;
137 }
138
139
1/2
✓ Branch 6 taken 945 times.
✗ Branch 7 not taken.
945 os << str.substr(start);
140 945 }
141
142 /////////////////////////////////////////////////////////////////////////////
143 164 void XmlElement::Attribute::csv(const Variable* var, const char *buf,
144 size_t nblocks, std::streamsize precision)
145 {
146 164 char delim = '\0';
147
148 // Save current and set new precision
149 164 precision = os.precision(precision);
150
151
2/2
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 164 times.
492 while (nblocks--) {
152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 164 times.
164 if (delim)
153 os << delim;
154 164 delim = ',';
155 164 var->dtype.print(os, buf, buf, buf+var->memSize);
156 164 buf += var->memSize;
157 }
158
159 // Reset previous precision
160 164 os.precision(precision);
161 164 }
162
163 /////////////////////////////////////////////////////////////////////////////
164 852 void XmlElement::Attribute::base64( const void *data, size_t len) const
165 {
166 static const char *base64Chr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
167 "abcdefghijklmnopqrstuvwxyz0123456789+/";
168 852 size_t i = 0;
169 852 size_t rem = len % 3;
170 852 const unsigned char *buf = reinterpret_cast<const unsigned char*>(data);
171
172 // First convert all characters in chunks of 3
173
2/2
✓ Branch 0 taken 4994 times.
✓ Branch 1 taken 852 times.
10840 while (i != len - rem) {
174 9988 os << base64Chr[ buf[i ] >> 2]
175 4994 << base64Chr[((buf[i ] & 0x03) << 4) + (buf[i+1] >> 4)]
176 4994 << base64Chr[((buf[i+1] & 0x0f) << 2) + (buf[i+2] >> 6)]
177 19976 << base64Chr[ (buf[i+2] & 0x3f) ];
178
179 4994 i += 3;
180 }
181
182 // Convert the remaining 1 or 2 characters
183
2/3
✓ Branch 0 taken 362 times.
✓ Branch 1 taken 490 times.
✗ Branch 2 not taken.
852 switch (rem) {
184 362 case 2:
185 724 os << base64Chr[ buf[i ] >> 2]
186 362 << base64Chr[((buf[i ] & 0x03) << 4) + (buf[i+1] >> 4)]
187 362 << base64Chr[ (buf[i+1] & 0x0f) << 2]
188 1448 << '=';
189 362 break;
190 490 case 1:
191 980 os << base64Chr[ buf[i] >> 2]
192 490 << base64Chr[ (buf[i] & 0x03) << 4]
193 1470 << "==";
194 490 break;
195 }
196 852 }
197
198 /////////////////////////////////////////////////////////////////////////////
199 52 void XmlElement::Attribute::hexDec( const void *data, size_t len) const
200 {
201 52 const unsigned char *buf =
202 reinterpret_cast<const unsigned char*>(data);
203 52 const char *hexValue[256] = {
204 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09",
205 "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13",
206 "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D",
207 "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27",
208 "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31",
209 "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
210 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45",
211 "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
212 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
213 "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63",
214 "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D",
215 "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
216 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81",
217 "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B",
218 "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95",
219 "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
220 "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9",
221 "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
222 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD",
223 "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
224 "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1",
225 "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB",
226 "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5",
227 "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
228 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9",
229 "FA", "FB", "FC", "FD", "FE", "FF"};
230
231
2/2
✓ Branch 0 taken 732 times.
✓ Branch 1 taken 52 times.
1516 while (len--)
232
1/2
✓ Branch 6 taken 732 times.
✗ Branch 7 not taken.
732 os << hexValue[*buf++];
233 52 }
234