Skip to content

Commit 8f0749c

Browse files
committed
Refactor container constructors and implement robust Terminal ID hex string parsing.
1 parent e12c53d commit 8f0749c

2 files changed

Lines changed: 29 additions & 21 deletions

File tree

include/open_loop_service.h

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,14 +1441,7 @@ namespace open_loop {
14411441
* @note The `explicit` keyword prevents implicit conversions (e.g., from an integer),
14421442
* which improves type safety.
14431443
*/
1444-
explicit container(const std::time_t card_effective_date_in_minutes) noexcept
1445-
: card_effective_date_(card_effective_date_in_minutes) {
1446-
// The constructor immediately propagates the effective date to its time-sensitive
1447-
// child objects. This ensures that the container and its parts are always in a
1448-
// consistent state from the moment of creation.
1449-
validation_.set_card_effective_date(card_effective_date_in_minutes);
1450-
history_.set_card_effective_date(card_effective_date_in_minutes);
1451-
}
1444+
container() = default;
14521445

14531446
/**
14541447
* @brief Sets the `general` data block for the CSA.
@@ -1952,6 +1945,8 @@ namespace open_loop {
19521945
static constexpr uint32_t TERMINAL_ID_MAX = 0xFFFFFF;
19531946
//! The maximum value for the RFU field (stored in 4 bits: 2^4 - 1).
19541947
static constexpr uint8_t RFU_MAX = 0x0F;
1948+
//! The required length of a terminal ID hex string (2 chars per byte for 3 bytes).
1949+
static constexpr size_t TERMINAL_ID_HEX_LENGTH = 6;
19551950

19561951
/**
19571952
* @brief Default constructor. Creates a record with all fields initialized to zero.
@@ -1995,13 +1990,32 @@ namespace open_loop {
19951990
}
19961991

19971992
/**
1998-
* @brief Sets the Terminal ID.
1999-
* @param id The terminal's unique identifier. What to send: A value in the range [0, 0xFFFFFF].
2000-
* @throws std::out_of_range if the ID exceeds the 24-bit limit.
1993+
* @brief Sets the Terminal ID from a hexadecimal string.
1994+
* @param hex_id The terminal's unique identifier as a hex string.
1995+
* What to send: A 6-character, case-insensitive string containing only
1996+
* hexadecimal characters (0-9, A-F). Example: "1122AA".
1997+
* @throws std::invalid_argument if `hex_id` is not exactly 6 characters long.
1998+
* @throws std::out_of_range if `hex_id` contains invalid characters or represents a value > 0xFFFFFF.
20011999
*/
2002-
void set_terminal_id(const uint32_t id) {
2003-
if (id > TERMINAL_ID_MAX) throw std::out_of_range("Terminal ID exceeds 24-bit limit.");
2004-
terminal_id_ = id;
2000+
void set_terminal_id(const std::string& hex_id) {
2001+
// First, perform a quick and inexpensive check on the string length.
2002+
if (hex_id.size() != TERMINAL_ID_HEX_LENGTH)
2003+
throw std::invalid_argument("Terminal ID hex string must be exactly 6 characters.");
2004+
2005+
// Use a stringstream for a robust conversion from hex string to an integer.
2006+
unsigned long long value = 0;
2007+
std::stringstream ss;
2008+
ss << std::hex << hex_id; // Tell the stream to interpret the input as hexadecimal.
2009+
2010+
// Try to extract the value and perform comprehensive validation.
2011+
// 1. `!(ss >> value)`: Fails if the string contains non-hex characters (e.g., "A1B2G3").
2012+
// 2. `ss.rdbuf()->in_avail() != 0`: Fails if there are leftover characters after a valid parse,
2013+
// which handles cases where the stream stops parsing early.
2014+
// 3. `value > TERMINAL_ID_MAX`: Fails if the parsed number exceeds the 24-bit limit.
2015+
if (!(ss >> value) || ss.rdbuf()->in_avail() != 0 || value > TERMINAL_ID_MAX)
2016+
throw std::out_of_range("Terminal ID string is invalid or its value is out of the 24-bit range.");
2017+
// If all checks pass, safely cast and assign the value.
2018+
terminal_id_ = static_cast<uint32_t>(value);
20052019
}
20062020

20072021
/**
@@ -2745,12 +2759,7 @@ namespace open_loop {
27452759
* @param card_effective_date_in_minutes The card's effective date. What to send: A `std::time_t`
27462760
* value representing minutes since the Unix epoch.
27472761
*/
2748-
explicit container(const std::time_t card_effective_date_in_minutes) noexcept
2749-
: card_effective_date_(card_effective_date_in_minutes) {
2750-
// Immediately propagate the effective date to ensure a consistent state.
2751-
validation_.set_card_effective_date(card_effective_date_in_minutes);
2752-
history_.set_card_effective_date(card_effective_date_in_minutes);
2753-
}
2762+
container() = default;
27542763

27552764
void set_general(const general& gen) noexcept {
27562765
general_ = gen;

test/main.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include <iostream>
22
#include <vector>
33
#include <iomanip>
4-
#include <chrono>
54
#include <cassert>
65
#include <stdexcept>
76
#include <functional>

0 commit comments

Comments
 (0)