My source code successfully compiles and produced in a total of 50 pictures.
However, none of the recovered images do match the original image.
All of the jpegs look like these below.
As you can see, they seem to have weird edges overlapping.
Some of them look okay, but still fail to match the original picture.
If you can give any insight on how to debug, please let me know.
Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("Could not open %s.\n", argv[1]);
return 1;
}
typedef uint8_t BYTE;
BYTE buffer[512];
char *filename[8];
int jpeg_counter = 0;
bool foundStartOfJPEG = false;
FILE *img;
// read memory card until the end of file
while(fread(buffer, sizeof(BYTE) * 512, 1, file) == 1)
{
// if buffer has a signature of JPEG file,
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && ((buffer[3]) & 0xf0) == 0xe0)
{
if (foundStartOfJPEG == true)
{
fclose(img);
jpeg_counter += 1;
}
foundStartOfJPEG = true;
// create a file with index
sprintf(*filename, "%03i.jpg", jpeg_counter);
// open that file to write into it
img = fopen(*filename, "w");
// write the block of memory (buffer), to that file
fwrite(buffer, sizeof(buffer), 1, img);
}
else if (foundStartOfJPEG == true)
{
fwrite(buffer, sizeof(buffer), 1, img);
}
}
fclose(file);
return 0;
}
I tried out your code and it works when you change filename from a pointer to an array (i.e. char *filename to char filename).
This also works and incorporates the use of pointers. Here p is a pointer that points to filename. However, I think its use is redundant. Without the use of p at all, you could say that filename is a pointer that points to the first element of filename, i.e. filename[0]. So when you used char *filename[8] that was like saying filename is a pointer that points to a pointer... Hope that makes sense!
typedef uint8_t BYTE;
BYTE buffer[512];
char filename[8];
char *p = filename;
int jpeg_counter = 0;
bool foundStartOfJPEG = false;
FILE *img;
// read memory card until the end of file
while(fread(buffer, sizeof(BYTE) * 512, 1, file) == 1)
{
// if buffer has a signature of JPEG file,
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && ((buffer[3]) & 0xf0) == 0xe0)
{
if (foundStartOfJPEG == true)
{
fclose(img);
}
jpeg_counter += 1;
foundStartOfJPEG = true;
// create a file with index
sprintf(p, "%03i.jpg", jpeg_counter);
// open that file to write into it
img = fopen(p, "w");
// write the block of memory (buffer), to that file
fwrite(buffer, sizeof(buffer), 1, img);
}
else if (foundStartOfJPEG == true)
{
fwrite(buffer, sizeof(buffer), 1, img);
}
}
Related
I'm writing this code to be able to recover(JPEGs_ memory from a memory card that has deleted them.
My code compiles and is able to run; however, the output images never load.
I tried doing debugging, but I can't seem to see what the issue could be.
Perhaps some pointers on how to debug code that only appears to indicate a problem after the code has produced an output would be useful. (if this indeed is what I am missing)
What is there that I could be missing?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
const int BLOCKSIZE = 512;
FILE *img = NULL;
int main(int argc, char *argv[])
{
//Check if there is only 1 argument entered
if (argc != 2)
{
printf("Usage: ./recover ###.jpg\n");
return 1;
}
//open memorry card and ensure that it's readable
FILE *raw_memory = fopen(argv[1], "r");
if (raw_memory == NULL)
{
printf("Could not open file\n");
return 2;
}
//Repeat until the end of card:
uint8_t *buffer = malloc(BLOCKSIZE);
int jpg_counter = 0;
bool jpg_found = false;
while (true) //Read 512 bytes into a buffer
{
size_t bytes_read = fread (buffer, 1, BLOCKSIZE, raw_memory);
// If end of raw_memory reached, exit loop
if (bytes_read < BLOCKSIZE)
{
break;
}
// If start of new JPG
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//Open new raw_memory and start writing
//If first JPG raw_memory
if (jpg_counter == 0)
{
//Open new raw_memory and start writing
char str[100];
sprintf(str, "%03i.jpg", jpg_counter);
img = fopen(str, "w");
if (img == NULL)
{
printf("Could not open jpeg file\n");
return 3;
}
fwrite(buffer, sizeof(buffer), 1, img);
jpg_counter++;
jpg_found = true;
}
else //close previously file and open a new one
{
fclose(img);
jpg_found = false;
char str[100];
sprintf(str, "%03i.jpg", jpg_counter);
img = fopen(str, "w");
if (img == NULL)
{
printf("Could not open jpeg file\n");
return 4;
}
fwrite(buffer, sizeof(buffer), 1, img);
jpg_found = true;
jpg_counter++;
}
}
else
{
if (jpg_found)
{
fwrite(buffer, sizeof(buffer), 1, img);
}
}
}
fclose(img);
fclose(raw_memory);
free(buffer);
}
A) Since you need 512 elements, instead of uint8_t *buffer = malloc(BLOCKSIZE); do at global level
uint8_t tmp[BLOCKSIZE];
uint8_t *buffer = &tmp[0];
B) Instead of fread (buffer, 1, BLOCKSIZE, raw_memory); do fread(buffer, sizeof(uint8_t), BLOCKSIZE, raw_memory); The same applies for fwrite(buffer, sizeof(buffer), 1, img); to fwrite(buffer, sizeof(uint8_t), BLOCKSIZE, img); This per documentation https://manual.cs50.io/3/fwrite
C) I think that many problems arise from the design of what is inside of this if statement (line 45)
// If start of new JPG
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//Open new raw_memory and start writing
//If first JPG raw_memory
if (jpg_counter == 0)
{
Try:
Changing if (jpg_counter == 0) for if (jpg_counter > 0) simplifying the if statements so only if there are already photo files you can close them, no else.
Getting rid of char str[100]; Instead try char str[8]; since 000.jpg is 7 chars long + '\0'.
You don't need jpg_found = false; on line 70, since that var is only useful before finding the first image.
Hope that's useful...
Edit 1: since buffer needs to be a pointer in fread and fwrite of BlOCKSIZE times the type, better that buffer points to an uint8_t array of size BLOCKSIZE, instead of using malloc.
Edit 2: Thus, no further need of free(buffer);
buffer is a pointer, so sizeof(buffer) is the size of a pointer, not the number of bytes in the buffer. If you declare the buffer as an array uint8_t buffer[BLOCKSIZE]; then the malloc and free aren't needed, and sizeof(buffer) will work as expected
Replacing sizeofbuffer with BLOCKSIZE should allocate enough bytes for the code to work
(credit: #user3386109)
Trying to solve this problem i keep finding the same errors:
:) recover.c exists.
:) recover.c compiles.
:) handles lack of forensic image
:( recovers 000.jpg correctly
000.jpg not found
:( recovers middle images correctly
001.jpg not found
:( recovers 049.jpg correctly
049.jpg not found
That makes me think that the files are not been read or opened at all and i can't find why because the code compiles.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
int main(int argc, char* argv[])
{
//checks if there is an input
if (argc != 2)
{
printf("./recover Usage: ./recover image \n");
return 1;
}
else
{
char* filename = argv[1];
FILE* input = fopen(filename, "r");
if (strcmp(filename, "card.raw") != 0)
{
printf("Unable to open: %s\n", filename);
return 2;
}
else
{
//Create buffer
uint8_t buffer[512];
//Create pointer for the buffer
FILE* output = NULL;
// create 8 bytes file
char files[8];
//Files counters
int jpeg_counter = 0;
//Check
while (fread(buffer, sizeof(buffer), 1, input))
{
//check 4 first bytes of file to see if they contain the jpg signature
if ((buffer[0] == 0xff) && (buffer[1] == 0xd8) && (buffer[2] == 0xff) && ((buffer[3] & 0xf0) == 0xe0))
{
if (output != NULL) {
// sprintf(char *str, const char *format, ...) and "03i" means 3 digits in format 001, 002...
sprintf(files, "%03i.jpg", jpeg_counter);
//use created pointer to save jpeg files from input folder card.raw
output = fopen(filename, "w");
//add jpeg to the new buffer using ouput pointer
fwrite(buffer, sizeof(buffer), 1, output);
// update counter
jpeg_counter++;
}
else //no more files to read(end of folder array) - or no images found.
{
printf("Could not open file\n");
return 0;
}
}
}
fclose(output);
fclose(input);
return 0;
}
}
}
Here is another attempt at a solution, however, it only writes out the first 512 bytes (unlike the original) but I don't think jpeg uses 512 bytes fixed chunks so neither the op or or #BarmakShemirani solution would work as expected. (buffer[3] & 0xf0) == 0xe0 means variable sized, application specific and there is a reference that data is laid out like TIFF, In either case op did not share card.raw so whatever format is used would be speculation:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FILENAME_LEN 8
int main(int argc, char* argv[]) {
int r = 0;
FILE *input = NULL;
if (argc != 2) {
printf("./recover Usage: ./recover image \n");
r = 1;
goto out;
}
char *filename = argv[1];
input = fopen(filename, "rb");
if (!strcmp(filename, "card.raw")) {
printf("Unable to open: %s\n", filename);
r = 2;
goto out;
}
for(int jpeg_counter = 0; !r; jpeg_counter++) {
uint8_t buffer[512];
size_t n = fread(buffer, sizeof(buffer), 1, input);
// use an existing library instead?
if(
n < 4 ||
buffer[0] != 0xff ||
buffer[1] != 0xd8 ||
buffer[2] != 0xff ||
(buffer[3] & 0xf0) != 0xe0
) {
printf("invalid header\n");
r = 3;
break;
}
char filename2[FILENAME_LEN];
if(snprintf(filename2, FILENAME_LEN, "%03i.jpg", jpeg_counter) >= FILENAME_LEN) {
printf("%s: output filename truncated", filename);
r = 4;
break;
};
FILE *output = fopen(filename2, "wb");
if(!output) {
printf("%s: fopen failed\n", filename);
r = 5;
break;
}
// TBD: replace with a loop once we figure out
// how a given file is terminated.
if(fwrite(buffer, n, 1, output) != n) {
printf("%s: write failed\n", filename);
r = 6;
}
fclose(output);
}
out:
if(input) fclose(input);
return r;
}
uint8_t buffer[512];
fread(buffer, sizeof(buffer), 1, input)
This should be change to: fread(buffer, 1, sizeof(buffer), input). This way fread will read up to 512 bytes. When it gets to the end of file, it reads whatever is left, for example 1 byte, and returns that number. Likewise, fwrite should change. It should write the same number which was read earlier.
Open the file in binary mode.
If fopen fails then stop immediately.
Check the file header only once, not every read loop.
Your condition for checking the file header may have a typo (buffer[3] & 0xf0) == 0xe0. Checking the first 3 bytes should be okay.
int main()
{
FILE* input = fopen("input.jpg", "rb");
if (!input)
{ perror("input error"); return 0; }
FILE* output = fopen("output.jpg", "wb");
if (!output)
{ perror("output error"); fclose(input); return 0; }
uint8_t buf[1000];
int check_header = 1;
while (1)
{
size_t read_count = fread(buf, 1, sizeof(buf), input);
if (!read_count)
break;
if (check_header)
{
if (buf[0] == 0xff && buf[1] == 0xd8 && buf[2] == 0xff)
// && buf[3] == 0xe0 ?
{ printf("header is okay\n"); }
else
{ printf("not okay\n"); break; }
check_header = 0; //don't check header again
}
fwrite(buf, 1, read_count, output);
}
fclose(input);
fclose(output);
return 0;
}
Thanks for the help. Tried those and got the same error. What surprisingly worked for me was to refactor even more the code and give use of the counter for the if conditions as shown below.
int main(int argc, char* argv[])
{
//checks if there is an input
if (argc != 2)
{
printf(".Usage: Looking for card.raw \n");
return 1;
}
else
{
char* filename = argv[1];
FILE* input;
input = fopen(filename, "r");
//to track if it fails to open
if (input == NULL)
{
printf("Could not open file");
return 2;
}
//Create buffer. Unsigned int variable type. Array of 512 bytes
uint8_t buffer[512];
//Create pointer for the buffer.
FILE* output = NULL;
// create 8 bytes file
char files[8];
//Files counters
int jpeg_counter = 0;
//Check
while (fread(buffer, sizeof(buffer), 1, input))
{
//check 4 first bytes of file to see if they contain the jpg signature
if ((buffer[0] == 0xff) && (buffer[1] == 0xd8) && (buffer[2] == 0xff) && ((buffer[3] & 0xf0) == 0xe0))
{
if (jpeg_counter != 0)
{
fclose(output);
}
// sprintf(char *str, const char *format, ...) and "03i" means 3 digits in format 001, 002...
sprintf(files, "%03i.jpg", jpeg_counter);
//use created pointer to save jpeg files from input folder card.raw
output = fopen(files, "w");
//add jpeg to the new buffer using ouput pointer
fwrite(buffer, sizeof(buffer), 1, output);
// update counter
jpeg_counter++;
} else if (jpeg_counter != 0)
{
fwrite(buffer, sizeof(buffer), 1, output);
}
}
fclose(output);
return 0;
}
}
This is in relation to my last post about finding the start of JPEGs and creating new jpg files with each new found JPEG. I am only getting part of one JPEG after running the below code (instead of the 50 that I know are in my card.raw file) and I am trying to run the debugger to find the issue. I am looking into my buffer to see why this is only executing the if(buffer[]...) statement once and dont understand how to read the value of what the debugger is showing me under local variables.
I am trying to compare the first four values to the hex values for a JPEG file signature and these BYTE values make no sense to me. If someone could please shed some light. Here is my code as well.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// using keyword typedef to give the uint8_t a new name of BYTE (capitalized by convention)
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
// must be two arguments or program not run correctly
if(argc != 2)
{
printf("Usage: ./recover filename\n");
return 1;
}
// open file and store its location in a pointer called infile
FILE *infile = fopen(argv[1], "r");
if(infile == NULL)
{
printf("file cannot be opened or doesnt exist...\n");
return 1;
}
// create buffer to store a filename with a formatted string of ###.jpg starting at 000.jpg
int number = 0;
char filename[8];
sprintf(filename, "%03i.jpg", number);
FILE *img = NULL;
// read using fread(), each 512 byte block into a buffer
//need a buffer of size 512 BYTEs
BYTE buffer[512];
while(fread(&buffer, sizeof(BYTE), 512, infile))
{
// this demarks a JPEG using bitwise logical & for last buffer bit of signature
if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
if(number == 0)
{
img = fopen(filename, "w");
if(img == NULL)
{
printf("Unable to open file\n");
return 1;
}
fwrite(&buffer, sizeof(BYTE), 512, img);
}
else
{
fclose(img);
number ++;
sprintf(filename, "%03i.jpg", number);
img = fopen(filename, "w");
if(img == NULL)
{
printf("Unable to open file\n");
return 1;
}
fwrite(&buffer, sizeof(BYTE), 512, img);
}
}
else if(img != NULL)
{
fwrite(&buffer, sizeof(BYTE), 512, img);
}
}
I have been working on an assignment that recovers deleted data from the memory card so that the image is viewable. My code compiles and runs fine and produces viewable jpeg images. The program also automatically titles the jpeg image by assigning a number to it. However, when I run it, it is only able produce about half of the images. The other half were unviewable, with random numbers as titles and the error 'unsupported image format' is shown. I'm not too sure what went wrong with my code and I'm fairly new to the intricacies but I suspect it has something to do with memory. Here is my code, any help would be really nice:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
bool function(unsigned char arr[], FILE *pointer);
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr,"Usage: ./recover image");
return 1;
}
// opening the memory card
FILE *memorycard = fopen(argv[1], "r");
if (memorycard == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
unsigned char buffer[512];
int i = 0;
char filename[8];
while(fread(buffer,1, 512, memorycard) == 512)
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//create a new file
sprintf(filename, "%03i.jpg", i);
//write the values currently stored in the buffer to the file
FILE *img = fopen(filename, "w");
fwrite(buffer, sizeof(char), 512, img);
memset (buffer, 0, 512);
//add one to the title of the next jpeg file
i++;
do
{
//read the next chunk of 512 bytes
fread(buffer,1, 512, memorycard);
}
while (function(buffer, img) == true);
}
}
}
bool function(unsigned char arr[], FILE *pointer)
{
if (arr[0] == 0xff && arr[1] == 0xd8 && arr[2] == 0xff && (arr[3] & 0xf0) == 0xe0)
{
//rewind by 512 bytes
fseek(pointer, -512, SEEK_CUR);
//close file being written to
fclose(pointer);
memset (arr, 0, 512);
return false;
}
else
{
//write values into the currently opened file
fwrite(arr, sizeof(char), 512, pointer);
memset(arr, 0, 512);
return true;
}
}
I changed a couple things in your code. In general try to always keep the file "cursor" moving in one direction (try not to seek backwards too much) because this can ruin time complexity especially for large sd cards. This is the modified code I came up with let me know if it works or might clear anything up for you. I haven't actually run this because I don't have anything to test with; however it should work in theory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
struct _imgblock{
// The first 4 bytes have a magic sequence and it is just easier to view them all as 1 integer
int32_t magicTag;
char buffer[508];
}__attribute__((packed));
typedef union{
struct _imgblock imageBlock;
unsigned char dataBuffer[512];
} Buffer;
// make sure this function matches the sequence sepcified in the original code (that the low order byte & 0xf0 is 0xe0 and the other bytes match 0xffd8ff)
bool buffer_starts_with_magic(Buffer* buff){
return (buff->imageBlock.magicTag & 0xf0) == 0xe0 && (buff->imageBlock.magicTag >> 8) & 0xffd8ff;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr,"Usage: ./recover image");
return 1;
}
// opening the memory card
FILE *memorycard = fopen(argv[1], "r");
if (memorycard == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
Buffer custom_buff;
int i = 0;
char filename[8];
FILE* openFile = NULL;
// Start reading 512 byte buffers from the file
while(fread(&custom_buff,1, sizeof(Buffer), memorycard) == sizeof(Buffer))
{
// If the buffer starts with the magic sequence found in the original code and a file is open
if(buffer_starts_with_magic(&custom_buff) && openFile){
// then end the current file and start a new one
fclose(openFile);
openFile = NULL;
}else if(openFile){
// else if the buffer doesnt start with the magic sequence append data and keep reading
goto appendBuffer;
}
//create the new file
sprintf(filename, "%03i.jpg", i++);
openFile = fopen(filename,"w");
appendBuffer: fwrite(custom_buff.dataBuffer,1,512,openFile);
}
if(openFile)
fclose(openFile);
openFile = NULL;
fclose(memorycard);
}
I am trying to use fread on a file containing multiple JPEGs and write the JPEGs into new files, but before I can do that I need to properly look through the file and look for the JPEGs based on their first bytes based on the if statement at the bottom of the code below.
I have not been able to get into the if statement, and have been trying to print out the bytes, but I have been running into issues in printing.
I'm looking to print just the 0 byte of the buffer, but my output is looking like this:
711151a6
cec117f0
7603c9a9
73599166
I'm very new to C and fread, and any help would be appreciated!
Code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// Check for 2 arguments, the name of the program and the file being read
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
else
{
//Open the file
FILE * fp;
fp = fopen(argv[1], "r");
//Get file length
fseek(fp, 0, SEEK_END);
int f_length = ftell(fp);
fseek(fp, 0, SEEK_SET);
// If not file is found then exit
if(fp == NULL)
{
printf("File not found\n");
return 2;
}
// Allocate buffer for fread function
int *buffer = (int*)malloc(f_length);
if (buffer == NULL)
{
printf("Buffer is null\n");
return 1;
}
// Read thorugh the file
while(fread(buffer, 512, 1, fp) == 1)
{
for (int i = 0; i < 1; i++)
{
printf("%x\n", buffer[i]);
}
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
printf("Found a jpg\n");
}
}
// Exit the program
return 0;
}
}
int *buffer is not correct because the intention is to deal with bytes and not ints. If int * is used, then for example, buffer[0] will be the first 4 bytes and not the first byte as intended. Change that to unsigned char *buffer.
So explicitly, that line should be the following (including removing the unnecessary cast):
unsigned char *buffer = malloc(f_length);