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