C not reading entire BMP file - fopen - c

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)
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

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

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.

Related

C generate image as unsigned char

How can I convert a generated image (with gd.h library https://libgd.github.io/manuals/2.1.1/files/preamble-txt.html) from 'gdImagePtr'(im) to 'unsighed char' (buffer).
Curentlly I am writing the image to a file, then I read the image
#include <gd.h>
...
//create image
gdImagePtr im; //declaration of the image
FILE *out; //output file
int white;
im = gdImageCreate(100,100); //create an image, 100
white = gdImageColorAllocate(im, 255, 255, 255); //
gdImageLine(im, 0, 0,100,100, white); // draw a line
out = fopen("my_path", "w"); //open a file
gdImageJpeg(im, out, -1); //write the image to the
/* be good, clean up stuff */
fclose(out);
gdImageDestroy(im);
//save image to buffer
unsigned char buffer[LENGTH],
FILE* fin = fopen("my_path", "rb"); // r for read, b for binary
if (fin == NULL) {
printf("open %s failed.", file_path);
return;
}
fread(buffer, sizeof(unsigned char), size, fin); // read sizeof(buffer) elements to our buffer
....
Curentlly I am writing the image to a file, then I read the image

Why does the measurement of the size of a file differ from the size of the string that contains it once buffered?

In order to write the content of a file in a buffer, I first need to know the size of the string to allocate. To do this, I use the following function:
long file_length(FILE *fp)
{
if (fp == NULL) return -1L;
fseek(fp, 0L, SEEK_END);
const long len = ftell(fp);
rewind(fp);
return len;
}
And I use it as follows to store the contents of my file:
char *file_content(const char *fname)
{
assert(access(fname, F_OK) != -1);
assert(access(fname, R_OK) != -1);
FILE *fp = fopen(fname, "r");
assert(fp != NULL);
const long flen = file_length(fp);
printf("Length of file: %ld\n", flen);
char *buff = malloc(flen + 1);
assert(buff != NULL);
fread(buff, sizeof(char), flen, fp);
buff[flen + 1] = '\0';
fclose(fp);
return buff;
}
And then I test:
int main()
{
char *content = file_content("test.txt");
printf("Length of buffer: %lld\n", strlen(content));
free(content);
return 0;
}
Here's test.txt:
Hello, world!
This is a simple test.
Stackoverflow.
My program then displays this:
Length of file: 57
Length of buffer: 53
As the file has 4 line feeds, I imagine that the result is related to their interpretation according to the different readings that are made (for the position of the file, with fseek, and for its buffering, with fread). But is it? Or maybe it changes depending on the platform or a reading mode?
If that's the case, so I would like to know how to get the same results, so that I can allocate the exact size of the string directly from my file_length function, without having to subtract the number of line feeds the file contains (if it's possible?) in order to be as optimal as possible.

Fread get different content for a .txt and a .jpeg file

I'm getting only 4 bytes in my buffer when I try to read the whole file (weight a lot more than 4B). But when I'm reading a .txt file, I successfully recover the whole file content.
I've searched in the fopen man, in the malloc mand and in the fread man, but I cant' understand why.
char* readFile(char* path)
{
/*VARIABLES*/
FILE *inFile;
long inFileSize;
long readSize;
char *buffer = NULL;
/*OPEN FILES*/
inFile = fopen(path,"rb");
/*ERROR HANDLING : FILES*/
if(!inFile) {
return "";
}
/*GETTING FILE SIZE*/
fseek(inFile, 0, SEEK_END);
inFileSize = ftell(inFile);
rewind(inFile);
printf("The file is %ld bytes long\n",inFileSize);
/*ALLOCATING MEMORY*/
buffer = (char*) malloc(sizeof(char) * (inFileSize + 1) );
/*READ THE CONTENT AND PUT IT IN THE BUFFER*/
readSize = fread(buffer, sizeof(char), inFileSize, inFile);
/*ERROR HANDLING : readed size != to the file size*/
if (inFileSize != readSize)
{
printf("Freeing buffer\n");
free(buffer);
buffer = NULL;
}
/*ADDING THE END STRING CODE*/
buffer[inFileSize] = '\0';
/*CLOSE THE FILE*/
fclose(inFile);
return buffer;
}
Also, when I change the image extension from .jpeg to .txt, I still get 4 bytes only.
Can you help me ?

Unclear reading file in C

I tried cyclically read file in buffer of 100 byte.
When i read file first time - buffer was full. Returned value is 0. No error and no eof (functions "ferror" and "feof" shows no error). Then i tried read file second time and again returned value is 0, no error and no eof. But then i have empty buffer. I don't know what is the problem?
if(fopen_s(&file_in, argv[1], "rb") == 0){
printf("File was opened.\n");
while(!feof(file_in)){
read_code = fread_s(file_data, 100, sizeof(unsigned char), 100, file_in);
if(ferror(file_in)) {
printf("Error!\n");
}
if(feof(file_in)) {
printf("Eof!\n");
}
printf("Read result: %d\n", read_code);
/*Using the buffer*/
memset(file_data, 0, 100);
}
fclose(file_in);
}
For the reasons given in comments regarding fopen_s, et. al., Here is an alternative implementation of reading a binary file using getc(), along with fopen(), fclose(), etc. (I am not using a Microsoft implementation, but am using ANSI C99)
It has a commented section I used to create a test binary file. Other than that it sizes the file you are reading so you can allocate the right amount of memory, then reads the binary data into a buffer.
For navigating your file, take a look at fseek() with its stdio.h defined arguments:
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
In this example, everything is closed or freed before exiting:
#include <windows.h>
#include <ansi_c.h>
long int getFileSizeFromPath(char * path)
{
FILE * file;
long int fileSizeBytes = 0;
file = fopen(path,"r");
if(file){
fseek(file, 0, SEEK_END);
fileSizeBytes = ftell(file);
fseek(file, 0, SEEK_SET);
fclose(file);
}
return fileSizeBytes;
}
int main(int argc, char *argv[])
{
FILE *fp=0;
char *binBuf;
long int size=0;
int i=0;
int byte=0;
//create 100 byte test file (c:\\dev\\tessst.bin)
// fp = fopen(argv[1], "wb");
//
// srand(clock());
// for(i=0;i<100;i++)
// {
// byte = rand();
// putc(byte, fp);
// }
// putc(EOF, fp);
//
// fclose(fp);
size = getFileSizeFromPath(argv[1]);
binBuf = calloc(size + 1, sizeof(char));
fp = fopen(argv[1], "rb");
byte = getc(fp);
while(byte != EOF)
{
binBuf[i++] = (char)byte;
byte = getc(fp);
}
fclose(fp);
free(binBuf);
return 0;
}

Creating copy of binary file from hex representation of it

I'd like to make copy of my binary file, but I need to make it from hex representation of my binary file.
In the first program I create txt file with with hex representation of my binary file:
#include <stdio.h>
#include <stdlib.h>
const int BYTE = 1;
int counter = 0;
int read;
long size;
FILE *file1 = NULL;
FILE *file2 = NULL;
fpos_t length;
int main() {
unsigned char hex[3];
unsigned char buffer[1];
file1 = fopen("server.pdf", "rb");
fseek(file1, 0, SEEK_END);
fgetpos(file1, &length);
size = length.__pos;
fseek(file1, 0, SEEK_SET);
if (file1) {
file2 = fopen("test.txt", "w");
while (counter < size) {
read = fread(buffer, 1, BYTE, file1);
counter += read;
i = 0;
while(i<read) {
sprintf(hex, "%02x", (unsigned int) buffer[i++]);
fwrite(hex, 1, BYTE, file2);
}
}
} else
printf("ERROR");
fclose(file1);
fclose(file2);
}
In the second, I read data from txt file and after that I write it to binary file:
#include <stdio.h>
FILE *file1;
FILE *file2;
int size;
fpos_t length;
int main(){
file1 = fopen("test.txt", "r");
fseek(file1, 0, SEEK_END);
fgetpos(file1, &length);
size = length.__pos;
fseek(file1, 0, SEEK_SET);
char buffer[1];
char hex[3];
int counter = 0;
int read;
if(file1){
file2 = fopen("test.pdf", "wb");
while (counter < size) {
read = fread(hex, 1, 3, file1);
counter += read;
sscanf(hex, "%02x", buffer);
fwrite(buffer, 1, 1, file2);
}
}
fclose(file1);
fclose(file2);
}
Unfortunately I can't open my copy. What is the reason?
Have you looked at the files content? You wont be able to sprintf the hex representation to the variable hex since it's 1 byte in size.
The variable hex is declared hex[BYTE] where BYTE = 1, but your sprintf format string looks like this: "%02x" ie 2 bytes, then you need room for a terminating zero.
The same goes for when you write to the file, you only write 1 byte from your hex string.
Declaring a variable as: var[1] is pointless you can achieve the same thing with var btw.
Besides this you should also add proper error handling, if you can not successfully open the file. This means checking the file pointer after your call to fopen, then take an appropriate action. perror() will print an error string that corresponds to errno, and in case of a file that does not exist it will print something like: "no such file or directory" or similar.
When you said you can't open your copy, you mean you have an error in fopen("test.txt", "r")? Did you check errno value? Check perror() and strerror().
Besides, you have no loop in second program.

Resources