additional_file_information.txt
来自「quake1 dos源代码最新版本」· 文本 代码 · 共 313 行
TXT
313 行
================================================================
Title : Tutorial: Returning additional information about a loaded file
(including "Returning the path a file was loaded from")
Date : 2001-12-28
Filename : ADDITIONAL_FILE_INFORMATION.TXT
Author : Matthias "Maddes" Buecher
Email Address : maddes@go.to
Homepage : Quake Info Pool
http://www.quake-info-pool.net/
Quake Standards Group (short QSG)
http://www.quakesource.org/
Complexity : Moderate
================================================================
Introduction
============
When a file is loaded with COM_Load*File you only get the pointer to the buffer
the file was loaded to, all other information (for example the filelength or the
path it was loaded from) are not available.
But it would be nice to print the path a file was loaded from, especially for
debugging reasons. So this tutorial will change Quake's load functions to return
a pointer to an information structure for the file, instead of the file's buffer.
Implementation
==============
Part #1 - Returning an info structure for a loaded file
The file information structure must contain the old result of the load
functions, the pointer to the buffer, and we can easily add the filelength to
the structure. Later we add a pointer to the searchpath the file was found in.
The information structure will be put in the file's buffer behind the file data,
this way the information is freed when the file's buffer is freed.
Define the new structure in COMMON.H before the function declarations...
// 2001-09-12 Returning information about loaded file by Maddes start
// new structure for passing back a loaded file
typedef struct loadedfile_s
{
byte *data; // memory the file is loaded to (directly before this structure)
int filelen; // length of the file
searchpath_t *path; // 2001-09-12 Returning from which searchpath a file was loaded by Maddes
} loadedfile_t;
// 2001-09-12 Returning information about loaded file by Maddes end
Now change all COM_Load*File functions in COMMON.C to return a pointer to this new
structure and change the declarations in COMMON.H accordingly. The declarations
should look like this...
loadedfile_t *COM_LoadStackFile (char *path, void *buffer, int bufsize);
loadedfile_t *COM_LoadTempFile (char *path);
loadedfile_t *COM_LoadHunkFile (char *path);
loadedfile_t *COM_LoadCacheFile (char *path, struct cache_user_s *cu);
...note that COM_LoadFile isn't declared in COMMON.H, but you have to change it :)
Before we change the main function COM_LoadFile we'll fix COM_LoadStackFile.
Instead of using a separate variable for the return value, we just return the
result of COM_LoadFile, so COM_LoadStackFile should look like this...
loadedfile_t *COM_LoadStackFile (char *path, void *buffer, int bufsize)
{
loadbuf = (byte *)buffer;
loadsize = bufsize;
return COM_LoadFile (path, 4);
}
In COM_LoadFile we need to calculate the necessary buffersize, as the filelength
is not sufficient anymore: pad the file length plus 1 to the next 4-byte border
and add the size of the information structure. This buffersize will be used
everywhere in COM_LoadFile instead of "len+1".
After the memory allocation we calculate the pointer to the information
structure by adding the padded file length plus 1 (see above) to the buffer
start. Then we set the structure accordingly: pointer to the buffer and file
length, later the searchpath of the file. At last we return the pointer of the
information structure instead of the data buffer.
Another enhancement is to use the full filename and not only its base for the
hunk name.
After all these changes COM_LoadFile should be like this...
loadedfile_t *COM_LoadFile (char *path, int usehunk) // 2001-09-12 Returning information about loaded file by Maddes
{
int h;
byte *buf;
char base[32];
int len;
// 2001-09-12 Returning information about loaded file by Maddes start
int bufsize;
loadedfile_t *fileinfo;
// 2001-09-12 Returning information about loaded file by Maddes end
buf = NULL; // quiet compiler warning
// look for it in the filesystem or pack files
len = COM_OpenFile (path, &h);
if (h == -1)
return NULL;
bufsize = ((len+1+3)&~3) + sizeof(struct loadedfile_s); // 2001-09-12 Returning information about loaded file by Maddes
// extract the filename base name for hunk tag
// 2001-12-28 Use full filename for hunk allocation by Maddes start
strncpy(base, COM_SkipPath(path), sizeof(base));
base[sizeof(base)-1] = 0;
// 2001-12-28 Use full filename for hunk allocation by Maddes end
if (usehunk == 1)
buf = Hunk_AllocName (bufsize, base); // 2001-09-12 Returning information about loaded file by Maddes
else if (usehunk == 2)
buf = Hunk_TempAlloc (bufsize); // 2001-09-12 Returning information about loaded file by Maddes
else if (usehunk == 0)
buf = Z_Malloc (bufsize); // 2001-09-12 Returning information about loaded file by Maddes
else if (usehunk == 3)
buf = Cache_Alloc (loadcache, bufsize, base); // 2001-09-12 Returning information about loaded file by Maddes
else if (usehunk == 4)
{
// 2001-09-12 Returning information about loaded file by Maddes start
if (bufsize > loadsize)
buf = Hunk_TempAlloc (bufsize);
// 2001-09-12 Returning information about loaded file by Maddes end
else
buf = loadbuf;
}
else
Sys_Error ("COM_LoadFile: bad usehunk");
if (!buf)
Sys_Error ("COM_LoadFile: not enough space for %s", path);
((byte *)buf)[len] = 0;
// 2001-09-12 Returning information about loaded file by Maddes start
fileinfo = (loadedfile_t *)(buf + ((len+1+3)&~3));
fileinfo->data = buf;
fileinfo->filelen = len;
fileinfo->path = NULL; // not yet
// 2001-09-12 Returning information about loaded file by Maddes end
Draw_BeginDisc ();
Sys_FileRead (h, buf, len);
COM_CloseFile (h);
Draw_EndDisc ();
return fileinfo; // 2001-09-12 Returning information about loaded file by Maddes
}
After we did all the main work, only the boring task of adapting the rest of the
source to the new functionality is left. Just search the source for all calls of
the COM_Load*File functions, typically the calls look like this...
(Example of Cmd_Exec_f of CMD.C)
f = (char *)COM_LoadHunkFile (Cmd_Argv(1));
if (!f)
{
Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
return;
}
... and convert it to this ...
loadedfile_t *fileinfo; // 2001-09-12 Returning information about loaded file by Maddes
// 2001-09-12 Returning information about loaded file by Maddes start
fileinfo = COM_LoadHunkFile(Cmd_Argv(1));
if (!fileinfo)
// 2001-09-12 Returning information about loaded file by Maddes end
{
Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
return;
}
f = (char *)fileinfo->data; // 2001-09-12 Returning information about loaded file by Maddes
Instead of checking the original buffer pointer we check the information
pointer, if it is NULL then the error handling is processed. If the information
pointer is filled, we set the original buffer pointer with the buffer pointer
from the info structure.
A special case is in Sys_Quit of SYS_DOS.C where the error handling doesn't quit
the function, there are two ways to handle this...
You should initialize the original buffer with NULL first and only set it
when an info structure was returned.
- OR -
Replace all checks of the original buffer with the info pointer, and the use
of the original buffer with the buffer pointer from the info structure.
Compile the engine and test it, then you can read on and add the searchpath of
the file to the info structure, which we'll use to display from which directory
a file was loaded from.
Part #2 - Adding the searchpath to the info structure
In the file find function COM_FindFile the searchpath of the file is already
known, so this function must only return the searchpath's pointer.
At first you have to move some structure definitions and #DEFINEs to COMMON.H as
these are later referenced in other files.
Move the following from COMMON.C to COMMON.H ...
//
// in memory
//
typedef struct
{
char name[MAX_QPATH];
int filepos, filelen;
} packfile_t;
typedef struct pack_s
{
char filename[MAX_OSPATH];
int handle;
int numfiles;
packfile_t *files;
} pack_t;
//
// on disk
//
typedef struct
{
char name[56];
int filepos, filelen;
} dpackfile_t;
typedef struct
{
char id[4];
int dirofs;
int dirlen;
} dpackheader_t;
#define MAX_FILES_IN_PACK 2048
... and also ...
typedef struct searchpath_s
{
char filename[MAX_OSPATH];
pack_t *pack; // only one of filename / pack will be used
struct searchpath_s *next;
} searchpath_t;
The function COM_FindFile in COMMON.C already has a return value (filesize), you
have to handle the path return value like the FILE value (a pointer where to
store the result).
So change its definition as following...
int COM_FindFile (char *filename, int *handle, FILE **file, searchpath_t **foundpath) // 2001-09-12 Returning from which searchpath a file was loaded by Maddes
... and before each (there are two) ....
return com_filesize;
... add this ...
// 2001-09-12 Returning from which searchpath a file was loaded by Maddes start
if ( foundpath )
{
*foundpath = search;
}
// 2001-09-12 Returning from which searchpath a file was loaded by Maddes end
The COM_FindFile function is used in the COM_*OpenFile functions of COMMON.C, so
we have to adapt them accordingly...
int COM_OpenFile (char *filename, int *handle, searchpath_t **foundpath) // 2001-09-12 Returning from which searchpath a file was loaded by Maddes
{
return COM_FindFile (filename, handle, NULL, foundpath); // 2001-09-12 Returning from which searchpath a file was loaded by Maddes
}
int COM_FOpenFile (char *filename, FILE **file, searchpath_t **foundpath) // 2001-09-12 Returning from which searchpath a file was loaded by Maddes
{
return COM_FindFile (filename, NULL, file, foundpath); // 2001-09-12 Returning from which searchpath a file was loaded by Maddes
}
... and do not forget to change their declarations in COMMON.H too.
Back in COM_LoadFile add a pointer variable for the searchpath, pass it to the
COM_OpenFile function and put the result in the info structure. Here are the
necessary code lines... (you should know where they belong :)
searchpath_t *foundpath; // 2001-09-12 Returning from which searchpath a file was loaded by Maddes
len = COM_OpenFile (path, &h, &foundpath); // 2001-09-12 Returning from which searchpath a file was loaded by Maddes
fileinfo->path = foundpath; // 2001-09-12 Returning from which searchpath a file was loaded by Maddes
Again the boring task of adapting the rest of the source to the new
functionality is left. Change all other calls of the COM_*OpenFile functions, so
that they use NULL for the path return value.
If you included LordHavoc's .LIT support go the Mod_LoadLighting function in
GL_MODEL.C and display the filename if file was found ...
if (fileinfo)
{
Con_Printf("%s loaded from %s\n", litfilename, s_lit->pack ? s_lit->pack->filename : s_lit->filename); // 2001-09-12 Displaying where .LIT file is loaded from by Maddes
...
Recompile and test.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?