File: cfile.h

package info (click to toggle)
freespace2 24.2.0%2Brepack-1
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid
  • size: 43,716 kB
  • sloc: cpp: 595,001; ansic: 21,741; python: 1,174; sh: 457; makefile: 248; xml: 181
file content (487 lines) | stat: -rw-r--r-- 17,279 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
/*
 * Copyright (C) Volition, Inc. 1999.  All rights reserved.
 *
 * All source code herein is the property of Volition, Inc. You may not sell 
 * or otherwise commercially exploit the source or things you created based on the 
 * source.
 *
*/ 



#ifndef __CFILE_H__
#define __CFILE_H__


#include "globalincs/pstypes.h"

#include <ctime>
#include <stdexcept>
#include <memory>
#include <utility>


#define CF_EOF (-1)

#define CF_SEEK_SET (0)
#define CF_SEEK_CUR (1)
#define CF_SEEK_END (2)

// Opaque file handle
struct CFILE;

// extra info that can be returned when getting a file listing
typedef struct {
	time_t write_time;
} file_list_info;


#define CF_MAX_FILENAME_LENGTH 	32		// Includes null terminater, so real length is 31
#define CF_MAX_PATHNAME_LENGTH 	256	// Includes null terminater, so real length is 255

#define CF_TYPE_ANY						-1		// Used to check in any directory

#define CF_TYPE_INVALID				0
#define CF_TYPE_ROOT				1			// Root must be 1!!
#define CF_TYPE_DATA				2
#define CF_TYPE_MAPS				3
#define CF_TYPE_TEXT				4
#define CF_TYPE_MODELS				5
#define CF_TYPE_TABLES				6
#define CF_TYPE_SOUNDS				7
#define CF_TYPE_VOICE				8
#define CF_TYPE_VOICE_BRIEFINGS		9
#define CF_TYPE_VOICE_CMD_BRIEF		10
#define CF_TYPE_VOICE_DEBRIEFINGS	11
#define CF_TYPE_VOICE_PERSONAS		12
#define CF_TYPE_VOICE_SPECIAL		13
#define CF_TYPE_VOICE_TRAINING		14
#define CF_TYPE_MUSIC				15
#define CF_TYPE_MOVIES				16
#define CF_TYPE_INTERFACE			17
#define CF_TYPE_FONT				18
#define CF_TYPE_EFFECTS				19
#define CF_TYPE_HUD					20
#define CF_TYPE_PLAYERS				21
#define CF_TYPE_PLAYER_IMAGES		22
#define CF_TYPE_SQUAD_IMAGES		23
#define CF_TYPE_SINGLE_PLAYERS		24
#define CF_TYPE_MULTI_PLAYERS		25
#define CF_TYPE_PLAYER_BINDS		26
#define CF_TYPE_CACHE				27
#define CF_TYPE_MULTI_CACHE			28
#define CF_TYPE_MISSIONS			29
#define CF_TYPE_CONFIG				30
#define CF_TYPE_DEMOS				31
#define CF_TYPE_CBANIMS				32
#define CF_TYPE_INTEL_ANIMS			33
#define CF_TYPE_SCRIPTS				34
#define CF_TYPE_FICTION				35
#define CF_TYPE_FREDDOCS			36

#define CF_MAX_PATH_TYPES                                                                                              \
	37 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES

// TRUE if type is specified and valid
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))

// #define's for the type parameter in cfopen.  
#define CFILE_NORMAL				0			// open file normally
#define CFILE_MEMORY_MAPPED	(1<<0)	//	open file as a memory-mapped file

#define CF_SORT_NONE	0
#define CF_SORT_NAME 1
#define CF_SORT_TIME 2
#define CF_SORT_REVERSE 3

/**
 * @brief Contains a collection of flags for specifying from where a CFILE should be opened
 *
 * There are two types of flags. CF_LOCATION_GAME_ROOT and CF_LOCATION_USER_ROOT specify in which basic root directory
 * CFile should search for files.
 *
 * The remaining flags control what type of location may be used for the operation. It's possible to restrict the
 * location to the primary mod, the remaining mods or the top-level root directory.
 */
enum CFileLocationFlags {
	CF_LOCATION_ROOT_GAME = 1 << 0, //!< The game root location. This is the location of the game data (e.g. FS2 retail)
	/**
	 * @brief The user directories.
	 *
	 * If the engine is in portable mode then using this flag exclusively will result in a failure to open files!
	 */
	CF_LOCATION_ROOT_USER = 1 << 1,

