First off, this is not a duplicate. I have already read Converting 1-bit bmp file to array in C/C++ and my question is about an inconsistency I'm seeing in the formulas provided with the one that works for me.
The Issue
I am trying to read in a 1-bit Bitmap image that was created in MS Paint. I've used the code provided by other answers on this site, but there are a few things I had to change to get it to work, and I want to understand why,
Change 1: lineSize must be doubled
Original
int lineSize = (w / 8 + (w / 8) % 4);
Mine:
int lineSize = (w/ 8 + (w / 8) % 4) * 2;
Change 2: Endianness must be reversed
Original:
for(k = 0 ; k < 8 ; k++)
... (data[fpos] >> k ) & 1;
Mine:
for (int k = 7; k >= 0; --k) {
... (data[rawPos] >> k) & 1;
Full Code
NOTE: This code works. There are some changes from the original, but the core read part is the same.
vector<vector<int>> getBlackAndWhiteBmp(string filename) {
BmpHeader head;
ifstream f(filename, ios::binary);
if (!f) {
throw "Invalid file given";
}
int headSize = sizeof(BmpHeader);
f.read((char*)&head, headSize);
if (head.bitsPerPixel != 1) {
f.close();
throw "Invalid bitmap loaded";
}
int height = head.height;
int width = head.width;
// Lines are aligned on a 4-byte boundary
int lineSize = (width / 8 + (width / 8) % 4) * 2;
int fileSize = lineSize * height;
vector<unsigned char> rawFile(fileSize);
vector<vector<int>> img(head.height, vector<int>(width, -1));
// Skip to where the actual image data is
f.seekg(head.offset);
// Read in all of the file
f.read((char*)&rawFile[0], fileSize);
// Decode the actual boolean values of the pixesl
int row;
int reverseRow; // Because bitmaps are stored bottom to top for some reason
int columnByte;
int columnBit;
for (row = 0, reverseRow = height - 1; row < height; ++row, --reverseRow) {
columnBit = 0;
for (columnByte = 0; columnByte < ceil((width / 8.0)); ++columnByte) {
int rawPos = (row * lineSize) + columnByte;
for (int k = 7; k >= 0 && columnBit < width; --k, ++columnBit) {
img[reverseRow][columnBit] = (rawFile[rawPos] >> k) & 1;
}
}
}
f.close();
return img;
}
#pragma pack(1)
struct BmpHeader {
char magic[2]; // 0-1
uint32_t fileSize; // 2-5
uint32_t reserved; // 6-9
uint32_t offset; // 10-13
uint32_t headerSize; // 14-17
uint32_t width; // 18-21
uint32_t height; // 22-25
uint16_t bitsPerPixel; // 26-27
uint16_t bitDepth; // 28-29
};
#pragma pack()
Potentially relevant information:
I'm using Visual Studio 2017
I'm compiling for C++14
I'm on a Windows 10 OS
Thanks.
Both of those line size formulas are incorrect.
For example, for w = 1, (w / 8 + (w / 8) % 4) results in zero. It's still zero if you multiply by two. It's expected to be 4 for width = 1.
The correct formula for line size (or bytes per line) is
((w * bpp + 31) / 32) * 4 where bpp is bits per pixel, in this case it is 1.
By coincidence the values are sometimes the same, for some smaller width values.
See also MSDN example:
DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
Also, 1-bit image has 2 palette entries, for a total of 8 bytes. It seems you are ignoring the palette and assuming that 0 is black, and 1 is white, always.
The part where you flip the bits is correct, the other code appears to be incorrect.
Lets say we have a single byte 1000 0000 This is mean to be a single row, starting with 7 zeros and ending in 1.
Your code is a bit confusing for me (but seems okay when you fix linesize). I wrote my own version:
void test(string filename)
{
BmpHeader head;
ifstream f(filename, ios::binary);
if(!f.good())
return;
int headsize = sizeof(BmpHeader);
f.read((char*)&head, headsize);
if(head.bitsPerPixel != 1)
{
f.close();
throw "Invalid bitmap loaded";
}
int height = head.height;
int width = head.width;
int bpp = 1;
int linesize = ((width * bpp + 31) / 32) * 4;
int filesize = linesize * height;
vector<unsigned char> data(filesize);
//read color table
uint32_t color0;
uint32_t color1;
uint32_t colortable[2];
f.seekg(54);
f.read((char*)&colortable[0], 4);
f.read((char*)&colortable[1], 4);
printf("colortable: 0x%06X 0x%06X\n", colortable[0], colortable[1]);
f.seekg(head.offset);
f.read((char*)&data[0], filesize);
for(int y = height - 1; y >= 0; y--)
{
for(int x = 0; x < width; x++)
{
int pos = y * linesize + x / 8;
int bit = 1 << (7 - x % 8);
int v = (data[pos] & bit) > 0;
printf("%d", v);
}
printf("\n");
}
f.close();
}
Test image:
(33 x 20 monochrome bitmap)
Output:
colortable: 0x000000 0xFFFFFF
000000000000000000000000000000000
000001111111111111111111111111110
000001111111111111111111111111110
000001111111111111111111111111110
000001111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111111110
011111111111111111111111111110010
011111111111111111111111111110010
011111111111111111111111111111110
000000000000000000000000000000000
Notice this line in above code:
int pos = y * linesize + x / 8;
int bit = 1 << (7 - x % 8);
int v = (data[pos] & bit) > 0;
printf("%d", v);
First I wrote it as
int bit = 1 << (x % 8);
But this shows the bits in the wrong order, so I had to change to 1 << (7 - x % 8) which is basically what you did also. I don't know why it's designed like that. There must be some historical reasons for it!
(above code is for little-endian machines only)
Related
I followed the code at this link read pixel value in bmp file to be able to read the RGB values of pixels and when I have the entire image as one color and read a random pixel's values they are correct. After this I tried to make it so the function would also try and find how many unique colors there were so I added a box with a different color to the image but the function still only finds one color. I'm wondering if maybe I'm somehow not looking at all the bytes contained in the BMP but I'm not sure how that would be as I'm new to trying this stuff.
To make sure the code wasn't finding different colored pixels but failing to add them to the list of unique pixels I tried printing output when a color is found that is different from the one that is always found but no output ever came from it.
struct Color {
int R = -1;
int G = -1;
int B = -1;
};
unsigned char* readBMP(char* filename) {
int i;
FILE* f = fopen(filename, "rb");
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f);
int width = *(int*)&info[18]; //the reason *(int*) is used here because there's an integer stored at 18 in the array that indicates how wide the BMP is
int height = *(int*)&info[22]; // same reasoning for *(int*)
int size = 3 * width * height;
unsigned char* data = new unsigned char[size];
fread(data, sizeof(unsigned char), size, f);
fclose(f);
// windows has BMP saved as BGR tuples and this switches it to RGB
for(i = 0; i < size; i += 3){
unsigned char tmp = data[i];
data[i] = data[i+2];
data[i+2] = tmp;
}
i = 0; // i is the x value of the pixel that is having its RGB values checked
int j = 0; // j is the y value of the pixel that is having its RGB values checked
unsigned char R = data[3 * (i * width + j)]; // value of R of the pixel at (i,j)
unsigned char G = data[3 * (i * width + j) + 1]; // value of G of the pixel at (i,j)
unsigned char B = data[3 * (i * width + j) + 2]; // value of B of the pixel at (i,j)
std::cout << "value of R is " << int(R);
std::cout << " value of G is " << int(G);
std::cout << " value of B is " << int(B);
Color num_colors[5];
int count;
int z;
int flag;
int iterator;
int sum;
for(count = 0; count < size; count += 1){
unsigned char R = data[3 * (i * width + j)];
unsigned char G = data[3 * (i * width + j) + 1];
unsigned char B = data[3 * (i * width + j) + 2];
sum = int(R) + int(G) + int(B);
if(sum != 301) {// 301 is the sum of the RGB values of the color that the program does manage to find
std::cout << sum;
}
flag = 0;
for(z = 0; z < 5; z += 1){
if(num_colors[z].R == R && num_colors[z].G == G && num_colors[z].B == B){
flag = 1;
}
}
if(flag == 1){
continue;
}
iterator = 0;
while(num_colors[iterator].R != -1){
iterator += 1;
}
num_colors[iterator].R = R;
num_colors[iterator].G = G;
num_colors[iterator].B = B;
}
int number = 0;
for(int r = 0; r < 5; r += 1){
std::cout << "\nValue of R here: " << num_colors[r].R;
if(num_colors[r].R != -1){
number += 1;
}
}
std::cout << "\nNumber of colors in image: " << number;
return data;
}
https://imgur.com/a/dXllIWL
This is the picture I'm using so there should be two colors found but the code only finds red pixels.
Your problem is that you are always checking the RGB values at (0,0)
i = 0; // i is the x value of the pixel that is having its RGB values checked
int j = 0; // j is the y value of the pixel that is having its RGB values checked
...
for(count = 0; count < size; count += 1){
unsigned char R = data[3 * (i * width + j)];
unsigned char G = data[3 * (i * width + j) + 1];
unsigned char B = data[3 * (i * width + j) + 2];
i and j defines the X and Y position of the pixel you are checking, but notice that you never change those in the loop. Your loop will keep doing the same thing over and over again. What you probably want is a double loop, going through all coordinates in your image:
for(int y=0; y<height; y++)
for(int x=0; x<width; x++){
unsigned char R = data[3 * (y * width + x) + 0];
unsigned char G = data[3 * (y * width + x) + 1];
unsigned char B = data[3 * (y * width + x) + 2];
Ok guys, it's the third time I'm posting the same question (previous are here and here).
Now at this time I will try to explain what's my problem:
So first them all, I need to rotate a .bmp image and it's not rotate correctly. But I don't need to rotate a random image with extension .bmp, I need to rotate this one. I've tried with many other images and all of them was rotated correctly, except mine.
In this moment my code it works just for 180-degree, how could make it to works on any degree which is multiple of 90-degree (I need to rotate my image just with 90, 180 or 270 degrees, not more).
I don't need any kind of external library for this code like CImage, OpenCV, ImageMagik and so on... I need to make this code to work.
So yeh, that's it. And here you can find my actual result.
CODE:
#include <array>
using namespace std;
struct BMP {
int width;
int height;
unsigned char header[54];
unsigned char *pixels;
int row_padded;
int size_padded;
};
void writeBMP(string filename, BMP image) {
string fileName = "Output Files\\" + filename;
FILE *out = fopen(fileName.c_str(), "wb");
fwrite(image.header, sizeof(unsigned char), 54, out);
unsigned char tmp;
for (int i = 0; i < image.height; i++) {
for (int j = 0; j < image.width * 3; j += 3) {
//Convert(B, G, R) to(R, G, B)
tmp = image.pixels[j];
image.pixels[j] = image.pixels[j + 2];
image.pixels[j + 2] = tmp;
}
}
fwrite(image.pixels, sizeof(unsigned char), image.size_padded, out);
fclose(out);
}
BMP readBMP(string filename) {
BMP image;
string fileName = "Input Files\\" + filename;
FILE *in = fopen(fileName.c_str(), "rb");
fread(image.header, sizeof(unsigned char), 54, in); // read the 54-byte header
// extract image height and width from header
image.width = *(int *) &image.header[18];
image.height = *(int *) &image.header[22];
image.row_padded = (image.width * 3 + 3) & (~3); // ok size of a single row rounded up to multiple of 4
image.size_padded = image.row_padded * image.height; // padded full size
image.pixels = new unsigned char[image.size_padded]; // yeah !
if (fread(image.pixels, sizeof(unsigned char), image.size_padded, in) == image.size_padded) {
unsigned char tmp;
for (int i = 0; i < image.height; i++) {
for (int j = 0; j < image.width * 3; j += 3) {
//Convert (B, G, R) to (R, G, B)
tmp = image.pixels[j];
image.pixels[j] = image.pixels[j + 2];
image.pixels[j + 2] = tmp;
}
}
}
fclose(in);
return image;
}
BMP rotate(BMP image, double degree) {
BMP newImage = image;
unsigned char *pixels = new unsigned char[image.size_padded];
int height = image.height;
int width = image.width;
for (int x = 0; x < height; x++) {
for (int y = 0; y < width; y++) {
pixels[(x * width + y) * 3 + 0] = image.pixels[((height - 1 - x) * width + (width - 1 - y)) * 3 + 0];
pixels[(x * width + y) * 3 + 1] = image.pixels[((height - 1 - x) * width + (width - 1 - y)) * 3 + 1];
pixels[(x * width + y) * 3 + 2] = image.pixels[((height - 1 - x) * width + (width - 1 - y)) * 3 + 2];
}
}
newImage.pixels = pixels;
return newImage;
}
int main() {
BMP image = readBMP("Input-1.bmp");
image = rotate(image, 180);
writeBMP("Output.bmp", image);
return 0;
}
You have major memory leak. pixels = new unsigned char[size]; must be freed otherwise there is potentially several megabytes leak with every rotation. You have to rewrite the function to keep track of memory allocations.
When you rotate the image by 90 or 270 of the image, the widht/height of image changes. The size may change too because of padding. The new dimension has to be recorded in header file.
In C++ you can use fopen, but std::fstream is preferred.
Here is an example which works in Windows for 24bit images only. In Big-endian systems you can't use memcpy the way I used it below.
Note, this is for practice only. As #datenwolf explained you should use a library for real applications. Most standard libraries such Windows GDI library (basic drawing functions) offer solution for these common tasks.
#include <iostream>
#include <fstream>
#include <string>
#include <Windows.h>
bool rotate(char *src, char *dst, BITMAPINFOHEADER &bi, int angle)
{
//In 24bit image, the length of each row must be multiple of 4
int padw = 4 - ((bi.biWidth * 3) % 4);
if(padw == 4) padw = 0;
int padh = 4 - ((bi.biHeight * 3) % 4);
if(padh == 4) padh = 0;
int pad2 = 0;
if(padh == 1 || padh == 3) pad2 = 2;
bi.biHeight += padh;
int w = bi.biWidth;
int h = bi.biHeight;
if(angle == 90 || angle == 270)
{
std::swap(bi.biWidth, bi.biHeight);
}
else
{
bi.biHeight -= padh;
}
for(int row = 0; row < h; row++)
{
for(int col = 0; col < w; col++)
{
int n1 = 3 * (col + w * row) + padw * row;
int n2 = 0;
switch(angle)
{
case 0: n2 = 3 * (col + w * row) + padw * row; break;
case 90: n2 = 3 * ((h - row - 1) + h * col) + pad2 * col; break;
case 180: n2 = 3 * (col + w * (h - row - 1)) + padw * (h - row - 1); break;
case 270: n2 = 3 * (row + h * col) + pad2 * col; break;
}
dst[n2 + 0] = src[n1 + 0];
dst[n2 + 1] = src[n1 + 1];
dst[n2 + 2] = src[n1 + 2];
}
}
for(int row = 0; row < bi.biHeight; row++)
for(int col = 0; col < padw; col++)
dst[bi.biWidth * 3 + col] = 0;
bi.biSizeImage = (bi.biWidth + padw) * bi.biHeight * 3;
return true;
}
int main()
{
std::string input = "input.bmp";
std::string output = "output.bmp";
BITMAPFILEHEADER bf = { 0 };
BITMAPINFOHEADER bi = { sizeof(BITMAPINFOHEADER) };
std::ifstream fin(input, std::ios::binary);
if(!fin) return 0;
fin.read((char*)&bf, sizeof(bf));
fin.read((char*)&bi, sizeof(bi));
int size = 3 * (bi.biWidth + 3) * (bi.biHeight + 3);
char *src = new char[size];
char *dst = new char[size];
fin.read(src, bi.biSizeImage);
//use 0, 90, 180, or 270 for the angle
if(rotate(src, dst, bi, 270))
{
bf.bfSize = 54 + bi.biSizeImage;
std::ofstream fout(output, std::ios::binary);
fout.write((char*)&bf, 14);
fout.write((char*)&bi, 40);
fout.write((char*)dst, bi.biSizeImage);
}
delete[]src;
delete[]dst;
return 0;
}
The BMP file format is a complicated, convoluted beast and there's no such thing as a "simple" BMP file reader. The code you have there makes certain hard coded assumptions on the files you're trying to read (24bpp true color, tightly packed, no compression) that it will flat (on its face) when it encounters anything that isn't that specific format. Unfortunately, for you, the majority of BMP files out there is not of that kind. To give you an idea of what a fully conforming BMP reader must support have a look at this page:
http://entropymine.com/jason/bmpsuite/bmpsuite/html/bmpsuite.html
And the code you have up there does not even check if there's a valid file magic bytes signature and if the header is valid. So that's your problem right there: You don't have a BMP file reader. You have something that actually spits out pixels if you're lucky enough the feed it something that by chance happens to be in the right format.
I'm trying to achieve compromise for my app, but got no luck (or rather knowledge) so far.
I've got bitmap for black-white screen, it looks like this (I use arduino byte style, because it's more readable)
{
B00111100, B01001000,
B00100100, B01010000,
B00111100, B01110000,
B00100100, B01001000
}
It is array of bytes, each byte representing 8 next horizontal pixels.
Problem is that I have to use bitmap, where each byte represents 8 next vertical pixels, so it's like turning it this way
{
B00000000,
B00000000,
B11110000,
B10100000,
B11110000,
B00000000,
B11110000,
B00100000,
B01100000,
B10010000
}
I tried, but ended up completely without any idea how to do this.
Edit. I could be misunderstod, so I added brackets to code, It's more clear right now.
Here is an example using plain C (gcc):
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef uint8_t byte;
void print_bin(byte x) {
printf("B");
for (int i = 0; i < 8; i++) {
printf("%s", (x >> (7-i)) % 2 ? "1" : "0");
}
printf("\n");
}
void reverse(byte* in, byte* out, int width, int height) {
int width_bytes = (width + 7) / 8;
int height_bytes = (height + 7) / 8;
// init *out. You can skip the next line if you are sure that *out is clear.
memset (out, 0, width * height_bytes);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (in[(y * width_bytes + x / 8)] & (1 << (7 - x % 8))) {
out[(x * height_bytes + y / 8)] |= (1 << (7 - y % 8));
}
}
}
}
#define WIDTH 13
#define HEIGHT 4
#define IN_SIZE (((WIDTH + 7) / 8) * HEIGHT)
#define OUT_SIZE (((HEIGHT + 7) / 8) * WIDTH)
int main() {
byte in[IN_SIZE] = {
0b00111100, 0b01001000,
0b00100100, 0b01010000,
0b00111100, 0b01110000,
0b00100100, 0b01001000
};
byte* out = calloc(OUT_SIZE, 1);
reverse (in, out, WIDTH, HEIGHT);
for (int i = 0; i < OUT_SIZE; i++) {
print_bin(out[i]);
}
}
And this is the result:
B00000000
B00000000
B11110000
B10100000
B10100000
B11110000
B00000000
B00000000
B00000000
B11110000
B00100000
B01100000
B10010000
If speed is an issue, you can do the following optimisation:
void reverse(byte* in, byte* out, int width, int height) {
int width_bytes = (width + 7) / 8;
int height_bytes = (height + 7) / 8;
// init *out. You can skip the next line if you are sure that *out is clear.
memset (out, 0, width * height_bytes);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int t; // optimisation
if ((x % 8) == 0) t = in[(y * width_bytes + x / 8)];
if (t & (1 << (7 - x % 8))) {
out[(x * height_bytes + y / 8)] |= (1 << (7 - y % 8));
}
}
}
}
So I'm trying to export a .bmp file in C++ code, and I have it working except for one major thing: line padding. I'm not 100% sure on how line padding works, but I know I need it. My algorithm works except for the padding, I manually added padding in a hex editor to my exported image and it worked. But how do I add padding? Here is what I have:
//Size of the file in bytes
int fileSize = 54 + (3 * width * height);
//The sections of the file
unsigned char generalHeader[14] = {'B','M',0,0, 0,0,0,0, 0,0,54,0, 0,0};
unsigned char DIBHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,24,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
unsigned char pixelArray[1000000];
unsigned char bmpPad[3] = {0, 0, 0};
//Set the binary portion of the generalHeader, mainly just file size
generalHeader[2] = (unsigned char)(fileSize);
generalHeader[3] = (unsigned char)(fileSize >> 8);
generalHeader[4] = (unsigned char)(fileSize >> 16);
generalHeader[5] = (unsigned char)(fileSize >> 24);
//The binary variable portion of the DIB header
DIBHeader[4] = (unsigned char)(width);
DIBHeader[5] = (unsigned char)(width >> 8);
DIBHeader[6] = (unsigned char)(width >> 16);
DIBHeader[7] = (unsigned char)(width >> 24);
DIBHeader[8] = (unsigned char)(height);
DIBHeader[9] = (unsigned char)(height >> 8);
DIBHeader[10] = (unsigned char)(height >> 16);
DIBHeader[11] = (unsigned char)(height >> 24);
//Loop through all width and height places to add all pixels
int counter = 0;
for(short j = height; j >= 0; j--)
{
for(short i = 0; i < width; i++)
{
//Add all 3 RGB values
pixelArray[counter] = pixelColour[i][j].red;
pixelArray[counter] = pixelColour[i][j].green;
pixelArray[counter] = pixelColour[i][j].blue;
counter++;
}
}
//Open it
ofstream fileWorking(fileName);
//Write the sections
fileWorking.write((const char*)generalHeader, 14);
fileWorking.write((const char*)DIBHeader, 40);
fileWorking.write((const char*)pixelArray, 3 * width * height);
//NO MEMORY LEAKS 4 ME
fileWorking.close();
pixelColour is of struct data type with the 3 colours, all type unsigned char. Any help is greatly appreciated!
In your case, each row must be a multiple of 4 bytes (32 bits).
int pad = 0; // Set pad byte count per row to zero by default.
// Each row needs to be a multiple of 4 bytes.
if ((width * 3) % 4 != 0) pad = 4 - ((width * 3) % 4); // 4 - remainder(width * 3 / 4).
Padding values can contain pretty much anything, but it is best to set them to 0. When you reach the end of writing each row, just write an additional pad number of zeroes (bytes) before writing the next row.
for(short j = height; j >= 0; j--) {
for(short i = 0; i < width; i++) {
//Add all 3 RGB values
pixelArray[counter++] = pixelColour[i][j].red; // Need to advance counter.
pixelArray[counter++] = pixelColour[i][j].green;
pixelArray[counter++] = pixelColour[i][j].blue;
}
for (int padVal = 0; padVal < pad; padVal++) pixelArray[counter++] = 0; // Pad.
}
Finally, you need to write a larger file size:
fileWorking.write((const char*) pixelArray, (3 * width + pad) * height);
I'm working on a program in c++ to do md5 checksums. I'm doing this mainly because I think I'll learn a lot of different things about c++, checksums, OOP, and whatever else I run into.
I'm having trouble the check sums and I think the problem is in the function padbuff which does the message padding.
#include "HashMD5.h"
int leftrotate(int x, int y);
void padbuff(uchar * buffer);
//HashMD5 constructor
HashMD5::HashMD5()
{
Type = "md5";
Hash = "";
}
HashMD5::HashMD5(const char * hashfile)
{
Type = "md5";
std::ifstream filestr;
filestr.open(hashfile, std::fstream::in | std::fstream::binary);
if(filestr.fail())
{
std::cerr << "File " << hashfile << " was not opened.\n";
std::cerr << "Open failed with error ";
}
}
std::string HashMD5::GetType()
{
return this->Type;
}
std::string HashMD5::GetHash()
{
return this->Hash;
}
bool HashMD5::is_open()
{
return !((this->filestr).fail());
}
void HashMD5::CalcHash(unsigned int * hash)
{
unsigned int *r, *k;
int r2[4] = {0, 4, 9, 15};
int r3[4] = {0, 7, 12, 19};
int r4[4] = {0, 4, 9, 15};
uchar * buffer;
int bufLength = (2<<20)*8;
int f,g,a,b,c,d, temp;
int *head;
uint32_t maxint = 1<<31;
//Initialized states
unsigned int h[4]{ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
r = new unsigned int[64];
k = new unsigned int[64];
buffer = new uchar[bufLength];
if(r==NULL || k==NULL || buffer==NULL)
{
std::cerr << "One of the dyn alloc failed\n";
}
// r specifies the per-round shift amounts
for(int i = 0; i<16; i++)
r[i] = 7 + (5 * ((i)%4) );
for(int i = 16; i < 32; i++)
r[i] = 5 + r2[i%4];
for(int i = 32; i< 48; i++)
r[i] = 4 + r3[i%4];
for(int i = 48; i < 63; i++)
r[i] = 6 + r4[i%4];
for(int i = 0; i < 63; i++)
{
k[i] = floor( fabs( sin(i + 1)) * maxint);
}
while(!(this->filestr).eof())
{
//Read in 512 bits
(this->filestr).read((char *)buffer, bufLength-512);
padbuff(buffer);
//The 512 bits are now 16 32-bit ints
head = (int *)buffer;
for(int i = 0; i < 64; i++)
{
if(i >=0 && i <=15)
{
f = (b & c) | (~b & d);
g = i;
}
else if(i >= 16 && i <=31)
{
f = (d & b) | (~d & b);
g = (5*i +1) % 16;
}
else if(i >=32 && i<=47)
{
f = b ^ c ^ d;
g = (3*i + 5 ) % 16;
}
else
{
f = c ^ (b | ~d);
g = (7*i) % 16;
}
temp = d;
d = c;
c = b;
b = b + leftrotate((a + f + k[i] + head[g]), r[i]);
a = temp;
}
h[0] +=a;
h[1] +=b;
h[2] +=c;
h[3] +=d;
}
delete[] r;
delete[] k;
hash = h;
}
int leftrotate(int x, int y)
{
return(x<<y) | (x >> (32 -y));
}
void padbuff(uchar* buffer)
{
int lack;
int length = strlen((char *)buffer);
uint64_t mes_size = length % UINT64_MAX;
if((lack = (112 - (length % 128) ))>0)
{
*(buffer + length) = ('\0'+1 ) << 3;
memset((buffer + length + 1),0x0,lack);
memcpy((void*)(buffer+112),(void *)&mes_size, 64);
}
}
In my test program I run this on the an empty message. Thus length in padbuff is 0. Then when I do *(buffer + length) = ('\0'+1 ) << 3;, I'm trying to pad the message with a 1. In the Netbeans debugger I cast buffer as a uint64_t and it says buffer=8. I was trying to put a 1 bit in the most significant spot of buffer so my cast should have been UINT64_MAX. Its not, so I'm confused about how my padding code works. Can someone tell me what I'm doing and what I'm supposed to do in padbuff? Thanks, and I apologize for the long freaking question.
Just to be clear about what the padding is supposed to be doing, here is the padding excerpt from Wikipedia:
The message is padded so that its length is divisible by 512. The padding works as follows: first a single bit, 1, is appended to the end of the message. This is followed by as many zeros as are required to bring the length of the message up to 64 bits fewer than a multiple of 512. The remaining bits are filled up with 64 bits representing the length of the original message, modulo 264.
I'm mainly looking for help for padbuff, but since I'm trying to learn all comments are appreciated.
The first question is what you did:
length % UINT64_MAX doesn't make sense at all because length is in bytes and MAX is the value you can store in UINT64.
You thought that putting 1 bit in the most significant bit would give the maximum value. In fact, you need to put 1 in all bits to get it.
You shift 1 by 3. It's only half the length of the byte.
The byte pointed by buffer is the least significant in little endian. (I assume you have little endian since the debugger showed 8).
The second question how it should work.
I don't know what exactly padbuff should do but if you want to pad and get UINT64_MAX, you need something like this:
int length = strlen((char *)buffer);
int len_of_padding = sizeof(uint64_t) - length % sizeof(uint64_t);
if(len_of_padding > 0)
{
memset((void*)(buffer + length), 0xFF, len_of_padding);
}
You worked with the length of two uint64 values. May be you wanted to zero the next one:
uint64_t *after = (uint64_t*)(buffer + length + len_of_padding);
*after = 0;