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