Descent3/cfile/cfile.h

348 lines
13 KiB
C
Raw Normal View History

2024-04-16 03:43:29 +00:00
/*
2024-05-16 15:21:30 +00:00
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
--- HISTORICAL COMMENTS FOLLOW ---
2024-04-16 03:43:29 +00:00
* $Logfile: /DescentIII/Main/lib/CFILE.H $
* $Revision: 16 $
* $Date: 10/18/99 1:27p $
* $Author: Kevin $
*
* Functions for reading & writing files. Includes code to read from libraries.
*
* $Log: /DescentIII/Main/lib/CFILE.H $
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 16 10/18/99 1:27p Kevin
* Added cf_IsFileInHog
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 15 9/14/99 7:49p Jeff
* added cf_OpenFileInLibrary() to force a file to be opened from a
2024-09-03 11:03:41 +00:00
* specific library. Added a way to get a CRC of a file given its CFILE
2024-04-16 03:43:29 +00:00
* *.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 14 5/20/99 5:32p Matt
* Store a lib handle, instead of a lib pointer, in the cfile struct.
* This will keep us from using a pointer to lib that's already been
* closed.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 13 3/22/99 6:26p Matt
* Cleaned up error handling in cfile and editor level loads.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 12 1/07/99 10:51p Jeff
* added psglob and support to do find in files for hog files
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 11 11/16/98 3:49p Jason
* changes for manage system
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 10 11/11/98 2:58p Jeff
* added cf_ClearAllSearchPaths() function
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 9 10/22/98 10:48a Matt
* Added code to keep the library file open all the time, which will
* hopefully speed up file loads.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 8 8/14/98 6:31p Matt
* Changed comment
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 7 7/28/98 12:27p Kevin
* Added CRC function
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 6 7/09/98 8:33p Samir
* Added cf_Rewind.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 5 3/19/98 3:18p Samir
* enforce constant char* arguments when needed. done in CFILE and bitmap
* libraries as well as ddio.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 4 2/26/98 11:01a Jason
* added cf_ChangeFileAttributes function
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 3 2/15/98 7:44p Matt
* Added groovy try/catch/throw error checking for cfile functions
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 2 12/17/97 4:09p Jason
* fixed compiler warning
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 11 5/23/97 2:27p Matt
* Text file newlines now handled internally.
* Don't look in libs for files opened for writing.
* Changed error message to print out errno.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 10 4/03/97 4:34p Jason
* added CopyFileTime to the cfile, ddio libs
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 9 3/03/97 6:21p Matt
* Changed cfile functions to use D3 naming convention
*
* $NoKeywords: $
*/
#ifndef CFILE_H
#define CFILE_H
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <filesystem>
#include <functional>
#include <vector>
2024-04-16 03:43:29 +00:00
struct library;
2024-04-16 18:56:40 +00:00
// The structure for a CFILE
struct CFILE {
2024-05-16 15:21:30 +00:00
char *name; // pointer to filename
FILE *file; // the file itself (on disk) or the HOG
int32_t lib_handle; // the handle of the library, or -1
uint32_t size; // length of this file
uint32_t lib_offset; // offset into HOG of start of file, or 0 if on disk
uint32_t position; // current position in file
uint32_t flags; // see values below
};
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Defines for cfile_error
enum CFileError {
CFE_READING = 1,
CFE_WRITING,
};
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// The structure thrown by a cfile error
struct cfile_error {
2024-05-16 15:21:30 +00:00
int read_write; // reading or writing? See defines.
const char *msg; // the error message
CFILE *file; // the file that got the error
};
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Flags for CFILE struct
enum CFileFlags {
CFF_TEXT = 1, // if this bit set, file is text
CFF_WRITING, // if bit set, file opened for writing
};
// return values for cfexist()
enum CFileExitStatus {
CFES_NOT_FOUND = 0,
CFES_ON_DISK,
CFES_IN_LIBRARY,
};
2024-04-16 03:43:29 +00:00
Move Base_directory into the cfile module The main motivation behind this commit is to make it easier to create a future commit. That future commit will will take multiple different functions from throughout the codebase and replace them with a new function named cf_LocatePath(). One of the functions that will get replaced is cf_FindRealFileNameCaseInsensitive(). There are tests for cf_FindRealFileNameCaseInsensitive() in cfile/tests/cfile_tests.cpp. When I make that future commit, I will have to change the tests in cfile/test/cfile_tests.cpp so that they test the cf_LocatePath() function instead of the cf_FindRealFileNameCaseInsensitive() function. There is an important difference between cf_LocatePath() and cf_FindRealFileNameCaseInsensitive(). cf_LocatePath() depends on the Base_directory variable. cf_FindRealFileNameCaseInsensitive() does not. In order to update the tests so that they use cf_LocatePath(), I need to make sure that the tests have access to the Base_directory variable. Before this change, the Base_directory variable was declared in Descent3/init.cpp. That meant that if a program wanted to access Base_directory, then it would have to link to Descent3/init.cpp. In other words, we would have to link to Descent3/init.cpp when compiling the program that currently tests cf_FindRealFileNameCaseInsensitive() but will test cf_LocatePath() in the future. I tried making that program link to Descent3/init.cpp, but I gave up after a wile. Descent3/init.cpp depends on a lot of other things in the codebase. In order to make it easier to create that future commit, this commit moves the Base_directory variable into the cfile module. When I create that future commit, I won’t have to mess with anything linking related because the cfile tests already link to the cfile module. Additionally, this change will make compiling that test program more efficient. There’s not need for the compiler to look at the entirety of Descent3/init.cpp just because we need a single variable from it.
2024-07-27 12:56:49 +00:00
// The "root" directory of the D3 file tree
extern std::filesystem::path Base_directory;
/* This function should be called at least once before you use anything else
* from this module.
*/
void cf_SetBaseDirectory(const std::filesystem::path &base_directory);
2024-04-16 18:56:40 +00:00
// See if a file is in a hog
bool cf_IsFileInHog(const std::filesystem::path &filename, const std::filesystem::path &hogname);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Opens a HOG file. Future calls to cfopen(), etc. will look in this HOG.
// Parameters: libname - the path & filename of the HOG file
// NOTE: libname must be valid for the entire execution of the program. Therefore, it should either
2024-04-16 03:43:29 +00:00
// be a fully-specified path name, or the current directory must not change.
2024-04-16 18:56:40 +00:00
// Returns: 0 if error, else library handle that can be used to close the library
int cf_OpenLibrary(const std::filesystem::path &libname);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Closes a library file.
// Parameters: handle: the handle returned by cf_OpenLibrary()
2024-04-16 03:43:29 +00:00
void cf_CloseLibrary(int handle);
/**
* Returns fixed case file name to actual case on disk for case-sensitive filesystems (Linux).
* @param relative_path the fixed case name to map to reality
* @param starting_dir optional directory to search within (default - current path)
* @return filename with actual case name or empty path if there no mapping in filesystem
* @note This function returns only filename without directory part, i.e.
* cf_FindRealFileNameCaseInsensitive("test/test.txt") will return only "test.txt" on success.
*/
std::filesystem::path cf_FindRealFileNameCaseInsensitive(const std::filesystem::path &relative_path,
const std::filesystem::path &starting_dir = ".");
/**
* Add directory path into paths to look in for files. If ext_list is empty,
* look in this directory for all files. Otherwise, the directory will only
* be searched for files that match one of the listed extensions.
* @param path directory to add; should be existing and resolvable directory.
* @param ext_list list of extensions, which only searched on that directory.
* @return
* false: path is not a real directory;
* true: path was successfully added.
*/
bool cf_SetSearchPath(const std::filesystem::path &path, const std::vector<std::filesystem::path> &ext_list = {});
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Removes all search paths that have been added by cf_SetSearchPath
void cf_ClearAllSearchPaths();
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Opens a file for reading or writing
// If a path is specified, will try to open the file only in that path.
// If no path is specified, will look through search directories and library files.
// Parameters: filename - the name if the file, with or without a path
2024-04-16 03:43:29 +00:00
// mode - the standard C mode string
2024-04-16 18:56:40 +00:00
// Returns: the CFile handle, or NULL if file not opened
CFILE *cfopen(const std::filesystem::path &filename, const char *mode);
2024-04-16 03:43:29 +00:00
// Opens a file for reading in a library, given the library id.
2024-04-16 18:56:40 +00:00
// Works just like cfopen, except it assumes "rb" mode and forces the file to be
2024-04-16 03:43:29 +00:00
// opened from the given library. Returns the CFILE handle or NULL if file
// couldn't be found or open.
CFILE *cf_OpenFileInLibrary(const std::filesystem::path &filename, int libhandle);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Returns the length of the specified file
// Parameters: cfp - the file pointer returned by cfopen()
2024-05-16 15:21:30 +00:00
uint32_t cfilelength(CFILE *cfp);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Closes an open CFILE.
// Parameters: cfile - the file pointer returned by cfopen()
void cfclose(CFILE *cfp);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Just like stdio fgetc(), except works on a CFILE
// Returns a char or EOF
int cfgetc(CFILE *cfp);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Just like stdio fseek(), except works on a CFILE
2024-05-16 15:21:30 +00:00
int cfseek(CFILE *cfp, long offset, int where);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Just like stdio ftell(), except works on a CFILE
2024-05-16 15:21:30 +00:00
long cftell(CFILE *cfp);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Returns true if at EOF
2024-04-16 03:43:29 +00:00
int cfeof(CFILE *cfp);
// Tells if the file exists
// Returns non-zero if file exists. Also tells if the file is on disk
// or in a hog - See return values in cfile.h
int cfexist(const std::filesystem::path &filename);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Reads the specified number of bytes from a file into the buffer
// DO NOT USE THIS TO READ STRUCTURES. This function is for byte
// data, such as a string or a bitmap of 8-bit pixels.
// Returns the number of bytes read.
// Throws an exception of type (cfile_error *) if the OS returns an error on read
2024-05-24 03:07:26 +00:00
int cf_ReadBytes(uint8_t *buf, int count, CFILE *cfp);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// The following functions read numeric vales from a CFILE. All values are
2024-04-16 03:43:29 +00:00
// stored in the file in Intel (little-endian) format. These functions
// will convert to big-endian if required.
2024-04-16 18:56:40 +00:00
// These funtions will throw an exception of if the value cannot be read,
// so do not call these if you don't require the data to be present.
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Read and return an integer (32 bits)
// Throws an exception of type (cfile_error *) if the OS returns an error on read
int32_t cf_ReadInt(CFILE *cfp, bool little_endian = true);
2024-04-16 03:43:29 +00:00
// Read and return a int16_t (16 bits)
2024-04-16 18:56:40 +00:00
// Throws an exception of type (cfile_error *) if the OS returns an error on read
int16_t cf_ReadShort(CFILE *cfp, bool little_endian = true);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Read and return a byte (8 bits)
// Throws an exception of type (cfile_error *) if the OS returns an error on read
int8_t cf_ReadByte(CFILE *cfp);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Read and return a float (32 bits)
// Throws an exception of type (cfile_error *) if the OS returns an error on read
float cf_ReadFloat(CFILE *cfp);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Read and return a double (64 bits)
// Throws an exception of type (cfile_error *) if the OS returns an error on read
double cf_ReadDouble(CFILE *cfp);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Reads a string from a CFILE. If the file is type binary, this
// function reads until a NULL or EOF is found. If the file is text,
// the function reads until a newline or EOF is found. The string is always
// written to the destination buffer null-terminated, without the newline.
// Parameters: buf - where the string is written
2024-04-16 03:43:29 +00:00
// n - the maximum string length, including the terminating 0
// cfp - the CFILE pointer
2024-04-16 18:56:40 +00:00
// Returns the number of bytes in the string, before the terminator
// Does not generate an exception on EOF
int cf_ReadString(char *buf, size_t n, CFILE *cfp);
// Writes the specified number of bytes from a file into the buffer
// DO NOT USE THIS TO WRITE STRUCTURES. This function is for byte
// data, such as a string or a bitmap of 8-bit pixels.
// Returns the number of bytes written.
// Throws an exception of type (cfile_error *) if the OS returns an error on write
2024-05-24 03:07:26 +00:00
int cf_WriteBytes(const uint8_t *buf, int count, CFILE *cfp);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Writes a null-terminated string to a file. If the file is type binary,
// the string is terminated in the file with a null. If the file is type
// text, the string is terminated with a newline.
// Parameters: buf - pointer to the string
2024-04-16 03:43:29 +00:00
// cfp = the CFILE pointer
2024-04-16 18:56:40 +00:00
// Returns the number of bytes written
// Throws an exception of type (cfile_error *) if the OS returns an error on write
2024-04-16 03:43:29 +00:00
int cf_WriteString(CFILE *cfp, const char *buf);
2024-04-16 18:56:40 +00:00
// Just like stdio fprintf(), except works on a CFILE
int cfprintf(CFILE *cfp, const char *format, ...);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// The following functions write numeric vales to a CFILE. All values are
// stored to the file in Intel (little-endian) format.
2024-04-16 03:43:29 +00:00
// All these throw an exception if there's an error on write.
2024-04-16 18:56:40 +00:00
// Write an integer (32 bits)
// Throws an exception of type (cfile_error *) if the OS returns an error on write
void cf_WriteInt(CFILE *cfp, int32_t i);
2024-04-16 03:43:29 +00:00
// Write a int16_t (16 bits)
2024-04-16 18:56:40 +00:00
// Throws an exception of type (cfile_error *) if the OS returns an error on write
void cf_WriteShort(CFILE *cfp, int16_t s);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Write a byte (8 bits). If the byte is a newline & the file is a text file, writes a CR/LF pair.
// Throws an exception of type (cfile_error *) if the OS returns an error on write
void cf_WriteByte(CFILE *cfp, int8_t b);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Write a float (32 bits)
// Throws an exception of type (cfile_error *) if the OS returns an error on write
2024-05-16 15:21:30 +00:00
void cf_WriteFloat(CFILE *cfp, float f);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Write a double (64 bits)
// Throws an exception of type (cfile_error *) if the OS returns an error on write
2024-05-16 15:21:30 +00:00
void cf_WriteDouble(CFILE *cfp, double d);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Copies a file. Returns TRUE if copied ok. Returns FALSE if error opening either file.
// Throws an exception of type (cfile_error *) if the OS returns an error on read or write
2024-04-16 03:43:29 +00:00
// If copytime is nonzero, copies the filetime info as well
bool cf_CopyFile(const std::filesystem::path &dest, const std::filesystem::path &src, int copytime = 0);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// Checks to see if two files are different.
// Returns TRUE if the files are different, or FALSE if they are the same.
bool cf_Diff(const std::filesystem::path &a, const std::filesystem::path &b);
2024-04-16 03:43:29 +00:00
// Copies the file time from one file to another
void cf_CopyFileTime(const std::filesystem::path &dest, const std::filesystem::path &src);
2024-04-16 03:43:29 +00:00
// rewinds cfile position
2024-04-16 03:43:29 +00:00
void cf_Rewind(CFILE *fp);
// Calculates a 32 bit CRC
uint32_t cf_GetfileCRC(const std::filesystem::path &src);
2024-05-24 02:51:16 +00:00
uint32_t cf_CalculateFileCRC(CFILE *fp); // same as cf_GetfileCRC, except works with CFILE pointers
2024-04-16 03:43:29 +00:00
/**
* Execute function for each file in lib that matches to extension.
* @param handle library handle where to search
* @param ext filtering extension
* @param func function callback
* @return count of applied files
*/
int cf_DoForeachFileInLibrary(int handle, const std::filesystem::path &ext,
const std::function<void(std::filesystem::path)> &func);
2024-04-16 03:43:29 +00:00
#endif