Engine changes vs the vendored upstream (full ledger in docs/upstream-patches.md): - Assets: replace the encrypted FILE000N.GLB archives with a catalog of pre-decrypted loose files (data/INDEX); GLB_SlotItems() drives mission-pack / registered-version detection; payloads never run the GLB cipher at runtime. - Platform: Linux/SDL2/ALSA only; Android, MSVC/MinGW, macOS packaging, bundled Windows SDL2 SDKs and the ENDOOM exit screen are gone; EXIT_Error now prints before exiting. - Rendering: decouple presentation from simulation -- sim stays at the original 70/3 Hz, frames render interpolated at display rate (player, map scroll, enemies, shots, bonuses, anims, shadows); menus keep 70 Hz pacing; vsync with a delay-guard fallback. - QoL: borderless window mode (Video/borderless), no menu cursor snapping onto default buttons. Fix four regressions from the render split: - Shield bars never redrew: RAP_ThinkStats latches g_oldshield each sim step before RAP_DisplayStats' dirty check could fire. Bars now draw unconditionally per rendered frame; g_oldsuper deleted, g_oldshield kept as sim-side damage-detection state only. - Dying ships despawned without exploding: the render loop never called ANIMS_DisplayHigh(); most air-death explosions register HIGH_AIR. Restored between the player and enemy shots, as upstream orders it. - Laser turret broke: reusing doneflag as a draw marker (it is hit/retire game state, and the turret retire path never frees its shot) hid the beam on hitting ticks and leaked one SHOTS pool slot per fire until no weapon could shoot. S_LINE tracers now carry an age counter: one Think pass, every render of their birth step, purged at the top of the next Think. - Muzzle flash was cleared per rendered frame, making it invisible at display refresh rates; now cleared once per simulation step.
858 lines
18 KiB
C++
858 lines
18 KiB
C++
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <sys/stat.h>
|
|
#include "common.h"
|
|
#include "glbapi.h"
|
|
#include "vmemapi.h"
|
|
#include "entypes.h"
|
|
|
|
#ifdef _WIN32
|
|
#include <io.h>
|
|
#endif // _WIN32
|
|
#ifdef __GNUC__
|
|
#include <unistd.h>
|
|
char* strupr(char* s)
|
|
{
|
|
char* tmp = s;
|
|
|
|
for (; *tmp; ++tmp) {
|
|
*tmp = toupper((unsigned char)*tmp);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
#endif // __GNUC__
|
|
#ifdef _MSC_VER
|
|
#include <windows.h>
|
|
#define PATH_MAX MAX_PATH
|
|
#endif // _MSC_VER
|
|
|
|
|
|
static const char* serial = "32768GLB";
|
|
static char exePath[PATH_MAX];
|
|
static int num_glbs;
|
|
static bool fVmem = 0;
|
|
|
|
/*
|
|
* define file descriptor used to access file.
|
|
*/
|
|
typedef struct
|
|
{
|
|
char name[16];
|
|
VM_OWNER vm_mem;
|
|
uint32_t size;
|
|
uint32_t offset;
|
|
uint32_t flags;
|
|
uint32_t lock_cnt;
|
|
}ITEMINFO;
|
|
|
|
typedef struct
|
|
{
|
|
ITEMINFO* item;
|
|
int items;
|
|
}FILEDESC;
|
|
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
|
typedef struct
|
|
{
|
|
uint16_t filenum;
|
|
uint16_t itemnum;
|
|
}ITEM_ID;
|
|
#else
|
|
typedef struct
|
|
{
|
|
uint16_t itemnum;
|
|
uint16_t filenum;
|
|
}ITEM_ID;
|
|
#endif
|
|
|
|
typedef union
|
|
{
|
|
ITEM_ID id;
|
|
uint32_t handle;
|
|
}ITEM_H;
|
|
|
|
static FILEDESC filedesc[MAX_GLB_FILES];
|
|
|
|
#define ITF_LOCKED 0x80000000L
|
|
#define ITF_ENCODED 0x40000000L
|
|
|
|
typedef enum
|
|
{
|
|
FI_CACHE,
|
|
FI_DISCARD,
|
|
FI_LOCK
|
|
}FI_MODE;
|
|
|
|
/***************************************************************************
|
|
GLB_EnCrypt - Encrypt Data
|
|
***************************************************************************/
|
|
void
|
|
GLB_EnCrypt(
|
|
const char* key, // INPUT : Key that will allow Decryption
|
|
void* buf, // INPUT : Buffer to Encrypt
|
|
int length // INPUT : Length of Buffer
|
|
)
|
|
{
|
|
char* buffer = (char*)buf;
|
|
int klen = strlen(key);
|
|
int prev_byte;
|
|
int kidx;
|
|
|
|
kidx = SEED % klen;
|
|
prev_byte = key[kidx];
|
|
|
|
while (length--)
|
|
{
|
|
prev_byte = (*buffer + key[kidx] + prev_byte) % 256;
|
|
*buffer++ = prev_byte;
|
|
|
|
if (++kidx >= klen)
|
|
kidx = 0;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_DeCrypt - Decrypt Data
|
|
***************************************************************************/
|
|
void
|
|
GLB_DeCrypt(
|
|
const char* key, // INPUT : Key that will allow Decryption
|
|
void* buf, // INPUT : Buffer to Encrypt
|
|
int length // INPUT : Length of Buffer
|
|
)
|
|
{
|
|
char* buffer = (char*)buf;
|
|
int klen = strlen(key);
|
|
int prev_byte;
|
|
int kidx;
|
|
char dchr;
|
|
|
|
kidx = SEED % klen;
|
|
prev_byte = key[kidx];
|
|
|
|
while (length--)
|
|
{
|
|
dchr = (*buffer - key[kidx] - prev_byte) % 256;
|
|
prev_byte = *buffer;
|
|
*buffer++ = dchr;
|
|
|
|
if (++kidx >= klen)
|
|
kidx = 0;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
Data catalog: INDEX maps asset ids to files in category dirs
|
|
(music/, sprites/, ... — see tools/glbextract.py). Ids are engine
|
|
handles, (archive slot << 16) | item index, sorted ascending.
|
|
------------------------------------------------------------------------*/
|
|
typedef struct
|
|
{
|
|
uint32_t id;
|
|
uint32_t size;
|
|
char path[64];
|
|
}CATENTRY;
|
|
|
|
static CATENTRY* catalog;
|
|
static int catalog_n;
|
|
static char dataRoot[PATH_MAX]; // "" when INDEX sits in the cwd
|
|
|
|
/*------------------------------------------------------------------------
|
|
GLB_LoadCatalog() - Parses INDEX (current directory first, then
|
|
exePath). Missing INDEX leaves the catalog empty; every slot then
|
|
reports zero items, which callers treat as "no data".
|
|
------------------------------------------------------------------------*/
|
|
static void
|
|
GLB_LoadCatalog(
|
|
void
|
|
)
|
|
{
|
|
char path[PATH_MAX];
|
|
FILE *handle;
|
|
|
|
if (catalog != NULL)
|
|
return;
|
|
|
|
strcpy(dataRoot, "");
|
|
|
|
handle = fopen("INDEX", "rb");
|
|
if (handle == NULL)
|
|
{
|
|
strcpy(dataRoot, exePath);
|
|
sprintf(path, "%sINDEX", exePath);
|
|
handle = fopen(path, "rb");
|
|
}
|
|
if (handle == NULL)
|
|
return;
|
|
|
|
while (true)
|
|
{
|
|
CATENTRY ce;
|
|
|
|
if (fscanf(handle, "%x %u %63s", &ce.id, &ce.size, ce.path) != 3)
|
|
break;
|
|
|
|
catalog = (CATENTRY*)realloc(catalog, (catalog_n + 1) * sizeof(CATENTRY));
|
|
if (catalog == NULL)
|
|
EXIT_Error("GLB_LoadCatalog: memory");
|
|
|
|
catalog[catalog_n++] = ce;
|
|
}
|
|
|
|
fclose(handle);
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_SlotItems() - Returns number of catalog items in one archive slot
|
|
***************************************************************************/
|
|
int
|
|
GLB_SlotItems(
|
|
int filenum // INPUT : archive slot number
|
|
)
|
|
{
|
|
int i;
|
|
int count;
|
|
|
|
GLB_LoadCatalog();
|
|
|
|
count = 0;
|
|
for (i = 0; i < catalog_n; i++)
|
|
{
|
|
if (catalog[i].id >> 16 == (uint32_t)filenum)
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
GLB_CatFind() - Binary search of the catalog by asset id.
|
|
------------------------------------------------------------------------*/
|
|
static CATENTRY*
|
|
GLB_CatFind(
|
|
uint32_t id
|
|
)
|
|
{
|
|
int lo;
|
|
int hi;
|
|
|
|
lo = 0;
|
|
hi = catalog_n - 1;
|
|
|
|
while (lo <= hi)
|
|
{
|
|
int mid = (lo + hi) / 2;
|
|
|
|
if (catalog[mid].id == id)
|
|
return &catalog[mid];
|
|
else if (catalog[mid].id < id)
|
|
lo = mid + 1;
|
|
else
|
|
hi = mid - 1;
|
|
}
|
|
|
|
EXIT_Error("GLB_CatFind: id %x not in catalog", id);
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
GLB_FillSlot() - Fills one slot's item descriptors from the catalog.
|
|
Extracted payloads are stored pre-decrypted, so no item stays flagged
|
|
ITF_ENCODED.
|
|
--------------------------------------------------------------------------*/
|
|
static void
|
|
GLB_FillSlot(
|
|
FILEDESC* fd, // INPUT: slot descriptor to fill
|
|
int filenum // INPUT : archive slot number
|
|
)
|
|
{
|
|
ITEMINFO* ii;
|
|
int i;
|
|
int n;
|
|
|
|
n = 0;
|
|
ii = fd->item;
|
|
|
|
for (i = 0; i < catalog_n && n < fd->items; i++)
|
|
{
|
|
CATENTRY* ce = &catalog[i];
|
|
const char* base;
|
|
|
|
if (ce->id >> 16 != (uint32_t)filenum)
|
|
continue;
|
|
|
|
base = strrchr(ce->path, '/');
|
|
base = (base != NULL) ? base + 1 : ce->path;
|
|
|
|
if (strlen(base) >= sizeof(ii->name))
|
|
EXIT_Error("GLB_FillSlot: item name too long: %s", base);
|
|
|
|
strcpy(ii->name, base);
|
|
ii->size = ce->size;
|
|
ii++;
|
|
n++;
|
|
}
|
|
}
|
|
|
|
/*************************************************************************
|
|
GLB_UseVM - Use virtual memory functions for heap managment.
|
|
*************************************************************************/
|
|
void
|
|
GLB_UseVM(
|
|
void
|
|
)
|
|
{
|
|
fVmem = 1;
|
|
}
|
|
|
|
/*************************************************************************
|
|
GLB_InitSystem() - Starts up .GLB file system
|
|
*************************************************************************/
|
|
int // Returns number of GLB resources opened.
|
|
GLB_InitSystem(
|
|
const char* exepath, // INPUT: Where program was run from
|
|
int innum, // INPUT: MAX .GLB FILES TO LOOK FOR
|
|
const char* iprefix // INPUT: FILENAME PREFIX ( NULL for "FILE" )
|
|
)
|
|
{
|
|
int opened;
|
|
int filenum;
|
|
int num;
|
|
char* p;
|
|
FILEDESC* fd;
|
|
|
|
/*
|
|
* Extract path from program source of execution.
|
|
*/
|
|
memset(exePath, 0, sizeof(exePath));
|
|
strcpy(exePath, exepath);
|
|
|
|
if ((p = strrchr(exePath, '\\')) != NULL)
|
|
*(p + 1) = '\0';
|
|
|
|
num_glbs = innum;
|
|
ASSERT(num_glbs >= 1 && num_glbs <= MAX_GLB_FILES);
|
|
|
|
(void)iprefix; // archive-name prefixes are obsolete with the catalog
|
|
memset(filedesc, 0, sizeof(filedesc));
|
|
|
|
/*
|
|
* Parse the catalog, then set up one descriptor per non-empty slot
|
|
*/
|
|
GLB_LoadCatalog();
|
|
|
|
opened = 0;
|
|
for (filenum = 0; filenum < num_glbs; filenum++)
|
|
{
|
|
fd = &filedesc[filenum];
|
|
|
|
if ((num = GLB_SlotItems(filenum)) != 0)
|
|
{
|
|
fd->items = num;
|
|
|
|
/*
|
|
* Note: calloc zeros out all memory that it allocates
|
|
*/
|
|
fd->item = (ITEMINFO*)calloc(num, sizeof(ITEMINFO));
|
|
|
|
if (fd->item == NULL)
|
|
EXIT_Error("GLB_InitSystem: memory ( init )");
|
|
|
|
GLB_FillSlot(fd, filenum);
|
|
opened++;
|
|
}
|
|
}
|
|
|
|
return (opened);
|
|
}
|
|
|
|
/*************************************************************************
|
|
GLB_Load() Loads a file to a pointer from a .GLB file
|
|
*************************************************************************/
|
|
int // RETURN : size of item read
|
|
GLB_Load(
|
|
char* inmem, // INPUT: memory pointer or NULL
|
|
int filenum, // INPUT: file number
|
|
int itemnum // INPUT: item in file number
|
|
)
|
|
{
|
|
ITEMINFO* ii;
|
|
char path[PATH_MAX];
|
|
FILE *f;
|
|
|
|
ASSERT(filenum >= 0 && filenum < num_glbs);
|
|
|
|
if (filedesc[filenum].item == NULL)
|
|
return 0;
|
|
|
|
ASSERT(itemnum < (WORD)filedesc[filenum].items);
|
|
|
|
ii = filedesc[filenum].item;
|
|
ii += itemnum;
|
|
|
|
if (inmem != NULL)
|
|
{
|
|
if (ii->vm_mem.obj != NULL && inmem != ii->vm_mem.obj)
|
|
memcpy(inmem, ii->vm_mem.obj, ii->size);
|
|
else
|
|
{
|
|
CATENTRY* ce = GLB_CatFind(((uint32_t)filenum << 16) | (uint32_t)itemnum);
|
|
char path[PATH_MAX];
|
|
|
|
sprintf(path, "%s%s", dataRoot, ce->path);
|
|
|
|
f = fopen(path, "rb");
|
|
if (f == NULL || fread(inmem, ii->size, 1, f) != 1)
|
|
EXIT_Error("GLB_Load: read failed on %s", path);
|
|
|
|
fclose(f);
|
|
}
|
|
}
|
|
|
|
return ii->size;
|
|
}
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*
|
|
GLB_FetchItem() - Loads item into memory only if free core exists.
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
|
|
static char*
|
|
GLB_FetchItem(
|
|
uint32_t handle,
|
|
FI_MODE mode
|
|
)
|
|
{
|
|
char* obj;
|
|
ITEM_H itm;
|
|
ITEMINFO* ii;
|
|
|
|
if (handle == ~0)
|
|
{
|
|
EXIT_Error("GLB_FetchItem: empty handle.");
|
|
return NULL;
|
|
}
|
|
|
|
itm.handle = handle;
|
|
|
|
ASSERT(itm.id.filenum < (WORD)num_glbs);
|
|
ASSERT(itm.id.itemnum < (WORD)filedesc[itm.id.filenum].items);
|
|
|
|
ii = filedesc[itm.id.filenum].item;
|
|
ii += itm.id.itemnum;
|
|
|
|
if (mode == FI_LOCK)
|
|
ii->flags |= ITF_LOCKED;
|
|
|
|
if ((obj = ii->vm_mem.obj) == NULL)
|
|
{
|
|
ii->lock_cnt = 0;
|
|
|
|
if (ii->size == 0)
|
|
ii->vm_mem.obj = NULL;
|
|
else
|
|
{
|
|
if (fVmem)
|
|
{
|
|
obj = (char*)VM_Malloc(ii->size,
|
|
(ii->flags & ITF_LOCKED) ? NULL : &ii->vm_mem,
|
|
(mode == FI_CACHE) ? 0 : 1);
|
|
}
|
|
else
|
|
{
|
|
obj = (char*)calloc(ii->size, sizeof(uint8_t));
|
|
}
|
|
|
|
if (mode == FI_LOCK)
|
|
ii->lock_cnt = 1;
|
|
|
|
ii->vm_mem.obj = obj;
|
|
|
|
if (obj != NULL)
|
|
{
|
|
GLB_Load(obj, itm.id.filenum, itm.id.itemnum);
|
|
}
|
|
}
|
|
}
|
|
else if (mode == FI_LOCK && fVmem)
|
|
{
|
|
ii->lock_cnt++;
|
|
VM_Lock(obj);
|
|
}
|
|
|
|
if (ii->vm_mem.obj == NULL && mode != FI_CACHE)
|
|
{
|
|
EXIT_Error("GLB_FetchItem: failed on %d bytes, mode=%d.", ii->size, mode);
|
|
}
|
|
|
|
if (mode == FI_DISCARD && fVmem)
|
|
VM_Touch(&ii->vm_mem);
|
|
|
|
return ii->vm_mem.obj;
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_CacheItem() - Loads item into memory only if free core exists.
|
|
***************************************************************************/
|
|
char*
|
|
GLB_CacheItem(
|
|
int handle
|
|
)
|
|
{
|
|
return GLB_FetchItem(handle, FI_CACHE);
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_GetItem() - Loads and allocates memory for a .GLB item
|
|
***************************************************************************/
|
|
char*
|
|
GLB_GetItem(
|
|
int handle // INPUT : handle of item
|
|
)
|
|
{
|
|
return GLB_FetchItem(handle, FI_DISCARD);
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_LockItem () - Keeps Item From being discarded.
|
|
***************************************************************************/
|
|
char*
|
|
GLB_LockItem(
|
|
int handle
|
|
)
|
|
{
|
|
return GLB_FetchItem(handle, FI_LOCK);
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_UnlockItem () - Allows item to be discarded from memory.
|
|
***************************************************************************/
|
|
void
|
|
GLB_UnlockItem(
|
|
int handle
|
|
)
|
|
{
|
|
ITEM_H itm;
|
|
ITEMINFO* ii;
|
|
|
|
if (handle == ~0)
|
|
return;
|
|
|
|
itm.handle = handle;
|
|
|
|
ASSERT(itm.id.filenum < (WORD)num_glbs);
|
|
ASSERT(itm.id.itemnum < (WORD)filedesc[itm.id.filenum].items);
|
|
|
|
ii = filedesc[itm.id.filenum].item;
|
|
ii += itm.id.itemnum;
|
|
|
|
if (ii->vm_mem.obj != NULL && fVmem)
|
|
{
|
|
if (ii->lock_cnt)
|
|
{
|
|
ii->lock_cnt--;
|
|
|
|
if (ii->lock_cnt)
|
|
return;
|
|
}
|
|
ii->flags &= ~ITF_LOCKED;
|
|
VM_Unlock(ii->vm_mem.obj, &ii->vm_mem);
|
|
}
|
|
else
|
|
{
|
|
ii->flags &= ~ITF_LOCKED;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_IsLabel () - tests to see if ID is a label or an Item
|
|
***************************************************************************/
|
|
int // RETURN: TRUE = Label
|
|
GLB_IsLabel(
|
|
int handle // INPUT : handle of item
|
|
)
|
|
{
|
|
ITEM_H itm;
|
|
ITEMINFO* ii;
|
|
|
|
if (handle == ~0)
|
|
return 0;
|
|
|
|
itm.handle = handle;
|
|
|
|
ASSERT(itm.id.filenum < (WORD)num_glbs);
|
|
ASSERT(itm.id.itemnum < (WORD)filedesc[itm.id.filenum].items);
|
|
|
|
ii = filedesc[itm.id.filenum].item;
|
|
ii += itm.id.itemnum;
|
|
|
|
return (ii->size == 0 ? 1 : 0);
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_ReadItem() - Loads Item into user memory for a .GLB item
|
|
***************************************************************************/
|
|
void
|
|
GLB_ReadItem(
|
|
int handle, // INPUT : handle of item
|
|
char* mem // INPUT : pointer to memory
|
|
)
|
|
{
|
|
ITEM_H itm;
|
|
ITEMINFO* ii;
|
|
|
|
if (handle == ~0)
|
|
return;
|
|
|
|
ASSERT(mem != NULL);
|
|
|
|
itm.handle = handle;
|
|
|
|
ASSERT(itm.id.filenum < (WORD)num_glbs);
|
|
ASSERT(itm.id.itemnum < (WORD)filedesc[itm.id.filenum].items);
|
|
|
|
ii = filedesc[itm.id.filenum].item;
|
|
ii += itm.id.itemnum;
|
|
|
|
if (mem != NULL)
|
|
{
|
|
GLB_Load(mem, itm.id.filenum, itm.id.itemnum);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_GetItemID () - Gets Item ID from the text name
|
|
***************************************************************************/
|
|
int // RETURN: Handle
|
|
GLB_GetItemID(
|
|
const char* in_name // INPUT : pointer to text name
|
|
)
|
|
{
|
|
ITEMINFO* ii;
|
|
ITEM_H itm;
|
|
int filenum;
|
|
int itemnum;
|
|
int maxloop;
|
|
|
|
ASSERT(in_name != NULL);
|
|
|
|
itm.handle = ~0;
|
|
if (*in_name != ' ' && *in_name != '\0')
|
|
{
|
|
for (filenum = 0; filenum < num_glbs; filenum++)
|
|
{
|
|
maxloop = filedesc[filenum].items;
|
|
ii = filedesc[filenum].item;
|
|
|
|
for (itemnum = 0; itemnum < maxloop; itemnum++)
|
|
{
|
|
if (strcmp(ii->name, in_name) == 0)
|
|
{
|
|
itm.id.filenum = filenum;
|
|
itm.id.itemnum = itemnum;
|
|
return itm.handle;
|
|
}
|
|
ii++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return itm.handle;
|
|
}
|
|
|
|
#if 0
|
|
/***************************************************************************
|
|
GLB_GetPtr() - Returns a pointer to item ( handle )
|
|
***************************************************************************/
|
|
char* // RETURN: pointer to item
|
|
GLB_GetPtr(
|
|
int handle // INPUT : handle of item
|
|
)
|
|
{
|
|
ITEM_H itm;
|
|
ITEMINFO* ii;
|
|
|
|
if (handle == ~0)
|
|
return NULL;
|
|
|
|
itm.handle = handle;
|
|
|
|
ASSERT(itm.id.filenum < (uint16_t)num_glbs);
|
|
ASSERT(itm.id.itemnum < (uint16_t)filedesc[itm.id.filenum].items);
|
|
|
|
ii = filedesc[itm.id.filenum].item;
|
|
ii += itm.id.itemnum;
|
|
|
|
return ii->memory;
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
GLB_FreeItem() - Frees memory for items and places items < MAX SIZE
|
|
***************************************************************************/
|
|
void
|
|
GLB_FreeItem(
|
|
int handle // INPUT : handle of item
|
|
)
|
|
{
|
|
ITEM_H itm;
|
|
ITEMINFO* ii;
|
|
|
|
if (handle == ~0)
|
|
return;
|
|
|
|
itm.handle = handle;
|
|
|
|
ASSERT(itm.id.filenum < (uint16_t)num_glbs);
|
|
|
|
if (itm.id.itemnum >= (uint16_t)filedesc[itm.id.filenum].items)
|
|
{
|
|
EXIT_Error("GLB_FreeItem - item out of range: %d > %d file %d.\n",
|
|
itm.id.itemnum, filedesc[itm.id.filenum].items, itm.id.filenum);
|
|
}
|
|
// ASSERT( itm.id.itemnum < ( WORD ) filedesc[ itm.id.filenum ].items );
|
|
|
|
ii = filedesc[itm.id.filenum].item;
|
|
ii += itm.id.itemnum;
|
|
|
|
if (ii->vm_mem.obj != NULL)
|
|
{
|
|
ii->flags &= ~ITF_LOCKED;
|
|
|
|
if (fVmem)
|
|
VM_Free(ii->vm_mem.obj);
|
|
else
|
|
free(ii->vm_mem.obj);
|
|
|
|
ii->vm_mem.obj = NULL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_FreeAll() - Frees All memory used by GLB items
|
|
***************************************************************************/
|
|
void
|
|
GLB_FreeAll(
|
|
void
|
|
)
|
|
{
|
|
int filenum;
|
|
int itemnum;
|
|
ITEMINFO* ii;
|
|
|
|
for (filenum = 0; filenum < num_glbs; filenum++)
|
|
{
|
|
ii = filedesc[filenum].item;
|
|
|
|
for (itemnum = 0; itemnum < filedesc[filenum].items; itemnum++)
|
|
{
|
|
if (ii->vm_mem.obj && (ii->flags & ITF_LOCKED) == 0)
|
|
{
|
|
if (fVmem)
|
|
VM_Free(ii->vm_mem.obj);
|
|
else
|
|
free(ii->vm_mem.obj);
|
|
|
|
ii->vm_mem.obj = NULL;
|
|
}
|
|
ii++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_ItemSize() - Returns Size of Item
|
|
***************************************************************************/
|
|
int // RETURN: sizeof ITEM
|
|
GLB_ItemSize(
|
|
int handle // INPUT : handle of item
|
|
)
|
|
{
|
|
ITEM_H itm;
|
|
ITEMINFO* ii;
|
|
|
|
if (handle == ~0)
|
|
return 0;
|
|
|
|
itm.handle = handle;
|
|
|
|
ASSERT(itm.id.filenum < (WORD)num_glbs);
|
|
ASSERT(itm.id.itemnum < (WORD)filedesc[itm.id.filenum].items);
|
|
|
|
ii = filedesc[itm.id.filenum].item;
|
|
ii += itm.id.itemnum;
|
|
|
|
return ii->size;
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_ReadFile () reads in a normal file
|
|
***************************************************************************/
|
|
int // RETURN: size of record
|
|
GLB_ReadFile(
|
|
const char* name, // INPUT : filename
|
|
char* buffer // OUTPUT: pointer to buffer or NULL
|
|
)
|
|
{
|
|
char fqp[PATH_MAX];
|
|
FILE *handle;
|
|
uint32_t sizerec;
|
|
|
|
if (access(name, 0) == -1)
|
|
{
|
|
strcpy(fqp, exePath);
|
|
strcat(fqp, name);
|
|
name = fqp;
|
|
}
|
|
|
|
if ((handle = fopen(name, "rb")) == NULL)
|
|
EXIT_Error("LoadFile: Open failed!");
|
|
|
|
fseek(handle, 0, SEEK_END);
|
|
sizerec = ftell(handle);
|
|
rewind(handle);
|
|
|
|
if (buffer && sizerec)
|
|
{
|
|
if (!fread(buffer, sizerec, 1, handle))
|
|
{
|
|
fclose(handle);
|
|
EXIT_Error("GLB_LoadFile: Load failed!");
|
|
}
|
|
}
|
|
|
|
fclose(handle);
|
|
|
|
return (sizerec);
|
|
}
|
|
|
|
/***************************************************************************
|
|
GLB_SaveFile () saves buffer to a normal file ( filename )
|
|
***************************************************************************/
|
|
void
|
|
GLB_SaveFile(
|
|
char* name, // INPUT : filename
|
|
char* buffer, // INPUT : pointer to buffer
|
|
int length // INPUT : length of buffer
|
|
)
|
|
{
|
|
FILE *handle;
|
|
|
|
if ((handle = fopen(name, "wb")) == NULL)
|
|
EXIT_Error("SaveFile: Open failed!");
|
|
|
|
if (length)
|
|
{
|
|
if (!fwrite(buffer, length, 1, handle))
|
|
{
|
|
fclose(handle);
|
|
EXIT_Error("GLB_SaveFile: Write failed!");
|
|
}
|
|
}
|
|
|
|
fclose(handle);
|
|
} |