	/**
	 * @brief The memory root
	 *
	 * This contains all the built-in files available to the engine.
	 */
	CF_LOCATION_ROOT_MEMORY = 1 << 2,

	/**
	 * @brief Mask for extracting root type from a location bit field
	 */
	CF_LOCATION_ROOT_MASK = 0xFFFF,

	CF_LOCATION_TYPE_ROOT = 1 << 16, //!< The basic, top-level root location
	/**
	 * @brief The primary mod location.
	 *
	 * This is the mod that appears first on the command line. If there are no mods then the root location is considered
	 * to be the primary mod
	 */
	CF_LOCATION_TYPE_PRIMARY_MOD = 1 << 17,
	/**
	 * @brief The remaining mods.
	 *
	 * If there are no mods on the command line then this might not include any valid location.
	 */
	CF_LOCATION_TYPE_SECONDARY_MODS = 1 << 18,

	/**
	 * @brief Bitmask for extracting the type from a location bit field
	 */
	CF_LOCATION_TYPE_MASK = 0xFFFF0000,

	/**
	 * @brief A combination of all flags
	 *
	 * This should be used when the default behavior without any location filtering is desired.
	 */
	CF_LOCATION_ALL = CF_LOCATION_ROOT_MASK | CF_LOCATION_TYPE_MASK
};

// callback function used for get_file_list() to filter files to be added to list.  Return 1
// to add file to list, or 0 to not add it.
extern int (*Get_file_list_filter)(const char *filename);

// extra check for child directory under CF_TYPE_*
// NOTE: if specified cf_get_file_list() will not search pack files!
// NOTE: specified string must not contain ':' or spaces or begin with DIR_SEPARATOR!
extern const char *Get_file_list_child;

// cfile directory. valid after cfile_init() returns successfully
#define CFILE_ROOT_DIRECTORY_LEN			256
extern char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN];
extern char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN];

//================= LOW-LEVEL FUNCTIONS ==================
int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
void cfile_close();

// add an extension to a filename if it doesn't already have it
const char *cf_add_ext(const char *filename, const char *ext);

// return filename of a CFILE you called cfopen() successfully on.
const char *cf_get_filename(const CFILE *cfile);

// return CF_TYPE (directory location type) of a CFILE you called cfopen() successfully on.
int cf_get_dir_type(const CFILE *cfile);

// Opens the file.  If no path is given, use the extension to look into the
// default path.  If mode is NULL, delete the file.
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode, int type = CFILE_NORMAL,
               int dir_type = CF_TYPE_ANY, bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
#define cfopen(...) _cfopen(LOCATION, __VA_ARGS__) // Pass source location to the function

struct CFileLocation;

// like cfopen(), but it accepts a fully qualified path only (ie, the result of a cf_find_file_location() call)
// NOTE: only supports reading files!!
CFILE *_cfopen_special(const char* source_file, int line, const CFileLocation &res, const char* mode,
	                   int dir_type = CF_TYPE_ANY);
#define cfopen_special(...) _cfopen_special(LOCATION, __VA_ARGS__) // Pass source location to the function

// Flush the open file buffer
int cflush(CFILE *cfile);

// will throw an error if cfread*() functions read past this mark
// converted to raw offsets when used, but gets passed actual length from current position
// setting 'len' to zero will disable the check
void cf_set_max_read_len(CFILE *cfile, size_t len);

// Deletes a file. Returns 0 on error, 1 if successful
int cf_delete(const char *filename, int dir_type, uint32_t location_flags = CF_LOCATION_ALL);

// Same as _access function to read a file's access bits
int cf_access(const char *filename, int dir_type, int mode);

// Returns 1 if the file exists, 0 if not.
// Checks only the file system.
int cf_exists(const char *filename, int dir_type);

// Goober5000
// Returns 1 if the file exists, 0 if not.
// Checks both the file system and the VPs.
int cf_exists_full(const char *filename, int dir_type);
// check num_ext worth of ext_list extensions
int cf_exists_full_ext(const char *filename, int dir_type, const int num_ext, const char **ext_list);

// ctmpfile() opens a temporary file stream.  File is deleted automatically when closed
CFILE *ctmpfile();

// Closes the file
int cfclose(CFILE *cfile);

//Checks if the given handle is valid
int cf_is_valid(CFILE *cfile);

// Returns size of file...
int cfilelength(CFILE *fp);

// Reads data
int cfread(void *buf, int elsize, int nelem, CFILE *fp);

// cfwrite() writes to the file
int cfwrite(const void *buf, int elsize, int nelem, CFILE *cfile);

// Moves the file pointer
int cfseek(CFILE *fp, int offset, int where);

// Returns current position of file.
int cftell(CFILE *fp);

// cfputc() writes a character to a file
int cfputc(int c, CFILE *cfile);

// cfputs() writes a string to a file
int cfputs(const char *str, CFILE *cfile);

// cfgetc() reads a character to a file
int cfgetc(CFILE *cfile);

// cfgets() reads a string from a file
char *cfgets(char *buf, int n, CFILE *cfile);

// cfeof() Tests for end-of-file on a stream
int cfeof(CFILE *cfile);

// Return the data pointer associated with the CFILE structure (for memory mapped files)
const void *cf_returndata(CFILE *cfile);

// get the 2 byte checksum of the passed filename - return 0 if operation failed, 1 if succeeded
int cf_chksum_short(const char *filename, ushort *chksum, int max_size = -1, int cf_type = CF_TYPE_ANY );

// get the 2 byte checksum of the passed file - return 0 if operation failed, 1 if succeeded
// NOTE : preserves current file position
int cf_chksum_short(CFILE *file, ushort *chksum, int max_size = -1);

// get the 32 bit CRC checksum of the passed filename - return 0 if operation failed, 1 if succeeded
int cf_chksum_long(const char *filename, uint *chksum, int max_size = -1, int cf_type = CF_TYPE_ANY );

// get the 32 bit CRC checksum of the passed file - return 0 if operation failed, 1 if succeeded
// NOTE : preserves current file position
int cf_chksum_long(CFILE *file, uint *chksum, int max_size = -1);

int cf_chksum_pack(const char *filename, uint *chk_long, bool full = false);

// convenient for misc checksumming purposes ------------------------------------------

// update cur_chksum with the chksum of the new_data of size new_data_size
ushort cf_add_chksum_short(ushort seed, ubyte *buffer, int size);

// update cur_chksum with the chksum of the new_data of size new_data_size
uint cf_add_chksum_long(uint seed, ubyte *buffer, size_t size);

// convenient for misc checksumming purposes ------------------------------------------

//================= HIGH LEVEL FUNCTIONS ==================

// rename a file, utilizing the extension to determine where file is.
#define CF_RENAME_SUCCESS				0					// successfully renamed the file
#define CF_RENAME_FAIL_ACCESS			1					// new name could not be created
#define CF_RENAME_FAIL_EXIST			2					// old name does not exist
int cf_rename(const char *old_name, const char *name, int type = CF_TYPE_ANY );

// Creates the directory path if it doesn't exist. Even creates all its
// parent paths.
void cf_create_directory(int dir_type, uint32_t location_flags = CF_LOCATION_ALL);

// changes the attributes of a file
void cf_attrib(const char *name, int set, int clear, int type);

// flush (delete all files in) the passed directory (by type), return the # of files deleted
// NOTE : WILL NOT DELETE READ-ONLY FILES
int cfile_flush_dir(int type);

// functions for reading from cfile
// These are all high level, built up from
// cfread.
char *cfgets(char *buf, size_t n, CFILE *fp);
char cfread_char(CFILE* file, char deflt = 0);
ubyte cfread_ubyte(CFILE* file, ubyte deflt = 0);
short cfread_short(CFILE* file, short deflt = 0);
ushort cfread_ushort(CFILE* file, ushort deflt = 0);
int cfread_int(CFILE* file, int deflt = 0);
uint cfread_uint(CFILE* file, uint deflt = 0);
float cfread_float(CFILE* file, float deflt = 0.0f);
void cfread_vector(vec3d* vec, CFILE* file, vec3d* deflt = nullptr);

// Reads variable length, null-termined string.   Will only read up
// to n characters.
void cfread_string(char *buf,int n, CFILE *file);
/**
 * @brief Read a fixed length string that is not null-terminated, with the length stored in file.
 *
 * If it is not null-terminated, the length of the string *must* be less than the size of the buffer (to make room for one)
 * 
 * @param buf Pre-allocated array to store string
 * @param buffer_size Size of pre-allocated array
 * @param file File to read from
 *
 * @note Appends NULL character to string (buf)
 */
void cfread_string_len(char *buf,int buffer_size, CFILE *file);

/**
 * @brief Read a string from the file where the length is stored in the file
 * @param file The file to read the string from
 * @return The string that was read
 */
SCP_string cfread_string_len(CFILE *file);

