I hope this is not a turkey of a question. My conditional to detect EOF does not seem to work. The code continues through the EOF and processes within the statement. When I recreate the text, it appears appropriately, however the entire bmp with garbage code also prints out telling me the end of text flag never was encoded. I have placed a printf statement in the next else conditional, however it never enters that to print. I can not see what the problem is, if it is right in front of me, or something more ominous. Thanks as always!
/*******************************************************************************
* This code is to take a text document and using steganography techniques, hide
* the text within a bmp. It will take each character of the text, parse it into
* four 2 bit pieces and inject those bits into the two least significant bits
* of each pixel color (BGR) byte as well as the line padding.
******************************************************************************/
#include <stdio.h>
/*******************************************************************************
* getIntFromArray (borrowed from class notes). Takes unsigned character array
* and assembles/returns an int value using bit shifting with OR.
******************************************************************************/
int getIntFromArray(unsigned char bytes[])
{
int n =
bytes[0] |
bytes[1] << 8 |
bytes[2] << 16 |
bytes[3] << 24;
return n;
}
/*******************************************************************************
* bitWise. Take unsigned char pointer and character, parses the character
* using bitwise manipulation and injects 2 bits into the 2 least significant
* bits of each pixel color byte as well as padding.
******************************************************************************/
void bitWise(unsigned char* bytes, char character)
{
int i;
char tmpChar;
for(i = 0; i < 4; ++i)
{
tmpChar = character;
tmpChar &= 3;
bytes[i] &= 252;
bytes[i] |= tmpChar;
character = character >> 2;
}
}
int flag = 0;
int main(int argc, char **argv)
{
char *infilename = argv[1];
char *outfilename = argv[2];
unsigned char header[54];
FILE *in = fopen(infilename, "rb");/*Command line input.*/
FILE *out = fopen(outfilename, "wb");/*Command line input.*/
int pixelWidth;
int pixelHeight;
int i;
int j;
fread(header, 1, 54, in);/* read header into array */
pixelWidth = getIntFromArray(&header[18]);
pixelHeight = getIntFromArray(&header[22]);
fwrite(header, 1, sizeof(header), out);/* write header to output file */
for(i = 0; i < pixelHeight; ++i)/*Loop to read pixel data from bmp.*/
{
for(j = 0; j < pixelWidth; ++j)
{
unsigned char bytes[4];
unsigned char character = 0;
fread(&bytes, 1, 4, in);/*Reads sequentially pixel and padding bytes.*/
if(flag == 0)/*Breakout flag, initially set to 0.*/
{
character = getchar();/*Takes in characters from stdin.*/
if(character != EOF)/*Breakout if EOF.*/
{
bitWise(bytes, character);
}
else
{
bitWise(bytes, 0);/*Sets end of hidden text with 4 bytes LSB to 0.*/
flag = 1;
}
}
fwrite(&bytes, 1, 4, out);
}
}
fclose(in);
fclose(out);
return 0;
}
You are assigning signed int to an unsigned int. The result will be not what you expect it to be. It will be a value with all bits set to 1. (EOF has value -1 so it is signed).
Long story short it should be int. Simple int character would serves the purpose.
Also another thing getchar() returns int.
int getchar(void);
There are few other things to do :-
fread return value should be checked.
size_t fread(void * restrict ptr,size_t size, size_t nmemb,FILE * restrict stream);
The fread function returns the number of elements successfully
read, which may be less than nmemb if a read error or end-of-file
is encountered. If size or nmemb is zero, fread returns zero and
the contents of the array and the state of the stream
remain unchanged
Another thing is to check the return value of fopen(). In case of failure the return value would be NULL.
There are two serious but common problems here which lead me to believe you're not reading a reputable book, or you're having serious problems with it, as the reputable book would cover those problems in early chapters.
Perhaps we should look at some other options, since whatever you're using now clearly isn't working for you. You could've been reading your book all of this time you were struggling with trial and error, and your book should have guided you nicely past these common issues.
The bottom line is: you need to respect return values.
Don't try to convert return values before you check them. In unsigned char character; character = getchar(); you're converting from what the books and getchar manual says is an int to an unsigned char, before you try to check it against EOF. That conversion may result in loss of data. Do you wonder which data you've lost?
If you're struggling to understand K&R2E or a manual, you should write a question about that which you don't understand, rather than moving on, confused, to write code which relies upon guesswork. Any guesswork is dangerous in languages such as C.
You should also check the return value of fread, and I'd expect to see the size parameter passed 54 and the count parameter passed 1 in your case. That way, you can treat occasions when fread only reads fifty-three bytes (or fifty-two, or fifty-one) as though it's the end of input, rather than treating that unexpectedly short input as though it's the expected size. Like the getchar manual, you can find out all about fread from the fread manual.
Ohh, and nowadays I get a whole lot of "but the Youtube videos" responses. Youtube isn't a good substitute for a reputable book. Anybody can jump on there and "just wing it", and the video you watch will likely be equally flawed as your own guesses. A reputable book, on the other hand, has had thousands of hours put into planning, peer reviewing, testing (on students, since these books are usually written by professors who also have classes to teach) and refactoring (based on the testing, to better deal with "hiccups" that occur).
The choice should be obvious, and the proof is in the eating of the pudding. If you've tried the "youtube" or "try it and see" methods, they're not working for you; what you see before you now is the result of that. Try something else. Good luck!
Related
I recently started dabbing in C again, a language I'm not particularly proficient at and, in fact, keep forgetting (I mostly code in Python). My idea here is to read data from a hypothetically large file as chunks and then process the data accordingly. For now, I'm simulating this by actually loading the whole file into a buffer of type short with fread. This method will be changed, since it would be a very bad idea for, say, a file that's 1 GB, I'd think. The end goal is to read a chunk as one, process, move the cursor, read another chunk and so on.
The file in question is 43 bytes and has the phrase "The quick brown fox jumps over the lazy dog". This size is convenient because it's a prime number, so no matter how many bytes I split it into, there will always be trailing garbage (due to the buffer having leftover space?). Data processing in this case is just printing out the shorts as two chars after byte manipulation (see code below)
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUFF_SIZE 1024
long file_size(FILE *f)
{
if (fseek(f, 0, SEEK_END) != 0) exit(EXIT_FAILURE); // Move cursor to the end
long file_size = ftell(f); // Determine position to get file size
rewind(f);
return file_size;
}
int main(int argc, char* argv[])
{
short buff[MAX_BUFF_SIZE] = {0}; // Initialize to 0 remove trailing garbage
char* filename = argv[1];
FILE* fp = fopen(filename, "r");
if (fp)
{
size_t size = sizeof(buff[0]); // Size in bytes of each chunk. Fixed to 2 bytes
int nmemb = (file_size(fp) + size - 1) / size; // Number of chunks to read from file
// (ceil f_size/size)
printf("Should read at most %d chunks\n", nmemb);
short mask = 0xFF; // Mask to take first or second byte
size_t num_read = fread(buff, size, nmemb, fp);
printf("Read %lu chunks\n\n", num_read); // Seems to have read more? Look into.
for (int i=0; i<nmemb; i++) {
char first_byte = buff[i] & mask;
char second_byte = (buff[i] >> 8) & mask; // Identity for 2 bytes. Keep mask for consistency
printf("Chunk %02d: 0x%04x | %c %c\n", // Remember little endian (bytes reversed)
i, buff[i], first_byte, second_byte);
}
fclose(fp);
} else
{
printf("File %s not found\n", filename);
return 1;
}
return 0;
}
Now yesterday, on printing out the last chunk of data I was getting "Chunk 21: 0xffff9567 | g". The last (first?) byte (0x67) is g, and I did expect some trailing garbage, but I don't understand why it was printing out so many bytes when the variable buff has shorts in it. At that point I was just printing the hex as %x, not %04x, and buff was not initialized to 0. Today, I decided to initialize it to 0 and not only did the garbage disappear, but I can't recreate the problem even after leaving buff uninitialized again.
So here are my questions that hopefully aren't too abstract:
Does fread look beyond the file when reading data and does it remove trailing garbage itself, or is it up to us?
Why was printf showing an int when the buffer is a short? (I assume %x is for ints) and why can't I replicate the behaviour even after leaving buff without initialization?
Should I always initialize the buffer to zero to remove trailing garbage? What's the usual approach here?
I hope these aren't too many, or too vague, questions, and that I was clear enough. Like I said, I don't know much about C but find low-mid level programming very interesting, especially when it comes to direct data bit/byte manipulation.
Hope you have a great day!
EDIT 1:
Some of you wisely suggested I use num_read instead of nmemb on the loop, since that's the return value of fread, but that means I'll discard the rest of the file (nmemb is 22 but num_read is 21). Is that the usual approach? Also, thank you for pointing out that %x was casting to unsigned int, hence the 4 bytes instead of 2.
EDIT 2:
For clarification, and since I mispoke in a comment, I'd like to keep the remaining byte (or data), while discarding the rest, which is undefined. I don't know if this is the usual approach since if I use num_read in the loop, whatever is leftover at the end is discarded, data or not. I'm more interested in knowing what the usual approach is: discard leftover data or remove anything that we know is undefined, in this case one of the bytes.
I am creating a simple encryption program.
I am adding chars to chars to create a new char.
As of now the new 'char' is often a represented by a '?'.
My assumption was that the char variable has a max sum and once it was passed it looped back to 0.
assumed logic:
if char a == 1 && char z == 255
then 256 should == a.
This does not apear to be the case.
This snippet adds a char to a char.
It often prints out something like:
for (int i = 0; i < half; ++i) {
halfM1[i] = halfM1[i] + halfP1[i];
halfM2[i] = halfM2[i] + halfP2[(half + i)];
}
printf("\n%s\n", halfM1 );
printf("%s\n", halfM2);
Returns:
a???
3d??
This snippet removes the added char and the strings go back to normal.
for (int i = 0; i < half; ++i) {
halfM1[i] = halfM1[i] - halfP1[i];
halfM2[i] = halfM2[i] - halfP2[(half + i)];
}
printf("\n%s\n", halfM1 );
printf("%s\n", halfM2);
returns:
messagepart1
messagepart2
The code technically works, but I would like the encryption to be in chars.
If question on why 'half' is everywhere.
The message and key are split in half so the first half and second half of message have separate encryption.
First of all, there is no such thing as "wraparound" for common char. A common char is a signed type in x86, and signed integers do not have wraparound. Instead the overflow leads to undefined behaviour. Additionally, the range of chars can be -128 ... 127, or even something
For cryptographic purposes you'd want to use unsigned chars, or even better, raw octets with uint8_t (<stdint.h>).
Second problem is that you're printing with %s. One of the possible 256 resulting characters is \0. If this gets into the resulting string, it will terminate the string prematurely. Instead of using %s, you should output it with fwrite(halfM1, buffer_size, 1, stdout). Of course the problem is that the output is still some binary garbage. For this purposes many Unix encryption programs will write to file, or have an option to output an ASCII-armoured file. A simple ASCII armouring would be to output as hex instead of binary.
The third is that there is an operation that is much better than addition/subtraction for cryptographic purposes: XOR, or halfM1[i] = halfM1[i] ^ halfP1[i]; - the beauty of which is that it is its own inverse!
I have been trying to make this program to convert a tga image for color into black and white. But i have no clue how to go about it. I am verry new to C and have yet to get the hang of the syntax and even proper usage of ubuntu.
I think my problem is somthing with tha tga files header cant be read. Because the result i get when trying this program on a tga file is an unopenable picture with no height. "height = 0".
Is there some good links for one to read up on C?
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct pixel {
uint8_t r, g, b, a;
};
static uint8_t *load_image(char *filename, int *sizex, int *sizey)
{
uint8_t *image;
char buf[512];
char *bufptr;
int ret;
FILE *fp = fopen(filename, "r");
bufptr = fgets(buf, 512, fp);
ret = fscanf(fp, "%d %d\n", sizex, sizey);
bufptr = fgets(buf, 512, fp);
image = malloc(*sizex * *sizey * 4);
int i;
uint8_t *ptr = image;
for (i=0; i<*sizex * *sizey; ++i) {
ret = fread(ptr, 1, 3, fp);
ptr += 4;
}
fclose(fp);
return image;
}
static int save_image(const char *filename, uint8_t *image, int sizex, int sizey)
{
FILE *fp = fopen(filename, "w");
fprintf(fp, "P6\n%d %d\n255\n", sizex, sizey);
int i;
uint8_t *ptr = image;
for (i=0; i<sizex * sizey; ++i) {
fwrite(ptr, 1, 3, fp);
ptr += 4;
}
fclose(fp);
return 1;
}
void convert_grayscale(uint8_t *input, uint8_t *output, int sizex, int sizey)
{
// Y = 0.299 * R + 0.587 * G + 0.114 * B
int i;
for (i = 0; i < sizex * sizey; ++i)
{
struct pixel *pin = (struct pixel*) &input[i*4];
struct pixel *pout = (struct pixel*) &output[i*4];
float luma = 0.299 * pin->r + 0.587 * pin->g + 0.114 * pin->b;
if (luma > 255)
luma = 255;
uint8_t intluma = (int) luma;
pout->r = intluma;
pout->g = intluma;
pout->b = intluma;
pout->a = 255;
}
}
int main()
{
uint8_t *inputimg, *outputimg;
int sizex, sizey;
inputimg = load_image("image.tga", &sizex, &sizey);
outputimg = malloc(sizex * sizey * 4);
convert_grayscale(inputimg, outputimg, sizex, sizey);
save_image("output.tga", outputimg, sizex, sizey);
}
(Personal note: A longer answer after reading Why Stackoverflow sucks. That should be Required Reading for everyone who gets Moderator privileges.)
The problem is your load_image code seems designed to read PPM (ASCII-based) images:
Each PPM image consists of the following:
1. A "magic number" for identifying the file type. A ppm image's magic number is the two characters "P6".
2. Whitespace (blanks, TABs, CRs, LFs).
3. A width, formatted as ASCII characters in decimal.
4. Whitespace.
5. A height, again in ASCII decimal.
6. Whitespace.
7. The maximum color value (Maxval), again in ASCII decimal. Must be less than 65536 and more than zero.
8. A single whitespace character (usually a newline).
9. A raster of Height rows [...]
-- your first fgets reads, then discards, the "magic number" line, followed by reading the width and height, and then discarding the "maxval" line.
It ought to work for PPM images (and you could rename this routine load_ppm_image) were it not for a single important issue: after all that ASCII stuff, you switch to fread, and so here is Warning #1.
Before opening your file, decide whether you are going to read exclusively ASCII text, or might need to read binary data.
The problem is that 'text mode' "w" converts certain characters when reading and writing into others. That's built-in behavior in all common C libraries; it attempts to fix the end-of-line characters mess that a previous generation of programmers left us with. Now, reading text files in text mode got a bit simpler, but reading binary data is impossible. You can't be sure you got exactly what was in the file.
Let's get on with Warning #2: not all file formats are the same.
The above routine works (mostly) for PPM images, but it will fail on TGA because its header is organized differently. The TGA header is described rather well here (a random pick of Google results).
The specification describes bytes, so first thing to do is change your fopen line to
FILE *fp = fopen(filename, "rb");
and, by the way, a good practice is to test if it was successful:
if (fp == NULL)
{
printf ("Opening the file '%s' failed\n", filename);
return NULL;
}
Then you can use fgetc or fread to read one or more bytes. Here comes Warning #3: use fread with care.
fread reads multiple bytes in the order in which they are stored into the file, and so you would think it may read an item such as width and height -- each a 2-byte integer value -- in one 'read' operation. But fread does not know the order of the bytes in your system (nor in the file itself), and so it could be it reads "lo-hi", as in the specification I pointed to, while in your computer the order of bytes in an integer is "hi-lo". To clarify: if the file contains this
80 00
and you read, then store, this with fread (&width,1,2, fp), these 2 bytes get stored into computer memory in that same order. The bytes are in Big-Endian order; the "large" byte is at the end. But if your computer happens to be a Little-Endian order system, you would not get the value 0x0080 = 128 but 0x8000 = 32768 instead!
The way to circumvent this is to read one byte at a time:
width = fgetc(fp) + (fgetc(fp)<<8);
will always read the data in the correct order: low first, then high. Only the sum gets stored (in the order for your system, but that's now irrelevant!).
With the above, I think I'm out of warnings. Using the TGA specifications as a guide, you can now open the file, read the header one byte at a time until you have all information that's needed, and continue to fread your raw image data into memory. You can safely use fread to read your image bytes three at a time because they will appear in the same order into memory as they were read (they are not integers or larger, so the "memory order" is not an issue).
A good approach to ensure you are reading the correct information is this:
Read one byte at a time, to prevent endianness issues.
Add a comment in your code detailing what it is
Print out the value
Check with the specifications if the value is allowed.
To get you started, after the fopen line (and the required check if it worked):
int idLength = fgetc(fp); /* length of id string after header */
printf ("id length: %u bytes\n", idLength);
int colorMapType = fgetc(fp); /* 0 = RGB */
printf ("color map type: %u\n", colorMapType);
if (colorMapType != 0)
{
printf ("unexpected color map type!\n");
return NULL;
}
int imageType = fgetc(fp); /* 0 = None, 1 = Indexed, 2 = RGB, 3 = Greyscale */
.. and so on. When the entire header has been read and you didn't encounter surprises, you are ready to set up things to read the actual image data. No changes needed there, your existing code should work just fine.
Post-edit: I see I used
int colorMapType = fgetc(fp);
where the 'color map type' is in fact a byte, not an integer. That is to allow a belt-and-suspenders approach. If you encounter the end of the file while you are reading the header, the code that fgetc returns is EOF. EOF cannot be stored into a char, because it is an integer value: 0xFFFFFFFF (more accurately: (int)-1). If you store it into a char, you cannot distinguish it from the perfectly okay value 0x000000FF (the value 255).
The belt-and-suspender approach is to check each and every single byte:
if (colorMapType == EOF)
{
printf ("encountered unexpected end of file!\n");
return NULL;
}
Overkill if you are working with a known file, and you know it's a valid TGA (you can view and edit it with bitmap editors), but if you ever plan to work on files of which you don't know if they are valid, you might need this.
Here i am using two different functions for calculating CRC16 for any type of file (.txt,.tar,.tar.gz,.bin,.scr,.sh etc) and different size also varies from 1 KB to 5 GB.
I want to achieve this
`cross platform
less time consuming
Have to work proper for any type of file and any size`
i got same value of CRC in both functions. but any one can tell me which one is more better to calculate CRC16 for any type of file with any size on different different platform.
Here we have to consider 0 to 255 all type characters.
Can any body please suggest me which one is good in my requirements.
Code of both functions :
First one which has int datatype in readChar here i am using int readChar
int CRC16_int(const char* filePath) {
//Declare variable to store CRC result.
unsigned short result;
//Declare loop variables.
int intInnerLoopIndex;
result = 0xffff; //initialize result variable to perform CRC checksum calculation.
//Store message which read from file.
//char content[2000000];
//Create file pointer to open and read file.
FILE *readFile;
//Use to read character from file.
int readChar;
//open a file for Reading
readFile = fopen(filePath, "rb");
//Checking file is able to open or exists.
if (!readFile) {
fputs("Unable to open file %s", stderr);
}
/*
Here reading file and store into variable.
*/
int chCnt = 0;
while ((readChar = getc(readFile)) != EOF) {
//printf("charcater is %c\n",readChar);
//printf("charcater is %c and int is %d \n",readChar,readChar);
result ^= (short) (readChar);
for (intInnerLoopIndex = 0; intInnerLoopIndex < 8; intInnerLoopIndex++) {
if ((result & 0x0001) == 0x0001) {
result = result >> 1; //Perform bit shifting.
result = result ^ 0xa001; //Perform XOR operation on result.
} else {
result = result >> 1; //Perform bit shifting.
}
}
//content[chCnt] = readChar;
chCnt++;
}
printf("\nCRC data length in file: %d", chCnt);
//This is final CRC value for provided message.
return (result);
}
Second one is unsigned char datatype of readChar Here i am using unsigned char readChar
int CRC16_unchar(const char* filePath) {
unsigned int filesize;
//Declare variable to store CRC result.
unsigned short result;
//Declare loop variables.
unsigned int intOuterLoopIndex, intInnerLoopIndex;
result = 0xffff; //initialize result variable to perform CRC checksum calculation.
FILE *readFile;
//Use to read character from file.
//The problem is if you read a byte from a file with the hex value (for example) 0xfe,
//then the char value will be -2 while the unsigned char value will be 254.
//This will significantly affect your CRC
unsigned char readChar;
//open a file for Reading
readFile = fopen(filePath, "rb");
//Checking file is able to open or exists.
if (!readFile) {
fputs("Unable to open file %s", stderr);
}
fseek(readFile, 0, SEEK_END); // seek to end of file
filesize = ftell(readFile); // get current file pointer
fseek(readFile, 0, SEEK_SET); // seek back to beginning of file
/*
Here reading file and store into variable.
*/
int chCnt = 0;
for (intOuterLoopIndex = 0; intOuterLoopIndex < filesize; intOuterLoopIndex++) {
readChar = getc(readFile);
printf("charcater is %c and int is %d\n",readChar,readChar);
result ^= (short) (readChar);
for (intInnerLoopIndex = 0; intInnerLoopIndex < 8; intInnerLoopIndex++) {
if ((result & 0x0001) == 0x0001) {
result = result >> 1; //Perform bit shifting.
result = result ^ 0xa001; //Perform XOR operation on
} else {
result = result >> 1; //Perform bit shifting.
}
}
chCnt++;
}
printf("\nCRC data length in file: %d", chCnt);
return (result);
}
Please Help me to figure out this problem
Thanks
First things first. Don't do file reading (or whatever the source is) and CRC calculating in the same function. This is bad design. File reading is typically not completely platform independent (although POSIX is your best friend), but CRC calculation can be done very platform independently. Also you might want to reuse your CRC algorithm for other kind of data sources which aren't accessed with fopen().
To give you a hint, the CRC function I always drop in to my projects has this prototype:
uint16_t Crc16(const uint8_t* buffer, size_t size,
uint16_t polynomial, uint16_t crc);
You don't have to call the function once and feed it the complete contents of the file. Instead you can loop through the file in blocks and call the function for each block. The polynomial argument in your case is 0xA001 (which is BTW a polynomial in 'reversed' form), and the crc argument is set to 0xFFFF the first time. Each subsequent time you call the function you pass the previous return value of the function to the crc argument.
In your second code frament (CRC16_unchar) you first determine the filesize and then read that number of bytes. Don't do that, it unnecessary limits you to handle files of maximum 4GB (in the most cases). Just reading until EOF is cleaner IMHO.
Furthermore I see that you are struggling with signed/unsigned bytes. Do know that
printf doesn't know if you pass an signed or unsigned integer. You tell printf with '%d' or '%u' how to interpret the integer.
Even in C itself there is hardly a difference between a signed and unsigned integer. C won't magically change the value of 255 to -1 if you do int8_t x = 255.
See this anser for more details about when C uses the signedness of an integer: When does the signedness of an integer really matter?. Rule of thumb: Just always use uint8_t for handling raw bytes.
So both functions are fine regarding signedness/integer size.
EDIT: As other users indicated in their answers, read the file in block instead per-byte:
uint16_t CRC16_int(const char* filePath) {
FILE *readFile;
const uint8_t buf[1024];
size_t len;
uint16_t result = 0xffff;;
/* Open a file for reading. */
readFile = fopen(filePath, "rb");
if (readFile == NULL) {
exit(1);
}
/* Read until EOF. */
while ( (len = fread(buf, sizeof(buf), 1, readFile)) > 0 ) {
result = Crc16(buf, len, 0xA001, result);
}
/* readFile could be in error state, check it with ferror() or feof() functions. */
return result;
}
Also you should alter you function prototype to make it possible to return an error, e.g.:
// Return true when successful, false on error. CRC is stored in result.
bool CRC16_int(const char* filePath, uint16_t *result)
You want to read and write 8-bit bytes using unsigned char instead of plain char because char can be either signed or unsigned and that's up to the compiler (allowed by the C standard). So, the value you get from getc() should be converted to unsigned char prior to being used in the CRC calculations. You could also fread() into an unsigned char. If you work with signed chars, sign extension of chars into ints will likely break your CRC calculations.
Also, per the C standard fseek(FilePtr, 0, SEEK_END) has undefined behavior for binary streams and binary streams need not meaningfully support SEEK_END in fseek(). In practice, though, this usually works as we want.
Another thing you should consider is checking for I/O errors. Your code is broken in this respect.
The datatype you do the calculation with should, in my opinion, not be the same that you read from the file. Doing one function call into the runtime library to read a single byte is simply not efficient. You should probably read on the order of 2-4 KB at a time, and then iterate over each returned "chunk" in whatever manner you choose.
There's also absolutely no point in reading in the size of the file in advance, you should simply read until reading returns less data than expected, in which case you can inspect feof() and ferror() to figure out what to do, typically just stop since you're done. See the fread() manual page.
I'm trying to read a BMP image (greyscales) with C, save values into an array, and convert this array to a string with values separated with a comma.
My program worked well under Windows 7 64-bit, but I had to move to Windows XP 32-bit because of library compatibility problems.
I have 1,750 images to read, and I want to store all of them in a single string.
When I launch my program it goes fine until the 509:th image, then I get a Segmentation Fault caused by fread(). Here's my code:
int i=0,j,k,num,len,length,l;
unsigned char *Buffer;
FILE *fp;
char *string,*finalstring;
char *query;
char tmp2[5],tmp[3];
query = (char *)malloc(sizeof(char)*200000000);
string = (char *)malloc(sizeof(char)*101376);
Buffer = (unsigned char *)malloc(sizeof(unsigned char)*26368);
BITMAPFILEHEADER bMapFileHeader;
BITMAPINFOHEADER bMapInfoHeader;
length = 0;
for (k =1;k<1751;k++)
{
strcpy(link,"imagepath");
//here just indexing the images from 0000 to 1750
sprintf(tmp2,"%.4d",k);
strcat(link,tmp2);
strcat(link,".bmp");
fp = fopen(link, "rb");
num = fread(&bMapFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
num = fread(&bMapInfoHeader,sizeof(BITMAPINFOHEADER),1,fp);
//seek beginning of data in bitmap
fseek(fp,54,SEEK_SET);
//read in bitmap file to data
fread(Buffer,26368,1,fp);
l=0;
for(i=1024;i<26368;i++)
{
itoa(Buffer[i],tmp,10);
len = strlen(tmp);
memcpy(string+l,tmp,len);
memcpy(string+l+len,",",1);
l = l+len+1;
}
memcpy(query,"",1);
memcpy(string,"",1);
printf("%i\n",k);
}
Thanks
Make it tmp[4]; for three digits and the terminating 0.
Also: where is the fclose? I suspect that you're running out of file handles.
Check, whether fp != 0.
Where did you get 101376 from? Each of your bytes take up at most 5 characters as a decimal number with comma (e.g. -127,), 5*26368 is 131840.
Get rid of the casts in malloc calls. And #include <stdlib.h>.
What's the output of this program, in both the 64-bit and 32-bit systems you're using?
#include <stdio.h>
int main(void) {
printf("sizeof (int) is %d\n", (int)(sizeof (int)));
printf("sizeof (int*) is %d\n", (int)(sizeof (int*)));
return 0;
}
Run your program in the debugger.
Set a breakpoint at the call to
fread -- make it conditional on
k==507 (this will stop it when you
expect the fread to be successful).
When the program hits the
breakpoint, examine the variables
and check what is about to be passed
to fread. The first one or two times
you hit the breakpoint, the values
will be good.
Then on the 509th time, you will
probably see bogus values being passed
to fread. Figure out where those
bogus values are coming from --
possibly set a conditional
breakpoint on the variable being set
to whatever the bogus value is.