In C++ I can initialize a vector using
std::vector<uint8_t> data = {0x01, 0x02, 0x03};
For convenience (I have python byte strings that naturally output in a dump of hex), I would like to initialize for a non-delimited hex value of the form:
std::vector<uint8_t> data = 0x229597354972973aabbe7;
Is there a variant of this that is valid c++?
Combining comments from Evg, JHbonarius and 1201ProgramAlarm:
The answer is that there is no direct way to group but a long hex value into a vector, however, using user defined literals provides a clever notation improvement.
First, using RHS 0x229597354972973aabbe7 anywhere in the code will fail because because unsuffixed literals are assumed to be of type int and will fail to be contained in the register. In MSVC, result in E0023 "integer constant is too large". Limiting to smaller hex sequences or exploring large data types may be possible with suffixed notation, but this would ruin any desire for simplicity.
Manual conversion is necessary, but user defined literals may provide a slightly more elegant notation. For example, we can enable conversion of a hex sequence to a vector with
std::vector<uint8_t> val1 = 0x229597354972973aabbe7_hexvec;
std::vector<uint8_t> val2 = "229597354972973aabbe7"_hexvec;
using the following code:
#include <vector>
#include <iostream>
#include <string>
#include <algorithm>
// Quick Utlity function to view results:
std::ostream & operator << (std::ostream & os, std::vector<uint8_t> & v)
{
for (const auto & t : v)
os << std::hex << (int)t << " ";
return os;
}
std::vector<uint8_t> convertHexToVec(const char * str, size_t len)
{
// conversion takes strings of form "FFAA54" or "0x11234" or "0X000" and converts to a vector of bytes.
// Get the first two characters and skip them if the string starts with 0x or 0X for hex specification:
std::string start(str, 2);
int offset = (start == "0x" || start == "0X") ? 2 : 0;
// Round up the number of groupings to allow for ff_hexvec fff_hexvec and remove the offset to properly count 0xfff_hexvec
std::vector<uint8_t> result((len + 1 - offset) / 2);
size_t ind = result.size() - 1;
// Loop from right to left in in pairs of two but watch out for a lone character on the left without a pair because 0xfff_hexvec is valid:
for (const char* it = str + len - 1; it >= str + offset; it -= 2) {
int val = (str + offset) > (it - 1); // check if taking 2 values will run off the start and use this value to reduce by 1 if we will
std::string s(std::max(it - 1, str + offset), 2 - val);
result[ind--] = (uint8_t)stol(s, nullptr, 16);
}
return result;
}
std::vector<uint8_t> operator"" _hexvec(const char*str, std::size_t len)
{
// Handles the conversion form "0xFFAABB"_hexvec or "12441AA"_hexvec
return convertHexToVec(str, len);
}
std::vector<uint8_t> operator"" _hexvec(const char*str)
{
// Handles the form 0xFFaaBB_hexvec and 0Xf_hexvec
size_t len = strlen(str);
return convertHexToVec(str, len);
}
int main()
{
std::vector<uint8_t> v;
std::vector<uint8_t> val1 = 0x229597354972973aabbe7_hexvec;
std::vector<uint8_t> val2 = "229597354972973aabbe7"_hexvec;
std::cout << val1 << "\n";
std::cout << val2 << "\n";
return 0;
}
The coder must decide whether this is superior to implementing and using a more traditional convertHexToVec("0x41243124FF") function.
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.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 12 months ago.
The community is reviewing whether to reopen this question as of 11 months ago.
Improve this question
I am given a text file with a number given to me in hex and I need to increment that hex number through each line if the file. How would I go about this in C++. Ex:
ORG 100 /Origin of Program is Hex 100
LDA ADS 100 /Load first address of operands
STA PTR 101 /Store in Pointer
LDA NBR 102 /Load minus 10
STA CTR 103 /stor in counter
CLA 104 /Clear Accumulator
LOP, ADD PTR I 105 /Add an operand to AC Indirect
ISZ PTR 106 /Increment Pointer
ISZ CTR 107 /Increment Counter
BUN LOP 108 /Repeat Loop again
STA SUM 109 /Store Sum
HLT 10A /Halt
ADS, HEX 150 10B
It can be difficult to know where to get started when faced with a data parsing problem. A solid approach to most problems is to read each line into a std::basic_string. Then work to parse the information you need from the string.
There are many ways to approach isolating the data you want from a string. From a simple character-by-character approach working from the start of the string to the end, or by using the very good string handling tools provided by std::string. In your case, the data you are interested in, the hex-digits, are characters 16 - 18 within each line. This makes it easy to use std::basic_string::substr member function to capture that substring of hex-digits in a string of its own. (If the value you want is the value after HEX, then just change to search for "HEX" as a substring in each line and then read the value after it)
For example, you can pass the filename to read as the first argument to your program and then read each line and isolate the hex-digits with something similar to:
#include <iostream>
#include <fstream>
/* if you need a constant, declare or #define them */
const int COL = 16; /* beginning column of hex value */
const int HLEN = 3; /* max number of hex digits */
const int HBASE = 16; /* base for stoul */
int main (int argc, char **argv) {
if (argc < 2) { /* validate at least 1-argument given for filename */
std::cerr << "error: filename argument required\n" <<
"usage: " << argv[0] << " filename\n";
return 1;
}
std::ifstream f (argv[1]); /* open filename provided as 1st argument */
if (!f.is_open()) { /* validate file is open for reading */
std::cerr << "file open failed: " << argv[1] << '\n';
return 1;
}
std::string s{}; /* string to hold line */
while (getline (f, s)) { /* read each line */
unsigned long val = 0;
std::string ss = s.substr(COL, HLEN); /* substring of hex digits */
...
Here you would also want to ignore the lines where characters 16 - 18 are simply whitespace (and you can add additional tests if you like to validate that each character is a valid hex-digit or blank -- that is left to you). To check if all characters are whitespace of either " \t\n" you can use the std::basic_string::find_first_not_of member function, e.g.
/* validate not all whitespace (optional all hex-digits) */
if (ss.find_first_not_of (" \t\n") != std::string::npos) {
...
With the hex-digits substring isolated in the string ss, you can now convert the hex-digits to an unsigned long value using std::stoul. While you can simply write val = std::stoul(ss, nullptr, 16);, you really need to use try/catch exception handling to catch and handle any error that may arise. The try/catch syntax can look a little awkward at first, but it boils down to (in pseudo code):
try {
/* your code here */
}
catch ( /* type of exception */ ) {
/* how you handle the error */
}
In the case of your hex-digit conversion with std::stoul you can use something like:
try { /* try/catch conversion of substing from hex-string to val */
val = std::stoul(ss, nullptr, 16);
std::cout << val << " -> " << (val + 1) << '\n';
}
catch (std::invalid_argument const& ex) { /* invalid argument */
std::cout << "std::invalid_argument::what(): " << ex.what() << '\n';
}
catch (std::out_of_range const& ex) { /* out-of-range */
std::cout << "std::out_of_range::what(): " << ex.what() << '\n';
}
(note: with only three hex-digits you won't have an out_of_range exception, but that handler is included for completeness)
Putting the entire program together and adding the std::ios::hex and std::ios::basefield format flags to std::cout so val is output in proper hexadecimal format you would have:
#include <iostream>
#include <fstream>
/* if you need a constant, declare or #define them */
const int COL = 16; /* beginning column of hex value */
const int HLEN = 3; /* max number of hex digits */
const int HBASE = 16; /* base for stoul */
int main (int argc, char **argv) {
if (argc < 2) { /* validate at least 1-argument given for filename */
std::cerr << "error: filename argument required\n" <<
"usage: " << argv[0] << " filename\n";
return 1;
}
std::ifstream f (argv[1]); /* open filename provided as 1st argument */
if (!f.is_open()) { /* validate file is open for reading */
std::cerr << "file open failed: " << argv[1] << '\n';
return 1;
}
std::string s{}; /* string to hold line */
std::cout.setf(std::ios::hex, std::ios::basefield); /* cout format */
while (getline (f, s)) { /* read each line */
unsigned long val = 0;
std::string ss = s.substr(COL, HLEN); /* substring of hex digits */
/* validate not all whitespace (optional all hex-digits) */
if (ss.find_first_not_of (" \t\n") != std::string::npos) {
try { /* try/catch conversion of substing from hex-string to val */
val = std::stoul(ss, nullptr, 16);
std::cout << val << " -> " << (val + 1) << '\n';
}
catch (std::invalid_argument const& ex) { /* invalid argument */
std::cout << "std::invalid_argument::what(): " << ex.what() << '\n';
}
catch (std::out_of_range const& ex) { /* out-of-range */
std::cout << "std::out_of_range::what(): " << ex.what() << '\n';
}
}
}
}
Example Use/Output
Compiling the code to an executable in ./bin/readhexoper and with your sample data in dat/hexoper.txt, you can see that each set of hex-digits is properly converted in val and then incremented by 1 for your desired result:
$ ./bin/readhexoper dat/hexoper.txt
100 -> 101
101 -> 102
102 -> 103
103 -> 104
104 -> 105
105 -> 106
106 -> 107
107 -> 108
108 -> 109
109 -> 10a
10a -> 10b
10b -> 10c
Obtaining the digits 150 after "HEX"
If your goal was not to increment all values beginning at position 16, but instead increment the value of 150 in the line:
You would only need to change the way you isolate the hex-digits. First with pos = s.find("HEX") to get the position of "HEX" in the string and then skip forward after "HEX" with pos = s.find_first_not_of (" \t\n", pos + sizeof "HEX") which leaves you ready to read the value of 150 after "ADS, HEX" in the final line. You can replace the content of your read-loop with the following:
while (getline (f, s)) { /* read each line */
unsigned long val = 0; /* value to increment */
size_t pos = 0; /* position within s */
/* find "HEX" in s - or read next line */
if ((pos = s.find("HEX")) == std::string::npos) {
continue;
}
/* after "HEX" find start of hex-digit - or read next line */
if ((pos = s.find_first_not_of (" \t\n", pos + sizeof "HEX")) ==
std::string::npos) {
continue;
}
std::string ss = s.substr (pos, HLEN); /* get hex-digit substring */
/* (optional - add check of ss all hex-digits) */
try { /* try/catch conversion of substing from hex-string to val */
val = std::stoul(ss, nullptr, 16);
std::cout << val << " -> " << (val + 1) << '\n';
}
catch (std::invalid_argument const& ex) { /* invalid argument */
std::cout << "std::invalid_argument::what(): " << ex.what() << '\n';
}
catch (std::out_of_range const& ex) { /* out-of-range */
std::cout << "std::out_of_range::what(): " << ex.what() << '\n';
}
}
Example Use/Output
In that case you would have:
$ ./bin/readhexoper dat/hexoper.txt
150 -> 151
There are no shortcuts to learning how to parse information from lines of input. So take it step-by-step, use the reference links and read up on the use of each of the std::string member functions. There is a lot that goes into string handling -- and there are many more ways you can approach this problem. But from an overview standpoint "Read the whole line and then parse what you need from it", will hold in most cases. Let me know if you have further questions.
Is there any way of getting only the numbers from this string input:
h8 f7
If tried fscanf. But, probably i'm using it wrong.
int positionOfTheKnight = 0, finalDestination = 0;
fscanf("%*s%d %*s%d", &positionOfTheKnight, &finalDestination);
cout << positionOfTheKnight << " " << finalDestination;
It shows this following error:
cpp|11|error: cannot convert 'const char*' to 'FILE* {aka _iobuf*}' for argument '1' to 'int fscanf(FILE*, const char*, ...)'|
I made a small sample to demonstrate multiple ways to read the example of OP:
#include <cstdio>
#include <iostream>
#include <string>
int rcToInt(char c, char r)
{
if (c < 'a' || c > 'h' || r < '1' || r > '8') {
std::cerr << "Wrong input!\n";
return -1;
}
return (c - 'a') * 8 + (r - '1'); // convert characters to index
}
int main()
{
{ // using scanf
std::cout << "Using scanf():\n";
char r0, c0, r1, c1;
if (scanf(" %c%c %c%c ", &c0, &r0, &c1, &r1) < 4) {
std::cerr << "Reading move with scanf() failed!\n";
} else {
const int pos0 = rcToInt(c0, r0), pos1 = rcToInt(c1, r1);
if (pos0 >= 0 && pos1 >= 0) {
std::cout << "Got " << c0 << r0 << " -> " << c1 << r1 << '\n';
}
}
}
{ // Yet another way to use scanf():
std::cout << "Using scanf():\n";
char c0[2], r0[2], c1[2], r1[2];
if (scanf("%1[a-h]%1[1-8] %1[a-h]%1[1-8] ", c0, r0, c1, r1) < 4) {
std::cerr << "Reading move with scanf() failed!\n";
} else {
const int pos0 = rcToInt(*c0, *r0), pos1 = rcToInt(*c1, *r1);
if (pos0 >= 0 && pos1 >= 0) {
std::cout << "Got " << c0 << r0 << " -> " << c1 << r1 << '\n';
}
}
}
{ // using std::cin
std::cout << "Using operator>>():\n";
char r0, c0, r1, c1;
if (!(std::cin >> c0 >> r0 >> c1 >> r1)) {
std::cerr << "Reading move with operator>>() failed!\n";
} else {
const int pos0 = rcToInt(c0, r0), pos1 = rcToInt(c1, r1);
if (pos0 >= 0 && pos1 >= 0) {
std::cout << "Got " << c0 << r0 << " -> " << c1 << r1 << '\n';
}
}
}
// There is still the [ENTER] in input queue which must be consumed:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// ...before proceeding
{ // using std::cin
std::cout << "Using std::getline():\n";
std::string line;
if (!std::getline(std::cin, line) || line.size() < 5) {
std::cerr << "Reading move with std::getline() failed!\n";
} else {
const char c0 = line[0], r0 = line[1], c1 = line[3], r1 = line[4];
const int pos0 = rcToInt(c0, r0), pos1 = rcToInt(c1, r1);
if (pos0 >= 0 && pos1 >= 0) {
std::cout << "Got " << c0 << r0 << " -> " << c1 << r1 << '\n';
}
}
}
// done
return 0;
}
Output:
Using scanf():
h8 f7↵
Got h8 -> f7
Using scanf():
f7 h8↵
Got f7 -> h8
Using operator>>():
h8 f7↵
Got h8 -> f7
Using std::getline():
f7 h8↵
Got f7 -> h8
Live Demo on coliru
All four alternatives follow the basic idea to read the input as characters and convert them to a corresponding index in the range of [0, 63] afterwards.
While char might represent characters, it's as well an integral value – specifically the smallest available integral type. In (C and) C++, this is no difference. A character '1' is stored as integer value 33 (assuming ASCII code)). '1' as well as 33 represent the same value. Hence, it is fine (and even recommended) to use character constants for arithmetic computations if appropriate (like in rcToInt() in the above example).
if (scanf(" %c%c %c%c ", &c0, &r0, &c1, &r1) < 4) {
Formatter starts with a space () to consume optionally pending white space.
%c stores one character. Hence, a char* argument (pointing to sufficient storage) has to be provided.
Formatter ends with a space () to consume the terminating ENTER as well.
The return value of scanf() is checked to grant that all 4 arguments will be assigned.
if (scanf(" %1[a-h]%1[1-8] %1[a-h]%1[1-8] ", c0, r0, c1, r1) < 4) {
Formatter starts and ends with a space () to consume surrounding white space (like in the previous example).
%1[a-h] reads a string of length 1 which may consist of characters a, b, ..., h only. There has to be provided storage for an extra byte as that formatter will always store an additional 0-terminator (\0). Hence, the declations char c0[2], r0[2], c1[2], r1[2]; in this case.
%1[1-8] similar like above for the characters 1, 2, ..., 8. Please note, that digits are read as characters.
if (!(std::cin >> c0 >> r0 >> c1 >> r1)) {
Read four char variables using stream input operators.
The iostream header provides a variety of overloaded operator>>s (e.g. std::istream& operator>>(std::istream&, char&)) for this.
The whitespace (occurring before reading c1) is skipped by default setting of std::cin.
if (!std::getline(std::cin, line) || line.size() < 5) {
Read a whole line into a std::string (which is grown appropriately).
Analyze characters in that std::string.
A combination of 3. and 4. would be to read a line with std::getline(), wrap the read line in a std::istringstream to parse it with input stream operators.
Sorry, if I swapped row and column in the above code. I'm no chess expert and not aware of the usual convertions.
I have been programming a while but I am fairly new to C++. I am writing a program that takes an .exe and gets its hex and stores it in and unsigned char array. I can take in the .exe and return its hex fine. My problem is I am having trouble storing the hex in the correct format in the char array.
When I print the array it outputs the hex but I need to add 0x to the front.
Sample output: 04 5F 4B F4 C5 A5
Needed output: 0x04 0x5F 0x4B 0xF4 0xC5 0xA5
I am trying to use hexcode[i] = ("0x%.2X", (unsigned char)c); to store it correctly and it still only seems to return the last two chars without the 0x.
I have also tried hexcode[i] = '0x' + (unsigned char)c; and looked into functions like sprintf.
Can anyone help me get my desired output? Is it even possible?
Full program -
#include <iostream>
unsigned char hexcode[99999] = { 0 };
//Takes exes hex and place it into unsigned char array
int hexcoder(std::string file) {
FILE *sf; //executable file
int i, c;
sf = fopen(file.c_str(), "rb");
if (sf == NULL) {
fprintf(stderr, "Could not open file.", file.c_str());
return 1;
}
for (i = 0;;i++) {
if ((c = fgetc(sf)) == EOF) break;
hexcode[i] = ("0x%.2X", (unsigned char)c);
//Print for debug
std::cout << std::hex << static_cast<int>(hexcode[i]) << ' ';
}
}
int main()
{
std::string file = "shuffle.exe"; // test exe to pass to get hex
hexcoder(file);
system("pause");
return 0;
}
I suppose you want to dump a file in hex format. So maybe it's something like the following code you are looking for.
Note that hexcode is changed to data type char instead of unsigned char such that it can be handled as a string containing printable characters.
int hexcoder(std::string file) {
FILE *sf; //executable file
int i, c;
sf = fopen(file.c_str(), "rb");
if (sf == NULL) {
fprintf(stderr, "Could not open file %s.", file.c_str());
return 1;
}
char hexcode[10000];
char* wptr = hexcode;
for (i = 0;;i++) {
if ((c = fgetc(sf)) == EOF) break;
wptr += sprintf(wptr,"0x%02X ", c);
}
*wptr = 0;
std::cout << hexcode;
return 0;
}
BTW: for printing out a value in hex format one could as well use...
printf("0x%2X ", c)
or
std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << c << " ";
Note that the latter requires #include <iomanip>.
But - in order to not change the semantics of your code too much - I kept the hexcode-string as target.
I have a problem I neither can solve on my own nor find answer anywhere. I have a file contains such a string:
01000000d08c9ddf0115d1118c7a00c04
I would like to read the file in the way, that I would do manually like that:
char fromFile[] =
"\x01\x00\x00\x00\xd0\x8c\x9d\xdf\x011\x5d\x11\x18\xc7\xa0\x0c\x04";
I would really appreciate any help.
I want to do it in C++ (the best would be vc++).
Thank You!
int t194(void)
{
// imagine you have n pair of char, for simplicity,
// here n is 3 (you should recognize them)
char pair1[] = "01"; // note:
char pair2[] = "8c"; // initialize with 3 char c-style strings
char pair3[] = "c7"; //
{
// let us put these into a ram based stream, with spaces
std::stringstream ss;
ss << pair1 << " " << pair2 << " " << pair3;
// each pair can now be extracted into
// pre-declared int vars
int i1 = 0;
int i2 = 0;
int i3 = 0;
// use formatted extractor to convert
ss >> i1 >> i2 >> i3;
// show what happened (for debug only)
std::cout << "Confirm1:" << std::endl;
std::cout << "i1: " << i1 << std::endl;
std::cout << "i2: " << i2 << std::endl;
std::cout << "i3: " << i3 << std::endl << std::endl;
// output is:
// Confirm1:
// i1: 1
// i2: 8
// i3: 0
// Shucks, not correct.
// We know the default radix is base 10
// I hope you can see that the input radix is wrong,
// because c is not a decimal digit,
// the i2 and i3 conversions stops before the 'c'
}
// pre-delcare
int i1 = 0;
int i2 = 0;
int i3 = 0;
{
// so we try again, with radix info added
std::stringstream ss;
ss << pair1 << " " << pair2 << " " << pair3;
// strings are already in hex, so we use them as is
ss >> std::hex // change radix to 16
>> i1 >> i2 >> i3;
// now show what happened
std::cout << "Confirm2:" << std::endl;
std::cout << "i1: " << i1 << std::endl;
std::cout << "i2: " << i2 << std::endl;
std::cout << "i3: " << i3 << std::endl << std::endl;
// output now:
// i1: 1
// i2: 140
// i3: 199
// not what you expected? Though correct,
// now we can see we have the wrong radix for output
// add output radix to cout stream
std::cout << std::hex // add radix info here!
<< "i1: " << i1 << std::endl
// Note: only need to do once for std::cout
<< "i2: " << i2 << std::endl
<< "i3: " << i3 << std::endl << std::endl
<< std::dec;
// output now looks correct, and easily comparable to input
// i1: 1
// i2: 8c
// i3: c7
// So: What next?
// read the entire string of hex input into a single string
// separate this into pairs of chars (perhaps using
// string::substr())
// put space separated pairs into stringstream ss
// extract hex values until ss.eof()
// probably should add error checks
// and, of course, figure out how to use a loop for these steps
//
// alternative to consider:
// read 1 char at a time, build a pairing, convert, repeat
}
//
// Eventually, you should get far enough to discover that the
// extracts I have done are integers, but you want to pack them
// into an array of binary bytes.
//
// You can go back, and recode to extract bytes (either
// unsigned char or uint8_t), which you might find interesting.
//
// Or ... because your input is hex, and the largest 2 char
// value will be 0xff, and this fits into a single byte, you
// can simply static_cast them (I use unsigned char)
unsigned char bin[] = {static_cast<unsigned char>(i1),
static_cast<unsigned char>(i2),
static_cast<unsigned char>(i3) };
// Now confirm by casting these back to ints to cout
std::cout << "Confirm4: "
<< std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(bin[0]) << " "
<< static_cast<int>(bin[1]) << " "
<< static_cast<int>(bin[2]) << std::endl;
// you also might consider a vector (and i prefer uint8_t)
// because push_back operations does a lot of hidden work for you
std::vector<uint8_t> bytes;
bytes.push_back(static_cast<uint8_t>(i1));
bytes.push_back(static_cast<uint8_t>(i2));
bytes.push_back(static_cast<uint8_t>(i3));
// confirm
std::cout << "\nConfirm5: ";
for (size_t i=0; i<bytes.size(); ++i)
std::cout << std::hex << std::setw(2) << std::setfill(' ')
<< static_cast<int>(bytes[i]) << " ";
std::cout << std::endl;
Note: The cout (or ss) of bytes or char can be confusing, not always giving the result you might expect. My background is embedded software, and I have surprisingly small experience making stream i/o of bytes work. Just saying this tends to bias my work when dealing with stream i/o.
// other considerations:
//
// you might read 1 char at a time. this can simplify
// your loop, possibly easier to debug
// ... would you have to detect and remove eoln? i.e. '\n'
// ... how would you handle a bad input
// such as not hex char, odd char count in a line
//
// I would probably prefer to use getline(),
// it will read until eoln(), and discard the '\n'
// then in each string, loop char by char, creating char pairs, etc.
//
// Converting a vector<uint8_t> to char bytes[] can be an easier
// effort in some ways. A vector<> guarantees that all the values
// contained are 'packed' back-to-back, and contiguous in
// memory, just right for binary stream output
//
// vector.size() tells how many chars have been pushed
//
// NOTE: the formatted 'insert' operator ('<<') can not
// transfer binary data to a stream. You must use
// stream::write() for binary output.
//
std::stringstream ssOut;
// possible approach:
// 1 step reinterpret_cast
// - a binary block output requires "const char*"
const char* myBuff = reinterpret_cast<const char*>(&myBytes.front());
ssOut.write(myBuff, myBytes.size());
// block write puts binary info into stream
// confirm
std::cout << "\nConfirm6: ";
std::string s = ssOut.str(); // string with binary data
for (size_t i=0; i<s.size(); ++i)
{
// because binary data is _not_ signed data,
// we need to 'cancel' the sign bit
unsigned char ukar = static_cast<unsigned char>(s[i]);
// because formatted output would interpret some chars
// (like null, or \n), we cast to int
int intVal = static_cast<int>(ukar);
// cast does not generate code
// now the formatted 'insert' operator
// converts and displays what we want
std::cout << std::hex << std::setw(2) << std::setfill('0')
<< intVal << " ";
}
std::cout << std::endl;
//
//
return (0);
} // int t194(void)
The below snippet should be helpful!
std::ifstream input( "filePath", std::ios::binary );
std::vector<char> hex((
std::istreambuf_iterator<char>(input)),
(std::istreambuf_iterator<char>()));
std::vector<char> bytes;
for (unsigned int i = 0; i < hex.size(); i += 2) {
std::string byteString = hex.substr(i, 2);
char byte = (char) strtol(byteString.c_str(), NULL, 16);
bytes.push_back(byte);
}
char* byteArr = bytes.data()
The way I understand your question is that you want just the binary representation of the numbers, i.e. remove the ascii (or ebcdic) part. Your output array will be half the length of the input array.
Here is some crude pseudo code.
For each input char c:
if (isdigit(c)) c -= '0';
else if (isxdigit(c) c -= 'a' + 0xa; //Need to check for isupper or islower)
Then, depending on the index of c in your input array:
if (! index % 2) output[outputindex] = (c << 4) & 0xf0;
else output[outputindex++] = c & 0x0f;
Here is a function that takes a string as in your description, and outputs a string that has \x in front of each digit.
#include <iostream>
#include <algorithm>
#include <string>
std::string convertHex(const std::string& str)
{
std::string retVal;
std::string hexPrefix = "\\x";
if (!str.empty())
{
std::string::const_iterator it = str.begin();
do
{
if (std::distance(it, str.end()) == 1)
{
retVal += hexPrefix + "0";
retVal += *(it);
++it;
}
else
{
retVal += hexPrefix + std::string(it, it+2);
it += 2;
}
} while (it != str.end());
}
return retVal;
}
using namespace std;
int main()
{
cout << convertHex("01000000d08c9ddf0115d1118c7a00c04") << endl;
cout << convertHex("015d");
}
Output:
\x01\x00\x00\x00\xd0\x8c\x9d\xdf\x01\x15\xd1\x11\x8c\x7a\x00\xc0\x04
\x01\x5d
Basically it is nothing more than a do-while loop. A string is built from each pair of characters encountered. If the number of characters left is 1 (meaning that there is only one digit), a "0" is added to the front of the digit.
I think I'd use a proxy class for reading and writing the data. Unfortunately, the code for the manipulators involved is just a little on the verbose side (to put it mildly).
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
struct byte {
unsigned char ch;
friend std::istream &operator>>(std::istream &is, byte &b) {
std::string temp;
if (is >> std::setw(2) >> std::setprecision(2) >> temp)
b.ch = std::stoi(temp, 0, 16);
return is;
}
friend std::ostream &operator<<(std::ostream &os, byte const &b) {
return os << "\\x" << std::setw(2) << std::setfill('0') << std::setprecision(2) << std::hex << (int)b.ch;
}
};
int main() {
std::istringstream input("01000000d08c9ddf115d1118c7a00c04");
std::ostringstream result;
std::istream_iterator<byte> in(input), end;
std::ostream_iterator<byte> out(result);
std::copy(in, end, out);
std::cout << result.str();
}
I do really dislike how verbose iomanipulators are, but other than that it seems pretty clean.
You can try a loop with fscanf
unsigned char b;
fscanf(pFile, "%2x", &b);
Edit:
#define MAX_LINE_SIZE 128
FILE* pFile = fopen(...);
char fromFile[MAX_LINE_SIZE] = {0};
char b = 0;
int currentIndex = 0;
while (fscanf (pFile, "%2x", &b) > 0 && i < MAX_LINE_SIZE)
fromFile[currentIndex++] = b;
I'm trying to construct a string from a byte array (libcrypto++) but I have issues with '0' in order to connect to SQS in c++
The result is almost correct except some '0' go at the end of the string.
std::string shaDigest(const std::string &key = "") {
byte out[64] = {0};
CryptoPP::SHA256().CalculateDigest(out, reinterpret_cast<const byte*>(key.c_str()), key.size());
std::stringstream ss;
std::string rep;
for (int i = 0; i < 64; i++) {
ss << std::hex << static_cast<int>(out[i]);
}
ss >> rep;
rep.erase(rep.begin()+64, rep.end());
return rep;
}
output:
correct : c46268185ea2227958f810a84dce4ade54abc4f42a03153ef720150a40e2e07b
mine : c46268185ea2227958f810a84dce4ade54abc4f42a3153ef72015a40e2e07b00
^ ^
Edit: I'm trying to do the same that hashlib.sha256('').hexdigest() in python does.
If that indeed works, here's the solution with my suggestions incorporated.
std::string shaDigest(const std::string &key = "") {
std::array<byte, 64> out {};
CryptoPP::SHA256().CalculateDigest(out.data(), reinterpret_cast<const byte*>(key.c_str()), key.size());
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (byte b : out) {
ss << std::setw(2) << static_cast<int>(b);
}
// I don't think `.substr(0,64)` is needed here;
// hex ASCII form of 64-byte array should always have 128 characters
return ss.str();
}
You correctly convert bytes in hexadecimal, and it works correctly as soon as the byte value is greater than 15. But below, the first hexa digit is a 0 and is not printed by default. The two absent 0 are for 0x03 -> 3 and 0x0a -> a.
You should use :
for (int i = 0; i < 64; i++) {
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(out[i]);
}
You need to set the width for the integer numbers for the proper zero-padding of numbers with otherwise less than two hexadecimal digits. Note that you need to re-set the width before every number that is inserted into the stream.
Example:
#include <iostream>
#include <iomanip>
int main() {
std::cout << std::hex << std::setfill('0');
for (int i=0; i<0x11; i++)
std::cout << std::setw(2) << i << "\n";
}
Output:
$ g++ test.cc && ./a.out
00
01
02
03
04
05
06
07
08
09
0a
0b
0c
0d
0e
0f
10
For reference:
http://en.cppreference.com/w/cpp/io/manip/setw
http://en.cppreference.com/w/cpp/io/manip/setfill