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);
}
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)
There is no logical errors with my code, but when I compile recover.c, a file called "recover" is produced, and when I give the command "./recover card.raw", it returns nothing to me (basically i only see "recover/ $" in my terminal).
Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define BLOCK 512
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
//reject invalid input
if (argc != 2)
{
printf("Usage: ./recover IMAGE");
return 1;
}
// Open memory card and reject if invalid file
FILE *file = fopen(argv[1], "r");
if (!file)
{
printf("!file\n");
return 2;
}
BYTE temp[512]; //allocate memory to a block (for reading)
char filename[8]; //allocate memory to filename
FILE *img; // there exists a file
int count = 0; // increase counter to read subsequent blocks
while (fread(temp, sizeof(BYTE), BLOCK , file) == 512)
{
BYTE buffer[4];
fread(buffer, sizeof(BYTE), 3 , file); //fread returns the number of items of size "sizeof(BYTE)" that were read, which is "3")
// look for beginning of a .jpeg (0xFF 0xD8 0xFF 0xe?)
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
sprintf(filename, "%03i.jpg", count);//TODO: 2 is a constant. Change later to increments. Change filename as well to increment
// open a new jpeg file, formatted as ###.jpg, starting at 000.jpg
//if loop to close the previous file (if previous file exists)
if (count > 1) //no need to close anything if first jpeg
{
fclose(img);
}
//This can be done by if counter = 0, continue searching for first jpeg, if counter != 0, close prev file and open new img
img = fopen(filename, "w");
if (!img)
{
printf("!img\n");
return 3;
}
fwrite(temp, BLOCK, 1, img);
count++; // write 512 bytes into new img file
}
else if (count > 0) //
{
fwrite(temp, BLOCK, 1, img); //write 512 bytes as a continuation of current opened jpeg file
}
}
}
Thanks in advance for helping me!
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);
}
}
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);
I'm working on an assignment for CS50 but i have a strange behaviour of a counter variable after running sprintf function:
//recover jpg files from memory
#include <stdio.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 2)
{
fprintf(stderr, "Please submit an input file\n");
return 1;
}
// remember filename
char *infile = argv[1];
// open input file
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 2;
}
// define the buffer as array of BYTEs
BYTE buffer[512];
// define the counter of images found
int counter = 0;
// declare the array for the filename
char filename[3];
while (fread(buffer, 512, 1, inptr)>0)
{
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0)
{
sprintf(filename, "%03i.jpg", counter);
printf("%c%c%c\n", filename[0],filename[1],filename[2]);
counter++;
}
}
}
I tried the debug50 tool and i saw that after running fprintf variable counter passes from 0 to a big strange number.
Any suggestions on where is the problem and how to fix it?
Thanks to the comments I got the error:
I forgot to consider the right length of 'filename' variable, and when running sprintf i was exceeding the memory allowed for it