xDrago
xDrago

Reputation: 2062

Read bin file in C not working as expected

Hey currently i have to do some exercises for a class but I am stuck. I am a bloody beginner in C and have to write a vm.

I am trying to read a .bin file to get information like format, version, amount of instructions ...

thats my code

FILE *inputFile;
char *charBuffer;
int *intBuffer;
long filelen;
char *inputPath = argv[i + 1];
inputFile = fopen(inputPath, "r");
fseek(inputFile, 0, SEEK_END);         
filelen = ftell(inputFile);             
rewind(inputFile);
charBuffer = (char *)malloc((filelen+1)*sizeof(char));
intBuffer = (int *)malloc((filelen+1)*sizeof(int));

fread(charBuffer, sizeof(char), 4, inputFile);

char *format = charBuffer;
printf("format: %s\n", format);

fread(intBuffer, sizeof(int), 1, inputFile);
int *version = intBuffer;
printf("version: %ls\n", version);

fread(intBuffer, sizeof(int), 1, inputFile);
int *instructionCount = intBuffer;
printf("instruction Count: %ls\n", instructionCount);

fread(intBuffer, sizeof(int), 1, inputFile);
int *variables = intBuffer;
printf("variable Count: %ls\n", variables);

and that is the output:

enter image description here

NJBF is correct but I was expected a 2 for version. Why is that such a weird cube with numbers in it? Why are Instructions and variables empty?

Unfortunately the class is only once per week and I cannot ask the instructor.

Thats what is in the test1.bin opened with hexdump

00000000  4e 4a 42 46 02 00 00 00  0b 00 00 00 00 00 00 00  |NJBF............|
00000010  03 00 00 01 04 00 00 01  00 00 00 02 0a 00 00 01  |................|
00000020  06 00 00 01 00 00 00 03  00 00 00 04 00 00 00 08  |................|
00000030  0a 00 00 01 00 00 00 0a  00 00 00 00              |............|
0000003c

These are the rules:

  4 bytes        'N', 'J', 'B', 'F' (identifies the format)
  4 bytes        version number (must match the VM's version number)
  4 bytes        number of instructions contained in the file
  4 bytes        number of variables in the static data area
  n * 4 bytes    instructions (the program to be executed)

Upvotes: 1

Views: 76

Answers (3)

prog-fh
prog-fh

Reputation: 16910

I would probably start with something like this


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

typedef struct
{
  char format[5];
  uint32_t version;
  uint32_t instruction_count;
  uint32_t variable_count;
  uint32_t *instructions;
} VmInfo;

uint32_t
u32_from_LE_bytes(const uint8_t *bytes)
{
  return (((uint32_t)bytes[0])<< 0)|
         (((uint32_t)bytes[1])<< 8)|
         (((uint32_t)bytes[2])<<16)|
         (((uint32_t)bytes[3])<<24);
}

bool // success
load_VmInfo(VmInfo *out_info,
            const char *filename)
{
  FILE *input=fopen(filename, "rb");
  if(!input)
  {
    return false;
  }
  uint8_t raw_header[16];
  if(fread(raw_header, sizeof(raw_header), 1, input)!=1)
  {
    fclose(input);
    return false;
  }
  memcpy(out_info->format, raw_header, 4);
  out_info->format[4]='\0';
  out_info->version=u32_from_LE_bytes(raw_header+4);
  out_info->instruction_count=u32_from_LE_bytes(raw_header+8);
  out_info->variable_count=u32_from_LE_bytes(raw_header+12);
  const size_t amount=out_info->instruction_count*sizeof(uint32_t);
  out_info->instructions=(uint32_t *)malloc(amount);
  if(!out_info->instructions)
  {
    abort();
  }
  if(fread(out_info->instructions, amount, 1, input)!=1)
  {
    fclose(input);
    free(out_info->instructions);
    return false;
  }
  for(uint32_t i=0; i<out_info->instruction_count; ++i)
  {
    const uint8_t *bytes=(const uint8_t *)out_info->instructions+i;
    out_info->instructions[i]=u32_from_LE_bytes(bytes);
  }
  fclose(input);
  return true;
}

int
main(void)
{
  VmInfo info;
  if(!load_VmInfo(&info, "test1.bin"))
  {
    fprintf(stderr,"bad VM file\n");
    return 1;
  }
  printf("format: %s\n", info.format);
  printf("version: %u\n", info.version);
  printf("instruction_count: %u\n", info.instruction_count);
  printf("variable_count: %u\n", info.variable_count);
  for(uint32_t i=0; i<info.instruction_count; ++i)
  {
    printf("  %u\n", info.instructions[i]);
  }
  free(info.instructions);
  return 0;
}

Oops, sorry I'm a bit late, I didn't see the accepted answer while I was writing.

Upvotes: 1

csknk
csknk

Reputation: 2039

It looks like you're trying to print integer data as a char with this line:

printf("version: %ls\n", version);

Because the data (an integer) can't be represented as an ASCII character, your terminal outputs the weird cube.

Try:

printf("version: %d\n", *version);

This should de-reference your integer pointer, and print it as a "raw" integer.

Upvotes: 1

Barmar
Barmar

Reputation: 781833

The version number is an int, not a string. You need to use %d format, and dereference the pointer.

printf("version: %d\n", *intBuffer);

You also need to add a null terminator to charBuffer before using %s to print.

fread(charBuffer, sizeof(char), 4, inputFile);
charBuffer[4] = 0;
printf("Format: %s\n", charBuffer);

Upvotes: 2

Related Questions