How can I set a strings value from hex? - c++

for example the text "Book of Summoning"s hex value is "42 6F 6F 6B 20 6F 66 20 53 75 6D 6D 6F 6E 69 6E 67"
so i would want to be able to set the variable as if i set it like string a = "book of summoing";
but using the hex value.
With input like this or something similar.
std::string hex = "42 6F 6F 6B 20 6F 66 20 53 75 6D 6D 6F 6E 69 6E 67";
I want to set a string variable with it so that the string will look like "Book of Summoning";
As if I were to look at this variable in debug mode, each character of the string would have one of these spaced hex values. But of course printing the string would print "Book of Summoning".
if i just new how to do it with one character i could build such a function.
OR if you can do with with decimal instead of hex that will work for me also, as ill just make a function to convert from hex to dec
EDIT:
in the debug mode i can see that the string hex[0] first char 'B' has a 66 beside it, which im guess is the dec value for that character. if i new how to get that value or set a string by setting that value i could do all this but i dont know if i can do that.

Like this:
std::string hex = "42 6F 6F 6B 20 6F 66 20 53 75 6D 6D 6F 6E 69 6E 67";
std::istringstream iss(hex);
int i;
while (iss >> std::hex >> i)
std::cout << static_cast<char>(i);
// alternatively
// s += static_cast<char>(i);
// where s is a std::string
This assumes the input is already sanitized and contains values that fit in a char.
Live demo.

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <iterator>
#include <algorithm>
int main()
{
std::string hex = "42 6F 6F 6B 20 6F 66 20 53 75 6D 6D 6F 6E 69 6E 67";
std::istringstream is( hex );
is >> std::hex;
std::copy( std::istream_iterator<int>( is ), std::istream_iterator<int>(),
std::ostream_iterator<char>( std::cout ) );
std::cout << std::endl;
}
EDIT: I added missed header <sstream>

The algorithm:
start traversing the input string
append in a temporary string the current character
at each space you:
convert the temporary string into a temporary number via strtol (or similar - where you can specify the base) using base 16
reset the temporary string to be empty
get the ASCII character for your temporary number
append it to the final string.
Go on as long as you have character in the input string.

Related

Reading CSV file lines with hex content and convert it to decimal

