I'm building a program for a class that pulls all bytes from a raw file in blocks of 512 bytes, searches the beginning bytes of each block for JPG signatures, and upon finding JPG signatures, writes out a JPG image. I have successfully pulled one JPG from the raw file, however the course indicates there are several more. After debugging in GDB, I've noticed that the variable "jpgname" never seems to have a value, and also, stepping through the program, I regularly step to the "fclose(inptr)" line, as if it were within the main while() loop. Am I using GDB incorrectly? Am I using sprintf() incorrectly? I would appreciate any feedback on this issue.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef uint8_t BYTE;
int main(void)
{
BYTE jpg1[4] = {0xff, 0xd8, 0xff, 0xe0};
BYTE jpg2[4] = {0xff, 0xd8, 0xff, 0xe1};
int open = 0;
FILE* outp;
char* jpgname = malloc(sizeof(char) * 8);
int counter;
//TODO - MAKE sure this isn't a bunch of garbage data
//open card file
FILE* inptr = fopen("card.raw", "r");
if (inptr == NULL)
{
printf("Could not open file\n");
return 2;
}
BYTE buffer[512];
fread(buffer, 512, 1, inptr);
//repeat until end of card
while(fread(buffer, 512, 1, inptr) > 0)
{
counter = 0;
//start of new jpg?
if((buffer[0] == jpg1[0] && buffer[1] == jpg1[1] && buffer[2] == jpg1[2] && buffer[3] == jpg1[3]) || (buffer[0] == jpg2[0] && buffer[1] == jpg2[1] && buffer[2] == jpg2[2] && buffer[3] == jpg2[3]))
{
sprintf(jpgname, "%d.jpg", counter);
if (open == 1)
{
//close
fclose(outp);
//name new file
outp = fopen(jpgname, "w");
//write new
fwrite(buffer, sizeof(buffer), 1, outp);
counter++;
}
else if (open == 0)
{
//write new file
outp = fopen(jpgname, "w");
fwrite(buffer, sizeof(buffer), 1, outp);
open = 1;
counter++;
}
}
else
{
if(open == 1)
{
fwrite(buffer, sizeof(buffer), 1, outp);
}
}
}
fclose(outp);
fclose(inptr);
//close any remaining files
}
BYTE buffer[512];
fread(buffer, 512, 1, inptr);
//repeat until end of card
while(fread(buffer, 512, 1, inptr) > 0)
You should check why you decided to drop the beginning 512 bytes read in.
FILE* inptr = fopen("card.raw", "r");
You should open input file and output files in binary mode like:
FILE* inptr = fopen("card.raw", "rb");
outp = fopen(jpgname, "wb");
Otherwise, the data read in or written out may be messed.
While I appreciate everyone's input and have made my code better as such, the error causing the program to not work at all was due to my counter being reset to 0 at the beginning of the loop.
while(fread(buffer, 512, 1, inptr) > 0)
{
counter = 0;
...
}
should be
counter = 0;
while(fread(buffer, 512, 1, inptr) > 0)
{
...
}
Related
So I'm trying CS50 Recover exercise (where you need to search for jpg files in a memory card and whenever you find one- you open a new file and write the jpg found to the new file). My code compiles and returns 51 jpegs instead of only 50 and all of them are incorrect. Please, I need some cues on what to focus at and fix/replace.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
// Check for valid usage
if ( argc != 2)
{
printf("Usage: ./recover IMAGE\n");
return 1;
}
// Check for valid image
FILE *image = fopen(argv[1], "r");
if (image == NULL)
{
return 1;
}
BYTE buffer[512];
int i = 0;
char new_image[8];
FILE *output;
FILE *output1;
while (fread (buffer, 1, 512, image) == 512)
{
// IF Start of a JPEG
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && ((buffer[3] & 0xf0) == 0xe0))
{
sprintf(new_image, "%03i.jpg", i);
//if first JPEG
if ( i == 0)
{
output = fopen(new_image, "w");
fwrite(buffer, 512, 1, output);
i++;
}
// if not first JPEG
else
{
fclose(output);
sprintf(new_image, "%03i.jpg", i);
output1 = fopen(new_image, "w");
fwrite(buffer, 1, 512, output1);
fclose(output1);
i++;
}
}
// if not start of a JPEG
else
{
output = output1 = fopen(new_image, "w");
fwrite(buffer, 1, 512, output);
}
}
fclose(image);
}
I'm trying to solve this problem which consists of reading data from a "memory card" and write it into new readable jpg files.
I'm getting 50 files named correctly as far as I can tell but their data is incorrect. to me it looks like it should be writing into each jpg the data read into the buffer from the card or argv[1] but I'm guessing I'm missing something and I can't figure out what.
this is what I wrote so far:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
int is_jpg(BYTE(buffer[]))
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xe0) == 0xe0)
{
return 1;
}
else
{
return 0;
}
}
int main(int argc, char *argv[])
{
BYTE buffer[512];
//checks argument validity
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
FILE *file = fopen(argv[1], "r");
//printf("continuing program\n");
//checks if the file exists
if (file == NULL)
{
printf("No file found\n");
return 2;
}
int file_count = 0;
char file_name[8];
//sprintf(file_name, "%03d.jpg", file_count);
FILE *image;
while (fread(buffer, 512, 1, file) == 1)
{
if (is_jpg(buffer) == 1)
{
if (file_count != 0)
{
fclose(image);
}
sprintf(file_name, "%03d.jpg", file_count);
image = fopen(file_name, "w");
fread(&buffer, 512, 1 , file);
fwrite(&buffer, 512, 1, image);
file_count++;
}
else if (file_count > 0)
{
fwrite(buffer, 512, 1, image);
}
//fwrite(&buffer, 512, 1, image);
}
}
When you detect the header, you do an extra fread [after the image = fopen(file_name, "w"); call].
You want to write the header to the output file/stream. But, the extra fread trashes the header data and the first block of the file is data and not the header as you desire.
You only want the fread at the top of the loop.
I got a segmentation fault with this code. Can anyone help? I have tried a couple of ways but still could not solve the problem. I tried replacing FILE *img = NULL by FILE *img, but it gives another error said variable 'img' is uninitialized when used in fwrite(buffer, 512, 1, img)
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
//Open memory card
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
FILE *file = fopen(argv[1], "r");
if (!file)
{
return 1;
}
//Read 512 bytes into a buffer
int counter = 0;
unsigned char buffer[512];
char filename[8];
FILE *img = NULL;
while (fread(buffer, 512, 1, file) == 1)
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] && 0xf0 == 0xe0))
{
//If first JPEG
if (counter == 0)
{
//open a new file
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
//write the array into the new file
fwrite(buffer, 512, 1, img);
counter++;
}
//if not first JPEG
else
{
//close the file
fclose(img);
//open a new file
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
//write the array into the new file
fwrite(buffer, 512, 1, img);
counter++;
}
}
//Else, if already found new JPEG
else
{
fwrite(buffer, 512, 1, img);
}
}
//Close any remaining files
fclose(img);
fclose(file);
return 0;
}
When this if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] && 0xf0 == 0xe0)) is not true (as with the first read), what does program do?
This comment //Else, if already found new JPEG needs to be put into code; ie the following write needs to be conditional.
I am completing a problem in CS50, and my code is successful although I don't understand the behavior of a test inside of it.
Line 63 if (feof(inptr))checks if the end of file is reached, and then I ask to print the size of a buffer pointer which should be less than what it was initialized to (512).
It still returns a value of 512 although the EOF is reached, which doesn't make sense.
Could someone tell me what is wrong?
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 2)
{
fprintf(stderr, "Usage: copy infile outfile\n");
return 1;
}
// remember filenames
char *infile = argv[1];
char *outfile = "000.jpg";
// open input file
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 2;
}
// open output file
FILE *outptr = fopen(outfile, "w");
if (outptr == NULL)
{
fclose(inptr);
fprintf(stderr, "Could not create %s.\n", outfile);
return 3;
}
// declaring variable
unsigned char buffer[512];
int count = 0;
int test = 512;
// Execute until we find end of card
while (!feof(inptr))
{
// Read buffer in card
fread(buffer, 1, sizeof(buffer), inptr);
// Checks for jpeg signature
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0)
{
fwrite(buffer, 1, sizeof(buffer), outptr);
fread(buffer, 1, sizeof(buffer), inptr);
// Checks if we are still in a jpeg, not the beginning of new one
while (buffer[0] != 0xff ||
buffer[1] != 0xd8 ||
buffer[2] != 0xff ||
(buffer[3] & 0xf0) != 0xe0)
{
// Exits loop if end of file
if (feof(inptr))
{
int size = sizeof(buffer);
printf("%i\n", size);
break;
}
fwrite(buffer, 1, sizeof(buffer), outptr);
fread(buffer, 1, sizeof(buffer), inptr);
}
if (feof(inptr))
{
break;
}
// Close jpeg
fclose(outptr);
// Change count to apply to next jpeg title
count++;
char img_num[4];
sprintf(img_num, "%03i.jpg", count);
// Assign new title to new jpeg
outfile = img_num;
printf("%s\n", outfile);
outptr = fopen(outfile, "w");
// We will have to read again in the main loop, so rewind
fseek(inptr, -512, SEEK_CUR);
}
}
printf("%i\n", test);
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// success
return 0;
}
sizeof(buffer) tells you how big buffer is. It does not tell you anything about what was in it—not how many bytes are currently valid, and not how many were read in the last fread.
The proper way to know how many bytes fread read is to use its return value. You ought to use code such as:
size_t BytesRead = fread(buffer, 1, sizeof(buffer), inptr);
If, after this statement, BytesRead is less than sizeof buffer, then fread did not read all the bytes you asked for. That is an indication that something is wrong, and it is a better indication than whether the file EOF flag is set.
(sizeof) returns size in bytes of the object representation of type
https://en.cppreference.com/w/cpp/language/sizeof
Since you allocated 512 bytes for buffer, sizeof will return 512. It doesn't matter what buffer is holding since its not a length check.
I could use some guidance on this pset from cs50. Below is the code i have so far. I am stuck at this point where i have no idea how to proceed. When i run the program it does output 16 jpg files but i cannot view them so something must be wrong. Any tips are welcome.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
// create buffer to store in
unsigned char buffer[512];
// array for filename is 8 for "000.jpg"
char jpgName[8];
// declaring counter for amount of jpegs
int jpgcounter = 0;
// open memory card file
FILE* inptr = fopen("card.raw", "r");
FILE* outptr = NULL;
if (inptr == NULL)
{
printf("Could not open %s.\n", "card.raw");
return 1;
}
// repeat until end of card
while(fread(buffer, sizeof(buffer), 1, inptr) == 1)
{
// find beginning of jpg
if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] == 0xe0 || buffer[3] == 0xe1))
{
// if allready a outptr file is open close it
if (outptr != NULL)
{
fclose(outptr);
}
// create filename for jpegs
sprintf(jpgName,"%03d.jpg", jpgcounter);
// open a new file with name defined by sprintf
FILE* outptr = fopen(jpgName, "w");
// write into the outfile from buffer
fwrite(&buffer, sizeof(buffer), 1, outptr);
// increment counter for jpegs
jpgcounter++;
}
}
fclose(inptr);
return 0;
}
If I understood your task correctly, you want something like this-please see below.
Hint: what are you planning to do if it is not beginning of jpg file?
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
unsigned char buffer[512] = {0};
char jpgName[8] = {0};
int jpgcounter = 0;
FILE* outptr = NULL;
// open memory card file
FILE* inptr = fopen("card.raw", "rb");
if (inptr == NULL)
{
printf("Could not open %s.\n", "card.raw");
return 1;
}
// Start reading
while(fread(buffer, sizeof(buffer), 1, inptr) == 1)
{
// Find beginning of jpg
if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] == 0xe0 || buffer[3] == 0xe1))
{
if(NULL!=outptr)
{
fclose(outptr);
outptr=NULL;
}
// Create filename for jpegs
sprintf(jpgName,"%03d.jpg", jpgcounter);
// Open a new file with name defined by sprintf
outptr = fopen(jpgName, "wb");
if (NULL == outptr)
{
printf("Could not open %s.\n", jpgName);
return 1;
}
// Write into the outfile from buffer
fwrite(buffer, sizeof(buffer), 1, outptr);
// Increment counter for jpegs
jpgcounter++;
}
else
{
// Continue writing to old file if it is not beginning of file
if(NULL!=outptr)
fwrite(buffer, sizeof(buffer), 1, outptr);
}
}
if(NULL!=outptr)
fclose(outptr);
if(NULL!=inptr)
fclose(inptr);
return 0;
}
This can't work:
while(fread(buffer, sizeof(buffer), 1, inptr) == 1)
{
// read 512 bytes from inptr and store them in buffer
fread(&buffer, sizeof(buffer) , 1, inptr);
as you use fread twice and the data read by the first get overwritten by the second. It looks as if this loses the first 512 bytes of every kB in the original file.
You should get further if you delete the second fread().