Reputation: 3
I'm trying to recover data from an SD card FAT32 knowing that when I find a .jpg
there, it will be there in order till the end of file.
Right now the program is able to recover 1 jpeg but stops. How can I improve it, or can someone point me the logic flaw?
Also at: http://pastebin.com/Rak6L5Z0
EDIT: card file http://www.mediafire.com/?et8pvhvacpy9kv1
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
#define BLOCKSIZE 512
int main(void)
{
// define 512 byte block
BYTE block[BLOCKSIZE];
// open memory card
FILE* fp = fopen("card.raw", "r");
// check if file opened
if (fp == NULL)
{
printf("Error opening file\n");
return 1;
}
// open output file
FILE* outfile;
outfile = NULL;
int num = 0;
char filename[14];
int x = 0;
int y = 1;
// main block till end of file
while (y == 1)
{
if ( x == 0)
{
// read every 512 block
fread(&block, sizeof(block), 1 , fp);
}
// if 4 first characters jpg
if ((block[0] == 0xff && block[1] == 0xd8 && block[2] == 0xff && block[3] == 0xe0) || (block[0] == 0xff && block[1] == 0xd8 && block[2] == 0xff && block[3] == 0xe1))
{
sprintf(filename, "%03d_output.jpg", num);
outfile = fopen(filename, "a");
fwrite(&block, sizeof(block), 1, outfile);
//fseek(fp, sizeof(block), SEEK_CUR);
fread(&block, sizeof(block), 1 , fp);
while (!((block[0] == 0xff && block[1] == 0xd8 && block[2] == 0xff && block[3] == 0xe0) || (block[0] == 0xff && block[1] == 0xd8 && block[2] == 0xff && block[3] == 0xe1)))
{
fwrite(&block, sizeof(block), 1, outfile);
y = fread(&block, sizeof(block), 1, fp);
}
//fseek(fp, -(sizeof(block)), SEEK_CUR);
fclose(outfile);
num++;
x = 1;
//y = fread(&block, sizeof(block), 1, fp);
}
//printf("%s\n", block);
}
// close memory card
fclose(fp);
return 0;
}
Upvotes: 0
Views: 935
Reputation: 754810
One problem is the outer loop:
while (y == 512)
{
...lots of code...
y = fread(&block, sizeof(block), 1, fp);
...some code...
}
The fread()
sets y
to 0
or 1
, so it is no longer 512, so the loop terminates.
I think there is also a problem with the if (x == 0)
followed by x = 1;
, but I'm not sure I understand the logic behind that part of the code. Certainly, x
is not reset to zero after the first file is read — if that matters.
This extracts files 000..050 from the sample data, and file
describes them all as one of these three types:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
#define BLOCKSIZE 512
static inline int is_jpeg_file_header(const BYTE *block)
{
if (block[0] == 0xff && block[1] == 0xd8 && block[2] == 0xff &&
(block[3] == 0xe0 || block[3] == 0xe1))
return 1;
return 0;
}
int main(void)
{
BYTE block[BLOCKSIZE];
const char file[] = "card.raw";
FILE* fp = fopen(file, "r");
if (fp == NULL)
{
fprintf(stderr, "Error opening file %s for reading\n", file);
return 1;
}
int num = 0;
while (fread(&block, sizeof(block), 1, fp) == 1)
{
if (is_jpeg_file_header(block))
{
char filename[20];
snprintf(filename, sizeof(filename), "%03d_output.jpg", num);
FILE* outfile = fopen(filename, "a");
if (outfile == 0)
{
fprintf(stderr, "Error opening file %s for writing\n", filename);
return 1;
}
printf("%s\n", filename);
fwrite(&block, sizeof(block), 1, outfile);
while (fread(&block, sizeof(block), 1 , fp) == 1 &&
!is_jpeg_file_header(block))
{
fwrite(&block, sizeof(block), 1, outfile);
}
fclose(outfile);
num++;
fseek(fp, -BLOCKSIZE, SEEK_CUR);
}
}
fclose(fp);
return 0;
}
This uses the fact that we're reading a disk image to seek back one block when you read the header of the next file. It is simpler than continuing the code.
The first 11 recovered images are all displayable in a web browser.
Upvotes: 1