Keyple Util C++ Library - 2.4.0
Component of the Keyple C++ middleware
ByteArrayUtil.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (c) 2025 Calypso Networks Association https://calypsonet.org/ *
3 * *
4 * See the NOTICE file(s) distributed with this work for additional *
5 * information regarding copyright ownership. *
6 * *
7 * This program and the accompanying materials are made available under the *
8 * terms of the Eclipse Public License 2.0 which is available at *
9 * http://www.eclipse.org/legal/epl-2.0 *
10 * *
11 * SPDX-License-Identifier: EPL-2.0 *
12 ******************************************************************************/
13
14#include "keyple/core/util/ByteArrayUtil.hpp"
15
16#include <string>
17#include <vector>
18
19#include "keyple/core/util/HexUtil.hpp"
20#include "keyple/core/util/KeypleAssert.hpp"
21#include "keyple/core/util/cpp/Character.hpp"
22#include "keyple/core/util/cpp/Pattern.hpp"
23#include "keyple/core/util/cpp/StringBuilder.hpp"
24#include "keyple/core/util/cpp/System.hpp"
25#include "keyple/core/util/cpp/exception/IllegalArgumentException.hpp"
26#include "keyple/core/util/cpp/exception/NegativeArraySizeException.hpp"
27
28namespace keyple {
29namespace core {
30namespace util {
31
32using keyple::core::util::cpp::System;
33using keyple::core::util::cpp::exception::ArrayIndexOutOfBoundsException;
34using keyple::core::util::cpp::exception::IllegalArgumentException;
35using keyple::core::util::cpp::exception::NegativeArraySizeException;
36
37const std::vector<uint8_t>
38ByteArrayUtil::extractBytes(
39 const std::vector<uint8_t>& src, const int bitOffset, const int nbBytes)
40{
41 if (bitOffset < 0) {
42 throw ArrayIndexOutOfBoundsException("negative index");
43 }
44
45 if (nbBytes < 0) {
46 throw NegativeArraySizeException("negative array size");
47 }
48
49 const int byteOffset = bitOffset / 8;
50 int lBitOffset = bitOffset % 8;
51
52 if (byteOffset >= static_cast<int>((src.size() - (lBitOffset ? 1 : 0)))) {
53 throw ArrayIndexOutOfBoundsException("pos + offset > src size");
54 }
55
56 std::vector<uint8_t> dest(nbBytes);
57
58 if (lBitOffset == 0) {
59 System::arraycopy(src, byteOffset, dest, 0, nbBytes);
60 } else {
61 const int rightShift = 8 - bitOffset;
62 for (int i = 0, j = byteOffset; j < byteOffset + nbBytes; i++, j++) {
63 dest[i]
64 = ((src[j] << lBitOffset)
65 | ((src[j + 1] & 0xFF) >> rightShift));
66 }
67 }
68
69 return dest;
70}
71
72const std::vector<uint8_t>
73ByteArrayUtil::extractBytes(const uint64_t src, const int nbBytes)
74{
75 if (nbBytes < 0) {
76 throw NegativeArraySizeException("negative array size");
77 }
78
79 std::vector<uint8_t> data(nbBytes);
80 int shift = 0;
81 int i = nbBytes - 1;
82
83 while (i >= 0) {
84 data[i] = ((src >> shift) & 0xFF);
85 shift += 8;
86 i--;
87 }
88
89 return data;
90}
91
92uint16_t
93ByteArrayUtil::extractShort(const std::vector<uint8_t>& src, const int offset)
94{
95 if (offset < 0 || offset > static_cast<int>(src.size() - 2)) {
96 throw ArrayIndexOutOfBoundsException(
97 "offset not in range [0...(src.size() - 2)");
98 }
99
100 return ((src[offset] & 0xFF) << 8) | (src[offset + 1] & 0xFF);
101}
102
103uint32_t
104ByteArrayUtil::extractInt(
105 const std::vector<uint8_t>& src,
106 const int offset,
107 const int nbBytes,
108 const bool isSigned)
109{
110 if (offset < 0) {
111 throw ArrayIndexOutOfBoundsException("negative offset");
112 }
113
114 if ((offset + nbBytes) > static_cast<int>(src.size())) {
115 throw ArrayIndexOutOfBoundsException("offset + nbBytes > src size");
116 }
117
118 /* C++ - doesn't make sense to have nbBytes > int size */
119 if (nbBytes > 4) {
120 throw IllegalArgumentException("nbBytes can't be bigger than 4");
121 }
122
123 uint32_t val = 0;
124 uint32_t complement = 0xFFFFFFFF;
125 int lOffset = offset;
126 int lNbBytes = nbBytes;
127 bool negative = false;
128
129 /* Check MSB byte negativeness */
130 negative = src[lOffset] > 0x7F;
131
132 /* Get value */
133 while (lNbBytes > 0) {
134 val |= ((src[lOffset++] & 0xFF) << (8 * (--lNbBytes)));
135 complement &= ~(
136 0xFF << 8 * lNbBytes); // cppcheck-suppress[integerOverflowCond]
137 }
138
139 /* If signed, add complement */
140 if (isSigned && negative) {
141 val |= complement;
142 }
143
144 return val;
145}
146
147uint64_t
148ByteArrayUtil::extractLong(
149 const std::vector<uint8_t>& src,
150 const int offset,
151 const int nbBytes,
152 const bool isSigned)
153{
154 int lOffset = offset;
155 int lNbBytes = nbBytes;
156
157 if (lOffset < 0 || lOffset > static_cast<int>(src.size() - lNbBytes)) {
158 throw ArrayIndexOutOfBoundsException(
159 "offset not in range [0...(src.size() - nbBytes)");
160 }
161
162 uint64_t val = 0L;
163 uint64_t complement = 0xFFFFFFFFFFFFFFFF;
164 bool negative = false;
165
166 /* Get value */
167 while (lNbBytes > 0) {
168 /* Check MSB byte negativeness */
169 negative
170 = negative ? true : ((src[lOffset] & 0xFF) > 0x7F ? true : false);
171 val
172 |= ((static_cast<uint64_t>(src[lOffset++] & 0xFF))
173 << (8 * (--lNbBytes)));
174 complement &= ~((static_cast<uint64_t>(0xFF)) << 8 * lNbBytes);
175 }
176
177 /* If signed, add complement */
178 if (isSigned && negative) {
179 val |= complement;
180 }
181
182 return static_cast<uint64_t>(val);
183}
184
185void
186ByteArrayUtil::copyBytes(
187 const uint64_t src,
188 std::vector<uint8_t>& dest,
189 const int offset,
190 const int nbBytes)
191{
192 if (offset < 0 || offset > static_cast<int>(dest.size() - nbBytes)) {
193 throw ArrayIndexOutOfBoundsException(
194 "offset not in range [0...(dest.size() - nbBytes)");
195 }
196
197 System::arraycopy(extractBytes(src, nbBytes), 0, dest, offset, nbBytes);
198}
199
200bool
201ByteArrayUtil::isValidHexString(const std::string& hex)
202{
203 return HexUtil::isValid(hex);
204}
205
206const std::string
207ByteArrayUtil::normalizeHexString(const std::string& hex)
208{
209 if (hex.length() % 2 != 0) {
210 return "0" + hex;
211 }
212
213 return hex;
214}
215
216std::vector<uint8_t>
217ByteArrayUtil::fromHex(const std::string& hex)
218{
219 Assert::getInstance()
220 .notEmpty(hex, "hex")
221 .isEqual(hex.length() % 2, 0, "hex size");
222
223 return HexUtil::toByteArray(hex);
224}
225
226const std::string
227ByteArrayUtil::toHex(const std::vector<uint8_t>& src)
228{
229 if (src.empty()) {
230 return "";
231 }
232
233 return HexUtil::toHex(src);
234}
235
236int
237ByteArrayUtil::twoBytesToInt(
238 const std::vector<uint8_t>& bytes, const int offset)
239{
240 return extractInt(bytes, offset, 2, false);
241}
242
243int
244ByteArrayUtil::twoBytesSignedToInt(
245 const std::vector<uint8_t>& bytes, const int offset)
246{
247 return extractInt(bytes, offset, 2, true);
248}
249
250int
251ByteArrayUtil::threeBytesToInt(
252 const std::vector<uint8_t>& bytes, const int offset)
253{
254 return extractInt(bytes, offset, 3, false);
255}
256
257int
258ByteArrayUtil::threeBytesSignedToInt(
259 const std::vector<uint8_t>& bytes, const int offset)
260{
261 return extractInt(bytes, offset, 3, true);
262}
263
264int
265ByteArrayUtil::fourBytesToInt(
266 const std::vector<uint8_t>& bytes, const int offset)
267{
268 return extractInt(bytes, offset, 4, true);
269}
270
271} /* namespace util */
272} /* namespace core */
273} /* namespace keyple */