0

I'm helping my son work on the recover.c assignment trying to recover JPEGs from card.raw disk image file. I'm running into a strange behavior trying to display bytes from my 512-byte buffer which is a character array. Here's some test code where I only read the first 11 512-byte blocks.

char block[512];
for (int i=0; i<11; i++)
{
    fread(block, 1, 512, infile);
    printf("Block %i: ", i);
    printf("Byte 0 = %X, Byte 1 = %X\n", block[0], block[1]);
}

I'm only trying to display the first 2 bytes of the 512-byte block because my if code can't match up the first 4 bytes to test if it is a JPEG. Here's the output I'm getting this output when I run the test code.

./recover card.raw
Size of infile is: 5250560
Block 0: Byte 0 = 0, Byte 1 = 0
Block 1: Byte 0 = 63, Byte 1 = 73
Block 2: Byte 0 = FFFFFFFF, Byte 1 = FFFFFFD8
Block 3: Byte 0 = 67, Byte 1 = FFFFFFB3
Block 4: Byte 0 = FFFFFFF6, Byte 1 = FFFFFFC8

I looked at card.raw with a binary viewer.

Block 0, 1, and 3 are outputting the correct 1-byte values for byte 0 and 1.
Block 2 and 4 are spitting out 4-byte values which has be baffled.

This explains why my I can't find any JPEG headers by trying to match block[0] through block[3] to the JPEG header values. Can anyone explain what I'm doing wrong here? Thank you.

1

I took a peek at someone else's answer and got a hint that I had to use the custom BYTE type rather than char type for my array.

// Must include stdint header
#include <stdint.h>

typedef uint8_t  BYTE;
BYTE buffer[512];

I'm still curious why the char type array didn't work.

1
  • char is a signed type. unsigned char would have worked just as well. Apr 13 '18 at 14:56
1

Essentially the problem comes from the implicit casting from char (which remember is just an 8-bit signed integer) to an unsigned hexadecimal integer (32-bits).

This programme shows the problem:

#include <stdio.h>
int main(void)
{
    char chars[] = {1, 127, -1, -128};
    for (int i = 0; i < 4; i++)
    {
        printf("signed int:%i unsigned int:%u unsigned hex:%x\n", chars[i], chars[i], chars[i]);
    }
}

Which outputs:

$ ./test
signed int:1 unsigned int:1 unsigned hex:1
signed int:127 unsigned int:127 unsigned hex:7f
signed int:-1 unsigned int:4294967295 unsigned hex:ffffffff
signed int:-128 unsigned int:4294967168 unsigned hex:ffffff80

Since the block uses signed chars, any byte whose first bit is a 1 will be negative. When you use the format specifier %X you tell the compiler that an unsigned hexadecimal integer need to be substituted here, which it does implicitly.

Note that this isn't an issue if you use and unsigned type because it's a widening type conversion, and doesn't lose data. However, since you are casting from signed to unsigned, the negative integer (8-bit or otherwise) overflows and gives a huge, unexpected number - due to how negative numbers are stored in memory

The solution is just to use an unsigned 8-bit data type like unsigned char or uint8_t (which is all a "BYTE" is, you've just used typedef to rename it).

You must log in to answer this question.

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