I'm wondering how to convert a hex string to a human readable string (if that makes any sense) this would be my first real encounter with hex values so I'm still learning about them and how to manage them.
I have a program which is reading in data from a file which contains raw packet data (hex) and I need to parse this information so it's human readable.
An example of what I need to do is something like this site does http://home2.paulschou.net/tools/xlate/ where you can put in hex and have it converted to text.
Taken from the C++ String Toolkit Library (StrTk) library, the following should suffice. Note that out should point to a piece of memory half the size of as std::distance(begin,end), and that the values in the range of [begin,end) be 0-9A-F or 0-9a-f
inline bool convert_hex_to_bin(const unsigned char* begin,
const unsigned char* end,
unsigned char* out)
{
if (std::distance(begin,end) % 2)
return false;
static const std::size_t symbol_count = 256;
static const unsigned char hex_to_bin[symbol_count] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 - 0x27
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x28 - 0x2F
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38 - 0x3F
0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x40 - 0x47
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x48 - 0x4F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 - 0x57
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 - 0x5F
0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x60 - 0x67
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 - 0x8F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 - 0x9F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0 - 0xA7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8 - 0xAF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB0 - 0xB7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB8 - 0xBF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0 - 0xC7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8 - 0xCF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0 - 0xD7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8 - 0xDF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE0 - 0xE7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE8 - 0xEF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0 - 0xF7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0xF8 - 0xFF
};
const unsigned char* itr = begin;
while (end != itr)
{
(*out) = static_cast<unsigned char>(hex_to_bin[*(itr++)] << 4);
(*out) |= static_cast<unsigned char>(hex_to_bin[*(itr++)] );
++out;
}
return true;
}
The C++-ish way to get a string containing the hexadecimal representation of a given number is to use the hex modifier for streams, as in this example:
const int i = 0xdeadbeef;
cout << "0x" << hex << i << endl; // prints "0xdeadbeef"
You can use the same modifier on string streams in case you need to have the hexadecimal representation in a string variable:
const int i = 0xdeadc0de;
ostringstream stream;
stream << "0x" << hex << i;
const string s = stream.str(); // s now contains "0xdeadc0de"
UPDATE:
If your input data is given as a string containing the hexadecimal representation of the characters of a string, you will need to know the encoding of the input string in order to display it correctly. In the simplest case, the string is something like ASCII which maps one byte to one character. So in a given input "414243", every two characters ("41", "42", "43) map to an ASCII value (65, 66, 67), which map to a character ("A", "B", "C").
Here's how to that in C++:
const string hexData = "414243";
assert( hexData.size() % 2 == 0 );
ostringstream asciiStream;
istringstream hexDataStream( hexData );
vector<char> buf( 3 ); // two chars for the hex char, one for trailing zero
while ( hexDataStream.good() ) {
hexDataStream.get( &buf[0], buf.size() );
if ( hexDataStream.good() ) {
asciiStream << static_cast<char>( std::strtol( &buf[0], 0, 16 ) );
}
}
const string asciiData = asciiStream.str(); // asciiData == "ABC"
Using std::strtol from <cstdlib> makes this easy; if you insist on using a template class for this, use std::stringstream to perform the conversion of the single sub strings (like "41") to decimal values (65).
fprintf(file, "%h", thing);
Something along those lines?
Hex is a way of displaying binary data. It is not "raw data" as you say. If the raw data you have contains a string, you should be able to see the string (possibly among other garbage) when you output it to the screen.
Here's a loop to print the ASCII characters in a block of data. To get anything else, you will have to deal with its format.
char *binary_data[ BUFFER_SIZE ];
size_t len = BUFFER_SIZE;
len = get_a_packet( data, len ); // or however you get data
for ( char *text_ptr = binary_data; text_ptr != binary_data + len; ++ text_ptr ) {
if ( * text_ptr <= '~' && * text_ptr >= ' ' ) { // if it's ascii
cerr << * text_ptr; // print it out
}
}
cerr << endl;
Related
Problem:
I am printing unsigned char array to display an image on a 7.5" waveshare e-Paper display using ESP32 with the following function:
Paint_DrawImage(const unsigned char *image_buffer, UWORD xStart, UWORD yStart, UWORD W_Image, UWORD H_Image)
That function prints an image to an e-paper display image where you also define the starting pixels (xStart, yStart) and the image size in pixels (W_Image, H_Image).
I have the code working with a sample unsigned char array below:
const unsigned char gImage_7in5_V2_b[2056] = { /* 0X00,0X01,0X20,0X03,0XE0,0X01, */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
.... not showing the whole array to save space};
There are some images that will save me a lot of time that are already converted into a similar format which is as an unsigned int with the example below:
const unsigned int icon64_50n[132]= {
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x03000000,0x000000E0,0x1F000000,0x000000E0,0x7F000000,0x000000E0,
.... not showing the whole array to save space};
I have tried defining the array as an unsigned char but that didn't work and was really slow uploading to the ESP32 with lots of warnings.
Question:
Is this considered a byte array? I am new to this data type and need guidance on how/what to search for here.
How do I convert the unsigned int array to unsigned char?
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
For a product I am co-designing I want to display bitmap icons on an LCD screen. Inspired by among others this tutorial I created a separate C-file with the byte array of the icon I am trying to display.
When I try to display the icon directly it seems to work. But when I try to do it indirectly - which is going to be nessecary eventually - it fails.
What really baffles me and what I seek to understand is; when I print out the array of the garbage icon (CHAR ARRAY) to the serial monitor and compare it to the byte array it is suppose to represent they match correctly.
But when I do the same for the image that is displayed correctly (ICON ARRAY), what I print to the serial monitor does not match the byte array it is displaying, the information I printed is not even consistent... How can this be ?!
I have been cracking my head over this for a week now so any help would be greatly appreciated.
The main file:
// --------------------------------------------------------------------------------------
// | This program is made for an arduino mega 2560 used in conjunction with the |
// | (chinese) OPEN-SMART 3.2 inch TFT LCD Shield ILI9327 |
// | This version of the program is a slimmed down one to clearly convey the problem |
// | I am currenlty having drawing pictures on this setup |
// --------------------------------------------------------------------------------------
// This program is based on the library obtained from
// https://drive.google.com/open?id=0B6uNNXJ2z4CxYktCQlViUkI1Sms
// There is also a demo available on YouTube
// https://www.youtube.com/watch?v=JQHGYnKeC0M&t=2s
#include <Adafruit_GFX.h> // Core graphics library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
// -------------------------------------------------------------------------------------
// | Variable declaration |
// -------------------------------------------------------------------------------------
// Set colors
#define BLACK 0x0000
#define BACKGROUND 0x07FF
// No idea with this does tbh
uint16_t g_identifier;
// Spacing variables
uint8_t cube_size = 75;
uint8_t padding = 3;
uint8_t ix1 = 5+2 * padding;
uint8_t ix2 = 5+3 * padding + cube_size;
uint8_t ix3 = 5+4 * padding + 2 * cube_size;
uint8_t ix4 = 5+5 * padding + 3 * cube_size;
uint16_t ix5 = 5+(6 * padding) + 4 * cube_size;
uint8_t iy1 = 5+1 * padding;
uint8_t iy2 = 5+3 * padding + cube_size;
uint8_t iy3 = 5+4 * padding + 2 * cube_size;
//Progmem Icon init
extern uint8_t icon_from_progmem[];
// -------------------------------------------------------------------------------------
// | Functions |
// -------------------------------------------------------------------------------------
// Standard drawbitmap function
void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) {
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
uint8_t byte = 0;
for (int16_t j = 0; j < h; j++, y++) {
for (int16_t i = 0; i < w; i++) {
if (i & 7) byte <<= 1;
else byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
if (byte & 0x80) tft.drawPixel(x + i, y, color);
}
}
}
// -------------------------------------------------------------------------------------
// | Setup |
// -------------------------------------------------------------------------------------
// I just copied this part to get the screen to work
void setup(void) {
Serial.begin(9600);
Serial.println(F("TFT LCD test"));
// tft.reset(); //we can't read ID on 9341 until begin()
g_identifier = tft.readID(); //
Serial.print("ID = 0x");
Serial.println(g_identifier, HEX);
if (g_identifier == 0x00D3 || g_identifier == 0xD3D3) g_identifier = 0x9481; // write-only shield
if (g_identifier == 0xFFFF) g_identifier = 0x9341; // serial
// g_identifier = 0x9329; // force ID
tft.begin(g_identifier); //to enable ILI9327 driver code
tft.setRotation(3); //Change orientation (landscape and portrait)
}
// -----------------------------------------------------------------------------------
// | Loop |
// -----------------------------------------------------------------------------------
void loop(void) {
tft.fillScreen(BACKGROUND); //
unsigned char myCharArray[512];
byte myChar;
for (int k = 0; k < 512; k++) {
// Create myCharArray from icon_from_progmem
myChar = pgm_read_byte(icon_from_progmem + k);
myCharArray[k] = char(myChar);
// Print data from myCharArry to the serial monitor
Serial.print("CHAR ARRAY: ");
Serial.print(k);
Serial.print(" ");
Serial.println(myChar);
}
// Visual separtion string
Serial.println("------------------------------------------------------------------");
// Print data from icon_from_progmem to serial monitor
for (int k=0; k<512; k++){
Serial.print("ICONS ARRAY: ");
Serial.print(k);
Serial.print(" ");
Serial.println(icon_from_progmem[k]);
}
// Draw the two icons on the screen
drawBitmap(ix2, iy1, myCharArray, 64, 64, BLACK);
drawBitmap(ix4, iy1, icon_from_progmem, 64, 64, BLACK);
delay(600000);
} // end of void loop
The separate file for the bitmap:
#include <avr/pgmspace.h>
// 'PlafLamp', 64x64px
const unsigned char icon_from_progmem [] PROGMEM = {
0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xc0, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x7f, 0x00, 0x00,
0x00, 0x01, 0xfc, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x0f, 0xc0, 0x00,
0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x03, 0xf0, 0x00,
0x00, 0x0f, 0x80, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00,
0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00,
0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00,
0x00, 0x00, 0x07, 0xc0, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x03, 0xe0, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x1f, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x7c, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x80, 0x3f, 0x00, 0x00,
0x00, 0x01, 0xf8, 0x03, 0xc0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x03, 0xc0, 0x0f, 0xc0, 0x00,
0x00, 0x07, 0xe0, 0x03, 0xc0, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x00,
0x00, 0x07, 0x80, 0x03, 0xc0, 0x01, 0xe0, 0x00, 0x00, 0x03, 0x00, 0x03, 0xc0, 0x00, 0xc0, 0x00,
0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00
};
What is displayed on the screen
The image on the left is the CHAR ARRAY and the image on the right is the ICON ARRAY.
in drawBitmap() you are iterating through bytes via pgm_read_byte()
In the avr-libc docs it says
Read a byte from the program space with a 16-bit (near) address.
Note:
The address is a byte address. The address is in the program space.
Your array that is a copy of the bitmap, "myCharArray", is not in program space so pgm_read_byte() does not operate correctly.
I am trying to replicate a bmp found here: https://en.wikipedia.org/wiki/BMP_file_format (its the 2x2 one). Whenever I try and open it in paint or photoviewer or whatever it says it isn't supported. I'm not sure what I am doing wrong here. I have gone over the hex values several times and everything (as far as I can tell) looks identical. Help?
#include <iostream>
#include <fstream>
using namespace std;
int main(){
ofstream bitmap;
unsigned char bm_header[14] =
/*BM*/ { 0x4D, 0x42,
/*70 bytes*/ 0x00, 0x00, 0x00, 0x46,
/*Unused */ 0x00, 0x00, 0x00, 0x00,
/* 54 bytes */ 0x00, 0x00, 0x00, 0x36 };
unsigned char dib_header[40] =
/*40 bytes*/ { 0x00, 0x00, 0x00, 0x28,
/*2 pixels wide*/ 0x00, 0x00, 0x00, 0x02,
/*2 pixels tall*/ 0x00, 0x00, 0x00, 0x02,
/*1 plane */ 0x00, 0x01,
/*24 bits */ 0x00, 0x18,
/*0 */ 0x00, 0x00, 0x00, 0x00,
/*16 bytes */ 0x00, 0x00, 0x00, 0x10,
/*2835 p/m wide*/ 0x00, 0x00, 0x0B, 0x13,
/*2835 p/m tall*/ 0x00, 0x00, 0x0B, 0x13,
/*0 colors*/ 0x00, 0x00, 0x00, 0x00,
/*0 import. colors*/0x00, 0x00, 0x00, 0x00 };
unsigned char pixel_header[16] =
{0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF,
0x00, 0x00,
0x00, 0x00, 0xFF,
0x00, 0xFF, 0x00,
0x00, 0x00 };
bitmap.open("mandelbrot_1.bmp", ios::out | ios::binary);
for(int i = 0; i < 14; i++) {
bitmap << bm_header[i];
}
for(int i = 0; i < 40; i++) {
bitmap << dib_header[i];
}
for(int i = 0; i < 16; i++) {
bitmap << pixel_header[i];
}
cout << "success!" << endl;
bitmap.close();
return 0;
}
Each field in bm_header and dib_header is reversed from what it should be. The values 0x4d, 0x42 spell out "MB", not "BM." The sequence 0x00, 0x00, 0x00, 0x46 is interpreted as 0x46000000 bytes, not 0x46 bytes. In general the bytes in the Wikipedia table are listed in the order that they should go into the file.
Go on YouTube and search for Handmade Hero Bitmap, or go on Handmade Hero's channel and watch episodes from 36 to 39.
Casey (the author) goes over literally everything you need to know in theory and in practice down to endianness quirks and struct tight packing.
Those episodes are easy enough to consume on their own even if you have no interest in the series or haven't watched the previous episodes.
I'd suggest you do an online search for BITMAPINFOHEADER. That will give you a structure you can use instead of manipulating bytes directly.
I'm trying to implement MD5 hash function in C++ and get correct results for some input values that I have found through some websites online which are some hexadecimal values. Up till this point I have been able to get it work correctly. However, when I try to do the same thing with ASCII strings, I'm out of luck and cannot really understand exactly what else should I do.
The first thing I have done is to convert ASCII string into hex value and append single 0x80 at the end after which follows a bunch of 0x00 s and at the last eight bytes the length of the non-appended message in hexadecimal.
For example, "test123" is represented in hexadecimal as "0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33" and its length in bytes is 7. Then the byte array to be used as input to hash function is as far as I get it is as below,
const uint8_t test123Array[64] = {
0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07
};
And when I applied the hash function, the result I get is,
e7 54 fa ea 1e d7 69 ba 85 59 62 bf 16 e9 98 48
Whereas result I get through online hash generator websites is something like
cc 03 e7 47 a6 af bb cb f8 be 76 68 ac fe be e5
The length of the data is not counted in bytes, but rather in bits. So, the length is not 7, but 56 (0x38). This length is then encoded into 64 bit in Little-Endian byte order.
The prepared input should look like this:
const uint8_t test123Array[64] = {
0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
The specification of MD5 you linked to contains everything you need to know about that. Take a closer look at Section "3.2 Step 2. Append Length" and the Encode function in Section "A.3 md5c.c".
I expect from is_bitwise_serializable trait to serialize class like following (without serialize function):
class A { int a; char b; };
BOOST_IS_BITWISE_SERIALIZABLE(A);
A a{2, 'x'};
some_archive << a; // serializes a bitwisely
I wonder, why is there a need to provide serialize function for bitwise_serializable class?
From the documentation:
Some simple classes could be serialized just by directly copying all bits of the class. This is, in particular, the case for POD data types containing no pointer members, and which are neither versioned nor tracked. Some archives, such as non-portable binary archives can make us of this information to substantially speed up serialization.
To indicate the possibility of bitwise serialization the type trait defined in the header file is_bitwise_serializable.hpp is used:
Here are the key points: this optimization
is optional in the archive types where it does apply
doesn't apply to all archive types e.g.
a binary archive that needs to be portable could not be implemented by copying out the raw memory representation (because it is implementation and platform depenedent)
a text archive might not desire to optimize this (e.g. it has different goals to, like "human readable XML", they might not want to encode your vector<A> as a large bas64 encoded blob).
Note that this also explains that is_bit_wise_serializable<T> is not partially specialized for any type that has is_pod<T>::value == true (This could technically be done easily):
some classes might not be interested in serializing all their state (so using bitwise copy would take a lot more space than just selecting the interesting bits (pun intended))
You didn't ask, specifically, but this is what the working implementation would look like:
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <sstream>
struct A { int a; char b;
template <typename Ar> void serialize(Ar& ar, unsigned) {
ar & a;
ar & b;
}
};
BOOST_IS_BITWISE_SERIALIZABLE(A)
int main() {
std::ostringstream oss;
boost::archive::binary_oarchive oa(oss);
A data { 1, 'z' };
oa << data;
}
UPDATE
In response to the commenter who basically posed the same question again, I came up with a demonstration when bitwise serializability would (a) kick in making a visible difference (b) not resulting in the smaller archive:
Live On Coliru
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/array.hpp>
#include <boost/serialization/serialization.hpp>
#include <array>
#include <fmt/ranges.h>
#include <span>
#include <sstream>
struct A {
int a;
char b;
void serialize(auto& ar, unsigned) { ar& a& b; }
};
#ifdef BITWISE
BOOST_IS_BITWISE_SERIALIZABLE(A)
#endif
int main() {
std::ostringstream oss;
{
boost::archive::binary_oarchive oa(oss,
boost::archive::no_header |
boost::archive::no_tracking |
boost::archive::no_codecvt);
std::array<A, 26> data{{
{1, 'z'}, {2, 'y'}, {3, 'x'}, {4, 'w'}, {5, 'v'}, {6, 'u'}, {7, 't'},
{8, 's'}, {9, 'r'}, {10, 'q'}, {11, 'p'}, {12, 'o'}, {13, 'n'}, {14, 'm'},
{15, 'l'}, {16, 'k'}, {17, 'j'}, {18, 'i'}, {19, 'h'}, {20, 'g'}, {21, 'f'},
{22, 'e'}, {23, 'd'}, {24, 'c'}, {25, 'b'}, {26, 'a'},
}};
oa << data;
}
auto raw = oss.str();
fmt::print("raw serialized form {} bytes: {::#04x}\n", //
raw.size(), std::vector(raw.begin(), raw.end()));
}
When built an run:
for def in REGULAR BITWISE; do g++ -std=c++20 -O2 -Wall -pedantic main.cpp -lboost_serialization -lfmt -o $def -D$def & done; wait
set -x; ./REGULAR; ./BITWISE
Prints
+ ./REGULAR
raw serialized form 148 bytes: [0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7a, 0x02, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00, 0x00, 0x00, 0x77, 0x05, 0x00, 0x00, 0x00, 0x76, 0x06, 0x00, 0x00, 0x00, 0x75, 0x07, 0x00, 0x00, 0x00, 0x74, 0x08, 0x00, 0x00, 0x00, 0x73, 0x09, 0x00, 0x00, 0x00, 0x72, 0x0a, 0x00, 0x00, 0x00, 0x71, 0x0b, 0x00, 0x00, 0x00, 0x70, 0x0c, 0x00, 0x00, 0x00, 0x6f, 0x0d, 0x00, 0x00, 0x00, 0x6e, 0x0e, 0x00, 0x00, 0x00, 0x6d, 0x0f, 0x00, 0x00, 0x00, 0x6c, 0x10, 0x00, 0x00, 0x00, 0x6b, 0x11, 0x00, 0x00, 0x00, 0x6a, 0x12, 0x00, 0x00, 0x00, 0x69, 0x13, 0x00, 0x00, 0x00, 0x68, 0x14, 0x00, 0x00, 0x00, 0x67, 0x15, 0x00, 0x00, 0x00, 0x66, 0x16, 0x00, 0x00, 0x00, 0x65, 0x17, 0x00, 0x00, 0x00, 0x64, 0x18, 0x00, 0x00, 0x00, 0x63, 0x19, 0x00, 0x00, 0x00, 0x62, 0x1a, 0x00, 0x00, 0x00, 0x61]
+ ./BITWISE
raw serialized form 221 bytes: [0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x77, 0x7f, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x76, 0x7f, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x75, 0x7f, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x74, 0x7f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x73, 0x7f, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x72, 0x7f, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x71, 0x7f, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x6c, 0x7f, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x69, 0x7f, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x66, 0x7f, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x65, 0x7f, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x64, 0x7f, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x63, 0x7f, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00]