Skip to content

Instantly share code, notes, and snippets.

@mekb-turtle
Created January 30, 2025 12:43
Show Gist options
  • Save mekb-turtle/553f519c44ab3de2f51f6d699402b680 to your computer and use it in GitHub Desktop.
Save mekb-turtle/553f519c44ab3de2f51f6d699402b680 to your computer and use it in GitHub Desktop.
C file reading util function
#include "util.h"
struct file get_file(FILE *fp, void *(*malloc_)(size_t), void *(*realloc_)(void *, size_t), void (*free_)(void *)) {
return (struct file){
.fp = fp,
.size = 0,
.capacity = 0,
.data = NULL,
.error = false,
.complete = false,
.free = free_,
.malloc = malloc_,
.realloc = realloc_,
};
}
bool read_at(struct file *f, size_t offset, size_t size, uint8_t **out_data, size_t *out_size) {
// read more data
size_t end = offset + size;
while (f->size < end && !f->complete) {
if (f->capacity == 0) f->capacity = 2; // initial capacity
while (end > f->capacity) {
size_t new_capacity = f->capacity * 2;
if (new_capacity < f->capacity) {
// overflow
f->error = true;
f->complete = true;
goto error;
}
f->capacity = new_capacity;
}
// resize buffer
if (f->data) {
void *new_data = f->realloc(f->data, f->capacity);
if (!new_data) goto error;
f->data = new_data;
} else
f->data = f->malloc(f->capacity);
if (!f->data) goto error;
// read data
size_t read = fread(f->data + f->size, 1, f->capacity - f->size, f->fp);
if (read < f->capacity - f->size) {
// error or eof
f->error = ferror(f->fp);
f->complete = f->error || feof(f->fp);
if (f->error) goto error;
}
f->size += read;
}
size_t read_size = f->size < end ? f->size - offset : size;
if (out_data) *out_data = f->data + offset;
if (out_size) *out_size = read_size;
return true;
error:
// free data
if (f->data) f->free(f->data);
f->data = NULL;
return false;
}
int read_byte(struct file *f, size_t offset) {
uint8_t *data;
size_t size;
if (!read_at(f, offset, 1, &data, &size)) return -1;
return *data;
}
bool open_file(char *file_name, struct file *f, void *(*malloc_)(size_t), void *(*realloc_)(void *, size_t), void (*free_)(void *)) {
FILE *fp = fopen(file_name, "rb");
if (!fp) return false;
*f = get_file(fp, malloc_, realloc_, free_);
return true;
}
void close_file(struct file *f) {
if (!f) return;
if (f->data) f->free(f->data);
f->data = NULL;
if (f->fp) fclose(f->fp);
f->fp = NULL;
}
bool is_little_endian() {
uint16_t test = 1;
return *((uint8_t *) &test) == 1;
}
uint16_t endian16(uint16_t value) {
if (!is_little_endian()) return value;
return (value >> 010) | (value << 010);
}
uint32_t endian32(uint32_t value) {
if (!is_little_endian()) return value;
return (value >> 030) | ((value >> 010) & 0xff00) | ((value << 010) & 0xff0000) | (value << 030);
}
uint64_t endian64(uint64_t value) {
if (!is_little_endian()) return value;
return (value >> 070) | ((value >> 050) & 0xff00) | ((value >> 030) & 0xff0000) | ((value >> 010) & 0xff000000) | ((value << 010) & 0xff00000000) | ((value << 030) & 0xff0000000000) | ((value << 050) & 0xff000000000000) | (value << 070);
}
#ifndef UTIL_H
#define UTIL_H
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
struct file {
FILE *fp;
size_t size, capacity;
uint8_t *data;
bool error, complete;
void *(*malloc)(size_t);
void *(*realloc)(void *, size_t);
void (*free)(void *);
};
struct file get_file(FILE *fp, void *(*malloc)(size_t), void *(*realloc)(void *, size_t), void (*free)(void *));
bool read_at(struct file *f, size_t offset, size_t size, uint8_t **out_data, size_t *out_size);
int read_byte(struct file *f, size_t offset);
bool open_file(char *file_name, struct file *f, void *(*malloc_)(size_t), void *(*realloc_)(void *, size_t), void (*free_)(void *));
void close_file(struct file *f);
bool is_little_endian();
uint16_t endian16(uint16_t value);
uint32_t endian32(uint32_t value);
uint64_t endian64(uint64_t value);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment