0

My code recovers all the images and correctly names them but fails check50.

This is check50 output:

:) recover.c exists
:) recover.c compiles
:) recovers 000.jpg correctly
:( recovers middle files correctly
:( recovers last file correctly
\ expected 015.jpg to exist

https://sandbox.cs50.net/checks/0393dc52b1274a32a31dfc0ae54d9d2f

This is my code:

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

typedef uint8_t BYTE;

unsigned long get_filesize(FILE *file);
bool isjpg(BYTE *block);
FILE* new_jpg(int *filenum);

int main(int argc, char* argv[])
{
    // open card image
    FILE *card = fopen("card.raw", "r");

    if (card == NULL)
    {
        printf("Unable to open file\n");
        return 1;
    }

    unsigned long file_size = get_filesize(card);

    FILE *jpg = NULL;

    // used to set the name of jpg files
    int filenumber = 0;

    // iterate over blocks
    for (int block_num = 1; ((block_num * 512) < file_size); block_num++)
    {
        BYTE *block = malloc(sizeof(BYTE) * 512);

        fread(block, sizeof(BYTE) * 512, 1, card);

        // check if block is start of jpg
        if(isjpg(block))
        {
            // close previous jpg and set pointer to null
            if (jpg != NULL)
            {
                fclose(jpg);

                jpg = NULL;
            }

            // open new jpg file
            jpg = new_jpg(&filenumber);

            if (jpg == NULL)
            {
                printf("Unable to create jpg file");
                return 2;
            }

            filenumber++;

            // write block to image file
            fwrite(block, sizeof(BYTE) * 512, 1, jpg);
        }
        // if block isn't start of jpg, just add block to file
        else if (jpg != NULL)
        {
            fwrite(block, sizeof(BYTE) * 512, 1, jpg);
        }

        free(block);
    }

    fclose(jpg);

    fclose(card);
}

// calculate file size moving cursor to end of file,
// store position and move to start
unsigned long get_filesize(FILE *file)
{
    fseek(file, 0l, SEEK_END);
    unsigned long size = ftell(file);
    fseek(file, 0l, SEEK_SET);

    return size;
}

// check first 3 bytes and the first four bits of fourth byte
//to see if block is the start of jpg 
bool isjpg(BYTE *block)
{
    return ( (block[0] == 0xff) && (block[1] == 0xd8) && (block[2] == 0xff) && ((block[4] ^ 0xe0) == 0xe0) );
}

// open new jpg file and returns pointer to it
FILE* new_jpg(int *filenum)
{
    char *filename = malloc(sizeof("000.jpg") + 1);

    // create file name based on number of file
    sprintf(filename, "%03i.jpg", *filenum);

    FILE *jpg = fopen(filename, "w");

    free(filename);

    return jpg;
}

Can someone help me fix this? Thanks

1

(block[4] ^ 0xe0) == 0xe0) What's block[4]?

4
  • It's the 4th byte of the file signature.
    – Daniel P.
    Oct 3 '16 at 1:42
  • 1
    No, it's the 5th byte. The first byte is block[0].
    – Cliff B
    Oct 3 '16 at 1:50
  • After fixing that it now segfaults somewhere, so another thing to fix. Think that is why it fails check50?
    – Daniel P.
    Oct 3 '16 at 18:44
  • Solved it! This line: for (int block_num = 1; ((block_num * 512) < file_size); block_num++) should been: for (int block_num = 1; ((block_num * 512) <= file_size); block_num++) it wasn't writing the last block in the last jpg. The segfault in my previous comment was because after "fixing" the block[4] line it didn't opened any jpg and was trying to close NULL pointer, dont know why but worked after simply deleting (block[4] ^ 0xe0) == 0xe0).
    – Daniel P.
    Oct 3 '16 at 19:52

You must log in to answer this question.

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