Is there a variant of this that is valid c++?
I think not.
The following code is valid C++, and uses a more "traditional hex conversion" process.
Confirm and remove the leading '0x', also confirm that all chars are
hex characters.
modifyFor_SDFE() - 'space delimited format extraction'
This function inserts spaces around the two char byte descriptors.
Note that this function also adds a space char at front and back of the modified string. This new string is used to create and initialize a std::stringstream (ss1).
- By inserting the spaces, the normal stream "formatted extraction" works cleanly
The code extracts each hex value, one by one, and pushes each into the vector, and ends when last byte is pushed (stream.eof()). Note the vector automatically grows as needed (no overflow will occur).
Note that the '0x' prefix is not needed .. because the stream mode is set to hex.
Note that the overflow concern (expressed above as "0x22...be7 is likely to overflow." has been simply side-stepped, by reading only a byte at a time. It might be convenient in future efforts to use much bigger hex strings.
#include <iostream>
using std::cout, std::cerr, std::endl, std::hex,
std::dec, std::cin, std::flush; // c++17
#include <iomanip>
using std::setw, std::setfill;
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
#include <vector>
using std::vector;
typedef vector<uint8_t> UI8Vec_t;
#include <cstdint>
#include <cassert>
class F889_t // Functor ctor and dtor use compiler provided defaults
{
bool verbose;
public:
int operator()(int argc, char* argv[]) // functor entry
{
verbose = ( (argc > 1) ? ('V' == toupper(argv[1][0])) : false );
return exec(argc, argv);
}
// 2 lines
private:
int exec(int , char** )
{
UI8Vec_t resultVec; // output
// example1 input
// string data1 = "0x229597354972973aabbe7"; // 23 chars, hex string
// to_ui8_vec(resultVec, data1);
// cout << (verbose ? "" : "\n") << " vector result "
// << show(ui8Vec); // show results
// example2 input 46 chars (no size limit)
string data = "0x330508465083084bBCcf87eBBaa379279543795922fF";
to_ui8_vec (resultVec, data);
cout << (verbose ? " vector elements " : "\n ")
<< show(resultVec) << endl; // show results
if(verbose) { cout << "\n F889_t::exec() (verbose) ("
<< __cplusplus << ")" << endl; }
return 0;
} // int exec(int, char**)
// 7 lines
void to_ui8_vec(UI8Vec_t& retVal, // output (pass by reference)
string sData) // input (pass by value)
{
if(verbose) { cout << "\n input data '" << sData
<< "' (" << sData.size() << " chars)" << endl;}
{ // misc format checks:
size_t szOrig = sData.size();
{
// confirm leading hex indicator exists
assert(sData.substr(0,2) == string("0x"));
sData.erase(0,2); // discard leading "0x"
}
size_t sz = sData.size();
assert(sz == (szOrig - 2)); // paranoia
// to test that this will detect any typos in data:
// temporarily append or insert an invalid char, i.e. sData += 'q';
assert(sData.find_first_not_of("0123456789abcdefABCDEF") == std::string::npos);
}
modifyFor_SDFE (sData); // SDFE - 'Space Delimited Formatted Extraction'
stringstream ss1(sData); // create / initialize stream with SDFE
if(verbose) { cout << " SDFE data '" << ss1.str() // echo init
<< "' (" << sData.size() << " chars)" << endl; }
extract_values_from_SDFE_push_back_into_vector(retVal, ss1);
} // void to_ui8_vec (vector<uint8_t>&, string)
// 13 lines
// modify s (of any size) for 'Space Delimited Formatted Extraction'
void modifyFor_SDFE (string& s)
{
size_t indx = s.size();
while (indx > 2)
{
indx -= 2;
s.insert (indx, 1, ' '); // indx, count, delimiter
}
s.insert(0, 1, ' '); // delimiter at front of s
s += ' '; // delimiter at tail of s
} // void modifyFor_SDFE (string&)
// 6 lines
void extract_values_from_SDFE_push_back_into_vector(UI8Vec_t& retVal,
stringstream& ss1)
{
do {
uint n = 0;
ss1 >> hex >> n; // use SDFE, hex mode - extract one field at a time
if(!ss1.good()) // check ss1 state
{
if(ss1.eof()) break; // quietly exit, this is a normal stream exit
// else make some noise before exit loop
cerr << "\n err: data input line invalid [" << ss1.str() << ']' << endl; break;
}
retVal.push_back(static_cast<uint8_t>(n & 0xff)); // append to vector
} while(true);
} // void extract_from_SDFE_push_back_to_vector(UI8Vec_t& , string)
// 6 lines
string show(const UI8Vec_t& ui8Vec)
{
stringstream ss ("\n ");
for (uint i = 0; i < ui8Vec.size(); ++i) {
ss << setfill('0') << setw(2) << hex
<< static_cast<int>(ui8Vec[i]) << ' '; }
if(verbose) { ss << " (" << dec << ui8Vec.size() << " elements)"; }
return ss.str();
}
// 5 lines
}; // class F889_t
int main(int argc, char* argv[]) { return F889_t()(argc, argv); }
Typical outputs when invoked with 'verbose' second parameter
$ ./dumy889 verbose
input data '0x330508465083084bBCcf87eBBaa379279543795922fF' (46 chars)
SDFE data ' 33 05 08 46 50 83 08 4b BC cf 87 eB Ba a3 79 27 95 43 79 59 22 fF ' (67 chars)
vector elements 33 05 08 46 50 83 08 4b bc cf 87 eb ba a3 79 27 95 43 79 59 22 ff (22 elements)
When invoked with no parameters
$ ./dumy889
33 05 08 46 50 83 08 4b bc cf 87 eb ba a3 79 27 95 43 79 59 22 ff
The line counts do not include empty lines, nor lines that are only a comment or only a brace. You may count the lines as you wish.