ascii85 decoder algorithm for adobe fails in some cases - c++

I am trying to develop a Ascii85 decoder in c++, in order to parse a bitmap file from an adobe illustrator file (*ai).
I have found an algorithm in java here and I have tried to rewrite it in c++.
The problem is that I have some cases that my encoded text is not being decoded correctly. For example if character "a" is the 7th and final character in my string (before the encoding) it is decoded as "`", which is the previous character in the ascii table. It is weird because I have tried to make the calculations of the algorithm manually, and I get "`" as a result. I am wondering if there is a bug in the algorithm or if it is not the correct algorithm for adobe ascii85 decoding.
Here is my code:
#include <QCoreApplication>
#include <stdio.h>
#include <string.h>
#include <QDebug>
// returns 1 when there are no more bytes to decode
// 0 otherwise
int decodeBlock(char *input, unsigned char *output, unsigned int inputSize) {
qDebug() << input << output << inputSize;
if (inputSize > 0) {
unsigned int bytesToDecode = (inputSize < 5)? inputSize : 5;
unsigned int x[5] = { 0 };
unsigned int i;
for (i = 0; i < bytesToDecode; i++) {
x[i] = input[i] - 33;
qDebug() << x[i] << ", i: " << i;
}
if (i > 0)
i--;
unsigned int value =
x[0] * 85 * 85 * 85 * 85 +
x[1] * 85 * 85 * 85 +
x[2] * 85 * 85 +
x[3] * 85 +
x[4];
for (unsigned int j = 0; j < i; j++) {
int shift = 8 * (3 - j); // 8 * 3, 8 * 2, 8 * 1, 8 * 0
unsigned char byte = (unsigned char)((value >> shift) & 0xff);
printf("byte: %c, %d\n", byte, byte);
*output = byte;
output++;
}
}
return inputSize <= 5;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
char x__input[] = "<~FE1f+#;K?~>";
unsigned char x__output[128] = { 0 };
char *input = x__input + 2;
unsigned int inputSize = (unsigned int)strlen(input);
inputSize -= 2;
unsigned char *output = x__output;
printf("decoding %s\n", input);
for (unsigned int i = 0; i < inputSize; i += 5, input += 5, output += 4)
if(decodeBlock(input, output, inputSize - i))
break;
printf("Output is: %s\n", x__output);
return a.exec();
}

What happens when inputSize is not multiple of 5??
unsigned int bytesToDecode = (inputSize < 5)? inputSize : 5;
you ASSUME that bytesToDecode is 5, while there will be some bytes with unknown values
So, when your character is the last at position 7, the above condition is true.
If the input is not a multiple of 5, then it MUST be padded with the value "u".
For more details about the encoding / decoding process, please check the Wikipedia page, where it is pretty well explained:
http://en.wikipedia.org/wiki/Ascii85#Example_for_Ascii85

Related

decompressing special rle - imageproc

I am trying to decompress an rle file which was compressed in special way .
I am getting back an image which is differenet then the original and I can't understand why.
1st Ill explain the way it was compressed :
the original Image is gray image with only 2 kind of pixels in it : White Or Black .
in the compression they used a byte to represent each sequence of pixels .
the MSB bit in each byte represent White(=1) or Black(=0) . the other 7 Bit represent the sequence so it can be maximum value of 127 .
for example 127 pixels of white will be : 11111111B => 255 DEC.
also 127DEC will represent 127 pixels of black (MSB is 0).
the original Image is 120x240 BMP and I am using a known function (it was given to me) to save BMP files so there is no problem in the saving of array to bmp files if all the rules were followed .
Also in the compressed file the first 2 BYTE will represent the arraysize . arraysize = rle[0]*256 + rle[1].
I'll put here only the part the decompress and compress ( I built them both)
void RleDeCompress(unsigned char rleimage[2 + 240 * 120], unsigned char decompressedimage[][NUMBER_OF_COLUMNS])
{
// 1st MSB bit from the 8 bit of each cell in the array represent color - Black or White
//2nd~7th BIT represent the number of times the color repeats itself
// first 2 cells in the array are represent the size of the array
int arraysize = rleimage[0] * 256 + rleimage[1];
int row = 0;
int col = 0;
unsigned char colormask = 128; //binary 10000000=128dec
unsigned char multiplymask = 127; // binary 01111111 = 127dec
unsigned int total = 0;
for (int i = 2; i < arraysize+2; i++)
{
unsigned char blackorwhitebinary = (rleimage[i] & colormask) >> 7 ; // mask only the msb and then shift it to be the lsb
unsigned char color = 255 * blackorwhitebinary; // decide if this is black or white
unsigned char multiply = rleimage[i] & multiplymask; // number of times the color repeats itself
for (int j = 0; j < multiply; j++)
{
decompressedimage[row][col] = color;
col++;
if (col == NUMBER_OF_COLUMNS)
{
row++;
col = 0;
}
if (row > NUMBER_OF_ROWS) cout << "error too many rows " << endl;
}
total += multiply;
// check total of cells real in the binary file
}
cout << "total is:" << total << endl;
}
void RleCompress(unsigned char image[][NUMBER_OF_COLUMNS], unsigned char RleImage[2 + 240 * 120])
{
unsigned char n = 0;
unsigned int N = 2;
unsigned int arrsize=0;
unsigned char temparray[ 240 * 120];
for (int row = 0; row < NUMBER_OF_ROWS; row++)
{
for (int column = 0; column < NUMBER_OF_COLUMNS; column++)
{
temparray[arrsize] = image[row][column] / 255;
arrsize++;
}
}
for (int i = 0; i < arrsize; i++)
{
n++;
if (n == 127)
{
RleImage[N+2] = temparray[i] * 128 + n;
n = 0;
N++;
}
else
{
if (i == arrsize)
{
RleImage[N + 2] = temparray[i] * 128 + n;
}
else
{
if (temparray[i] != temparray[i + 1])
{
RleImage[N + 2] = temparray[i] * 128 + n;
n = 0;
N++;
}
}
}
}
RleImage[0] = N / 256;
RleImage[1] = N % 256;
}
void SaveRleFile(unsigned char RleImage[2 + 240 * 120])
{
ofstream myfile;
myfile.open("P01C.bin", ios::out | ios::binary);
if (myfile.is_open())
{
int index = 0;
while (index < 2 + 120 * 240)
{
myfile << RleImage[index];
index++;
}
cout << "index is :" << index << endl;
}
myfile.close();
}
void LoadRleBinFile(char binfilename[], unsigned char * image)
{
//for (int j = 0; j < 2 + 120 * 240; j++) image[j] = 255; //clears the array from garbage and sets all of it to white.
ifstream myfile;
char c;
int i = 0;
myfile.open(binfilename, ios::in | ios::binary); // open file in binary mode input only
if (myfile.is_open())
{
while (!myfile.eof())
{
myfile.get(c);
image[i] = (unsigned char) c;
i++;
}
}
else
cout << "error while opening file " << endl;
myfile.close();
}
void main()
{
unsigned char GrayImage[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
unsigned char Rlearray[2 + 240 * 120]; //rlearray size is unknown when first initialzing . worst case is 2 + 240*120
LoadGrayImageFromTrueColorBmpFile(GrayImage, "P01A.bmp");
StoreGrayImageAsGrayBmpFile(GrayImage, "P01B.bmp");
//--------------------------------------------------------------------------------------------------------------------------
ConvertGrayImageToBlackWhite(GrayImage);
StoreGrayImageAsGrayBmpFile(GrayImage, "P01B2.bmp");
RleCompress(GrayImage, Rlearray);
SaveRleFile(Rlearray);
LoadRleBinFile("P01C.rle", Rlearray);
RleDeCompress(Rlearray, GrayImage);
StoreGrayImageAsGrayBmpFile(GrayImage, "P01C.BMP");
//WaitForUserPressKey();
}
I found a way to check that there is a problem and it's in the code .
the number of pixels in the picture (120*240 =28800 )should be ,or atleast thats what seems most logic to me , equal to the sum of all the sequence because if not then we didn't compressed the whole image.
In my code the sum of all the sequences is about 17000 . != 28800 .
I don't understand if I didn't compressed right or didnt decompressed right but from looking on the binary file (with binary viewer program) it seems the binary rle file is ok .

How do I run the following code

I have a relatively big C++ project that I'm trying to figure out how to run.
There are 3 code files as outlined below and 2 .wav audio files - test.wav and poolIR.wav.
The program is supposed to convolve the test file with the impulse response and produce a third output file. The 2 audio files must be passed to the program at runtime and I am new to C/C++, so I'm trying to see how I should do it. Can anyone help me out please. Below is the code.
I am using WINDOWS 7 and I have gcc installed.
convolve.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <fstream>
#include <iostream>
#include <math.h>
#include "CWav.h"
using namespace std;
#define DEBUG_MODE
/* Test tone frequency in Hz */
#define FREQUENCY 440.0
/* Test tone duration in seconds */
#define DURATION 2.0
/* Standard sample rate in Hz */
#define SAMPLE_RATE 44100.0
/* Standard sample size in bits */
#define BITS_PER_SAMPLE 16
/* Standard sample size in bytes */
#define BYTES_PER_SAMPLE (BITS_PER_SAMPLE/8)
/* Number of channels */
#define MONOPHONIC 1
#define STEREOPHONIC 2
#define SIZE 8
#define PI 3.141592653589793
#define TWO_PI (2.0 * PI)
#define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
void outputToFile(double data[], CWav* original , int numberOfSamples, char* outputFile);
void four1(double data[], int nn, int isign);
void writeWaveFileHeader(int channels, int numberSamples, int bitsPerSample, double sampleRate, FILE *outputFile);
size_t fwriteIntLSB(int data, FILE *stream);
void getSignal(CWav *input, double x[]);
size_t fwriteShortLSB(short int data, FILE *stream);
void outputToFile(double data[], CWav* original , int numberOfSamples, char* outputFile);
// The four1 FFT from Numerical Recipes in C,
// p. 507 - 508.
// Note: changed float data types to double.
// nn must be a power of 2, and use +1 for
// isign for an FFT, and -1 for the Inverse FFT.
// The data is complex, so the array size must be
// nn*2. This code assumes the array starts
// at index 1, not 0, so subtract 1 when
// calling the routine (see main() below).
void four1(double data[], int nn, int isign)
{
unsigned long n, mmax, m, j, istep, i;
double wtemp, wr, wpr, wpi, wi, theta;
double tempr, tempi;
n = nn << 1;
j = 1;
for (i = 1; i < n; i += 2) {
if (j > i) {
SWAP(data[j], data[i]);
SWAP(data[j+1], data[i+1]);
}
m = nn;
while (m >= 2 && j > m) {
j -= m;
m >>= 1;
}
j += m;
}
mmax = 2;
while (n > mmax) {
istep = mmax << 1;
theta = isign * (6.28318530717959 / mmax);
wtemp = sin(0.5 * theta);
wpr = -2.0 * wtemp * wtemp;
wpi = sin(theta);
wr = 1.0;
wi = 0.0;
for (m = 1; m < mmax; m += 2) {
for (i = m; i <= n; i += istep) {
j = i + mmax;
tempr = wr * data[j] - wi * data[j+1];
tempi = wr * data[j+1] + wi * data[j];
data[j] = data[i] - tempr;
data[j+1] = data[i+1] - tempi;
data[i] += tempr;
data[i+1] += tempi;
}
wr = (wtemp = wr) * wpr - wi * wpi + wr;
wi = wi * wpr + wtemp * wpi + wi;
}
mmax = istep;
}
}
void writeWaveFileHeader(int channels, int numberSamples, int bitsPerSample,
double sampleRate, FILE *outputFile)
{
/* Calculate the total number of bytes for the data chunk */
int dataChunkSize = channels * numberSamples * (bitsPerSample / 8);
/* Calculate the total number of bytes for the form size */
int formSize = 36 + dataChunkSize;
/* Calculate the total number of bytes per frame */
short int frameSize = channels * (bitsPerSample / 8);
/* Calculate the byte rate */
int bytesPerSecond = (int)ceil(sampleRate * frameSize);
/* Write header to file */
/* Form container identifier */
fputs("RIFF", outputFile);
/* Form size */
fwriteIntLSB(formSize, outputFile);
/* Form container type */
fputs("WAVE", outputFile);
/* Format chunk identifier (Note: space after 't' needed) */
fputs("fmt ", outputFile);
/* Format chunk size (fixed at 16 bytes) */
fwriteIntLSB(16, outputFile);
/* Compression code: 1 = PCM */
fwriteShortLSB(1, outputFile);
/* Number of channels */
fwriteShortLSB((short)channels, outputFile);
/* Output Sample Rate */
fwriteIntLSB((int)sampleRate, outputFile);
/* Bytes per second */
fwriteIntLSB(bytesPerSecond, outputFile);
/* Block alignment (frame size) */
fwriteShortLSB(frameSize, outputFile);
/* Bits per sample */
fwriteShortLSB(bitsPerSample, outputFile);
/* Sound Data chunk identifier */
fputs("data", outputFile);
/* Chunk size */
fwriteIntLSB(dataChunkSize, outputFile);
}
/******************************************************************************
*
* function: fwriteIntLSB
*
* purpose: Writes a 4-byte integer to the file stream, starting
* with the least significant byte (i.e. writes the int
* in little-endian form). This routine will work on both
* big-endian and little-endian architectures.
*
* internal
* functions: none
*
* library
* functions: fwrite
*
******************************************************************************/
size_t fwriteIntLSB(int data, FILE *stream)
{
unsigned char array[4];
array[3] = (unsigned char)((data >> 24) & 0xFF);
array[2] = (unsigned char)((data >> 16) & 0xFF);
array[1] = (unsigned char)((data >> 8) & 0xFF);
array[0] = (unsigned char)(data & 0xFF);
return fwrite(array, sizeof(unsigned char), 4, stream);
}
/******************************************************************************
*
* function: fwriteShortLSB
*
* purpose: Writes a 2-byte integer to the file stream, starting
* with the least significant byte (i.e. writes the int
* in little-endian form). This routine will work on both
* big-endian and little-endian architectures.
*
* internal
* functions: none
*
* library
* functions: fwrite
*
******************************************************************************/
size_t fwriteShortLSB(short int data, FILE *stream)
{
unsigned char array[2];
array[1] = (unsigned char)((data >> 8) & 0xFF);
array[0] = (unsigned char)(data & 0xFF);
return fwrite(array, sizeof(unsigned char), 2, stream);
}
void getSignal(CWav *input, double x[]) {
for ( int i = 0; i < input->mySignalSize; i++ )
x[i] = ((double)input->my_signal[i])/32678.0;
}
void outputToFile(double output_signal[], CWav* original , int numberOfSamples, char* outputFile) {
/* Open a binary output file stream for writing */
FILE *outputFileStream = fopen(outputFile, "wb");
/* Write the WAVE file header */
writeWaveFileHeader(original->myChannels, numberOfSamples, original->myBitsPerSample,
original->mySampleRate, outputFileStream);
int i;
float maxValInResult = -1.0;
for (i = 0; i < numberOfSamples; i++ )
if ( output_signal[i] > maxValInResult )
maxValInResult = output_signal[i];
float maxValInInput = -1.0;
for (i = 0; i < numberOfSamples; i++ )
if (original->my_signal[i] > maxValInInput )
maxValInInput = original->my_signal[i];
for (i = 0; i < numberOfSamples; i++ )
fwriteShortLSB((short)(output_signal[i] / maxValInResult * maxValInInput), outputFileStream);
/* Close the output file stream */
fclose(outputFileStream);
}
//convolve inputfile IRfile outputfile as inputs to main
int main(int argc, char* argv[])
{
if (argc != 4) {
cout << "USAGE: ./convolve inputfile IRfile outputfile" << endl;
//system("PAUSE");
return 0;
}
cout << argv[0] << endl;
cout << "Input File:" << argv[1] << endl;
cout << "IRfile:" << argv[2] << endl;
cout << "outputfile File:" <<argv[3] << endl;
char *outputFilename = argv[3];
/* Create the sine wave test tone, using the specified
frequency, duration, and number of channels, writing to
a .wav file with the specified output filename */
//createTestTone(FREQUENCY, DURATION, MONOPHONIC, BITS_PER_SAMPLE, SAMPLE_RATE, outputFilename);
CWav *inputSignal = new CWav();
inputSignal->readInput(argv[1]);
//manipulate(inputSignal, 2);
CWav *impulse = new CWav();
impulse->readInput(argv[2]);
cout << "Input Signal: " << inputSignal->mySignalSize << ", Impulse Size: " << impulse->mySignalSize << endl;
double h[impulse->mySignalSize];
double x[inputSignal->mySignalSize];
getSignal(impulse, h);
getSignal(inputSignal, x);
int sizeH = impulse->mySignalSize;
int sizeX = inputSignal->mySignalSize;
cout << "SIZES(H,X)" << endl;
cout << sizeH << endl;
cout << sizeX << endl;
int maxSize = 0;
if(sizeX >= sizeH) {
maxSize = sizeX;
}
else {
maxSize = sizeH;
}
cout << "maxSize: " << maxSize << endl;
int power = 0;
int pow2 = 0;
pow2 = (int) log2(maxSize) + 1;
pow2 = pow(2,pow2);
cout << "POW :" << pow2 << endl;
int i = 0;
int doublePow2 = 2 * pow2;
//set hComplex with 0's
double hComplex[doublePow2];
double *xComplex = new double[doublePow2];
//set hComplex , xComplex with 0's
for(i = 0; i < doublePow2; i++) {
hComplex[i] = 0.0;
xComplex[i] = 0.0;
}
//padding the complex number with 0 and the real number with original value for h
for(i = 0; i < sizeH; i++) {
hComplex[2*i] = h[i];
}
//padding the complex number with 0 and the real number with original value for x
for(i = 0; i < sizeX; i++) {
xComplex[2*i] = x[i];
}
four1(hComplex, pow2, 1);
four1(xComplex, pow2, 1);
double *yComplex = new double[doublePow2];
for(i = 0; i < pow2 ; i++) {
yComplex[i*2] = xComplex[i] * hComplex[i] - xComplex[i+1] * hComplex[i+1];
yComplex[i*2+1] = xComplex[i+1] * hComplex[i] + xComplex[i] * hComplex[i+1];
}
four1(yComplex-1, pow2, -1);
outputToFile(yComplex, inputSignal, pow2, outputFilename);
}
CWav.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <fstream>
#include <iostream>
#include "CWav.h"
using namespace std;
void CWav::readInput(char *filename)
{
ifstream inFile( filename, ios::in | ios::binary);
//printf("Reading wav file...\n"); // for debugging only
inFile.seekg(4, ios::beg);
inFile.read( (char*) &myChunkSize, 4 ); // read the ChunkSize
inFile.seekg(16, ios::beg);
inFile.read( (char*) &mySubChunk1Size, 4 ); // read the SubChunk1Size
inFile.seekg(20, ios::beg);
inFile.read( (char*) &myFormat, sizeof(short) ); // read the file format. This should be 1 for PCM
//inFile.seekg(22, ios::beg);
inFile.read( (char*) &myChannels, sizeof(short) ); // read the # of channels (1 or 2)
//inFile.seekg(24, ios::beg);
inFile.read( (char*) &mySampleRate, sizeof(int) ); // read the samplerate
//inFile.seekg(28, ios::beg);
inFile.read( (char*) &myByteRate, sizeof(int) ); // read the byterate
//inFile.seekg(32, ios::beg);
inFile.read( (char*) &myBlockAlign, sizeof(short) ); // read the blockalign
//inFile.seekg(34, ios::beg);
inFile.read( (char*) &myBitsPerSample, sizeof(short) ); // read the bitspersample
inFile.seekg(40, ios::beg);
inFile.read( (char*) &myDataSize, sizeof(int) ); // read the size of the data
// read the data chunk
myData = new char[myDataSize];
inFile.seekg(44, ios::beg);
inFile.read(myData, myDataSize);
inFile.close(); // close the input file
my_signal = NULL;
if ( myBitsPerSample == 8 )
{
mySignalSize = myDataSize;
my_signal = new short[mySignalSize];
for ( int i = 0; i < myDataSize; i++ )
my_signal[i] = (short)( (unsigned char) myData[i] );
}
else if ( myBitsPerSample == 16 ){
mySignalSize = myDataSize / 2;
my_signal = new short[mySignalSize];
short val;
for ( int i = 0; i < myDataSize; i+=2 )
{
val = (short)( (unsigned char) myData[i] );
val += (short)( (unsigned char) myData[i+1] ) * 256;
my_signal[i/2] = val;
}
}
}
CWav.h:
#ifndef CWavH
#define CWavH
class CWav
{
private:
char* myData;
public:
int myChunkSize;
int mySubChunk1Size;
short myFormat;
short myChannels;
int mySampleRate;
int myByteRate;
short myBlockAlign;
short myBitsPerSample;
int myDataSize;
short *my_signal;
int mySignalSize;
public:
void readInput(char *filename);
};
#endif
Then I have 2 audio files.
poolIR.wav AND test.wav
C++ is not a scripting language, you have to compile it first.
To compile the code using gcc try the following
(assuming that all files are in the same directory):
g++ convolve.cpp CWav.cpp -o convolve.exe
That should generate an executable file named convolve.exe.
The -o flag specifies the output file name (convolve.exe).
See the gcc documentation for details.

Negative heights when converting SRTM data

I want to get the height for a certain latitude/longitude pair from the NASA SRTM dataset (http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/Eurasia/).
As a starter I want to get all heights from a HGT file:
int totalPx = 1201; //3 degree
char buffer[2];
for (int i=0; i<totalPx; i++)
{
for (int j=0; j<totalPx; j++)
{
int pos = (i * totalPx + j) * 2;
m_openedFile.seek(pos); //m_openedFile is a Qt QFile
m_openedFile.read(buffer, 2);
short h = 0 | (buffer[0] << 8) | (buffer[1] << 0);
if (h < 0)
printf("%d", h);
}
}
This seems to work for some coordinates (e.g. the height values look plausible) but there are also many negative height values. How can I correctly read the SRTM/HGT file?
Regards,
Beware of sign extension when converting char to int
// char buffer[2];
unsigned char buffer[2];
short h = buffer[0] << 8 | buffer[1];
I figured it out: the problem was the signed char instead of the unsigned char which lead to the wrong bit shifts:
int totalPx = 1201; //3 degree
unsigned char buffer[2];
for (int i=0; i<totalPx; i++)
{
for (int j=0; j<totalPx; j++)
{
int pos = (i * totalPx + j) * 2;
m_openedFile.seek(pos); //m_openedFile is a Qt QFile
m_openedFile.read(buffer, 2);
short h = 0 | (buffer[0] << 8) | (buffer[1] << 0);
if (h < 0)
printf("%d", h);
}
}

c++ unsigned char memory copy

I need to pass an unsigned char array from one method to another, and i tried using this code:
{
unsigned char *lpBuffer = new unsigned char[182];
ReceiveSystemState(lpBuffer);
}
BOOL ReceiveSystemState(unsigned char *lpBuffer)
{
unsigned char strRecvBuffer[182] = { 0 };
//strRecvBuffer construction
memcpy(lpBuffer, strRecvBuffer, sizeof(strRecvBuffer));
return TRUE;
}
Neither of those 3 methods (used in ReceiveSystemState) worked as i expected. After using each one of them all that it is copied is the first char from strRecvBuffer and nothing more. The strRecvBuffer has empty chars from element to element, but i need those as they are, because that string is a message from a hardware device and that message will be anallysed using a protocol. What do i miss here? Do i initialize lpBuffer wrong?
EDIT: I've used a simple memcpy method to do the job. Still the same result: all that it is copied is the first char of strRecvBuffer.
EDIT2: Working code:
{
unsigned char *lpBuffer = new unsigned char[182];
ReceiveSystemState(lpBuffer);
for (int i = 0; i < 144; i++)
{
memcpy(&c_dateKG[i], lpBuffer + i * sizeof(unsigned char), sizeof(unsigned char) );
}
}
BOOL ReceiveSystemState(unsigned char *lpBuffer)
{
unsigned char strRecvBuffer[182] = { 0 };
//strRecvBuffer construction
memcpy(lpBuffer, strRecvBuffer, sizeof(strRecvBuffer));
return TRUE;
}
Your code is absolutely garbage. Some notes:
Use sizeof:
Use sizeof(static_massive_name); or count_of_arr_elements * sizeof(arr_type);
For example:
unsigned char src[255];
unsigned char dst[255];
// fill src with random data
for (int i = 0; i < 255; ++i) {
src[i] = static_cast<unsigned char> (rand() % 255);
}
memcpy(dst, src, sizeof(dst));
// now dst will have copied values from src (random numbers)
UPDATE:
Full source code for testing:
#include <iostream>
#include <string.h>
#include <time.h>
#include <stdlib.h>
using namespace std;
void print(unsigned char* arr, size_t size) {
for (size_t i = 0; i < size; ++i) {
// see type casting (to int)!!!
cout << "arr[" << i << "] = " << (int)arr[i]<< endl;
}
}
int main() {
srand(time(0));
// unsigned char type hold values from 0 to 255
unsigned char src[15];
unsigned char dst[15];
for (int i = 0; i < 15; ++i) {
src[i] = rand() % 255;
}
memcpy(dst, src, sizeof(dst));
print(src, 15);
print(dst, 15);
return 0;
}
Result:
arr[0] = 34
arr[1] = 80
arr[2] = 183
arr[3] = 112
arr[4] = 18
arr[5] = 120
arr[6] = 183
arr[7] = 0
arr[8] = 0
arr[9] = 0
arr[10] = 0
arr[11] = 57
arr[12] = 137
arr[13] = 4
arr[14] = 8
arr[0] = 34
arr[1] = 80
arr[2] = 183
arr[3] = 112
arr[4] = 18
arr[5] = 120
arr[6] = 183
arr[7] = 0
arr[8] = 0
arr[9] = 0
arr[10] = 0
arr[11] = 57
arr[12] = 137
arr[13] = 4
arr[14] = 8

How can I pad my md5 message with c/c++

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;