Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: read binary file to memory, alter buffer, write buffer to file

The goal: Open a file with binary data, read the whole file into memory, change some parts oft he file, write the memory buffer to the file, close the file. Profit?

The problem: I have just started learning C and I can't find enough information about how to change to binary data in the memory buffer. Coming from a web developer background (php, python, as3) this is new territory for me.

The context: I have a function which takes the path to the file and a pointer adress to a char pointer memory buffer. It then opens the file, loops through the file and writes data to the memory buffer. Finally closes the file.

The purpose of the binary file is to hold category-ids for some objects and their position is their own id. The category-ids are represented as 2 byte shorts. So essentially it's just a binary file filled with lots of shorts that I want to be able to read and change.

Here's what I got so far:

main.c:

#include "binary-handler.h"

void showFileBuffer(char *buffer, unsigned int fileSize){
    int i = 0;
    for(; i < fileSize; ++i){
        printf("<%d:%x>\n", i, ((char *)buffer)[i]);
    }
}

int main(){
    char path[] = "assets/map-squares.bin";
    char *buffer;
    int fileSize;
    fileSize = readFileToMemory(path, &buffer);
    showFileBuffer(buffer, fileSize);

    //Code to change buffer
    //Code to write buffer to file
    return 0;
}

binary-handler.c:

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

unsigned int getFileSize(FILE **file){
    unsigned int size;
    if(fseek(*file, 0, SEEK_END) == -1){ return -1; }
    size = ftell(*file);
    fseek(*file, 0, SEEK_SET);
    return size;
}

char *getFileBuffer(FILE **file, unsigned int fileSize){
    char *buffer = malloc(fileSize + 1);
    fread(buffer, fileSize, 1, *file);
    return buffer;
}

unsigned int readFileToMemory(char path[], char **buffer){
    unsigned int fileSize;

    FILE *file = fopen(path, "rb");
    if(file != NULL){
        fileSize = getFileSize(&file);
        *buffer = getFileBuffer(&file, fileSize);
        fclose(file);
        return fileSize;
    }else{
        *buffer = NULL;
        return -1;
    }
}

1. Will this code produce the first step (reading file to memory) correctly?

2. If yes, how can I change, say the 2nd object in the buffer to have a value of 0F 00?

3. How can I take the buffer and write it back to the file?

4. Is there a way for me to check the values in the buffer in a verbose way?

All in all I just want help with getting a grasp of the whole concept so I can solve this myself.

Thanks!

Edit: Removed the looping of the file. Added a function which prints the whole buffer.

like image 970
rzetterberg Avatar asked Feb 27 '11 16:02

rzetterberg


1 Answers

1) No. You do not need to loop in getFileBuffer since you read the entire file with fread. You also do not need to call fseek because every time you read from the file you will advance within the file stream automatically. I haven't debugged your code, but it looks like by the time your loop completes, every element in buffer will contain the same value and it will be equal to whatever is the last byte in your file.

Note: The arguments your specified for fread are backwards. The second parameter is the size of the type you are reading which should be sizeof(char). The third parameter should be the amount of chars you want to read which should be fileSize. Your code still works, though, but it is saying it wants to read 1 object that is fileSize bytes long when you are reading fileSize objects that are 1 byte long.

2) You can read the second short value like this (in little endian):

short n = 0;
n |= buffer[2] << 0;
n |= buffer[3] << 8;

You can write the short back to the file like this:

buffer[2] = n >> 0;
buffer[3] = n >> 8;

3) fwrite

4) I don't understand what you are asking.

like image 153
Marlon Avatar answered Oct 18 '22 10:10

Marlon