// functions for writing cfiles
int cfwrite_char(char c, CFILE *file);
int cfwrite_float(float f, CFILE *file);
int cfwrite_int(int i, CFILE *file);
int cfwrite_uint(uint i, CFILE *file);
int cfwrite_short(short s, CFILE *file);
int cfwrite_ushort(ushort s, CFILE *file);
int cfwrite_ubyte(ubyte u, CFILE *file);

// writes variable length, null-termined string.
int cfwrite_string(const char *buf, CFILE *file);

/**
 * @brief Write a fixed length string (not including its null terminator), with the length stored in file
 *
 * @param buf String to write to file
 * @param file File to write to
 */
int cfwrite_string_len(const char *buf, CFILE *file);

int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort = CF_SORT_NONE,
                     SCP_vector<file_list_info>* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
int cf_get_file_list(int max, char** list, int type, const char* filter, int sort = CF_SORT_NONE,
                     file_list_info* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int type, const char* filter,
                                  int sort = CF_SORT_NONE, file_list_info* info = nullptr,
                                  uint32_t location_flags = CF_LOCATION_ALL);
void cf_sort_filenames( int n, char **list, int sort, file_list_info *info = NULL );
void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_list_info> *info = NULL );

struct CFileLocation {
	bool found = false;
	SCP_string name_ext;
	SCP_string full_name;
	size_t size          = 0;
	size_t offset        = 0;
	time_t m_time        = 0;
	const void* data_ptr = nullptr;

	explicit CFileLocation(bool found_in = false) : found(found_in) {}
};

// Searches for a file.   Follows all rules and precedence and searches
// CD's and pack files.
// Input:  filespace   - Filename & extension
//         pathtype    - See CF_TYPE_ defines in CFILE.H
//         max_out     - Maximum string size to be stuffed into pack_filename
// Output: pack_filename - Absolute path and filename of this file.   Could be a packfile or the actual file.
//         size        - File size
//         offset      - Offset into pack file.  0 if not a packfile.
// Returns: If not found returns 0.
CFileLocation cf_find_file_location(const char* filespec, int pathtype,
                                    uint32_t location_flags = CF_LOCATION_ALL);

struct CFileLocationExt : public CFileLocation {
	int extension_index = -1;

	explicit CFileLocationExt(int extension_index_in = -1)
	    : CFileLocation(extension_index_in >= 0), extension_index(extension_index_in)
	{
	}
};

// Searches for a file.   Follows all rules and precedence and searches
// CD's and pack files.  Searches all locations in order for first filename using ext filter list.
// Input:  filename    - Filename & extension
//         ext_num     - number of extensions to look for
//         ext_list    - extension filter list
//         pathtype    - See CF_TYPE_ defines in CFILE.H
//         max_out     - Maximum string length that should be stuffed into pack_filename
// Output: pack_filename - Absolute path and filename of this file.   Could be a packfile or the actual file.
//         size        - File size
//         offset      - Offset into pack file.  0 if not a packfile.
// Returns: If not found returns -1, else returns offset into ext_list.
// (NOTE: This function is exponentially slow, so don't use it unless truely needed!!)
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype);

// Functions to change directories
int cfile_chdir(const char *dir);

#ifdef _WIN32
int cfile_chdrive(int DriveNum, int flag);
#endif

// push current directory on a 'stack' (so we can restore it) and change the directory
int cfile_push_chdir(int type);

// restore directory on top of the stack
int cfile_pop_dir();

int cfile_get_path_type(const SCP_string& dir);

namespace cfile
{
	// exceptions and other errors
	class cfile_error : public std::exception
	{
		public:
			cfile_error() : m_excuse("CFILE Exception")
			{
			}

			explicit cfile_error(std::string excuse) : m_excuse(std::move(excuse))
			{
			}

			~cfile_error() noexcept override = default;

			const char *what() const noexcept override {
				return m_excuse.c_str();
			}

		private:
			std::string m_excuse;
	};

	class max_read_length : public cfile_error
	{
		public:
		explicit max_read_length(const std::string &excuse) : cfile_error(excuse)
			{
			}

			max_read_length() : cfile_error("Attempted to read beyond length limit")
			{
			}
	};

}

// This allows to use std::unique_ptr with CFILE
namespace std {
template <>
struct default_delete<CFILE> {
	void operator()(CFILE* ptr)
	{
		if (cf_is_valid(ptr)) {
			cfclose(ptr);
		}
	}
};
} // namespace std

#endif	/* __CFILE_H__ */