2023-08-28 20:46:50 -07:00
|
|
|
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
|
|
|
# pragma once
|
|
|
|
# include "strings.hpp"
|
|
|
|
#endif
|
2023-08-21 17:30:13 -07:00
|
|
|
|
2023-07-25 20:00:57 -07:00
|
|
|
#pragma region File Handling
|
2023-07-24 15:19:37 -07:00
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
enum FileModeFlag
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
EFileMode_READ = bit( 0 ),
|
|
|
|
EFileMode_WRITE = bit( 1 ),
|
|
|
|
EFileMode_APPEND = bit( 2 ),
|
|
|
|
EFileMode_RW = bit( 3 ),
|
|
|
|
GEN_FILE_MODES = EFileMode_READ | EFileMode_WRITE | EFileMode_APPEND | EFileMode_RW,
|
|
|
|
};
|
|
|
|
|
|
|
|
// NOTE: Only used internally and for the file operations
|
2024-12-06 21:21:09 -08:00
|
|
|
enum SeekWhenceType
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
ESeekWhence_BEGIN = 0,
|
|
|
|
ESeekWhence_CURRENT = 1,
|
|
|
|
ESeekWhence_END = 2,
|
|
|
|
};
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
enum FileError
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
EFileError_NONE,
|
|
|
|
EFileError_INVALID,
|
|
|
|
EFileError_INVALID_FILENAME,
|
|
|
|
EFileError_EXISTS,
|
|
|
|
EFileError_NOT_EXISTS,
|
|
|
|
EFileError_PERMISSION,
|
|
|
|
EFileError_TRUNCATION_FAILURE,
|
|
|
|
EFileError_NOT_EMPTY,
|
|
|
|
EFileError_NAME_TOO_LONG,
|
|
|
|
EFileError_UNKNOWN,
|
|
|
|
};
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
union FileDescriptor
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
void* p;
|
|
|
|
sptr i;
|
|
|
|
uptr u;
|
|
|
|
};
|
|
|
|
|
2024-12-07 14:17:02 -08:00
|
|
|
typedef u32 FileMode;
|
2024-12-06 21:21:09 -08:00
|
|
|
typedef struct FileOperations FileOperations;
|
2023-07-24 15:19:37 -07:00
|
|
|
|
|
|
|
#define GEN_FILE_OPEN_PROC( name ) FileError name( FileDescriptor* fd, FileOperations* ops, FileMode mode, char const* filename )
|
2024-10-27 15:58:37 -07:00
|
|
|
#define GEN_FILE_READ_AT_PROC( name ) b32 name( FileDescriptor fd, void* buffer, ssize size, s64 offset, ssize* bytes_read, b32 stop_at_newline )
|
2024-12-04 08:01:53 -08:00
|
|
|
#define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, mem_ptr_const buffer, ssize size, s64 offset, ssize* bytes_written )
|
2023-07-24 15:19:37 -07:00
|
|
|
#define GEN_FILE_SEEK_PROC( name ) b32 name( FileDescriptor fd, s64 offset, SeekWhenceType whence, s64* new_offset )
|
|
|
|
#define GEN_FILE_CLOSE_PROC( name ) void name( FileDescriptor fd )
|
|
|
|
|
|
|
|
typedef GEN_FILE_OPEN_PROC( file_open_proc );
|
|
|
|
typedef GEN_FILE_READ_AT_PROC( FileReadProc );
|
|
|
|
typedef GEN_FILE_WRITE_AT_PROC( FileWriteProc );
|
|
|
|
typedef GEN_FILE_SEEK_PROC( FileSeekProc );
|
|
|
|
typedef GEN_FILE_CLOSE_PROC( FileCloseProc );
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
struct FileOperations
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
FileReadProc* read_at;
|
|
|
|
FileWriteProc* write_at;
|
|
|
|
FileSeekProc* seek;
|
|
|
|
FileCloseProc* close;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern FileOperations const default_file_operations;
|
|
|
|
|
|
|
|
typedef u64 FileTime;
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
enum DirType
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
GEN_DIR_TYPE_FILE,
|
|
|
|
GEN_DIR_TYPE_FOLDER,
|
|
|
|
GEN_DIR_TYPE_UNKNOWN,
|
|
|
|
};
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
struct DirInfo;
|
2023-07-24 15:19:37 -07:00
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
struct DirEntry
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
2024-12-04 23:53:14 -08:00
|
|
|
char const* filename;
|
|
|
|
DirInfo* dir_info;
|
|
|
|
u8 type;
|
2023-07-24 15:19:37 -07:00
|
|
|
};
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
struct DirInfo
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
char const* fullpath;
|
|
|
|
DirEntry* entries; // zpl_array
|
|
|
|
|
|
|
|
// Internals
|
|
|
|
char** filenames; // zpl_array
|
2024-12-12 09:55:15 -08:00
|
|
|
StrBuilder buf;
|
2023-07-24 15:19:37 -07:00
|
|
|
};
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
struct FileInfo
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
FileOperations ops;
|
|
|
|
FileDescriptor fd;
|
|
|
|
b32 is_temp;
|
|
|
|
|
|
|
|
char const* filename;
|
|
|
|
FileTime last_write_time;
|
|
|
|
DirEntry* dir;
|
|
|
|
};
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
enum FileStandardType
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
EFileStandard_INPUT,
|
|
|
|
EFileStandard_OUTPUT,
|
|
|
|
EFileStandard_ERROR,
|
|
|
|
|
|
|
|
EFileStandard_COUNT,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get standard file I/O.
|
|
|
|
* @param std Check zpl_file_standard_type
|
|
|
|
* @return File handle to standard I/O
|
|
|
|
*/
|
|
|
|
FileInfo* file_get_standard( FileStandardType std );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Closes the file
|
|
|
|
* @param file
|
|
|
|
*/
|
|
|
|
FileError file_close( FileInfo* file );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the currently opened file's name
|
|
|
|
* @param file
|
|
|
|
*/
|
|
|
|
inline
|
|
|
|
char const* file_name( FileInfo* file )
|
|
|
|
{
|
|
|
|
return file->filename ? file->filename : "";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Opens a file
|
|
|
|
* @param file
|
|
|
|
* @param filename
|
|
|
|
*/
|
|
|
|
FileError file_open( FileInfo* file, char const* filename );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Opens a file using a specified mode
|
|
|
|
* @param file
|
|
|
|
* @param mode Access mode to use
|
|
|
|
* @param filename
|
|
|
|
*/
|
|
|
|
FileError file_open_mode( FileInfo* file, FileMode mode, char const* filename );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads from a file
|
|
|
|
* @param file
|
|
|
|
* @param buffer Buffer to read to
|
|
|
|
* @param size Size to read
|
|
|
|
*/
|
2024-10-27 15:58:37 -07:00
|
|
|
b32 file_read( FileInfo* file, void* buffer, ssize size );
|
2023-07-24 15:19:37 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads file at a specific offset
|
|
|
|
* @param file
|
|
|
|
* @param buffer Buffer to read to
|
|
|
|
* @param size Size to read
|
|
|
|
* @param offset Offset to read from
|
|
|
|
* @param bytes_read How much data we've actually read
|
|
|
|
*/
|
2024-10-27 15:58:37 -07:00
|
|
|
b32 file_read_at( FileInfo* file, void* buffer, ssize size, s64 offset );
|
2023-07-24 15:19:37 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads file safely
|
|
|
|
* @param file
|
|
|
|
* @param buffer Buffer to read to
|
|
|
|
* @param size Size to read
|
|
|
|
* @param offset Offset to read from
|
|
|
|
* @param bytes_read How much data we've actually read
|
|
|
|
*/
|
2024-10-27 15:58:37 -07:00
|
|
|
b32 file_read_at_check( FileInfo* file, void* buffer, ssize size, s64 offset, ssize* bytes_read );
|
2023-07-24 15:19:37 -07:00
|
|
|
|
2024-12-05 21:33:58 -08:00
|
|
|
typedef struct FileContents FileContents;
|
2023-07-24 15:19:37 -07:00
|
|
|
struct FileContents
|
|
|
|
{
|
|
|
|
AllocatorInfo allocator;
|
|
|
|
void* data;
|
2024-10-27 15:58:37 -07:00
|
|
|
ssize size;
|
2023-07-24 15:19:37 -07:00
|
|
|
};
|
|
|
|
|
2024-12-05 21:33:58 -08:00
|
|
|
constexpr b32 file_zero_terminate = true;
|
|
|
|
constexpr b32 file_no_zero_terminate = false;
|
2023-07-24 15:19:37 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads the whole file contents
|
|
|
|
* @param a Allocator to use
|
|
|
|
* @param zero_terminate End the read data with null terminator
|
|
|
|
* @param filepath Path to the file
|
|
|
|
* @return File contents data
|
|
|
|
*/
|
|
|
|
FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const* filepath );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a size of the file
|
|
|
|
* @param file
|
|
|
|
* @return File size
|
|
|
|
*/
|
|
|
|
s64 file_size( FileInfo* file );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Seeks the file cursor from the beginning of file to a specific position
|
|
|
|
* @param file
|
|
|
|
* @param offset Offset to seek to
|
|
|
|
*/
|
2024-10-27 15:58:37 -07:00
|
|
|
s64 file_seek( FileInfo* file, s64 offset );
|
2023-07-24 15:19:37 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Seeks the file cursor to the end of the file
|
|
|
|
* @param file
|
|
|
|
*/
|
2024-10-27 15:58:37 -07:00
|
|
|
s64 file_seek_to_end( FileInfo* file );
|
2023-07-24 15:19:37 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the length from the beginning of the file we've read so far
|
|
|
|
* @param file
|
|
|
|
* @return Our current position in file
|
|
|
|
*/
|
2024-10-27 15:58:37 -07:00
|
|
|
s64 file_tell( FileInfo* file );
|
2023-07-24 15:19:37 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes to a file
|
|
|
|
* @param file
|
|
|
|
* @param buffer Buffer to read from
|
|
|
|
* @param size Size to read
|
|
|
|
*/
|
2024-10-27 15:58:37 -07:00
|
|
|
b32 file_write( FileInfo* file, void const* buffer, ssize size );
|
2023-07-24 15:19:37 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes to file at a specific offset
|
|
|
|
* @param file
|
|
|
|
* @param buffer Buffer to read from
|
|
|
|
* @param size Size to write
|
|
|
|
* @param offset Offset to write to
|
|
|
|
* @param bytes_written How much data we've actually written
|
|
|
|
*/
|
2024-10-27 15:58:37 -07:00
|
|
|
b32 file_write_at( FileInfo* file, void const* buffer, ssize size, s64 offset );
|
2023-07-24 15:19:37 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes to file safely
|
|
|
|
* @param file
|
|
|
|
* @param buffer Buffer to read from
|
|
|
|
* @param size Size to write
|
|
|
|
* @param offset Offset to write to
|
|
|
|
* @param bytes_written How much data we've actually written
|
|
|
|
*/
|
2024-10-27 15:58:37 -07:00
|
|
|
b32 file_write_at_check( FileInfo* file, void const* buffer, ssize size, s64 offset, ssize* bytes_written );
|
2023-07-24 15:19:37 -07:00
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
enum FileStreamFlags : u32
|
2024-10-27 15:58:37 -07:00
|
|
|
{
|
|
|
|
/* Allows us to write to the buffer directly. Beware: you can not append a new data! */
|
|
|
|
EFileStream_WRITABLE = bit( 0 ),
|
|
|
|
|
|
|
|
/* Clones the input buffer so you can write (zpl_file_write*) data into it. */
|
|
|
|
/* Since we work with a clone, the buffer size can dynamically grow as well. */
|
|
|
|
EFileStream_CLONE_WRITABLE = bit( 1 ),
|
2024-12-04 23:53:14 -08:00
|
|
|
|
|
|
|
EFileStream_UNDERLYING = GEN_U32_MAX,
|
2024-10-27 15:58:37 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Opens a new memory stream
|
|
|
|
* @param file
|
|
|
|
* @param allocator
|
|
|
|
*/
|
|
|
|
b8 file_stream_new( FileInfo* file, AllocatorInfo allocator );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Opens a memory stream over an existing buffer
|
|
|
|
* @param file
|
|
|
|
* @param allocator
|
|
|
|
* @param buffer Memory to create stream from
|
|
|
|
* @param size Buffer's size
|
|
|
|
* @param flags
|
|
|
|
*/
|
|
|
|
b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize size, FileStreamFlags flags );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves the stream's underlying buffer and buffer size.
|
|
|
|
* @param file memory stream
|
|
|
|
* @param size (Optional) buffer size
|
|
|
|
*/
|
|
|
|
u8* file_stream_buf( FileInfo* file, ssize* size );
|
|
|
|
|
|
|
|
extern FileOperations const memory_file_operations;
|
|
|
|
|
|
|
|
inline
|
|
|
|
s64 file_seek( FileInfo* f, s64 offset )
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
s64 new_offset = 0;
|
|
|
|
|
|
|
|
if ( ! f->ops.read_at )
|
|
|
|
f->ops = default_file_operations;
|
|
|
|
|
|
|
|
f->ops.seek( f->fd, offset, ESeekWhence_BEGIN, &new_offset );
|
|
|
|
|
|
|
|
return new_offset;
|
|
|
|
}
|
|
|
|
|
2024-10-27 15:58:37 -07:00
|
|
|
inline
|
|
|
|
s64 file_seek_to_end( FileInfo* f )
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
s64 new_offset = 0;
|
|
|
|
|
|
|
|
if ( ! f->ops.read_at )
|
|
|
|
f->ops = default_file_operations;
|
|
|
|
|
|
|
|
f->ops.seek( f->fd, 0, ESeekWhence_END, &new_offset );
|
|
|
|
|
|
|
|
return new_offset;
|
|
|
|
}
|
|
|
|
|
2024-10-27 15:58:37 -07:00
|
|
|
inline
|
|
|
|
s64 file_tell( FileInfo* f )
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
s64 new_offset = 0;
|
|
|
|
|
|
|
|
if ( ! f->ops.read_at )
|
|
|
|
f->ops = default_file_operations;
|
|
|
|
|
|
|
|
f->ops.seek( f->fd, 0, ESeekWhence_CURRENT, &new_offset );
|
|
|
|
|
|
|
|
return new_offset;
|
|
|
|
}
|
|
|
|
|
2024-10-27 15:58:37 -07:00
|
|
|
inline
|
|
|
|
b32 file_read( FileInfo* f, void* buffer, ssize size )
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
s64 cur_offset = file_tell( f );
|
|
|
|
b32 result = file_read_at( f, buffer, size, file_tell( f ) );
|
|
|
|
file_seek( f, cur_offset + size );
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-10-27 15:58:37 -07:00
|
|
|
inline
|
|
|
|
b32 file_read_at( FileInfo* f, void* buffer, ssize size, s64 offset )
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
return file_read_at_check( f, buffer, size, offset, NULL );
|
|
|
|
}
|
|
|
|
|
2024-10-27 15:58:37 -07:00
|
|
|
inline
|
|
|
|
b32 file_read_at_check( FileInfo* f, void* buffer, ssize size, s64 offset, ssize* bytes_read )
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
if ( ! f->ops.read_at )
|
|
|
|
f->ops = default_file_operations;
|
|
|
|
return f->ops.read_at( f->fd, buffer, size, offset, bytes_read, false );
|
|
|
|
}
|
|
|
|
|
2024-10-27 15:58:37 -07:00
|
|
|
inline
|
|
|
|
b32 file_write( FileInfo* f, void const* buffer, ssize size )
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
s64 cur_offset = file_tell( f );
|
|
|
|
b32 result = file_write_at( f, buffer, size, file_tell( f ) );
|
|
|
|
|
|
|
|
file_seek( f, cur_offset + size );
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-10-27 15:58:37 -07:00
|
|
|
inline
|
|
|
|
b32 file_write_at( FileInfo* f, void const* buffer, ssize size, s64 offset )
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
return file_write_at_check( f, buffer, size, offset, NULL );
|
|
|
|
}
|
|
|
|
|
2024-10-27 15:58:37 -07:00
|
|
|
inline
|
|
|
|
b32 file_write_at_check( FileInfo* f, void const* buffer, ssize size, s64 offset, ssize* bytes_written )
|
2023-07-24 15:19:37 -07:00
|
|
|
{
|
|
|
|
if ( ! f->ops.read_at )
|
|
|
|
f->ops = default_file_operations;
|
|
|
|
|
|
|
|
return f->ops.write_at( f->fd, buffer, size, offset, bytes_written );
|
|
|
|
}
|
|
|
|
|
2023-07-25 20:00:57 -07:00
|
|
|
#pragma endregion File Handling
|