Directory: | ./ |
---|---|
File: | src/msrproto/DataConverter.cpp |
Date: | 2024-11-05 15:23:15 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 44 | 68 | 64.7% |
Branches: | 27 | 98 | 27.6% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Copyright (C) 2021 Richard Hacker (lerichi at gmx dot net), | ||
4 | * Florian Pose (fp at igh dot de), | ||
5 | * Bjarne von Horn (vh at igh dot de). | ||
6 | * | ||
7 | * This file is part of the PdCom library. | ||
8 | * | ||
9 | * The PdCom 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 by | ||
11 | * the Free Software Foundation, either version 3 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * The PdCom 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 PdCom library. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | *****************************************************************************/ | ||
23 | |||
24 | #include "DataConverter.h" | ||
25 | |||
26 | #include "ProtocolHandler.h" | ||
27 | #include "Variable.h" | ||
28 | |||
29 | #include <cmath> | ||
30 | #include <cstdint> | ||
31 | #include <cstring> | ||
32 | #include <pdcom5/Exception.h> | ||
33 | #include <pdcom5/Process.h> | ||
34 | #include <pdcom5/SizeTypeInfo.h> | ||
35 | #include <pdcom5/details.h> | ||
36 | #include <sstream> | ||
37 | |||
38 | using PdCom::impl::MsrProto::DataDecoder; | ||
39 | using PdCom::impl::MsrProto::DataEncoder; | ||
40 | using PdCom::impl::MsrProto::Variable; | ||
41 | |||
42 | 24 | void DataDecoder::readFromHexDec( | |
43 | const char *s, | ||
44 | const Variable &var, | ||
45 | unsigned int blocksize) | ||
46 | { | ||
47 | 24 | resize(0); | |
48 | 24 | resize(blocksize * var.totalSizeInBytes()); | |
49 | 24 | uint8_t *dst = reinterpret_cast<uint8_t *>(data()); | |
50 | size_t c1, c2; | ||
51 | 24 | const char *c = s; | |
52 | static const uint8_t hexDecTable[] = {0, 1, 2, 3, 4, 5, 6, 7, | ||
53 | 8, 9, 0, 0, 0, 0, 0, 0, | ||
54 | 0, 10, 11, 12, 13, 14, 15}; | ||
55 | |||
56 |
4/8✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 24 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 24 times.
|
24 | if (!s or strlen(s) < var.totalSizeInBytes() * 2) |
57 | ✗ | throw ProtocolError("invalid hexvalue attribute"); | |
58 | |||
59 | 24 | size_t bytes = var.totalSizeInBytes(); | |
60 | 115 | do { | |
61 | 139 | c1 = *c++ - '0'; | |
62 | 139 | c2 = *c++ - '0'; | |
63 |
2/4✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
|
139 | if (c1 >= sizeof(hexDecTable) or c2 >= sizeof(hexDecTable)) |
64 | ✗ | throw ProtocolError("invalid hexvalue attribute"); | |
65 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 139 times.
|
139 | *dst++ = (hexDecTable[c1] << 4) + hexDecTable[c2]; |
66 |
2/2✓ Branch 0 taken 115 times.
✓ Branch 1 taken 24 times.
|
139 | } while (--bytes); |
67 | 24 | } | |
68 | |||
69 | ////////////////////////////////////////////////////////////////////// | ||
70 | ✗ | void DataDecoder::readFromString( | |
71 | const char *s, | ||
72 | const Variable &var, | ||
73 | unsigned int blocksize) | ||
74 | { | ||
75 | ✗ | if (!s) | |
76 | ✗ | throw ProtocolError("invalid value attribute"); | |
77 | |||
78 | ✗ | const auto nelem = blocksize * var.numberOfElements(); | |
79 | ✗ | resize(0); | |
80 | ✗ | resize(nelem * var.type_info->element_size); | |
81 | |||
82 | ✗ | std::istringstream is(s); | |
83 | ✗ | double src; | |
84 | |||
85 | |||
86 | ✗ | is.imbue(std::locale::classic()); | |
87 | |||
88 | ✗ | for (size_t i = 0; i < nelem && is; ++i) { | |
89 | ✗ | if (i) | |
90 | ✗ | is.ignore(1); | |
91 | |||
92 | // istream does not like nan | ||
93 | ✗ | if (!strncmp("-nan", s + is.tellg(), 4)) { | |
94 | ✗ | is.ignore(4); | |
95 | ✗ | src = -NAN; | |
96 | } | ||
97 | else { | ||
98 | ✗ | is >> src; | |
99 | } | ||
100 | |||
101 | ✗ | PdCom::details::copyData( | |
102 | ✗ | data() + i * var.type_info->element_size, var.type_info->type, | |
103 | &src, PdCom::TypeInfo::double_T, 1); | ||
104 | } | ||
105 | |||
106 | ✗ | if (!is) | |
107 | ✗ | throw ProtocolError("invalid value attribute"); | |
108 | } | ||
109 | |||
110 | |||
111 | 53 | void DataDecoder::readFromBase64( | |
112 | const char *s, | ||
113 | const size_t input_len, | ||
114 | const Variable &var, | ||
115 | unsigned int blocksize) | ||
116 | { | ||
117 | 53 | resize(0); | |
118 | 53 | resize(blocksize * var.totalSizeInBytes() | |
119 | + 2 /* buffer must be longer for padding */); | ||
120 | 53 | const size_t expected_size = blocksize * var.totalSizeInBytes(); | |
121 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 53 times.
|
53 | if (!PdCom::impl::MsrProto::readFromBase64( |
122 | 53 | data(), s, input_len, expected_size)) | |
123 | ✗ | throw ProtocolError("Invalid base64 value"); | |
124 | 53 | } | |
125 | |||
126 | 108 | bool PdCom::impl::MsrProto::readFromBase64( | |
127 | char *dst, | ||
128 | const char *base64, | ||
129 | const size_t len, | ||
130 | size_t buflen) | ||
131 | { | ||
132 | uint8_t c1, c2; | ||
133 | static const uint8_t base64Value[256] = { | ||
134 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
135 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
136 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 62, 0, 63, | ||
137 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, | ||
138 | 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | ||
139 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, | ||
140 | 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | ||
141 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, | ||
142 | }; | ||
143 |
2/4✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 108 times.
|
108 | if (!base64 or !*base64) |
144 | ✗ | return false; | |
145 | |||
146 |
3/4✓ Branch 0 taken 105 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 105 times.
|
108 | if (len % 4 or len < 4) |
147 | 3 | return false; | |
148 | |||
149 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 103 times.
|
105 | if (len / 4 != (buflen + 2) / 3) |
150 | 2 | return false; | |
151 | |||
152 |
2/2✓ Branch 0 taken 251 times.
✓ Branch 1 taken 103 times.
|
354 | for (const char *const end = base64 + len; base64 != end;) { |
153 | 251 | c1 = base64Value[uint8_t(*base64++)]; | |
154 | 251 | c2 = base64Value[uint8_t(*base64++)]; | |
155 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 251 times.
|
251 | *dst++ = (c1 << 2) | (c2 >> 4); |
156 | |||
157 | 251 | c1 = base64Value[uint8_t(*base64++)]; | |
158 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 251 times.
|
251 | *dst++ = (c2 << 4) | (c1 >> 2); |
159 | |||
160 | 251 | c2 = base64Value[uint8_t(*base64++)]; | |
161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 251 times.
|
251 | *dst++ = (c1 << 6) | c2; |
162 | } | ||
163 | |||
164 | 103 | return true; | |
165 | } | ||
166 | |||
167 | 15 | void DataEncoder::toHex( | |
168 | PdCom::TypeInfo const &dst_type, | ||
169 | const void *src, | ||
170 | PdCom::TypeInfo::DataType src_type, | ||
171 | size_t n, | ||
172 | PdCom::impl::MsrProto::XmlStream &os) | ||
173 | { | ||
174 | 15 | converted_value_.resize(0); | |
175 | 15 | converted_value_.resize(n * dst_type.element_size); | |
176 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | details::copyData(converted_value_.data(), dst_type.type, src, src_type, n); |
177 | |||
178 | static constexpr char hexTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', | ||
179 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; | ||
180 | |||
181 |
2/2✓ Branch 6 taken 35 times.
✓ Branch 7 taken 15 times.
|
50 | for (const auto c : converted_value_) |
182 |
2/4✓ Branch 3 taken 35 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 35 times.
✗ Branch 8 not taken.
|
35 | os << hexTable[c >> 4] << hexTable[c & 0x0F]; |
183 | |||
184 | 15 | converted_value_.resize(0); | |
185 | 15 | } | |
186 |