0

My program is managing to detect only 10 jpegs and the files are corrupted. I think my main issue might be the way my loops are constructed or my calls to fseek() but I'm not sure... Any advice is appreciated.

Here is my code so far:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>

typedef uint8_t  BYTE;

int main (int argc, char* argv[]) 
{
    //Verify proper number of arguments
    if (argc != 2) 
    {
        fprintf(stderr, "Usage: ./recover file\n");
        return 1;
    }

    //Remember file names
    char *infile = argv[1];

    //Open the input file, return error if not found
    FILE *recover = fopen(infile, "r");

    if (recover == NULL) 
    {
        fprintf(stderr, "Could not open %s.\n", infile);
        return 2;
    }

    //Counts number of jpegs found
    int count = 0;

    //Stores the jpeg signature to look for
    char header[4] = {0xff, 0xd8, 0xff, 0xe0};

    //Create a buffer with the maximum size of the file to hold the images.
    fseek(recover, 0L, SEEK_END);
    long file_size = ftell(recover);
    char *outfile = malloc(sizeof(BYTE) * file_size);
    rewind(recover);

    BYTE buffer[512];

    FILE *outptr;

    size_t bufferLen;

    //Read card from beginning to end
    do
    {
        //Check for the number of bytes left, if less then 512 the loop should exit.
        bufferLen = fread(&buffer, 1, 512, recover);

        //Read blocks of 512 bytes into memory
        fread(&buffer, 512, 1, recover);

        //If signature is found
        if (buffer[0] == header[0] && buffer[1] == header[1] &&
            buffer[2] == header[2] && (buffer[3] & 0xf0) == 0xe0) 
        {

           //Create a file with the right name.
           snprintf(outfile, 8, "%003i.jpg", count);

           //Open the file we just named so we can write the content of the image
           outptr = fopen(outfile, "w");

           //Continue writing to the same file until another signature is found 
           do
           {
                //Read from buffer 1 block at the time
                fread(&buffer, 512, 1, recover);

                fwrite(recover, 512, 1, outptr);

                fseek(recover, 512, SEEK_CUR);

           } while (buffer[0] != header[0] && buffer[1] != header[1] &&
             buffer[2] != header[2] && (buffer[3] & 0xf0) != 0xe0);

            //Close the image file.
            fclose(outptr);

            //Increment the count for using it as name of next image.
            count++;

        }//end "if"

        else
            fseek(recover, 512, SEEK_CUR);

    } while(bufferLen == 512);

    //Free memory
    free(outfile);

    //Close file

    fclose(recover);

    //success
    return 0; 

}
2

This program is skipping a lot of blocks in the infile, which will cause the problems you describe.

This

do
    {
        //Check for the number of bytes left, if less then 512 the loop should exit.
        bufferLen = fread(&buffer, 1, 512, recover);

        //Read blocks of 512 bytes into memory
        fread(&buffer, 512, 1, recover);

reads two blocks in a row. If the first jpg happened to start at an "even" block, program would never detect it. [Actually that's not precise, because of the else fseek problem mentioned later]. We have to assume there is at least one jpg that starts at an "odd" block; program is producing output, therefore control does get to the next do loop. Program should not do the second fread.

The first problem when control reaches here:

do
           {
                //Read from buffer 1 block at the time
                fread(&buffer, 512, 1, recover);

                fwrite(recover, 512, 1, outptr);

                fseek(recover, 512, SEEK_CUR);

It never writes the signature block (the first thing it does is read the next block). Second, it skips blocks because it reads a block, writes a block, skips (fseek) a block, repeat. Program should not skip any blocks (fseek) while it is processing a jpg.

That leaves one (big) problem in the second do loop. An infinite loop. When program is processing the last jpg, it will never encounter another sig. Because that fread does not check for end-of-file in any way, it will keep reading past the end of infile, and writing, usually until disk fills up and program aborts. [Program does not get stuck in infinite loop now because it never process the last jpg in the file].

The final fseek here:

else
            fseek(recover, 512, SEEK_CUR);

is a problem, because it's going to skip a block. Program should not skip any blocks before it finds the first signature, because it will, in all likelyhood miss a signature.

Also, outfile should be allocated to hold the file name. You know that outfile will be "nnn.jpg". That is a string length of 7 (plus 1 for the null-byte!). This:

 fseek(recover, 0L, SEEK_END);
    long file_size = ftell(recover);
    char *outfile = malloc(sizeof(BYTE) * file_size);
    rewind(recover);

will allocate outfile for 11830784 bytes, the size of the supplied card.raw.

1
  • Thank you! Actually I was working on it right before I read your post and I just figured out exactly what you described, that I was skipping a lot of blocks because of my calls to fread and fseek. I fixed the issue to the best of my abilities and now I can see 49 jpgs so I'm making progress. Your explanations are very clear though and it really helped me understand a few more details that were not so clear to me, like the memory allocation size of the outfile and the problem with the potential infinite do-while loop never detecting the end of file. – Mynah Feb 4 '17 at 15:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .