| Directory: | ./ |
|---|---|
| File: | src/msrproto/DataConverter.cpp |
| Date: | 2025-02-12 12:41:42 |
| 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 |