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!
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)
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);
}
}
This program accepts a filename as input and should recover all jpegs on that file. It reads 512 bytes at a time, checking for the start of a new jpeg.
The program compiles when I run it, but it gives a segmentation fault. Please advise me how I can go about fixing this.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// check for proper usage
if (argc != 2)
{
printf("Usage: 1 command line argument\n");
return 1;
}
// check if file can be opened
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("Cannot be opened\n");
return 2;
}
// read 512 bytes into buffer until end of card
int buffer[128];
int counter;
counter = 0;
char filename[8];
FILE *img = NULL;
while(fread(buffer, 4, 128, file) == 128)
{
//check if start of new JPEG
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//check if first JPEG
if (counter == 0)
{
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
fwrite(buffer, 4, 128, img);
counter += 1;
}
else if (counter > 0)
{
fclose(img);
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
fwrite(buffer, 4, 128, img);
counter += 1;
}
}
else if (counter > 0)
{
fwrite(buffer, 4, 128, img);
}
}
fclose(img);
fclose(file);
return 0;
}
The call fread(buffer, 4, 128, file) reads (as you rightly say) 512 bytes into the array of 128 integers. However, when you then test for the start of a new JPEG file in this code:
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//...
you are inspecting the low bytes of each of the first four integers in the array, rather than (as you should be) checking the first four bytes of the array. These four bytes will all be in the first integer element (buffer[0]).
Thus, your program will never find the start of a new JPEG and, consequently, the img file will never be opened ... and you are then calling fclose with a NULL file pointer, which is undefined behaviour and likely to cause the segmentation fault you see.
Instead (assuming the correct 'endianness'), do the following check:
if ((buffer[0] & 0xfffffff0) == 0xffd8ffe0)
{
//...
To allow for the 'wrong endianness', you could check for either byte order in buffer[0]:
if ((buffer[0] & 0xfffffff0) == 0xffd8ffe0 || (buffer[0] & 0xf0ffffff) == 0xe0ffd8ff)
{
//...
Better still, just read (and write) the buffer for what it is - an array of 512 bytes, with code like this:
unsigned char buffer[512];
//...
while(fread(buffer, 1, 512, file) == 512)
{
//...
This way, you can keep your 'JPEG start' test as it is.
fclose(img) is the culprit. img is NULL. In order to find out why, you can insert some printf after your fopen. Here is the link to debug any segfaults in the future.
$ ./recover card.raw
Memory access error: invalid parameter; abort execution.
# fclose's parameter (0x0) is not a valid FILE pointer.
# Stack trace (most recent call first) of the error.
# [0] file:/recover.c::55, 5
# [1] [libc-start-main]
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 doing a problem set provided by Harvard's online lecture.
I've finally made a solution to recover a set of JPEG images from a file (card.raw).
It seems like the code itself does not throw errors, but it is returning distorted image and I am a little clueless to why it might be happening.
[Link to an image example] https://prnt.sc/q0tb4f
Here's my code
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
//check usage
if (argc != 2)
{
return 1;
}
// open file
FILE* input = fopen(argv[1], "r");
// return error if file does not existS
if (!input)
{
return 1;
printf("file does not exists");
}
// create an array with 512 bytess of bytes
unsigned char bytes[512];
// create count variable
int count = 0;
// create an empty string for filename
char filename[7];
// create an empty output file
FILE* output = NULL;
// repeat until end of input
while (fread(bytes, 1, sizeof(bytes), input) != 0)
{
// read 1 block of 512 bytes at a time
fread(bytes, 1, sizeof(bytes), input);
// check if beginning of jpeg file
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0)
{
// if already found a jpeg, close the file
if (count > 0)
{
fclose(output);
}
// name file
sprintf(filename, "%03i.jpg", count);
// open file
output = fopen(filename, "w");
// write file
fwrite(bytes, 1, sizeof(bytes), output);
// increment count
count++;
}
if (output != NULL)
{
// keep writing if jpeg header is already found
fwrite(bytes, 1, sizeof(bytes), output);
}
}
fclose(output);
fclose(input);
}
My uneducated assumption is unable to see why it might be happening.
I can only imagine that this might be happening from opening and closing files in improper step.
This is the problem:
while (fread(bytes, 1, sizeof(bytes), input) != 0)
{
// read 1 block of 512 bytes at a time
fread(bytes, 1, sizeof(bytes), input);
You're calling fread twice per loop. As a result, the body of the loop only sees the odd-numbered blocks. Remove the second fread.
A second problem (as #SteveFriedl points out) is that the buffer the code uses for the filename is too small.
char filename[7];
sprintf(filename, "%03i.jpg", count);
You need at least 8 bytes for a file name like "123.jpg", because you need room for the NUL terminator. However, note that
"%03i" uses at least 3 characters. It could use more, e.g. if count reaches 1000. So I would declare the buffer as char filename[32]; to avoid any chance of buffer overflow.
You've also got two fwrites when only one is needed:
output = fopen(filename, "w");
// write file
fwrite(bytes, 1, sizeof(bytes), output);
// increment count
count++;
}
if (output != NULL)
{
// keep writing if jpeg header is already found
fwrite(bytes, 1, sizeof(bytes), output);
}
After opening a new file, the code writes the first block, and then writes it again. Remove the first fwrite and let the second fwrite take care of the first block.
Another problem is that the code makes an implicit assumption that if fread doesn't return 0, then it's read a full block. That assumption is OK if the file size is a multiple of the block size, but it's better not to make any assumptions. So the condition in the while loop should be
while (fread(bytes, 1, sizeof(bytes), input) == sizeof(bytes))
here is recover working.
#include <stdio.h>
#include <stdlib.h>
int isAJpg(unsigned char bytes[]);
int main(int argc, char *argv[])
{
if (argc != 2)
{
return 1;
}
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
return 1;
}
char filename[10];
int count = 0;
unsigned char bytes[512];
FILE *output;
int jpgfound = 0;
while (fread(bytes, 512, 1, file) != 0)
{
// if it is a jpg
if (isAJpg(bytes) == 1)
{
if (jpgfound == 1)
{
fclose(output);
}
else
{
jpgfound = 1;
}
// name file
sprintf(filename, "%03d.jpg", count);
// open file
output = fopen(filename, "a");
count++;
}
if (jpgfound == 1)
{
// writes to a file
fwrite(&bytes, 512, 1, output);
}
}
//close the files
fclose(output);
fclose(file);
}
// check in it is a jpg
int isAJpg(unsigned char bytes[])
{
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0)
{
return 1;
}
return 0;
}