Keyple Util C++ Library 2.0.0
Reference Terminal Reader API for C++
BerTlvUtil.cpp
Go to the documentation of this file.
1/**************************************************************************************************
2 * Copyright (c) 2021 Calypso Networks Association https://calypsonet.org/ *
3 * *
4 * See the NOTICE file(s) distributed with this work for additional information regarding *
5 * copyright ownership. *
6 * *
7 * This program and the accompanying materials are made available under the terms of the Eclipse *
8 * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0 *
9 * *
10 * SPDX-License-Identifier: EPL-2.0 *
11 **************************************************************************************************/
12
13#include "BerTlvUtil.h"
14
15/* Keyple Core Util */
16#include "Arrays.h"
19
20namespace keyple {
21namespace core {
22namespace util {
23
24using namespace keyple::core::util::cpp;
26
27BerTlvUtil::BerTlvUtil() {}
28
29const std::map<const int, const std::vector<uint8_t>> BerTlvUtil::parseSimple(
30 const std::vector<uint8_t>& tlvStructure, const bool primitiveOnly)
31{
32 try {
33 return parseBufferSimple(tlvStructure, primitiveOnly);
34 } catch (const IndexOutOfBoundsException& e) {
35 (void)e;
36 throw IllegalArgumentException("Invalid TLV structure.");
37 }
38}
39
40const std::map<const int, std::vector<std::vector<uint8_t>>> BerTlvUtil::parse(
41 const std::vector<uint8_t>& tlvStructure, const bool primitiveOnly)
42{
43 try {
44 return parseBuffer(tlvStructure, primitiveOnly);
45 } catch (const IndexOutOfBoundsException& e) {
46 (void)e;
47 throw IllegalArgumentException("Invalid TLV structure.");
48 }
49}
50
51bool BerTlvUtil::isConstructed(const int tagId)
52{
53 if (tagId < 0 || tagId > 0xFFFFFF) {
54 throw IllegalArgumentException("Tag Id out of range.");
55 }
56
57 if (tagId <= 0xFF) {
58 return (tagId & 0x20) != 0;
59 }
60
61 if (tagId <= 0xFFFF) {
62 return (tagId & 0x2000) != 0;
63 }
64
65 return (tagId & 0x200000) != 0;
66}
67
68const std::map<const int, const std::vector<uint8_t>> BerTlvUtil::parseBufferSimple(
69 const std::vector<uint8_t>& tlvStructure, const bool primitiveOnly)
70{
71
72 std::map<const int, const std::vector<uint8_t>> tlvs;
73 int offset = 0;
74
75 do {
76 const int tagSize = getTagSize(tlvStructure, offset);
77 const std::vector<uint8_t> tagBytes =
78 Arrays::copyOfRange(tlvStructure, offset, offset + tagSize);
79 const int tag = getTag(tlvStructure, offset, tagSize);
80 const int lengthSize = getLengthSize(tlvStructure, offset + tagSize);
81 const int valueSize = getLength(tlvStructure, offset + tagSize, lengthSize);
82 const std::vector<uint8_t> value =
83 Arrays::copyOfRange(tlvStructure,
84 offset + tagSize + lengthSize,
85 offset + tagSize + lengthSize + valueSize);
86
87 offset += tagSize + lengthSize + valueSize;
88
89 if ((tagBytes[0] & 0x20) != 0) {
90 /* Tag is constructed */
91 if (!primitiveOnly) {
92 tlvs.insert({tag, value});
93 }
94
95 const std::map<const int, const std::vector<uint8_t>> parse =
96 parseSimple(value, primitiveOnly);
97 tlvs.insert(parse.begin(), parse.end());
98 } else {
99 /* Tag is primitive */
100 tlvs.insert({tag, value});
101 }
102 } while (offset < static_cast<int>(tlvStructure.size()));
103
104 return tlvs;
105}
106
107const std::map<const int, std::vector<std::vector<uint8_t>>> BerTlvUtil::parseBuffer(
108 const std::vector<uint8_t>& tlvStructure, const bool primitiveOnly)
109{
110 std::map<const int, std::vector<std::vector<uint8_t>>> tlvs;
111 int offset = 0;
112
113 do {
114 const int tagSize = getTagSize(tlvStructure, offset);
115 const std::vector<uint8_t> tagBytes =
116 Arrays::copyOfRange(tlvStructure, offset, offset + tagSize);
117 const int tag = getTag(tlvStructure, offset, tagSize);
118 const int lengthSize = getLengthSize(tlvStructure, offset + tagSize);
119 const int valueSize = getLength(tlvStructure, offset + tagSize, lengthSize);
120 const std::vector<uint8_t> value =
121 Arrays::copyOfRange(tlvStructure,
122 offset + tagSize + lengthSize,
123 offset + tagSize + lengthSize + valueSize);
124
125 offset += tagSize + lengthSize + valueSize;
126
127 if ((tagBytes[0] & 0x20) != 0) {
128 /* Tag is constructed */
129 if (!primitiveOnly) {
130 std::vector<std::vector<uint8_t>>& values = getOrInitTagValues(tlvs, tag);
131 values.push_back(value);
132 }
133
134 std::map<const int, std::vector<std::vector<uint8_t>>> tlvs2 =
135 parse(value, primitiveOnly);
136
137 for (const auto & entry : tlvs2) {
138 std::vector<std::vector<uint8_t>>& values = getOrInitTagValues(tlvs, entry.first);
139 Arrays::addAll(values, entry.second);
140 }
141 } else {
142 /* Tag is primitive */
143 std::vector<std::vector<uint8_t>>& values = getOrInitTagValues(tlvs, tag);
144 values.push_back(value);
145 }
146
147 } while (offset < static_cast<int>(tlvStructure.size()));
148
149 return tlvs;
150}
151
152std::vector<std::vector<uint8_t>>& BerTlvUtil::getOrInitTagValues(
153 std::map<const int, std::vector<std::vector<uint8_t>>>& tlvs, const int tag)
154{
155 const auto it = tlvs.find(tag);
156
157 if (it == tlvs.end()) {
158 std::vector<std::vector<uint8_t>> values;
159 tlvs.insert({tag, values});
160 }
161
162 /* Look again and return reference */
163 return tlvs.find(tag)->second;
164}
165
166int BerTlvUtil::getTagSize(const std::vector<uint8_t>& tlvStructure, const int offset)
167{
168 /* C++: prevent accessing unexisting values */
169 if (offset >= static_cast<int>(tlvStructure.size())) {
170 throw IndexOutOfBoundsException("Invalid index");
171 }
172
173 if ((tlvStructure[offset] & 0x1F) == 0x1F) {
174 if ((tlvStructure[offset + 1] & 0x80) == 0) {
175 return 2;
176 } else {
177 if ((tlvStructure[offset + 2] & 0x80) != 0) {
178 throw IllegalArgumentException("Invalid tag.");
179 }
180 }
181
182 return 3;
183 } else {
184 return 1;
185 }
186}
187
188int BerTlvUtil::getTag(const std::vector<uint8_t>& tlvStructure, const int offset, const int size)
189{
190 switch (size) {
191 case 1:
192 return tlvStructure[offset] & 0xFF;
193 case 2:
194 return ((tlvStructure[offset] & 0xFF) << 8) + (tlvStructure[offset + 1] & 0xFF);
195 case 3:
196 return ((tlvStructure[offset] & 0xFF) << 16)
197 + ((tlvStructure[offset + 1] & 0xFF) << 8)
198 + (tlvStructure[offset + 2] & 0xFF);
199 default:
200 throw IllegalArgumentException("Bad tag size.");
201 }
202}
203
204int BerTlvUtil::getLengthSize(const std::vector<uint8_t>& tlvStructure, const int offset)
205{
206 int firstByteLength = tlvStructure[offset] & 0xff;
207
208 switch (firstByteLength) {
209 case 0x82:
210 return 3;
211 case 0x81:
212 return 2;
213 default:
214 if (firstByteLength >= 0x80) {
215 throw IllegalArgumentException("Invalid length.");
216 }
217
218 return 1;
219 }
220}
221
222int BerTlvUtil::getLength(const std::vector<uint8_t>& tlvStructure,
223 const int offset,
224 const int size)
225{
226 switch (size) {
227 case 1:
228 return tlvStructure[offset] & 0x7F;
229 case 2:
230 return tlvStructure[offset + 1] & 0xFF;
231 case 3:
232 return ((tlvStructure[offset + 1] & 0xFF) << 8) + (tlvStructure[offset + 2] & 0xFF);
233 default:
234 throw IllegalArgumentException("Bad length size.");
235 }
236}
237
238}
239}
240}
static const std::map< const int, const std::vector< uint8_t > > parseSimple(const std::vector< uint8_t > &tlvStructure, const bool primitiveOnly)
Definition: BerTlvUtil.cpp:29
static bool isConstructed(const int tagId)
Definition: BerTlvUtil.cpp:51
static const std::map< const int, std::vector< std::vector< uint8_t > > > parse(const std::vector< uint8_t > &tlvStructure, const bool primitiveOnly)
Definition: BerTlvUtil.cpp:40
static bool addAll(std::vector< T > &a, const std::vector< T > &b)
Definition: Arrays.h:155
static std::vector< char > copyOfRange(const std::vector< char > &original, const size_t from, const size_t to)
Definition: Arrays.h:82