Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
FileDataAdapter.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/card/calypso/FileDataAdapter.hpp"
15
16#include "keyple/core/util/ByteArrayUtil.hpp"
17#include "keyple/core/util/KeypleAssert.hpp"
18#include "keyple/core/util/cpp/Arrays.hpp"
19#include "keyple/core/util/cpp/KeypleStd.hpp"
20#include "keyple/core/util/cpp/System.hpp"
21#include "keyple/core/util/cpp/exception/IndexOutOfBoundsException.hpp"
22
23namespace keyple {
24namespace card {
25namespace calypso {
26
27using keyple::core::util::Assert;
28using keyple::core::util::ByteArrayUtil;
29using keyple::core::util::cpp::Arrays;
30using keyple::core::util::cpp::System;
31using keyple::core::util::cpp::exception::IndexOutOfBoundsException;
32
33FileDataAdapter::FileDataAdapter()
34{
35}
36
37FileDataAdapter::FileDataAdapter(const std::shared_ptr<FileData>& source)
38{
39 const std::map<const uint8_t, std::vector<uint8_t>>& sourceContent
40 = source->getAllRecordsContent();
41
42 for (const auto& entry : sourceContent) {
43 mRecords.insert({entry.first, entry.second});
44 }
45}
46
47const std::map<const std::uint8_t, std::vector<uint8_t>>&
48FileDataAdapter::getAllRecordsContent() const
49{
50 return mRecords;
51}
52
53std::vector<std::uint8_t>
54FileDataAdapter::getContent() const
55{
56 return getContent(1);
57}
58
59std::vector<std::uint8_t>
60FileDataAdapter::getContent(std::uint8_t numRecord) const
61{
62 const auto it = mRecords.find(numRecord);
63 if (it == mRecords.end()) {
64 mLogger->warn("Record not set [rec=%]\n", numRecord);
65 return std::vector<std::uint8_t>();
66 } else {
67 return it->second;
68 }
69}
70
71std::vector<std::uint8_t>
72FileDataAdapter::getContent(
73 std::uint8_t numRecord,
74 std::uint8_t dataOffset,
75 std::uint8_t dataLength) const
76{
77 Assert::getInstance()
78 .greaterOrEqual(dataOffset, 0, "dataOffset")
79 .greaterOrEqual(dataLength, 1, "dataLength");
80
81 const auto it = mRecords.find(numRecord);
82 if (it == mRecords.end()) {
83 mLogger->warn("Record not set [rec=%]\n", numRecord);
84 return std::vector<std::uint8_t>();
85 }
86
87 const std::vector<std::uint8_t>& content = it->second;
88 if (dataOffset >= static_cast<int>(content.size())) {
89 throw IndexOutOfBoundsException(
90 "Offset [" + std::to_string(dataOffset) + "] >= "
91 + "content length [" + std::to_string(content.size()) + "]");
92 }
93
94 const int toIndex = dataOffset + dataLength;
95 if (toIndex > static_cast<int>(content.size())) {
96 throw IndexOutOfBoundsException(
97 "Offset [" + std::to_string(dataOffset) + "] + " + "Length ["
98 + std::to_string(dataLength) + "] = " + "["
99 + std::to_string(toIndex) + "] > " + "content length ["
100 + std::to_string(content.size()) + "]");
101 }
102
103 return Arrays::copyOfRange(content, dataOffset, toIndex);
104}
105
106std::shared_ptr<int>
107FileDataAdapter::getContentAsCounterValue(int numCounter) const
108{
109 Assert::getInstance().greaterOrEqual(numCounter, 1, "numCounter");
110
111 const auto it = mRecords.find(1);
112 if (it == mRecords.end()) {
113 mLogger->warn("Record not set [rec=1]\n");
114 return nullptr;
115 }
116
117 const std::vector<std::uint8_t>& rec1 = it->second;
118 const int counterIndex = (numCounter - 1) * 3;
119 if (counterIndex >= static_cast<int>(rec1.size())) {
120 mLogger->warn(
121 "Counter not set [counter=%, counterCount=%]\n",
122 numCounter,
123 rec1.size() / 3);
124 return nullptr;
125 }
126
127 if (counterIndex + 3 > static_cast<int>(rec1.size())) {
128 throw IndexOutOfBoundsException(
129 "Counter #" + std::to_string(numCounter) + " "
130 + "has a truncated value (nb of actual counters = "
131 + std::to_string(rec1.size() / 3) + ")");
132 }
133
134 return std::make_shared<int>(
135 ByteArrayUtil::extractInt(rec1, counterIndex, 3, false));
136}
137
138std::map<const int, const int>
139FileDataAdapter::getAllCountersValue() const
140{
141 std::map<const int, const int> result;
142
143 const auto it = mRecords.find(1);
144
145 if (it == mRecords.end()) {
146 mLogger->warn("Record not set [rec=1]\n");
147 return result;
148 }
149
150 const std::vector<std::uint8_t> rec1 = it->second;
151 const int length = static_cast<int>(rec1.size() - (rec1.size() % 3));
152 for (int i = 0, c = 1; i < length; i += 3, c++) {
153 result.insert({c, ByteArrayUtil::extractInt(rec1, i, 3, false)});
154 }
155
156 return result;
157}
158
159void
160FileDataAdapter::setContent(
161 std::uint8_t numRecord, const std::vector<std::uint8_t>& content)
162{
163 mRecords[numRecord] = content;
164}
165
166void
167FileDataAdapter::setCounter(
168 std::uint8_t numCounter, const std::vector<std::uint8_t>& content)
169{
170 setContent(1, content, (numCounter - 1) * 3);
171}
172
173void
174FileDataAdapter::setContent(
175 std::uint8_t numRecord,
176 const std::vector<std::uint8_t>& content,
177 int offset)
178{
179 std::vector<std::uint8_t> newContent;
180 const int newLength = static_cast<int>(offset + content.size());
181
182 const auto it = mRecords.find(numRecord);
183 if (it == mRecords.end()) {
184 newContent = std::vector<std::uint8_t>(newLength);
185
186 } else {
187 const std::vector<std::uint8_t> oldContent = it->second;
188 if (static_cast<int>(oldContent.size()) <= offset) {
189 newContent = std::vector<std::uint8_t>(newLength);
190 System::arraycopy(oldContent, 0, newContent, 0, oldContent.size());
191
192 } else if (static_cast<int>(oldContent.size()) < newLength) {
193 newContent = std::vector<std::uint8_t>(newLength);
194 System::arraycopy(oldContent, 0, newContent, 0, offset);
195
196 } else {
197 newContent = oldContent;
198 }
199 }
200
201 System::arraycopy(content, 0, newContent, offset, content.size());
202
203 mRecords[numRecord] = newContent;
204}
205
206void
207FileDataAdapter::fillContent(
208 std::uint8_t numRecord,
209 const std::vector<std::uint8_t>& content,
210 int offset)
211{
212 std::vector<uint8_t> contentLeftPadded = content;
213
214 if (offset != 0) {
215 contentLeftPadded = std::vector<std::uint8_t>(offset + content.size());
216 System::arraycopy(
217 content, 0, contentLeftPadded, offset, content.size());
218 }
219
220 const auto it = mRecords.find(numRecord);
221 if (it == mRecords.end()) {
222 mRecords[numRecord] = contentLeftPadded;
223 } else {
224 /*
225 * Make sure it's a non-const reference as it is updated in-place in the
226 'else' section
227 */
228 std::vector<std::uint8_t>& actualContent = it->second;
229
230 if (actualContent.size() < contentLeftPadded.size()) {
231 for (int i = 0; i < static_cast<int>(actualContent.size()); i++) {
232 contentLeftPadded[i] |= actualContent[i];
233 }
234
235 mRecords[numRecord] = contentLeftPadded;
236 } else {
237 for (int i = 0; i < static_cast<int>(contentLeftPadded.size());
238 i++) {
239 actualContent[i] |= contentLeftPadded[i];
240 }
241 }
242 }
243}
244
245void
246FileDataAdapter::addCyclicContent(const std::vector<std::uint8_t>& content)
247{
248 std::vector<std::uint8_t> descendingKeys;
249
250 for (auto it = mRecords.rbegin(); it != mRecords.rend(); ++it) {
251 descendingKeys.push_back(it->first);
252 }
253
254 for (const auto& i : descendingKeys) {
255 mRecords[static_cast<uint8_t>(i + 1)] = mRecords[i];
256 }
257
258 mRecords[static_cast<std::uint8_t>(1)] = content;
259}
260
261std::ostream&
262operator<<(std::ostream& os, const FileDataAdapter& fda)
263{
264 os << "FILE_DATA_ADAPTER: {"
265 << "RECORDS = " << fda.mRecords << "}";
266
267 return os;
268}
269
270}
271}
272}
std::ostream & operator<<(std::ostream &os, const CalypsoCardAdapter &cca)