cog/Frameworks/Dumb/dumb/DUMBFILE_SYSTEM.md

227 lines
5.6 KiB
Markdown

Specification of DUMBFILE_SYSTEM
================================
DUMB is designed filesystem-agnostic, even though the C standard library
already defines an abstraction over files on a disk. This is useful because
Allegro 4 and 5 define their own abstractions.
To register your own filesystem abstraction with DUMB, you must create an
instance of struct `DUMBFILE_SYSTEM`, fill in your own function pointers
according to the specification below, and call `register_dumbfile_system` on
your instance.
The header `dumb.h` defines `DUMBFILE_SYSTEM` as a struct of function pointers:
```
typedef struct DUMBFILE_SYSTEM
{
void *(*open)(const char *filename);
int (*skip)(void *f, dumb_off_t n);
int (*getc)(void *f);
dumb_ssize_t (*getnc)(char *ptr, size_t n, void *f);
void (*close)(void *f);
int (*seek)(void *f, dumb_off_t n);
dumb_off_t (*get_size)(void *f);
}
DUMBFILE_SYSTEM;
```
Here, `dumb_off_t` is a signed integer at least 64 bits wide, it is intended
to measure file offsets. The return type `dumb_ssize_t` is a signed integer
exactly as wide as `size_t`, it is intended to store either a `size_t` or a
negative error code. Both `dumb_*_t` are defined in `dumb.h`.
The function pointers `skip` and `getnc` are optional, i.e., you may set
some of these to `NULL` in your struct instance. DUMB will then try to
mimick the missing functions' behavior by calling your `getc` several times.
If DUMB is built with debugging flags, it will assert that all other
functions are not `NULL`. In release mode, DUMB will silently fail.
Your non-`NULL` function pointers must conform to the following specification.
open
----
```
void *(*open)(const char *filename);
```
Open a file for reading.
Arguments:
* `const char *filename`: A normal filename as understood by the operating
system. Will be opened for reading.
Returns as `void *`:
* the address of a file handle on successfully opening the file.
DUMB will pass this file handle as argument to other functions of
the `DUMBFILE_SYSTEM`.
* `NULL` on error during opening the file.
Each file has a *position* internally managed by DUMB. A newly opened file
has a position of 0. Other functions from the `DUMBFILE_SYSTEM` can move
this position around.
DUMB allocates memory for the successfully opened file, and will store opaque
information in that memory, e.g., the DUMB-internal file position. This memory
be freed when DUMB calls `close` on the file's handle. The memory is separate
from your own filesystem implementation: You are responsible for supplying the
data, and DUMB is responsible for storing anything about interpreting that
data.
skip
----
```
int (*skip)(void *f, dumb_off_t n);
```
Advance the position in the file.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
* `dumb_off_t n`: Number of bytes to advance in the file. DUMB will only
call this with `n >= 0`. For `n < 0`, the behavior of `skip` is undefined.
Returns as `int`:
* `0` on successfully skipping ahead by `n` bytes.
* `-1` on error.
It is legal to set `skip = NULL` in a `DUMBFILE_SYSTEM`. DUMB will then call
`getc` a total of `n` times to skip ahead in a file. For speed, it is
advisable to supply a proper `skip` implementation.
getc
----
```
int (*getc)(void *f);
```
Read a byte from the file.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
Returns as `int`:
* the value of the byte read, on successfully reading one byte.
* `-1` on error.
After a succesful read, DUMB will treat the file as advanced by one byte.
getnc
-----
```
dumb_ssize_t (*getnc)(char *ptr, size_t n, void *f);
```
Read up to the given number of bytes from the file into a given buffer.
* `char *ptr`: The start of a buffer provided by DUMB.
* `size_t n`: The length of the number of bytes to be read.
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
Returns as `dumb_ssize_t`:
* the number of bytes successfully read, if it was possible to read at least
one byte.
* `-1` on error.
This function shall bytes from the file `f` and store them in sequence in the
buffer beginning at `ptr`. It shall read fewer than `n` bytes if end of file
is encountered before `n` bytes could have been read, otherwise it should read
`n` bytes.
It is legal to set `skip = NULL` in a `DUMBFILE_SYSTEM`. DUMB will then call
`getc` a total of `n` times and store the results in its buffer.
close
-----
```
void (*close)(void *f);
```
Closes a file that has been opened before with `open`.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
DUMB will deallocate the memory that it used to interpret the file. You are
free to treat your resource however you would like: You may deallocate it, or
keep it around for other things. For example, Allegro 5's implementation
of `close` takes a void pointer and does nothing with it at all.
seek
----
```
int (*seek)(void *f, dumb_off_t n);
```
Jump to an arbitrary position in the file.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
* `dumb_off_t n`: The position in the file, relative to the beginning.
There is no guarantee whether `n >= 0`.
Returns as `int`:
* `0` on successfully seeking in the file.
* `-1` on error.
DUMB will modify its internal position of the file accordingly.
A value of `n < 0` shall set the file into an erroneous state from which no
bytes can be read.
get_size
--------
```
dumb_off_t (*get_size)(void *f);
```
Get the length in bytes, i.e., the position after the final byte, of a file.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
Returns as `dumb_off_t`:
* the length of the file in bytes.