Mercurial > molko
view libmlk-core/mlk/core/vfs.h @ 641:fcd124e513ea
core: reintroduce VFS
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 01 Oct 2023 09:18:01 +0200 |
parents | 9850089c9671 |
children |
line wrap: on
line source
/* * vfs.h -- virtual file system abstraction * * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef MLK_CORE_VFS_H #define MLK_CORE_VFS_H /** * \file mlk/core/vfs.h * \brief Virtual file system abstraction. * * This module offers an abstract interface to load files and perform read/write * operation on them. This can be useful for games that are designed to load * large assets from compressed archives. * * The molko frameworks comes with two implementations: * * | module | support | remarks | * |--------------------|-------------|------------------------------------| * | mlk/core/vfs-dir.h | read, write | opens file relative to a directory | * | mlk/core/vfs-zip.h | read | zip archive files extractor | * * ## Opening mode * * Both VFS interfaces and function can take a `const char *` mode argument to * indicate user open mode. Each implementation can take specific interface * options but the following are reserved and must be understood by each: * * - `e`: start writing at end * - `r`: open for reading * - `t`: truncate file (can't be used without `w`) * - `w`: open for writing (create file but keep content if exists) * * Mode `e` is meaning less when combined with `t`. * * \note In contrast to C `fopen` function, modes can be mixed which means `r`, * `w` and `rw` means read-only, write-only and read-write respectively. * * ## Initialize a VFS * * To use this module, you must first open a VFS interface. It is usually * implemented using the ::MLK_CONTAINER_OF macro. * * Example with mlk/core/vfs-dir.h * * ```c * struct mlk_vfs_dir dir; * * mlk_vfs_dir_init(&dir, "/usr/share/mario"); * ``` * * The abstract interface will be located in the `vfs` field for each * implementation. * * ## Opening files * * Once your VFS module is initialized, you can call ::mlk_vfs_open to load an * entry from it: * * ```c * struct mlk_vfs_file *file; * char content[1024]; * size_t len; * * file = mlk_vfs_open(&dir.vfs, "block.png", "r"); * * if (!file) * your_handle_failure_function(); * * // The function does not append a NUL terminator. * len = mlk_vfs_file_read(file, content, sizeof (content) - 1); * * if (len == (size_t)-1) * your_handle_failure_function(); * * // Use content freely... * ``` * * ## Cleaning up resources * * Opened files SHOULD be destroyed before the VFS itself because depending on * the underlying implementation, it is possible that those opened files have * direct references to the VFS module. * * ```c * mlk_vfs_file_finish(file); * mlk_vfs_finish(&dir.vfs); * ``` */ #include <stddef.h> struct mlk_vfs_file; /** * \struct mlk_vfs * \brief Abstract VFS loader. */ struct mlk_vfs { /** * (read-write, borrowed, optional) * * Arbitrary user data for callbacks. */ void *data; /** * (read-write) * * Open the file from the VFS. * * The mode argument must contain the following letters: * * - `+`: truncate file if exists * - `r`: open for reading * - `w`: open for writing * - `x`: open exclusive mode * * \pre self != NULL * \pre entry != NULL * \pre mode != NULL * \param self this vfs * \param entry the entry filename * \param mode open mode as described above * \return a VFS file or NULL on failure */ struct mlk_vfs_file * (*open)(struct mlk_vfs *self, const char *entry, const char *mode); /** * (read-write) * * Cleanup resources. * * \pre self != NULL * \param self this vfs */ void (*finish)(struct mlk_vfs *self); }; /** * \struct mlk_vfs_file * \brief Abstract VFS file. */ struct mlk_vfs_file { /** * (read-write, borrowed, optional) * * Arbitrary user data for callbacks. */ void *data; /** * (read-write, optional) * * Attempt to read file entry into the buffer destination. The function * can read less bytes than requested. * * If the function is NULL, an error is returned with an error string * telling that the operation is not supported. * * \pre self != NULL * \pre buf != NULL * \param self this VFS file * \param buf the buffer destination * \param bufsz maximum buffer size to read * \return the number of bytes read or -1 on error */ size_t (*read)(struct mlk_vfs_file *self, void *buf, size_t bufsz); /** * (read-write, optional) * * Attempt to write file entry from the buffer source. The function can * write less bytes than requested. * * If the function is NULL, an error is returned with an error string * telling that the operation is not supported. * * \pre self != NULL * \pre buf != NULL * \param self this VFS file * \param buf the buffer source * \param bufsz the buffer length * \return the number of bytes written or -1 on error */ size_t (*write)(struct mlk_vfs_file *self, const void *buf, size_t bufsz); /** * (read-write, optional) * * Attempt to flush pending input/output on the underlying interface. * * If the function is NULL, it is considered success. * * \pre self != NULL * \param self this VFS file * \return 0 on success or -1 on error */ int (*flush)(struct mlk_vfs_file *self); /** * (read-write, optional) * * Cleanup resources for this VFS file. * * \pre self != NULL * \param self this VFS file */ void (*finish)(struct mlk_vfs_file *self); }; #if defined(__cplusplus) extern "C" #endif /** * Invoke ::mlk_vfs::open if not NULL. */ struct mlk_vfs_file * mlk_vfs_open(struct mlk_vfs *vfs, const char *entry, const char *mode); /** * Invoke ::mlk_vfs::finish if not NULL. */ void mlk_vfs_finish(struct mlk_vfs *vfs); /** * Invoke ::mlk_vfs_file::read if not NULL. */ size_t mlk_vfs_file_read(struct mlk_vfs_file *file, void *buf, size_t bufsz); /** * Convenient function to read an entire file content using repeated calls to * ::mlk_vfs_file_read function until end of file is reached. * * The returned string is dynamically allocated and must be free'd using * ::mlk_alloc_free function. * * \pre file != NULL * \param file this VFS file * \param len pointer receiving the number of bytes read (can be NULL) * \return the string content (user owned) */ char * mlk_vfs_file_read_all(struct mlk_vfs_file *file, size_t *len); /** * Invoke ::mlk_vfs_file::finish if not NULL. */ size_t mlk_vfs_file_write(struct mlk_vfs_file *file, void *buf, size_t bufsz); /** * Invoke ::mlk_vfs_file::flush if not NULL. */ int mlk_vfs_file_flush(struct mlk_vfs_file *file); /** * Invoke ::mlk_vfs_file::finish if not NULL. */ void mlk_vfs_file_finish(struct mlk_vfs_file *file); #if defined(__cplusplus) } #endif #endif /* MLK_CORE_VFS_H */