Here is my CSV file and its contents are in hex.
a3 42 fe 9e 89
a3 43 14 9d cd
a3 43 1e 02 82
a3 43 23 bd 85
a3 43 39 d5 83
a3 43 3e b9 8d
a3 43 3f 44 c0
a3 43 50 c9 49
a3 43 67 29 c8
a3 43 67 43 0d
I need only the second-last value and the code to extract that value is this.
void getvalues(){
std::ifstream data("mydata1.CSV");
int row_count =0;
std::string line;
while(std::getline(data,line))
{
row_count +=1;
std::stringstream lineStream(line);
std::string cell;
int column_count = 0;
while(std::getline(lineStream,cell,' '))
{
column_count+=1;
if ( column_count == 5){
std::cout << std::dec<< cell[0]<< std::endl;
}
}
}
Since I am reading the lines into a string cell, I am unable to do any conversion. At first I tried wrapping the cell with an int but it returns me the ASCII value of the character which is quite obvious and I shouldn't have done that.
If you want to convert a string to an integer, you can use std::stoi, which is included in the string package. By default, you can use stoi as such:
int num = std::stoi(cell)
However since we want to parse a base 16 hex number, then we need to use it like:
int num = std::stoi(cell, 0, 16)
Quick article about this: https://www.includehelp.com/stl/convert-hex-string-to-integer-using-stoi-function-in-cpp-stl.aspx

How can I display an integer variable as thier intended ASCII letters in `cout` when parsing a binary file?

When I use hexdump -C on the command line to examine this MIDI file, we can see that some bytes of this binary file are ASCII letters that are meant to be human readable text.
00000000 4d 54 68 64 00 00 00 06 00 01 00 08 00 78 4d 54 |MThd.........xMT|
000024f0 2f 00 4d 54 72 6b 00 00 00 19 00 ff 21 01 00 00 |/.MTrk......!...|
00002500 ff 03 0c 62 79 20 42 65 65 74 68 6f 76 65 6e 00 |...by Beethoven.|
00002510 ff 2f 00 4d 54 72 6b 00 00 00 18 00 ff 21 01 00 |./.MTrk......!..|
For debugging purposes, when I have a variable that holds an integer that I know represents a string of ASCII characters, I would like to simply display the ASCII characters in cout.
I this case, the first four bytes of the file are 0x4d546864, which represent the letters MThd.
uint32_t n32Bits = 0;
ifs.read((char*)&n32Bits, sizeof(uint32_t));
n32Bits = BigEndianToLittleEndian(n32Bits); // reverse byte order
This is the integer:
std::cout << "n32Bits: " << n32Bits <<std::endl; // 1297377380
I can easily display it as hex:
std::cout << "n32Bits: " << std::hex << n32Bits <<std::endl; // 4d546864
Now, I want this line to output the letters MThd just like hexdump does.:
std::cout << "n32Bits: " << std::ascii << n32Bits <<std::endl; // compile error.
Isn't there some simple built-in way to dump ASCII letters from integers that represent ASCII letters?
There is no formatting spec like std::ascii but there is a string constructor you can use:
std::string int2str((char*)&n32Bits, 4);
std::cout << "n32Bits: " << int2str << std::endl;
This constructor takes a char buffer and length.
There is no built-in function to print raw bytes as an ASCII string the way a hex dump does. You will have to do that yourself manually, eg:
#include <algorithm>
#include <iterator>
#include <cctype>
#include <cstring>
char buffer[sizeof(n32Bits)];
std::memcpy(buffer, &n32Bits, sizeof(n32Bits));
std::transform(std::begin(buffer), std::end(buffer), std::begin(buffer),
[](unsigned char ch){ return std::isprint(ch) ? static_cast<char>(ch) : '.'; }
);
std::cout << "n32Bits: ";
std::cout.write(buffer, sizeof(buffer));
std::cout << std::endl;
Online Demo
int a = 0x4d546864;
// swap_bytes(a);
int b[] = {a, 0};
cout << (char*)b <<endl;

Remove Control Characters out of a string

I have a string given, which contains the following content (so the following lines are stored in a String-variable):
S*⸮
------------------------
K!
NAG 00.10
K"
NMAGICSTAR 2 L V1.0-1
K#
AUFSTELLORT: S 00000000
K$
GERAET NR.: 0000000000
KC
ZULASSUNGS NR.:411107770
K)
BAUART: NAG5A02
K(
ABLAUFDATUM: 2021/04
------------------------
Can anyone help me or give me a short hint how to remove the control codes (so the S*⸮ respectively the K!) out of this string (there is always a small rectangle before the control code, i don't know why it is removed)? So that in the end, it's
------------------------
NAG 00.10
NMAGICSTAR 2 L V1.0-1
AUFSTELLORT: S 00000000
GERAET NR.: 0000000000
ZULASSUNGS NR.:411107770
BAUART: NAG5A02
ABLAUFDATUM: 2021/04
------------------------
Let me finally quote something out of the documentation, maybe it helps:
Each line is max. 24 characters long and must end with LF [0Ah]
Control Code "ESC 'S' 21h LF" means: XON Startsequence with manufacturer code, machine code and dataset code
I am trying to do this whole task on an ESP32/ Arduino IDE (C++).
This is not an anwser. You may use the following code to print you string as integer in hex form. Every 12 characters a wide separation, and every 24 a new line. The arrange makes easier for you to count 24 characters.
#include <iostream>
void dump_str(const std::string&str)
{
int n;
std::cout << std::hex;
for (int i=0; i<str.size(); i++)
{
n = str[i];
if (i%24==0) std::cout << std::endl;
else if (i%12 == 0 ) std::cout <<" ";
if (n<16) std::cout << " " << '0' << n;
else std::cout << " " << n;
}
}
int main ()
{
std::string str ( "some\r\ttest\rst\2\athis is \n a ran\5dom\10g\n\nTake this for granted. To bo or not to be\a\a\t\t");
dump_str(str);
}
Print-out of this example:(meaning of the number can be checked in an ascii table google search.)
73 6f 6d 65 0d 09 74 65 73 74 0d 73 74 02 07 74 68 69 73 20 69 73 20 0a
20 61 20 72 61 6e 05 64 6f 6d 08 67 0a 0a 54 61 6b 65 20 74 68 69 73 20
66 6f 72 20 67 72 61 6e 74 65 64 2e 20 54 6f 20 62 6f 20 6f 72 20 6e 6f
74 20 74 6f 20 62 65 07 07 09 09
Send you string to above function dum_str(string), and copy the resultant table appending to your post.
Here's how to split the string at \r and \n characters. This way you can iterate each line separately.
void str_split(const std::string& in, std::vector<std::string>& out, const std::string& delim=" \t\r\n")
{
std::string::size_type firstPos = in.find_first_not_of(delim);
std::string::size_type secondPos = in.find_first_of(delim, firstPos);
out.clear();
if(firstPos != std::string::npos)
out.push_back( in.substr( firstPos, secondPos - firstPos ) );
while( secondPos != std::string::npos )
{
firstPos = in.find_first_not_of(delim, secondPos);
if(firstPos == std::string::npos)
break;
secondPos = in.find_first_of( delim, firstPos );
out.push_back( in.substr( firstPos, secondPos - firstPos ) );
}
}

Convert special characters(UTF-8)

I am trying to convert charactes à with #include <iconv.h> but i receive garbage �.
This is the code
#include <stdio.h>
#include <string.h>
#include <iconv.h>
#include <iostream>
int main()
{
char *gbk_str = "àèì asdsa sd aä";
char dest_str[100];
char *out = dest_str;
size_t inbytes = strlen(gbk_str);
size_t outbytes = sizeof dest_str;
iconv_t conv = iconv_open("ISO8859-1", "UTF-8");
if (conv == (iconv_t)-1) {
std::cout <<"iconv_open";
return 1;
}
if (iconv(conv, &gbk_str, &inbytes, &out, &outbytes) == (size_t)-1) {
std::cout << "iconv";
return 1;
}
dest_str[sizeof dest_str - outbytes] = 0;
puts(dest_str);
return 0;
}
Come back with :
Itlian character: POLS 6000 Impianto riduzione d. velocità
byte encoding : 50 4f 4c 53 20 36 30 30 30 20 49 6d 70 69 61 6e 74 6f 20 72 69 64 75 7a 69 6f 6e 65 20 64 2e 20 76 65 6c 6f 63 69 74 c3 a0
Converted: POLS 6000 Impianto riduzione d. velocità -> POLS 6000 Impianto riduzione d. velocit340
You have to set your terminal character encoding to ISO8859-1. In my Linux's Mate Terminal it is:
Terminal >> Set Character Encoding >> Central European (WINDOWS-1250)
Then I was able to see correct output from your program. Without this change it was indeed a garbage.

How to get the cout buffer to flush on ubuntu

I recently submitted an assignment that I had started using VS code and the Ubuntu WSL terminal and G++ compiler, but had to switch to Visual Studio 2019 because when I would output several strings on the same line, they would write over each other. The assignment had me read data from a file and place each element into an "ArrayList" (our self made vector class) of "Car" objects and output each cars elements to the user. We would also have to search through the list of cars to find cars of certain models and print all cars of that model. Not only could I not cout all of these elements on the same line, I could not compare elements (strings) with each other. Why would this only happen on Ubuntu? Why can't I clear the cout buffer with std::cout.flush(); or std::cout << std::flush;? Why can't I compare the elements to each other?
I have tried to flush the system in numerous ways (as I have found from other posts) such as: std::cerr, std::cout << std::flush;. The only thing that seems to work is if I use std::endl, however, I need these to be placed on the same line. I also cannot compare two strings using the == operand (or any other). Although, I can compare two int elements just fine.
Here is my (shortened) cars.data (.data was a requirement for the assignment) that held all the cars' elements that were to be stored into an "ArrayList":
1
Tesla
Model 3
Black
2
Chevrolet
Volt
Grey
3
Tesla
Model S
White
4
Nissan
Leaf
White
5
Toyota
Prius
Red
My implementation for storing each element into the "ArrayList":
ArrayList cars_list(15);
std::fstream cars;
cars.open("cars.data");
int tempID;
std::string tempIDstr;
std::string tempMake;
std::string tempModel;
std::string tempColor;
if (cars.is_open())
{
for (int i = 0; !cars.eof(); ++i)
{
std::getline(cars, tempIDstr);
tempID = std::stoi( tempIDstr );
std::getline(cars, tempMake);
std::getline(cars, tempModel);
std::getline(cars, tempColor);
Car tempCar(tempID, tempMake, tempModel, tempColor);
std::cout.flush();
std::cout << tempIDstr << " ";
std::cout.flush();
std::cout << tempMake << " ";
std::cout.flush();
std::cout << tempModel << " ";
std::cout.flush();
std::cout << tempColor << " " << std::endl;
cars_list.push_back(tempCar);
}
}
cars.close();
And a function that I have used to compare strings to search the list:
void searchByMake(ArrayList list)
{
std::string make;
std::cout << "Enter the make you would like to search: ";
std::cin >> make;
std::cin.clear();
std::cin.ignore(10000,'\n');
// Searching through the cars_list for the Make
for (int i = 0; i < list.size(); ++i)
{
Car tempCar = list.get(i);
if (make.compare(tempCar.getMake()) == 0)
{
std::cout << "ID:\t" << tempCar.getID() << "\n"
<< "Make:\t" << tempCar.getMake() << "\n"
<< "Model:\t" << tempCar.getModel() << "\n"
<< "Color:\t" << tempCar.getColor() << "\n\n";
}
}
}
The results of the first segment of code are (I noticed the spaces before each output):
Black 3
Greyvrolet
White S
Whitean
Redusta
The expected output should look like:
1 Tesla Model 3 Black
2 Chevrolet Volt Grey
3 Tesla Model S White
4 Nissan Leaf White
5 Toyota Prius Red
And whenever I try to compare strings the output returns a blank line:
Enter the make you would like to search: Tesla
Expected output would be:
Enter the make you would like to search: Tesla
id: 1
Make: Tesla
Model: Model 3
Color: Black
id: 3
Make: Tesla
Model: Model S
Color: White
My teacher mentioned that the issue may be with Ubuntu itself not being able to clear the buffer even when prompted to, but I still can't find a solution. FYI This is a passed assignment that I can no longer get credit for, this question is strictly out of curiosity and a desire to still use Ubuntu WSL as my development terminal.
Do not control your read loop with !cars.eof() see: Why !.eof() inside a loop condition is always wrong.. The crux of the issue being after your last successful read with the file-position-indicator sitting immediately before end-of-file, no .eofbit() has been set on your stream. You then check !cars.eof() (which tests true) and you proceed.
You then call, e.g. std::getline 4-times never checking the return. The read fails on your very first std::getline(cars, tempIDstr); setting .eofbit(), but you have no way of detecting that, so you continue, invoking Undefined Behavior repeatedly attempting to read from a stream with .eofbit() set, and then using the indeterminate values in tempIDstr, etc.. as if they contained valid data.
Instead either loop continually checking the return of each input function used, or use the return of your read function as the condition in your read loop, for example you could do something similar to:
std::ifstream f(argv[1]); /* open file for reading */
...
while (getline (f,tmp.IDstr) && getline (f,tmp.Make) &&
getline (f,tmp.Model) && getline (f,tmp.Color))
cars_list[n++] = tmp;
Above, your loop only succeeds if ALL of your calls to getline succeed and only then, if all succeed, is your data used in your cars_list.
Now on to your classic carriage-return problem. It is clear the file you are reading from contains DOS line-ending. For example, if you look at the actual contents of your input file, you will see:
Example Input File with DOS "\r\n" Line-Endings
Note the DOS line-endings denoted 0d 0a (decimal 13 10) "\r\n":
$ hexdump -Cv dat/cars_dos.txt
00000000 31 0d 0a 54 65 73 6c 61 0d 0a 4d 6f 64 65 6c 20 |1..Tesla..Model |
00000010 33 0d 0a 42 6c 61 63 6b 0d 0a 32 0d 0a 43 68 65 |3..Black..2..Che|
00000020 76 72 6f 6c 65 74 0d 0a 56 6f 6c 74 0d 0a 47 72 |vrolet..Volt..Gr|
00000030 65 79 0d 0a 33 0d 0a 54 65 73 6c 61 0d 0a 4d 6f |ey..3..Tesla..Mo|
00000040 64 65 6c 20 53 0d 0a 57 68 69 74 65 0d 0a 34 0d |del S..White..4.|
00000050 0a 4e 69 73 73 61 6e 0d 0a 4c 65 61 66 0d 0a 57 |.Nissan..Leaf..W|
00000060 68 69 74 65 0d 0a 35 0d 0a 54 6f 79 6f 74 61 0d |hite..5..Toyota.|
00000070 0a 50 72 69 75 73 0d 0a 52 65 64 0d 0a |.Prius..Red..|
0000007d
Your file has DOS "\r\n" line-endings. How does getline() work? By default getline() read up to the first '\n' character, extracting the '\n' from the input stream, but not storing it as part of the string returned. This leaves an embedded '\r' at the end of each string you store. Why does this matter? the '\r' (carriage-return) does just what its namesake says. Acting like an old typewriter, the cursor position is reset to the beginning of the line. (explaining why you see your output being overwritten -- it is) You write text until a '\r' is encountered and then the cursor is positioned back at the beginning of the line, what is written next overwrites what you just output there.
Instead your file should be a file with Unix/POSIX line-endings:
Example Input File with Unix/POSIX '\n' Line-Endings
Note the Unix/POSIX line-endings are denoted as 0a (decimal 10) '\n':
$ hexdump -Cv dat/cars.txt
00000000 31 0a 54 65 73 6c 61 0a 4d 6f 64 65 6c 20 33 0a |1.Tesla.Model 3.|
00000010 42 6c 61 63 6b 0a 32 0a 43 68 65 76 72 6f 6c 65 |Black.2.Chevrole|
00000020 74 0a 56 6f 6c 74 0a 47 72 65 79 0a 33 0a 54 65 |t.Volt.Grey.3.Te|
00000030 73 6c 61 0a 4d 6f 64 65 6c 20 53 0a 57 68 69 74 |sla.Model S.Whit|
00000040 65 0a 34 0a 4e 69 73 73 61 6e 0a 4c 65 61 66 0a |e.4.Nissan.Leaf.|
00000050 57 68 69 74 65 0a 35 0a 54 6f 79 6f 74 61 0a 50 |White.5.Toyota.P|
00000060 72 69 75 73 0a 52 65 64 0a |rius.Red.|
00000069
To see the effect let's look at a short example that reads your input file, both with Unix/POSIX line-endings and again with DOS line-endings to see the difference in action. The short example could be:
#include <iostream>
#include <fstream>
struct ArrayList {
std::string IDstr, Make, Model, Color;
};
int main (int argc, char **argv) {
if (argc < 2) {
std::cerr << "error: insufficient input.\n" <<
"usage: " << argv[0] << " filename.\n";
return 1;
}
std::ifstream f(argv[1]);
ArrayList cars_list[15], tmp;
size_t n = 0;
while (getline (f,tmp.IDstr) && getline (f,tmp.Make) &&
getline (f,tmp.Model) && getline (f,tmp.Color))
cars_list[n++] = tmp;
for (size_t i = 0; i < n; i++)
std::cout << " " << cars_list[i].IDstr
<< " " << cars_list[i].Make
<< " " << cars_list[i].Model
<< " " << cars_list[i].Color << '\n';
}
Now let's look at the output if your file has Unix/POSIX line endings:
Example Use/Output
$ ./bin/arraylist_cars dat/cars.txt
1 Tesla Model 3 Black
2 Chevrolet Volt Grey
3 Tesla Model S White
4 Nissan Leaf White
5 Toyota Prius Red
Now lets look at the output after reading the file with DOS line ending:
$ ./bin/arraylist_cars dat/cars_dos.txt
Black 3
Greyrolet
White S
Whiten
Redusa
That looks curiously similar to the output you report. Hint, in WSL you should have a tool called dos2unix (which converts line-endings from DOS to Unix). Use it on your input file, e.g. dos2unix filename. Now re-run your program (after fixing your read loop) using the file as input and your problem should disappear.
(if you don't have dos2unix installed, then install it, e.g. sudo apt-get dos2unix)
Look things over and let me know if you have further questions.