0

I've been working on this problem for a little bit, but right now I have no clue why my code isn't working. Right now it spits out the 50 jpgs like it's supposed to, but they're all blank. Anyone have any idea where I went wrong?

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

int main(int argc, char *argv[])
{
    // checks for exactly 2 args
    if (argc != 2)
    {
        printf("Usage: ./recover input.raw\n");

        return 1;
    }

    // checks if 2nd arg is a file
    FILE *input = fopen(argv[1], "r");
    if (input == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    // initialize variables
    uint8_t buffer[512];
    char filename[7];
    FILE* output = NULL;
    int counter = 0;

    // repeat until input cant be read
    while (fread(&buffer, 512, 1, input))
    {
        // jpg header
        if (buffer[0] == 0xff &&
            buffer[1] == 0xd8 &&
            buffer[2] == 0xff &&
            (buffer[3] & 0xf0) == 0xe0)
        {
            // closes if output exists
            if (output != NULL)
            {
                fclose(output);
            }

            // sets filename to "xxx.jpg", opens a new file with that name, writes to file, and increases counter by 1.
            sprintf(filename, "%03i.jpg", counter);
            output = fopen(filename, "w");
            fwrite(&buffer, 512, 1, output);
            counter++;
        }
        else if (output != NULL) // if currently on a jpg but not the first
        {
            // write to current file.
            fwrite(&buffer, 512, 1, output);
        }
    }

    // close all.
    fclose(output);
    fclose(input);

    return 0;
}
2

Haven't seen this problem in a few months. I understand your frustration because it's a very subtle problem to find! ;-)

This is a good example of why it's important to run a program through a debugger and carefully watch what happens.

The first clue is that all the files become corrupted. That often indicates that there's a problem with the file header - the first block of data in the file. If you were to look at the first few bytes of the file, you'd likely find that the first byte in every jpeg file is 0x00. That's an important clue too!

If you were to step through the code, you'd see that the first byte is getting overwritten at a certain point. If you look closely, you'd see that when this line of code executes, the buffer gets overwritten:

        sprintf(filename, "%03i.jpg", counter);

So why does this happen, you ask? Good question. It's safe to assume that sprintf has no bugs, so it surely has to be something to do with one of the parameters in this call to sprintf. Counter is an int, not too many things can go wrong there. Besides, counter is being read, not written, and the issue is a write problem. So, what about filename?????

Let's check the fundamentals and look at the declaration:

char filename[7];

Now, consider what's being written into filename - the name of the file that's been constructed. It has 3 digits, a dot, and 3 chars. That totals 7. Seems ok, right?

Wrong! The sprintf call will also write the oh-so-important end-of-string (EOS) marker! That makes a write of 8 bytes, not 7. BTW, did you know that the value of the EOS marker is 0x00 ??? Are you catching on yet? ;-)

Here's the scoop. Most function calls that write text will write out whatever they are told to write, regardless of how much space is allocated to the target. In this case, sprintf is running out of space to write the EOS marker, so it just writes it to the next byte in physical memory. It's very common in this pset that the next byte in physical memory is the buffer! So, the first byte gets overwritten to 0x00.

In short, here's what happens. A signature block is read from the input file and written to the buffer. Since it's a sig block, the current output file, if any, is closed. Next, the new filename is constructed and written to filename. In the process, the first byte of the buffer, containing a signature block, is overwritten to 0x00. The new output file is then opened and the corrupted signature/header block is written out. boom!

Can't get much more detailed than that! But don't worry too much. A lot of people make this mistake. Once they do, they rarely repeat it! ;-)

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

1
  • I figured that it had something to do with the header, but I had no idea that the filename array was making it corrupt. I changed it to 8 bytes instead of 7, and now it works. Thanks for the help!
    – rio
    Mar 28 at 18:07

You must log in to answer this question.

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