Liam G
Liam G

Reputation: 791

C not reading entire BMP file - fopen

So I am trying to read a .bmp file in C. I am later going to encrypt the file using openssl libraries - but that's only background info.

I need to open the file in binary mode (obviously) but for whatever reason when I try to open the file, it only reads in 4 bytes. When I try to output this exact file I just opened (for error testing) it outputs the following - 88 24 AD FB.

In my troubleshooting I decided to try this on a text file (54 bytes) and I get the exact same result.

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(){

    char * fileName="pic_original.bmp";

    //read the file from given filename in binary mode
    printf("Start to read the .bmp file \n");

    FILE *image;
    image = fopen(fileName,"rb");

    //print the size of the image (4 bytes every damn time)
    printf("Size of image: %d\n",sizeof(image));

    //output the exact file that was read (error testing)
    FILE *test;
    test = fopen("./test.bin", "w");
    fwrite(image, sizeof(image), 1, test);

    fclose(test);
    fclose(image);


    return 1;
}

This is the image (uploaded as png for some reason)

image

Not exactly sure where I'm going wrong here but I'm not very seasoned in C.

Cheers, Liam

EDIT 1:

//allocate memory for the header and image
char *headerBuf = (char *)malloc(54);
char *imageBuf = (char *)malloc(sizeof(image)-54); //this line is wrong - thanks to user EOF

//allocate memory for the final ciphertext
char *imagecipherCBC = (char *)malloc(sizeof(image)); //wrong also

//read first 54 bytes (header)
rewind(image);
fread(headerBuf,54,1,image);

//read the bitmap image until the end of the file
fread(imageBuf,sizeof(image),1,image); //also wrong

Upvotes: 0

Views: 1914

Answers (2)

tommybee
tommybee

Reputation: 2551

Well, The size of the image is of course, 4 bytes which is a file pointer on a 32 bit machine.

I think you have to prepare some image buffer of your bmp file as a simple example, then you can do encrypt and decrypt the contents of this image buffer if your file is not too big.

static void read_from_image(char *imageBuf, int fileLength)
{
    const char * outFileName="c:/DEV/temp/test.bin";
    char headerBuf[54];
    char *imagecipherCBC;

    FILE *test;
    test = fopen(outFileName, "wb");

    //allocate memory for the final ciphertext
    imagecipherCBC = (char *)malloc(fileLength *sizeof(char));

    //read first 54 bytes (header)
    //fread(headerBuf,54,1,image);
    memcpy(headerBuf, imageBuf, 54 * sizeof(char));

    //read the bitmap image until the end of the file
    //fread(imageBuf,sizeof(image),1,image); //also wrong

    fwrite(imageBuf, fileLength * sizeof(char), 1, test);
    fflush(test);
    fclose(test);

    free(imagecipherCBC),imagecipherCBC = NULL;
    free(imageBuf),imageBuf = NULL;

    return;
}

You can have a file length and an image buffer in a main function.

    int main(int argc, char *argv[])
{
    const char * fileName="c:/DEV/temp/pic_original.bmp";

    int fileLength = 0;

    FILE *image;
    char *imageBuffer;

    imageBuffer = NULL;
    image = fopen(fileName,"rb");

    printf("read the file from given filename in binary mode \n");
    printf("Start to read the .bmp file \n");

    //try to get a file length;
    fseek(image, 0, SEEK_END);
    fileLength = ftell(image);
    fseek(image, 0, SEEK_SET);
    rewind(image);

    imageBuffer = (char*)malloc(fileLength * sizeof(char));

    //print the size of the image (4 bytes every damn time)
    printf("read the file from given filename in binary mode \n");
    printf("Size of image file pointer: %d\n",sizeof(image));
    printf("Size of image: %d\n",fileLength);

    //output the exact file that was read (error testing)
    fread(imageBuffer,sizeof(char),fileLength*sizeof(char), image);

    fclose(image);

    read_from_image(imageBuffer, fileLength);

    return 0;
}

good luck

Upvotes: 1

Barmak Shemirani
Barmak Shemirani

Reputation: 31599

If your goal is to encrypt the file then read the entire file in to buffer, encrypt it, and save it as binary. You can find the file size by moving the file pointer to the end. Example:

int main()
{
    FILE *fin;
    fin = fopen("pic_original.bmp", "rb");
    fseek(fin, 0, SEEK_END);
    int filesize = ftell(fin);
    rewind(fin);

    char *buf = malloc(filesize);
    fread(buf, 1, filesize, fin);
    fclose(fin);

    //encrypt the buffer...

    FILE *fout = fopen("output.bmp", "wb");
    fwrite(buf, 1, filesize, fout);
    fclose(fout);

    return 0;
}

This will work with any file. OpenSSL already has functions to encrypt files directly.

If for some reason you want to keep the header the same, and only change the bits which follow, then read the header separately:

int main()
{
    FILE *fin = fopen("input.bmp", "rb");
    if(!fin) { printf("cannot open input\n"); return 0; }

    FILE *fout = fopen("output.bmp", "wb");
    if(!fout) { printf("cannot open output\n"); return 0; }

    fseek(fin, 0, SEEK_END);
    int filesize = ftell(fin);
    if(filesize <= 54)
    {
        printf("wrong filesize\n");
        return 0;
    }
    rewind(fin);

    char *header = malloc(54);
    char *buf = malloc(filesize - 54);
    //encrypt buf...
    fread(header, 1, 54, fin);
    fread(buf, 1, filesize - 54, fin);
    fclose(fin);

    fwrite(header, 1, 54, fout);
    fwrite(buf, 1, filesize - 54, fout);
    fclose(fout);

    free(header);
    free(buf);
    return 0;
}

I suppose this has the advantage that encrypted bitmap will still be recognized as a bitmap. But only encryption methods does not add extra bytes to the output.

Note that 8-bit, 4-bit and monochrome bitmaps have a palette which come after the 54 byte heading, then comes the image bits.

Upvotes: 1

Related Questions