Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
CommandReadRecordMultiple.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/CommandReadRecordMultiple.hpp"
15
16#include <map>
17#include <memory>
18#include <vector>
19
20#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
21#include "keyple/card/calypso/CardAccessForbiddenException.hpp"
22#include "keyple/card/calypso/CardDataAccessException.hpp"
23#include "keyple/card/calypso/CardIllegalParameterException.hpp"
24#include "keyple/card/calypso/CardSecurityContextException.hpp"
25#include "keyple/core/util/ApduUtil.hpp"
26#include "keyple/core/util/HexUtil.hpp"
27#include "keyple/core/util/cpp/Arrays.hpp"
28#include "keyple/core/util/cpp/System.hpp"
29
30namespace keyple {
31namespace card {
32namespace calypso {
33
34using keyple::core::util::ApduUtil;
35using keyple::core::util::HexUtil;
36using keyple::core::util::cpp::Arrays;
37using keyple::core::util::cpp::System;
38
39const std::map<int, const std::shared_ptr<Command::StatusProperties>>
40 CommandReadRecordMultiple::STATUS_TABLE = [] {
41 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
42 Command::STATUS_TABLE);
43
44 m.insert(
45 {{0x6700,
46 std::make_shared<Command::StatusProperties>(
47 "Lc value not supported",
48 typeid(CardIllegalParameterException))},
49 {0x6981,
50 std::make_shared<Command::StatusProperties>(
51 "Incorrect EF type: Binary EF",
52 typeid(CardDataAccessException))},
53 {0x6982,
54 std::make_shared<Command::StatusProperties>(
55 "Security conditions not fulfilled (PIN code not presented,"
56 " encryption required)",
57 typeid(CardSecurityContextException))},
58 {0x6985,
59 std::make_shared<Command::StatusProperties>(
60 "Access forbidden (Never access mode, Stored value log file"
61 " and a Stored value operation was done during the current "
62 "session)",
63 typeid(CardAccessForbiddenException))},
64 {0x6986,
65 std::make_shared<Command::StatusProperties>(
66 "Incorrect file type: the Current File is not an EF. "
67 "Supersedes 6981h",
68 typeid(CardDataAccessException))},
69 {0x6A80,
70 std::make_shared<Command::StatusProperties>(
71 "Incorrect command data (incorrect Tag, incorrect Length, "
72 "R. Length > RecSize, R. Offset + R. Length > RecSize, R. "
73 "Length = 0)",
74 typeid(CardIllegalParameterException))},
75 {0x6A82,
76 std::make_shared<Command::StatusProperties>(
77 "File not found", typeid(CardDataAccessException))},
78 {0x6A83,
79 std::make_shared<Command::StatusProperties>(
80 "Record not found (record index is 0, or above NumRec)",
81 typeid(CardDataAccessException))},
82 {0x6B00,
83 std::make_shared<Command::StatusProperties>(
84 "P1 or P2 value not supported",
85 typeid(CardIllegalParameterException))},
86 {0x6200,
87 std::make_shared<Command::StatusProperties>(
88 "Successful execution, partial read only: issue another "
89 "Read Record Multiple from record (P1 + (Size of returned "
90 "data) / (R. Length)) to continue reading")}});
91 return m;
92 }();
93
94CommandReadRecordMultiple::CommandReadRecordMultiple(
95 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
96 transactionContext,
97 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
98 std::uint8_t sfi,
99 std::uint8_t recordNumber,
100 std::uint8_t offset,
101 std::uint8_t length)
102: Command(
103 CardCommandRef::READ_RECORD_MULTIPLE,
104 nullptr,
105 transactionContext,
106 commandContext)
107, mSfi(sfi)
108, mRecordNumber(recordNumber)
109, mOffset(offset)
110, mLength(length)
111{
112 const uint8_t p2 = (sfi * 8 + 5);
113 const std::vector<uint8_t> dataIn = {0x54, 0x02, offset, length};
114
115 /* APDU Case 4 - always outside secure session */
116 setApduRequest(
117 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
118 transactionContext->getCard()->getCardClass().getValue(),
119 getCommandRef().getInstructionByte(),
120 recordNumber,
121 p2,
122 dataIn)));
123
124 std::stringstream extraInfo;
125 extraInfo << "SFI:" << sfi << "h, "
126 << "RECORD_NUMBER:" << recordNumber << ", "
127 << "OFFSET:" << offset << ", "
128 << "LENGTH:" << length;
129
130 addSubName(extraInfo.str());
131}
132
133void
134CommandReadRecordMultiple::finalizeRequest()
135{
136 /* NOP */
137}
138
139bool
140CommandReadRecordMultiple::isCryptoServiceRequiredToFinalizeRequest() const
141{
142 return false;
143}
144
145bool
146CommandReadRecordMultiple::synchronizeCryptoServiceBeforeCardProcessing()
147{
148 return true;
149}
150
151void
152CommandReadRecordMultiple::parseResponse(
153 std::shared_ptr<ApduResponseApi> apduResponse)
154{
155 if (!setApduResponseAndCheckStatusInBestEffortMode(apduResponse)) {
156 return;
157 }
158
159 const std::vector<std::uint8_t> dataOut = apduResponse->getDataOut();
160 const int nbRecords = static_cast<int>(dataOut.size()) / mLength;
161
162 for (int i = 0; i < nbRecords; i++) {
163 getTransactionContext()->getCard()->setContent(
164 mSfi,
165 static_cast<uint8_t>(mRecordNumber + i),
166 Arrays::copyOfRange(dataOut, i * mLength, (i + 1) * mLength),
167 mOffset);
168 }
169}
170
171const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
172CommandReadRecordMultiple::getStatusTable() const
173{
174 return STATUS_TABLE;
175}
176
177} /* namespace calypso */
178} /* namespace card */
179} /* namespace keyple */