binRick / c_rvfs

Read-only virtual file system

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

rvfs

Read-only virtual file system

Purpose

The purpose of this is to be able to ship single executables / libraries where all the external assets & files can be bundled into the binary, and also to provide a comfortable interface
to work with these files inside the application / library.

It has other use cases as well, it can be used to archive multiple files into one, just like .tar.gz or .zip; However; rvfs does not currently compress the data.

Example Use cases

  • VST Plugins that requires external files to function
  • Games that depends on external shader files
  • Any other application that depends on external files in some way

usage

// Populates a RVFSFile struct with recursive content of directory,
// including files in it.
void rvfs_create_from(RVFSFile *f, const char *filepath, const char *name);

// Write a rvfs archive
void rvfs_write(RVFSFile *f, const char *filepath);

// Read a rvfs archive from disk
void rvfs_read(RVFSFile *f, const char *filepath);

// Extract the contents of an rvfs archive to disk
void rvfs_extract(RVFSFile *f, const char *filepath);

// Grab a file from an archive.
RVFSFile* rvfs_get_file(RVFSFile* f, const char* filepath);

// free & deallocate RVFSFile struct.
void rvfs_free(RVFSFile *f);

Basic example:

#include <rvfs/rvfs.h>
#include <stdio.h>

int main(int argc, char *argv[]) {

  // create an archive in-memory from specified path to directory
  RVFSFile f = {};
  rvfs_create_from(&f, argv[1], 0);
  rvfs_free(&f);

  // read an archive from disk into memory
  RVFSFile rf = {};
  rvfs_read(&rf, "test.rvfs");

  // find a file from an archive in memory
  RVFSFile* myfile = rvfs_get_file(&rf, "assets/hello.txt");

  if (myfile) {
    printf("Found it %s\n", myfile->name);
  }

  // extract archive to disk
  rvfs_extract(&rf, "./extract");

  // free RVFSFile struct
  rvfs_free(&rf);

  return 0;
}

CLI

There's also some command line utilities if you compile the executable.
Here's how to use it:

# create an archive
rvfs package <inputdir> <destfile>.rvfs

# extract an archive
rvfs extract <inputfile>.rvfs <destdir>

# query an archive for a specific file
rvfs find <inputfile> <path>

# list the contents of an archive
rvfs show <inputfile>

Linking a .rvfs file into your library or executable

First convert the .rvfs file to a .o file

objcopy -B i386 -I binary -O elf32-i386 <your-file>.rvfs <your-file>.o

Then you can link it to your lib/executable and access the data like this:

extern uint8_t foo_data[]      asm("_binary_foo_data_bin_start");
extern uint8_t foo_data_size[] asm("_binary_foo_data_bin_size");
extern uint8_t foo_data_end[]  asm("_binary_foo_data_bin_end");


int main(int argc, char* argv[]) {
    size_t foo_size = (size_t)((void *)foo_data_size);
    void  *foo_copy = malloc(foo_size);
    assert(foo_copy);
    memcpy(foo_copy, foo_data, foo_size);
    
    // foo_copy should now be an instance of `RVFSFile`.
    RVFSFile* rvfs_file = (RVFSFile*)foo_copy;
}

"foo" in this case would be what you named your .o file.

.rvfs file format specification

The file contains the following fields:

typedef struct RVFS_FILE_STRUCT {
  uint32_t filepath_length;         // length of filepath in bytes
  char *filepath;                   // path to where the file was loaded from
  uint32_t name_length;             // length of name in bytes
  char *name;                       // name of file without path
  uint8_t is_directory;             // is it a directory or not? (1 / 0)
  uint32_t size;                    // length of the `bytes` field following
  uint8_t *bytes;                   // file contents
  uint32_t children_length;         // how many children this node has
  struct RVFS_FILE_STRUCT *children // list of children;
} RVFSFile;

About

Read-only virtual file system


Languages

Language:C 76.8%Language:Meson 13.0%Language:Makefile 7.9%Language:Shell 2.2%