I wrote this code to recover 50 images from cs50 pset4 recover. The code can only retrieve 4 images all of which are not the right ones. It is compiling fine. When i use printf to debug it seems like the if(found) piece of code runs many times when name_count == 0 more than it is supposed to.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
typedef uint8_t BYTE;
const int BLOCK_SIZE = 152;
bool is_a_jpeg(BYTE *buffer);
int main(int argc, char *argv[])
{
//Check if there are exactly two commandline arguments
if (argc != 2)
{
printf("usage: ./IMAGE\n");
return 1;
}
//Open a storage device and chack if it has data
FILE *input = fopen(argv[1], "r");
if (input == NULL)
{
fclose(input);
printf("Could not open file.\n");
return 2;
}
//Create a file to write into and clear it
FILE *img = NULL;
//Declar an interger of counting images
int name_count = 0;
// create buffer
BYTE buffer[BLOCK_SIZE];
//Declare space for saving the filename
char filename[8];
//Declare a bolean variable used to check for already found images
bool found = false;
//A function for reading through the device looking for images
while (fread(buffer, BLOCK_SIZE, 1, input))
{
//If a jpeg image is found notify the program(set found = true)
//and start writing the data to a new file
if (is_a_jpeg(buffer))
{
found = true;
//If we are not writing the first image, close the previous one
if (name_count > 0)
{
fclose(img);
}
//Create incrementing filenames for each new picture i.e 000.jpg, 001.jpg etc.
sprintf(filename, "%03d.jpg", name_count);
//Open an initially created empty file and start writing to it
img = fopen (filename, "w");
name_count++;
fwrite(buffer, BLOCK_SIZE, 1, img);
}
//Continue writing to a file as soon as it is found until another JPEG image is found
if(found)
{
fwrite(buffer, BLOCK_SIZE, 1, img);
}
}
//Close all the files
fclose(input);
fclose(img);
return 0;
}
//Function to check for a JPEG Image
bool is_a_jpeg(BYTE *buffer)
{
return buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0;
}
cs50 results for check50
printing dot everytime if(found) code runs. The code unnecessarily spends a lot of time on the first image before closing it
There are some problems in the posted code:
the block size should be 512 bytes, not 152.
you should not fclose(file) if fopen failed. This has undefined behavior.
you unconditionally close img at the end, which may have undefined behavior if no JPG file was found or if the last JPG file could not be open.
both the disk image file and the jpg destination files must be open in binary mode. This may explain unexpected behavior if you are working on Windows.
Here is a modified version:
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef uint8_t BYTE;
const int BLOCK_SIZE = 512;
bool is_a_jpeg(const BYTE *buffer);
int main(int argc, char *argv[]) {
//Check if there are exactly two commandline arguments
if (argc != 2) {
printf("usage: ./IMAGE\n");
return 1;
}
//Open a storage device and check if it has data
FILE *input = fopen(argv[1], "rb");
if (input == NULL) {
fprintf(stderr, "Could not open file %s: %s.\n", argv[1], strerror(errno));
return 2;
}
//Create a file to write into and clear it
FILE *img = NULL;
//Declare an integer of counting images
int name_count = 0;
// create buffer
BYTE buffer[BLOCK_SIZE];
//Declare space for saving the filename
char filename[16];
//A function for reading through the device looking for images
while (fread(buffer, BLOCK_SIZE, 1, input)) {
//If a jpeg image is found notify the program(set found = true)
//and start writing the data to a new file
if (is_a_jpeg(buffer)) {
//close the current image file if any
if (img) {
fclose(img);
img = NULL;
}
//Create incrementing filenames for each new picture i.e 000.jpg, 001.jpg etc.
sprintf(filename, "%03d.jpg", name_count);
name_count++;
//Create an empty file and start writing to it
img = fopen(filename, "wb");
if (img == NULL) {
fprintf(stderr, "Could not open output file %s: %s.\n", filename, strerror(errno));
}
}
//Continue writing to a file as soon as it is found until another JPEG image is found
if (img) {
if (!fwrite(buffer, BLOCK_SIZE, 1, img)) {
fprintf(stderr, "Error writing to %s: %s.\n", filename, strerror(errno));
fclose(img);
img = NULL;
}
}
}
//Close all the files
fclose(input);
if (img)
fclose(img);
return 0;
}
//Function to check for a JPEG Image
bool is_a_jpeg(const BYTE *buffer) {
return buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0;
}
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 have to make a program that extract images from a RAW file. It's specified that the system file is fat32 and blocks of data are 512 bytes. The below program works, at least with the file that is provided for testing, but when i try to use RAW files that I found on the internet, not works and yields a segmentation fault error. Valgrind report some bytes still reachable.
I think I'm reading less or more bytes that the block size for data in the file, so:
How could I know the size of each block data inside the file?
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
// Check for two arguments
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
// Open the forensic image
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
fprintf(stderr, "It's not possible open the file :(\n");
return 2;
}
// Initialize values
int count = 0;
BYTE buffer[512];
char filename[8];
FILE *out = NULL;
// Read blocks of data from forensic image
while (fread(&buffer, sizeof(BYTE), sizeof(buffer), file))
{
// Check if there is a JPG signature
if (buffer[0] == 0xff && buffer[1] == 0xd8
&& buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
// If isn't first loop, close previous output file
if (count != 0)
{
fclose(out);
}
// Save name for current output file
sprintf(filename, "%03i.jpg", count++);
// Open output file
out = fopen(filename, "w");
// Check if file is right
if (out == NULL)
{
fprintf(stderr, "File could not open :(\n");
return 3;
}
// Write data to output file
fwrite(&buffer, sizeof(BYTE), sizeof(buffer), out);
}
// If isn't first loop, write data
else if (count != 0)
{
fwrite(&buffer, sizeof(BYTE), sizeof(buffer), out);
}
}
fclose(out);
fclose(file);
}
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.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
// open memory card
if(argc > 2 )
{
printf("Usage: ./recover image");
return 1;
}
FILE *file = fopen(argv[1], "r");
FILE *img;
// repeat until end
int i = 0;
// 512 bytes into buffer
uint8_t buffer[2048];
char *filename = malloc(8);
// if start of new jpeg
while(fread(&buffer, 512, 4, file)) // read card
{
if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) // if start new jpeg
{
// if first
i++;
sprintf(filename, "%03i.jpg", i);
img = fopen(filename, "w");
fwrite(&buffer, sizeof(uint8_t), 1, img); // fixed
}
//else
else
{
// if still reading jpeg
if(img != NULL)
{
fwrite(&buffer, sizeof(uint8_t), 1, img);
}
}
}
//close
free(filename);
fclose(file);
return 0;
}
I think my code is pretty close to being done but the images returned are invalid or unsupported image format. It compiles fine and it returns 12 images. I do not want to look at a solution to fix this. Where did my code mess up?
I'm stuck in this problem:
Result:
:) recover.c exists.
:) recover.c compiles.
:) handles lack of forensic image
:) recovers 000.jpg correctly
:) recovers middle images correctly
:( recovers 049.jpg correctly
recovered image does not match
The file compiles correctly and all the 50 .jpg files are clear, however there is this small issue with the last file (049.jpg: recovered image does not match) and I just cannot figure out the reason.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main(int argc, char *argv[])
{
// ensure 1 command-line argument:
if(argc != 2)
{
fprintf(stderr, "Usage: name of forensic image from which to recover JPEGs");
return 1;
}
// open the memory card file:
FILE *file = fopen(argv[1], "r");
if (!file)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
fclose(file);
return 2;
}
//fseek(file, 0, SEEK_SET);
unsigned char buffer[512];
char* filename = malloc(50 * sizeof(int));
if (!filename)
{
return 3;
}
bool jpeg_found = false;
int f = 0;
int n = 0;
while (!(feof(file)))
{
sprintf(filename, "%03i.jpg", f);
FILE *img = fopen(filename, "w");
if (!filename) return 6;
if (f > 0) fwrite(buffer, 1, 512, img);
n = 0;
while (n == 0)
{
if (feof(file))
{
fclose(img);
break;
}
fread(buffer, 1, 512, file); //read 512 bytes into a buffer
if (buffer[0] == 0xff && // start of a new JPEG?
buffer[1] == 0xd8 &&
buffer[2] == 0xff && (
buffer[3] & 0xf0) == 0xe0)
{
if (jpeg_found) // have you already found a JPEG or not?
{
// YES: close the previous file and open a new one,
fclose(img);
f += 1;
n = 1;
}
else // NO: start very 1st JPEG
{
fwrite(buffer, 1, 512, img);
jpeg_found = true;
}
}
else
{
if (jpeg_found) // Have your already found a JPEG or not?
{
// YES: Those 512 bytes belong to the current opened JPEG file
fwrite(buffer, 1, 512, img);
}
else // NO: Discard the 512 bytes and go to the start of the loop
{
continue;
}
}
}
}
free(filename);
fclose(file);