Keyple Card Generic C++ Library - 4.0.0
Component of the Keyple C++ middleware
CardTransactionManagerAdapter.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/generic/CardTransactionManagerAdapter.hpp"
15
16#include <memory>
17#include <string>
18#include <vector>
19
20#include "keyple/card/generic/ApduRequestAdapter.hpp"
21#include "keyple/card/generic/CardRequestAdapter.hpp"
22#include "keyple/core/util/ApduUtil.hpp"
23#include "keyple/core/util/ByteArrayUtil.hpp"
24#include "keyple/core/util/HexUtil.hpp"
25#include "keyple/core/util/KeypleAssert.hpp"
26#include "keyple/core/util/cpp/exception/Exception.hpp"
27#include "keypop/card/CardBrokenCommunicationException.hpp"
28#include "keypop/card/CardResponseApi.hpp"
29#include "keypop/card/ChannelControl.hpp"
30#include "keypop/card/ProxyReaderApi.hpp"
31#include "keypop/card/ReaderBrokenCommunicationException.hpp"
32#include "keypop/card/UnexpectedStatusWordException.hpp"
33#include "keypop/reader/CardCommunicationException.hpp"
34#include "keypop/reader/InvalidCardResponseException.hpp"
35#include "keypop/reader/ReaderCommunicationException.hpp"
36
37namespace keyple {
38namespace card {
39namespace generic {
40
41using keyple::core::util::ApduUtil;
42using keyple::core::util::Assert;
43using keyple::core::util::ByteArrayUtil;
44using keyple::core::util::HexUtil;
45using keyple::core::util::cpp::exception::Exception;
46using keypop::card::CardBrokenCommunicationException;
47using keypop::card::CardResponseApi;
48using keypop::card::ProxyReaderApi;
49using keypop::card::ReaderBrokenCommunicationException;
50using keypop::card::UnexpectedStatusWordException;
51using keypop::reader::CardCommunicationException;
52using keypop::reader::InvalidCardResponseException;
53using keypop::reader::ReaderCommunicationException;
54
55const std::string CardTransactionManagerAdapter::APDU_COMMAND = "apduCommand";
56
57CardTransactionManagerAdapter::CardTransactionManagerAdapter(
58 std::shared_ptr<CardReader> reader, const std::shared_ptr<SmartCard> card)
59: mReader(reader)
60{
61 Assert::getInstance().notNull(reader, "reader").notNull(card, "card");
62}
63
64CardTransactionManager&
65CardTransactionManagerAdapter::prepareApdu(const std::string& apduCommand)
66{
67 Assert::getInstance()
68 .notEmpty(apduCommand, APDU_COMMAND)
69 .isTrue(HexUtil::isValid(apduCommand), APDU_COMMAND);
70
71 prepareApdu(HexUtil::toByteArray(apduCommand));
72
73 return *this;
74}
75
76CardTransactionManager&
77CardTransactionManagerAdapter::prepareApdu(
78 const std::vector<uint8_t>& apduCommand)
79{
80 Assert::getInstance().isInRange(
81 static_cast<int>(apduCommand.size()), 5, 261, "length");
82
83 mApduRequests.push_back(std::make_shared<ApduRequestAdapter>(apduCommand));
84
85 return *this;
86}
87
88CardTransactionManager&
89CardTransactionManagerAdapter::prepareApdu(
90 const uint8_t cla,
91 const uint8_t ins,
92 const uint8_t p1,
93 const uint8_t p2,
94 const std::vector<uint8_t>& dataIn,
95 const uint8_t le)
96{
97 mApduRequests.push_back(
98 std::make_shared<ApduRequestAdapter>(
99 ApduUtil::build(cla, ins, p1, p2, dataIn, le)));
100
101 return *this;
102}
103
104CardTransactionManager&
105CardTransactionManagerAdapter::prepareApdu(
106 const uint8_t cla,
107 const uint8_t ins,
108 const uint8_t p1,
109 const uint8_t p2,
110 const std::vector<uint8_t>& dataIn)
111{
112 mApduRequests.push_back(
113 std::make_shared<ApduRequestAdapter>(
114 ApduUtil::build(cla, ins, p1, p2, dataIn)));
115
116 return *this;
117}
118
119CardTransactionManager&
120CardTransactionManagerAdapter::processCommands(
121 const ChannelControl channelControl)
122{
123 mApduResponses.clear();
124
125 if (mApduRequests.empty()) {
126 return *this;
127 }
128
129 std::shared_ptr<CardResponseApi> cardResponse;
130
131 try {
132 auto cardRequest
133 = std::make_shared<CardRequestAdapter>(mApduRequests, false);
134 auto control = channelControl == ChannelControl::CLOSE_AFTER
135 ? keypop::card::ChannelControl::CLOSE_AFTER
136 : keypop::card::ChannelControl::KEEP_OPEN;
137
138 cardResponse = std::dynamic_pointer_cast<ProxyReaderApi>(mReader)
139 ->transmitCardRequest(cardRequest, control);
140
141 } catch (const ReaderBrokenCommunicationException& e) {
142 mApduRequests.clear();
143 throw ReaderCommunicationException("Reader communication error", e);
144
145 } catch (const CardBrokenCommunicationException& e) {
146 mApduRequests.clear();
147 throw CardCommunicationException("Card communication error", e);
148
149 } catch (const UnexpectedStatusWordException& e) {
150 mApduRequests.clear();
151 throw InvalidCardResponseException("APDU error", e);
152 }
153
154 mApduRequests.clear();
155
156 for (const auto& apduResponse : cardResponse->getApduResponses()) {
157 mApduResponses.push_back(apduResponse->getApdu());
158 }
159
160 return *this;
161}
162
163const std::vector<std::vector<uint8_t>>
164CardTransactionManagerAdapter::getResponsesAsByteArrays()
165{
166 return mApduResponses;
167}
168
169const std::vector<std::string>
170CardTransactionManagerAdapter::getResponsesAsHexStrings()
171{
172 std::vector<std::string> apduResponsesHex;
173
174 for (const auto& bytes : mApduResponses) {
175 apduResponsesHex.push_back(HexUtil::toHex(bytes));
176 }
177
178 return apduResponsesHex;
179}
180
181} /* namespace generic */
182} /* namespace card */
183} /* namespace keyple */