0

So, I've been struggling with this bug for a couple days now and can't seem to figure out how to fix it. I've also noticed that the final image file is WAY larger than any of the other jpg's my program spits out, so my reasoning is that the program doesn't know when to stop writing to the image file and close it, as it never encounters another JFIF header. I experimented with a couple of functions that try to identify "zeroed" blocks of memory, so that they don't end up on the final image, but even then, 049.jpg still comes out with around 3.2 megabytes of size, while the other files measure around 30~50 kb.

My code:

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

typedef uint8_t BYTE;
int size(FILE *file);
int check_zero(BYTE buffer[512]);

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)
    {
        return 1;
    }

    BYTE buffer[512];
    double file_size = size(file);
    int jpeg_count = 0;
    FILE *image;

    for (int i = 0; i < file_size; i++)
    {
        fread(buffer, 1, 512, file);

        if ((buffer[0] == 0xff) && (buffer[1]  == 0xd8) && (buffer[2] == 0xff) && ((buffer[3] & 0xf0) == 0xe0))
        {
            char name[7];
            if (jpeg_count == 0)
            {
                sprintf(name, "%03i.jpg", jpeg_count);
                image = fopen(name, "w");
                fwrite(buffer, 1, 512, image);
            }
            else
            {
                fclose(image);
                sprintf(name, "%03i.jpg", jpeg_count);
                image = fopen(name, "w");
                fwrite(buffer, 1, 512, image);
            }

            jpeg_count++;
        }
        else if (jpeg_count > 0)
        {
            if (check_zero(buffer) == 1)
            {
                if (image != NULL)
                {
                    fclose(image);
                }
            }
            else
            {
                fwrite(buffer, 1, 512, image);
            }
        }
    }
}

int size(FILE *file)
{
    BYTE buffer[512];
    int file_size = 0;

    do
    {
        file_size++;
    }
    while(fread(buffer, 1, 512, file) == 512);

    rewind(file);
    return file_size;
}

int check_zero(BYTE buffer[512])    // Checks if memory block is zeroed
{
    for (int i = 0; i < 512; i++)
    {
        if (buffer[i] == 00000000)
        {

        }
        else
        {
            return 0;
        }
    }
    return 1;
}
1

Think about what this code does:

for (int i = 0; i < file_size; i++)
{
    fread(buffer, 1, 512, file);

It says to execute the loop once for every byte in the file, and then reads 512 bytes at a time. That means that the last output file will get the last block of data written out a whole lot of extra times.

The reason that the last block is written out repeatedly is because EOF on the input file was reached, so the buffer doesn't get overwritten with new data. It just keeps the last block that was written to it, so that block just keeps getting copied out to the output file.

To fix this, maybe the file size should be divided by 512? But this has problems too. What happens if the last block is less than 512 bytes?

A better solution would be to use a while loop that reads data and checks for EOF somehow. I'll leave it to you to read the man page on the read functions and to figure out how you can use the return codes. ;-)

[EDIT] I just looked at the rest of the code and I don't understand why there's a check_zero function. I suspect that it's looking to see if the buffer is set to all zeros on the assumption that the code attempted a read past the end of the input file. There are two problems with that.

First, if there is a region of all black pixels, each pixel will be coded as 000000, so there could be a block that is legitimately all zeros.

Second, when the fread tries to read past EOF, the read will fail, the fread call will return an appropriate code, and most importantly, the buffer is not reset. Instead, it will just contain whatever it had before, i.e., the last 512 bytes read from the input file.

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

3
  • The file_size variable is generated by the size() function, which works with a do... while() loop. It adds 1 to the variable, then checks if the return value is the full 512, so because it checks after the increment, it still works if the last chunk is smaller than 512 bytes. I'm also not sure what the excess data actually is, but it doesn't seem to be all zeroes. Any ideas? Mar 15 '20 at 23:10
  • see edit in answer.
    – Cliff B
    Mar 16 '20 at 0:06
  • Using feof() I was able to make it work, turns out it really was repeatedly writing whatever was left in the buffer when it tried to read past the EOF. Mar 16 '20 at 0:25

You must log in to answer this question.

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