11 #define _CFILE_INTERNAL
92 #define CFILE_STACK_MAX 8
95 static int Cfile_stack_pos = 0;
102 static const char *Cfile_cdrom_dir = NULL;
107 static int cfget_cfile_block();
108 static CFILE *cf_open_fill_cfblock(
const char*
source,
int line, FILE *
fp,
int type);
113 #elif defined SCP_UNIX
114 static CFILE *cf_open_mapped_fill_cfblock(
const char*
source,
int line, FILE *
fp,
int type);
117 static void cf_chksum_long_init();
119 static void dump_opened_files()
122 auto cb = &Cfile_block_list[
i];
124 mprintf((
" %s:%d\n", cb->source_file, cb->line_num));
129 static void cfile_close()
131 mprintf((
"Still opened files:\n"));
138 #define MIN_NUM_PATH_COMPONENTS 2
140 #define MIN_NUM_PATH_COMPONENTS 3
150 static bool cfile_in_root_dir(
const char *exe_path)
154 const char *
p = exe_path;
168 token_count += new_token;
169 }
while (*p !=
'\0');
200 if (cfile_in_root_dir(buf)) {
202 "FreeSpace2/Fred2 cannot be run from a drive root directory!",
235 cf_chksum_long_init();
237 Cfile_cdrom_dir = cdrom_dir;
259 int cfile_chdrive(
int DriveNum,
int flag )
268 _chdrive( DriveNum );
275 if ( (!flag) && (n != org) )
293 static int _cfile_chdir(
const char *new_dir,
const char *cur_dir
__UNUSED)
296 const char *
path = NULL;
297 const char no_dir[] =
"\\.";
300 const char *colon = strchr(new_dir,
':');
303 if (!cfile_chdrive(tolower(*(colon - 1)) -
'a' + 1, 1))
321 cfile_chdrive(tolower(cur_dir[0]) -
'a' + 1, 1);
355 strncpy(Cfile_stack[Cfile_stack_pos++], OriginalDirectory,
360 return _cfile_chdir(dir, OriginalDirectory);
378 return _cfile_chdir(dir, OriginalDirectory);
385 if ( !Cfile_stack_pos )
410 find_handle = _findfirst(
"*", &find );
411 if (find_handle != -1) {
413 if (!(find.attrib & _A_SUBDIR) && !(find.attrib & _A_RDONLY)) {
420 }
while (!_findnext(find_handle, &find));
421 _findclose( find_handle );
423 #elif defined SCP_UNIX
425 memset(&globinfo, 0,
sizeof(globinfo));
426 int status = glob(
"*", 0, NULL, &globinfo);
428 for (
unsigned int i = 0;
i < globinfo.gl_pathc;
i++) {
432 stat(globinfo.gl_pathv[
i], &statbuf);
433 if (S_ISREG(statbuf.st_mode)) {
463 flen = strlen(filename);
467 if ((flen < 4) ||
stricmp(path + flen - elen, ext)) {
490 path_type, filename);
492 return (
_unlink(longname) != -1);
505 return access(longname,mode);
518 if ( (filename == NULL) || !strlen(filename) )
529 if ( (filename == NULL) || !strlen(filename) )
538 if ( (filename == NULL) || !strlen(filename) )
541 if ( (num_ext <= 0) || (ext_list == NULL) )
556 FILE *
fp = fopen(longname,
"rb");
560 DWORD z = GetFileAttributes(longname);
561 SetFileAttributes(longname, z | set & ~clear);
578 ret_code = rename(old_longname, new_longname );
609 dir_tree[num_dirs++] = current_dir;
617 for (i=num_dirs-1; i>=0; i-- ) {
620 if (
_mkdir(longname)==0 ) {
621 mprintf((
"CFILE: Created new directory '%s'\n", longname ));
662 Assert(file_path && strlen(file_path));
675 if ( strchr(mode,
'w') || strchr(mode,
'+') || strchr(mode,
'a') ) {
678 if ( strpbrk(file_path,
"/") ) {
680 if ( strpbrk(file_path,
"/\\:") ) {
693 Assert( !(type & CFILE_MEMORY_MAPPED) );
702 if(strcspn(mode,
"ra+") != strlen(mode) && (strchr(mode,
't') || !strchr(mode,
'b')))
706 unsigned int max =
sizeof(happy_mode) - 2;
709 for( i = 0; i < strlen(mode); i++)
715 happy_mode[
i] = mode[
i];
720 happy_mode[
i] =
'\0';
730 FILE *fp = fopen(longname, happy_mode);
732 return cf_open_fill_cfblock(source, line, fp, dir_type);
743 strcpy_s(copy_file_path, file_path);
746 if (
cf_find_file_location( copy_file_path, dir_type,
sizeof(longname) - 1, longname, &size, &offset, localize ) ) {
749 nprintf((
"CFileDebug",
"Requested file %s found at: %s\n", file_path, longname));
751 if ( type & CFILE_MEMORY_MAPPED ) {
758 hFile = CreateFile(longname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
760 if (hFile != INVALID_HANDLE_VALUE) {
761 return cf_open_mapped_fill_cfblock(source, line, hFile, dir_type);
763 #elif defined SCP_UNIX
764 FILE *fp = fopen( longname,
"rb" );
766 return cf_open_mapped_fill_cfblock(source, line, fp, dir_type);
773 FILE *fp = fopen( longname,
"rb" );
778 return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size );
781 return cf_open_fill_cfblock(source, line, fp, dir_type);
809 Assert( file_path && strlen(file_path) );
814 if ( strchr(mode,
'w') ) {
820 FILE *fp = fopen( file_path,
"rb" );
827 return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size);
830 return cf_open_fill_cfblock(source, line, fp, dir_type);
849 return cf_open_fill_cfblock(
LOCATION, fp, 0);
862 static int cfget_cfile_block()
868 cb = &Cfile_block_list[
i];
878 nprintf((
"Warning",
"A free Cfile_block could not be found.\n"));
881 mprintf((
"Out of cfile blocks! Currently opened files:\n"));
884 Assertion(
false,
"There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
885 "This is probably caused by a programming or scripting error where a file does not get closed.");
901 Assert(cfile->
id >= 0 && cfile->
id < MAX_CFILE_BLOCKS);
902 cb = &Cfile_block_list[cfile->
id];
908 result = UnmapViewOfFile((
void*)cb->
data);
910 result = CloseHandle(cb->hInFile);
912 result = CloseHandle(cb->hMapFile);
915 #elif defined SCP_UNIX
921 result = fclose(cb->
fp);
924 }
else if ( cb->
fp != NULL ) {
926 result = fclose(cb->
fp);
942 if(cfile->
id < 0 || cfile->
id >= MAX_CFILE_BLOCKS)
963 static CFILE *cf_open_fill_cfblock(
const char* source,
int line, FILE *fp,
int type)
967 cfile_block_index = cfget_cfile_block();
968 if ( cfile_block_index == -1 ) {
1002 static CFILE *cf_open_packed_cfblock(
const char* source,
int line, FILE *fp,
int type,
int offset,
int size)
1007 cfile_block_index = cfget_cfile_block();
1008 if ( cfile_block_index == -1 ) {
1042 static CFILE *cf_open_mapped_fill_cfblock(
const char* source,
int line,
HANDLE hFile,
int type)
1043 #elif defined SCP_UNIX
1044 static CFILE *cf_open_mapped_fill_cfblock(
const char* source,
int line, FILE *fp,
int type)
1049 cfile_block_index = cfget_cfile_block();
1050 if ( cfile_block_index == -1 ) {
1067 cfbp->hInFile = hFile;
1076 cfbp->hMapFile = CreateFileMapping(cfbp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
1077 if (cfbp->hMapFile == NULL) {
1078 nprintf((
"Error",
"Could not create file-mapping object.\n"));
1082 cfbp->
data = (
ubyte*)MapViewOfFile(cfbp->hMapFile, FILE_MAP_READ, 0, 0, 0);
1084 #elif defined SCP_UNIX
1087 cfbp->
data = mmap(NULL,
1114 Assert(cfile->
id >= 0 && cfile->
id < MAX_CFILE_BLOCKS);
1115 cb = &Cfile_block_list[cfile->
id];
1136 Assert( (cfile->
id >= 0) && (cfile->
id < MAX_CFILE_BLOCKS) );
1157 if (
cfread( &f,
sizeof(f), 1, file) != 1)
1171 if (
cfread( &i,
sizeof(i), 1, file) != 1)
1185 if (
cfread( &i,
sizeof(i), 1, file) != 1)
1199 if (
cfread( &s,
sizeof(s), 1, file) != 1)
1213 if (
cfread( &s,
sizeof(s), 1, file) != 1)
1227 if (
cfread( &b,
sizeof(b), 1, file) != 1)
1239 vec->
xyz.x = vec->
xyz.y = vec->
xyz.z = 0.0f;
1255 ang->
p = ang->
b = ang->
h = 0.0f;
1272 if (
cfread( &b,
sizeof(b), 1, file) != 1)
1295 Assertion( (len < n),
"len: %i, n: %i", len, n );
1297 cfread(buf, len, 1, file);
1307 return cfwrite(&f,
sizeof(f), 1, file);
1313 return cfwrite(&i,
sizeof(i), 1, file);
1319 return cfwrite(&i,
sizeof(i), 1, file);
1325 return cfwrite(&s,
sizeof(s), 1, file);
1331 return cfwrite(&s,
sizeof(s), 1, file);
1336 return cfwrite(&b,
sizeof(b), 1, file);
1363 return cfwrite( &b,
sizeof(b), 1, file);
1368 if ( (!buf) || (buf && !buf[0]) ) {
1371 int len = strlen(buf);
1372 if(!
cfwrite(buf, len, 1, file)){
1380 int len = strlen(buf);
1386 return cfwrite(buf,len,1,file);
1397 Assert(cfile->
id >= 0 && cfile->
id < MAX_CFILE_BLOCKS);
1398 cb = &Cfile_block_list[cfile->
id];
1419 if(buf == NULL || elsize == 0 || nelem == 0)
1426 Error(
LOCATION,
"Attempt to write to a VP file (unsupported)");
1430 if(cb->
data != NULL)
1436 size_t bytes_written = 0;
1437 size_t size = elsize * nelem;
1439 bytes_written = fwrite(buf, 1, size, cb->
fp);
1442 if (bytes_written > 0) {
1443 cb->
size += bytes_written;
1447 #if defined(CHECK_SIZE) && !defined(NDEBUG)
1451 return ((
int)bytes_written / elsize);
1469 Error(
LOCATION,
"Attempt to write character to a VP file (unsupported)");
1473 if(cb->
data != NULL)
1491 #if defined(CHECK_SIZE) && !defined(NDEBUG)
1516 Error(
LOCATION,
"Attempt to write character to a VP file (unsupported)");
1520 if(cb->
data != NULL)
1531 cb->
size += strlen(str);
1535 #if defined(CHECK_SIZE) && !defined(NDEBUG)
1553 if ( result == 1 ) {
1580 for (i=0; i<n-1; i++ ) {
1584 int ret =
cfread( &tmp_c, 1, 1, cfile );
1594 }
while ( c == 13 );
1596 if ( c==
'\n' )
break;
1608 #define CRC32_POLYNOMIAL 0xEDB88320
1609 static uint CRCTable[256];
1611 #define CF_CHKSUM_SAMPLE_SIZE 512
1619 sum1 = sum2 = (
int)(seed);
1623 if (sum1 >= 255 ) sum1 -= 255;
1628 return (
ushort)((sum1 << 8) + sum2);
1641 crc = (crc >> 8) ^ CRCTable[(crc ^ *p++) & 0xff];
1646 static void cf_chksum_long_init()
1651 for (i = 0; i < 256; i++) {
1654 for (j = 8; j > 0; j--) {
1688 cfseek(cfile, 0, SEEK_SET);
1698 read_size = max_size - cf_total;
1702 cf_len =
cfread(cf_buffer, 1, read_size, cfile);
1716 }
while((cf_len > 0) && (cf_total < max_size));
1724 const int safe_size = 2097152;
1725 const int header_offset = 32;
1733 if (chk_long == NULL) {
1738 FILE *fp = fopen(filename,
"rb");
1748 fseek(fp, 0, SEEK_END);
1749 max_size = ftell(fp);
1753 fseek(fp, 0, SEEK_SET);
1757 CLAMP(max_size, 0, safe_size);
1760 "max_size (%d) > header_offset in packfile %s", max_size, filename);
1761 max_size -= header_offset;
1763 fseek(fp, -(max_size), SEEK_END);
1773 read_size = max_size - cf_total;
1776 cf_len = fread(cf_buffer, 1, read_size, fp);
1784 }
while ( (cf_len > 0) && (cf_total < max_size) );
1794 CFILE *cfile = NULL;
1806 ret_val = cf_chksum_do(cfile, chksum, NULL, max_size);
1824 start_pos =
cftell(file);
1825 if(start_pos == -1){
1833 ret_code = cf_chksum_do(file, chksum, NULL, max_size);
1844 CFILE *cfile = NULL;
1856 ret_val = cf_chksum_do(cfile, NULL, chksum, max_size);
1874 start_pos =
cftell(file);
1875 if(start_pos == -1){
1883 ret_code = cf_chksum_do(file, NULL, chksum, max_size);
1899 Assert(cfile->
id >= 0 && cfile->
id < MAX_CFILE_BLOCKS);
1900 cb = &Cfile_block_list[cfile->
id];
void cfread_angles(angles *ang, CFILE *file, int ver, angles *deflt)
int cf_is_valid(CFILE *cfile)
int cfwrite_ushort(ushort s, CFILE *file)
#define CF_TYPE_SINGLE_PLAYERS
int cf_get_dir_type(CFILE *cfile)
int cf_delete(const char *filename, int path_type)
Delete the specified file.
#define CF_TYPE_VOICE_DEBRIEFINGS
void cf_set_max_read_len(CFILE *cfile, size_t len)
#define CF_RENAME_FAIL_ACCESS
int cfread(void *buf, int elsize, int nelem, CFILE *fp)
void cf_attrib(const char *name, int set, int clear, int type)
int cfwrite_ubyte(ubyte b, CFILE *file)
CFILE * _cfopen_special(const char *source, int line, const char *file_path, const char *mode, const int size, const int offset, int dir_type)
int cfwrite_uint(uint i, CFILE *file)
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
#define DIR_SEPARATOR_CHAR
#define CF_TYPE_VOICE_SPECIAL
#define CFILE_MEMORY_MAPPED
struct vec3d::@225::@227 xyz
const char * Osreg_user_dir
void cf_free_secondary_filelist()
#define Assertion(expr, msg,...)
void cfread_string(char *buf, int n, CFILE *file)
int cfwrite_angles(angles *ang, CFILE *file)
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out=0, char *pack_filename=NULL, int *size=NULL, int *offset=NULL, bool localize=false)
#define CF_TYPE_PLAYER_IMAGES
#define CF_TYPE_SQUAD_IMAGES
int cf_create_default_path_string(char *path, uint path_max, int pathtype, const char *filename, bool localize)
const char * detect_home(void)
GLenum GLuint GLenum GLsizei const GLchar * buf
#define CF_TYPE_MULTI_CACHE
int cf_chksum_pack(const char *filename, uint *chk_long, bool full)
#define CLAMP(x, min, max)
int _getcwd(char *buffer, unsigned int len)
int cfwrite_char(char b, CFILE *file)
int cfile_push_chdir(int type)
Push current directory onto a 'stack' and change to a new directory.
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int cf_find_file_location(const char *filespec, int pathtype, int max_out, char *pack_filename, int *size, int *offset, bool localize=false)
#define CF_CHKSUM_SAMPLE_SIZE
int _mkdir(const char *path)
char * cfgets(char *buf, int n, CFILE *cfile)
int cfwrite_float(float f, CFILE *file)
cf_pathtype Pathtypes[CF_MAX_PATH_TYPES]
#define CF_TYPE_MULTI_PLAYERS
#define DIR_SEPARATOR_STR
int cf_exists_full(const char *filename, int dir_type)
#define CF_TYPE_VOICE_CMD_BRIEF
int _chdir(const char *path)
int cfile_flush_dir(int dir_type)
int cfwrite_string(const char *buf, CFILE *file)
#define CF_RENAME_FAIL_EXIST
Cfile_block Cfile_block_list[MAX_CFILE_BLOCKS]
uint cf_add_chksum_long(uint seed, ubyte *buffer, int size)
#define CF_TYPE_VOICE_BRIEFINGS
int cfwrite_string_len(const char *buf, CFILE *file)
Write a fixed length string (not including its null terminator), with the length stored in file...
int cfputc(int c, CFILE *cfile)
int cf_rename(const char *old_name, const char *name, int dir_type)
int cfwrite(const void *buf, int elsize, int nelem, CFILE *cfile)
#define CF_TYPE_INTEL_ANIMS
short cfread_short(CFILE *file, int ver, short deflt)
#define CF_TYPE_INTERFACE
int cfile_chdir(const char *dir)
Change to the specified directory.
int cfwrite_int(int i, CFILE *file)
void cf_set_version(CFILE *cfile, int version)
int cf_chksum_short(const char *filename, ushort *chksum, int max_size, int cf_type)
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
int cf_chksum_long(const char *filename, uint *chksum, int max_size, int cf_type)
ubyte cfread_ubyte(CFILE *file, int ver, ubyte deflt)
GLuint const GLchar * name
void cfread_vector(vec3d *vec, CFILE *file, int ver, vec3d *deflt)
char * cf_add_ext(const char *filename, const char *ext)
void cf_build_secondary_filelist(const char *cdrom_dir)
GLboolean GLboolean GLboolean b
int cfputs(const char *str, CFILE *cfile)
char cfread_char(CFILE *file, int ver, char deflt)
char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN]
cf_init_lowlevel_read_code(cfp, 0, 0, 0)
int cfwrite_short(short s, CFILE *file)
#define MIN_NUM_PATH_COMPONENTS
#define CF_TYPE_SPECIFIED(path_type)
#define CFILE_ROOT_DIRECTORY_LEN
GLsizei const GLchar ** path
int MessageBox(HWND h, const char *s1, const char *s2, int i)
#define CFILE_BLOCK_UNUSED
ushort cfread_ushort(CFILE *file, int ver, ushort deflt)
void cf_create_directory(int dir_type)
#define CF_TYPE_SOUNDS_8B22K
int cfread_int(CFILE *file, int ver, int deflt)
#define CF_TYPE_SOUNDS_16B11K
float cfread_float(CFILE *file, int ver, float deflt)
GLsizei GLsizei GLchar * source
#define CF_MAX_PATH_TYPES
void * cf_returndata(CFILE *cfile)
int cfwrite_vector(vec3d *vec, CFILE *file)
int cfclose(CFILE *cfile)
#define CF_TYPE_VOICE_PERSONAS
#define CF_TYPE_VOICE_TRAINING
int cfilelength(CFILE *cfile)
#define CF_RENAME_SUCCESS
int cf_exists(const char *filename, int dir_type)
int cf_access(const char *filename, int dir_type, int mode)
uint cfread_uint(CFILE *file, int ver, uint deflt)
int cfile_init(const char *exe_dir, const char *cdrom_dir)
Initialize the cfile system. Called once at application start.
int cf_exists_full_ext(const char *filename, int dir_type, const int num_ext, const char **ext_list)
CFILE * _cfopen(const char *source, int line, const char *file_path, const char *mode, int type, int dir_type, bool localize)
ushort cf_add_chksum_short(ushort seed, ubyte *buffer, int size)
void cfread_string_len(char *buf, int n, CFILE *file)
Read a fixed length string that is not null-terminated, with the length stored in file...
int cfseek(CFILE *fp, int offset, int where)