mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-18 00:00:29 +02:00
613 lines
14 KiB
C
613 lines
14 KiB
C
/*
|
|
DATA.C
|
|
|
|
symbols in this file:
|
|
001089A0 0020:
|
|
_data_allocation_size (0000)
|
|
001089C0 00d0:
|
|
_data_initialize (0000)
|
|
00108A90 00b0:
|
|
_datum_try_and_get (0000)
|
|
00108B40 00d0:
|
|
_datum_get (0000)
|
|
00108C10 00b0:
|
|
_data_verify (0000)
|
|
00108CC0 0030:
|
|
_datum_initialize (0000)
|
|
00108CF0 0050:
|
|
_data_new (0000)
|
|
00108D40 0030:
|
|
_data_dispose (0000)
|
|
00108D70 0020:
|
|
_data_make_invalid (0000)
|
|
00108D90 00a0:
|
|
_datum_new_at_index (0000)
|
|
00108E30 00c0:
|
|
_datum_new (0000)
|
|
00108EF0 0050:
|
|
_datum_delete (0000)
|
|
00108F40 0090:
|
|
_data_delete_all (0000)
|
|
00108FD0 0060:
|
|
_data_iterator_new (0000)
|
|
00109030 00e0:
|
|
_data_iterator_next (0000)
|
|
00109110 0090:
|
|
_data_next_index (0000)
|
|
001091A0 0090:
|
|
_data_prev_index (0000)
|
|
00109230 0110:
|
|
_data_compact (0000)
|
|
00109340 0020:
|
|
_data_make_valid (0000)
|
|
0027D310 0005:
|
|
??_C@_04MEMAJGDJ@name?$AA@ (0000)
|
|
0027D318 0010:
|
|
??_C@_0BA@HDDJANCC@maximum_count?$DO0?$AA@ (0000)
|
|
0027D328 001d:
|
|
??_C@_0BN@PKENIDAC@c?3?2halo?2SOURCE?2memory?2data?4c?$AA@ (0000)
|
|
0027D348 002d:
|
|
??_C@_0CN@EMICPANB@identifier?5?$HM?$HM?5?$CBdata?9?$DOidentifier_@ (0000)
|
|
0027D378 000c:
|
|
??_C@_0M@FOPPJIAE@data?9?$DOvalid?$AA@ (0000)
|
|
0027D384 0029:
|
|
??_C@_0CJ@PGGNIIAJ@?$CFs?5index?5?$CD?$CFd?5?$CI0x?$CFx?$CJ?5is?5unused?5or@ (0000)
|
|
0027D3B0 002a:
|
|
??_C@_0CK@PGJBLDEL@?$CFs?5data?5array?5?$EA?$CFp?5is?5bad?5or?5not?5@ (0000)
|
|
0027D3DC 0016:
|
|
??_C@_0BG@NCCMBKGF@iterator?9?$DOdata?9?$DOvalid?$AA@ (0000)
|
|
0027D3F4 0031:
|
|
??_C@_0DB@COCANJJJ@uninitialized?5iterator?5passed?5to@ (0000)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
#include "data.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static void datum_initialize(struct data_array *data, struct datum_header *header);
|
|
static boolean data_usable(struct data_array *data, void const *caller);
|
|
void platform_log(const char *format, ...);
|
|
|
|
/* ---------- globals */
|
|
|
|
/* ---------- public code */
|
|
|
|
long data_allocation_size(
|
|
short maximum_count,
|
|
short size)
|
|
{
|
|
return maximum_count*size+sizeof(struct data_array);
|
|
}
|
|
|
|
void data_initialize(
|
|
struct data_array *data,
|
|
const char *name,
|
|
short maximum_count,
|
|
short size)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 64, maximum_count>0);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 65, size>0);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 66, name);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 67, data);
|
|
|
|
csmemset(data, 0, sizeof(*data));
|
|
csstrncpy(data->name, name, sizeof(data->name)-1);
|
|
data->maximum_count = maximum_count;
|
|
data->size = size;
|
|
data->signature = 'd@t@';
|
|
data->data = data+1;
|
|
data->valid = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
void *datum_try_and_get(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header = NULL;
|
|
short identifier;
|
|
short absolute_index;
|
|
|
|
if (index!=NONE)
|
|
{
|
|
identifier = index>>16;
|
|
absolute_index = index;
|
|
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 371, data->valid);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
372,
|
|
identifier || !data->identifier_zero_invalid);
|
|
|
|
if (absolute_index>=0 && absolute_index<data->maximum_count)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
if (!header->identifier || (identifier && header->identifier!=identifier))
|
|
{
|
|
header = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return header;
|
|
}
|
|
|
|
void *datum_get(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header;
|
|
short identifier;
|
|
short absolute_index;
|
|
|
|
identifier = index>>16;
|
|
absolute_index = index;
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 396, data->valid);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
397,
|
|
identifier || !data->identifier_zero_invalid);
|
|
|
|
if (absolute_index>=0 && absolute_index<data->count)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
if (header->identifier && (!identifier || identifier==header->identifier))
|
|
{
|
|
return header;
|
|
}
|
|
}
|
|
|
|
#ifdef HALO_RELEASE
|
|
/* port: a release build's message too, and where it was asked from
|
|
(debug.txt's reference address places it in the build): the caller
|
|
goes on with the NULL and crashes, with nothing else to say which
|
|
array and which caller it was */
|
|
{
|
|
char message[128];
|
|
|
|
csprintf(
|
|
message,
|
|
"%.32s index #%d (0x%x) is unused or changed (asked from %p)",
|
|
data->name,
|
|
index&0xFFFF,
|
|
index,
|
|
__builtin_return_address(0));
|
|
release_assert_failed(message, "c:\\halo\\SOURCE\\memory\\data.c", 412, TRUE);
|
|
}
|
|
#else
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
412,
|
|
FALSE,
|
|
csprintf(
|
|
temporary,
|
|
"%s index #%d (0x%x) is unused or changed",
|
|
data->name,
|
|
index&0xFFFF,
|
|
index));
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void data_verify(
|
|
struct data_array *data)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 457, data);
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
470,
|
|
data->data &&
|
|
data->signature=='d@t@' &&
|
|
data->maximum_count>=0 &&
|
|
data->count>=0 &&
|
|
data->count<=data->maximum_count &&
|
|
data->first_free_absolute_index>=0 &&
|
|
data->first_free_absolute_index<=data->maximum_count &&
|
|
data->actual_count>=0 &&
|
|
data->actual_count<=data->count,
|
|
csprintf(temporary, "%s data array @%p is bad or not allocated", data->name, data));
|
|
|
|
return;
|
|
}
|
|
|
|
struct data_array *data_new(
|
|
const char *name,
|
|
short maximum_count,
|
|
short size)
|
|
{
|
|
struct data_array *data = (struct data_array *)match_malloc(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
41,
|
|
data_allocation_size(maximum_count, size));
|
|
|
|
if (data)
|
|
{
|
|
data_initialize(data, name, maximum_count, size);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
void data_dispose(
|
|
struct data_array *data)
|
|
{
|
|
data_verify(data);
|
|
csmemset(data, 0, sizeof(*data));
|
|
match_free("c:\\halo\\SOURCE\\memory\\data.c", 89, data);
|
|
|
|
return;
|
|
}
|
|
|
|
void data_make_invalid(
|
|
struct data_array *data)
|
|
{
|
|
data_verify(data);
|
|
data->valid = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
long datum_new_at_index(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header;
|
|
short absolute_index = index;
|
|
short identifier = index>>16;
|
|
long result = NONE;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 123, data->valid);
|
|
if (!data_usable(data, __builtin_return_address(0)))
|
|
return NONE;
|
|
|
|
if (absolute_index>=0 && absolute_index<data->maximum_count && identifier)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
if (!header->identifier)
|
|
{
|
|
data->actual_count++;
|
|
if (absolute_index>=data->count)
|
|
{
|
|
data->count = absolute_index+1;
|
|
}
|
|
|
|
datum_initialize(data, header);
|
|
header->identifier = identifier;
|
|
result = identifier<<16 | absolute_index;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
long datum_new(
|
|
struct data_array *data)
|
|
{
|
|
struct datum_header *header;
|
|
short absolute_index;
|
|
long size;
|
|
long result = NONE;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 163, data->valid);
|
|
if (!data_usable(data, __builtin_return_address(0)))
|
|
return NONE;
|
|
|
|
absolute_index = data->first_free_absolute_index;
|
|
size = data->size;
|
|
header = (struct datum_header *)((byte *)data->data+size*absolute_index);
|
|
while (absolute_index<data->maximum_count)
|
|
{
|
|
if (!header->identifier)
|
|
{
|
|
datum_initialize(data, header);
|
|
data->actual_count++;
|
|
data->first_free_absolute_index = absolute_index+1;
|
|
if (data->count<=absolute_index)
|
|
{
|
|
data->count = absolute_index+1;
|
|
}
|
|
|
|
result = header->identifier<<16 | absolute_index;
|
|
break;
|
|
}
|
|
|
|
absolute_index++;
|
|
header = (struct datum_header *)((byte *)header+size);
|
|
}
|
|
/* port: none free from first_free_absolute_index on (and none before it
|
|
is, as ever): the next search starts at the end, until a datum is deleted
|
|
(datum_delete lowers it), rather than walking a full array again. A full
|
|
array (the AI's props, with many actors) was walked on every new datum. */
|
|
if (result == NONE)
|
|
data->first_free_absolute_index = data->maximum_count;
|
|
|
|
return result;
|
|
}
|
|
|
|
void data_make_valid(
|
|
struct data_array *data)
|
|
{
|
|
data_verify(data);
|
|
data->valid = TRUE;
|
|
data_delete_all(data);
|
|
|
|
return;
|
|
}
|
|
|
|
void datum_delete(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header = (struct datum_header *)datum_get(data, index);
|
|
header->identifier = 0;
|
|
|
|
if (((short)index)<data->first_free_absolute_index)
|
|
{
|
|
data->first_free_absolute_index = index;
|
|
}
|
|
|
|
if (((short)index)+1==data->count)
|
|
{
|
|
do
|
|
{
|
|
header =(struct datum_header *)((byte *)header-data->size);
|
|
data->count--;
|
|
}
|
|
while (data->count > 0 && !header->identifier);
|
|
}
|
|
data->actual_count--;
|
|
|
|
return;
|
|
}
|
|
|
|
void data_delete_all(
|
|
struct data_array *data)
|
|
{
|
|
short absolute_index;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 226, data->valid);
|
|
|
|
data->count = 0;
|
|
data->actual_count = 0;
|
|
data->first_free_absolute_index = 0;
|
|
csstrncpy((char *)&data->next_identifier, data->name, sizeof(data->next_identifier));
|
|
data->next_identifier |= 0x8000;
|
|
|
|
for (absolute_index = 0; absolute_index<data->maximum_count; absolute_index++)
|
|
{
|
|
((struct datum_header *)((byte *)data->data+data->size*absolute_index))->identifier = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void data_iterator_new(
|
|
struct data_iterator *iterator,
|
|
struct data_array *data)
|
|
{
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 249, data->valid);
|
|
|
|
iterator->data = data;
|
|
iterator->signature = (unsigned long)data^'iter';
|
|
iterator->absolute_index = 0;
|
|
iterator->datum_index = NONE;
|
|
|
|
return;
|
|
}
|
|
|
|
void *data_iterator_next(
|
|
struct data_iterator *iterator)
|
|
{
|
|
struct datum_header *header;
|
|
short absolute_index;
|
|
long datum_index;
|
|
long size;
|
|
void *result = NULL;
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
268,
|
|
iterator->signature==((unsigned long)iterator->data^'iter'),
|
|
"uninitialized iterator passed to iterator_next()");
|
|
data_verify(iterator->data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 271, iterator->data->valid);
|
|
|
|
absolute_index = iterator->absolute_index;
|
|
size = iterator->data->size;
|
|
header = (struct datum_header *)((byte *)iterator->data->data+size*absolute_index);
|
|
while (absolute_index<iterator->data->count)
|
|
{
|
|
datum_index = header->identifier<<16 | absolute_index;
|
|
absolute_index++;
|
|
if (header->identifier)
|
|
{
|
|
iterator->datum_index = datum_index;
|
|
result = header;
|
|
break;
|
|
}
|
|
|
|
header = (struct datum_header *)((byte *)header+size);
|
|
}
|
|
iterator->absolute_index = absolute_index;
|
|
|
|
return result;
|
|
}
|
|
|
|
long data_next_index(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header;
|
|
long result = NONE;
|
|
short absolute_index = index+1;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 303, data->valid);
|
|
|
|
if (absolute_index>=0 && absolute_index<data->count)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
while (absolute_index<data->count)
|
|
{
|
|
if (header->identifier)
|
|
{
|
|
result = header->identifier<<16 | absolute_index;
|
|
break;
|
|
}
|
|
|
|
absolute_index++;
|
|
header = (struct datum_header *)((byte *)header+data->size);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
long data_prev_index(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header;
|
|
long result = NONE;
|
|
short absolute_index;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 335, data->valid);
|
|
|
|
absolute_index = index==NONE ? data->count-1 : index-1;
|
|
if (absolute_index>=0 && absolute_index<data->count)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
do
|
|
{
|
|
if (header->identifier)
|
|
{
|
|
result = header->identifier<<16 | absolute_index;
|
|
break;
|
|
}
|
|
|
|
header = (struct datum_header *)((byte *)header-data->size);
|
|
}
|
|
while (absolute_index-->=0);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void data_compact(
|
|
struct data_array *data)
|
|
{
|
|
void *compacted_data;
|
|
/* Keep the null sentinel distinct; VC7 coalesces it with compacted_count. */
|
|
void *empty = NULL;
|
|
struct datum_header *datum;
|
|
short compacted_count;
|
|
short absolute_index;
|
|
|
|
compacted_data = match_malloc(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
421,
|
|
data->maximum_count*data->size);
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 424, data->valid);
|
|
|
|
if (compacted_data!=empty)
|
|
{
|
|
datum = data->data;
|
|
absolute_index = (long)empty;
|
|
compacted_count = (short)(long)empty;
|
|
while (absolute_index<data->count)
|
|
{
|
|
if (datum->identifier)
|
|
{
|
|
csmemcpy(
|
|
(byte *)compacted_data+compacted_count*data->size,
|
|
datum,
|
|
data->size);
|
|
compacted_count++;
|
|
}
|
|
|
|
absolute_index++;
|
|
datum = (struct datum_header *)((byte *)datum+data->size);
|
|
}
|
|
|
|
csmemcpy(data->data, compacted_data, compacted_count*data->size);
|
|
csmemset(
|
|
(byte *)data->data+compacted_count*data->size,
|
|
0,
|
|
(data->maximum_count-compacted_count)*data->size);
|
|
data->actual_count = compacted_count;
|
|
data->count = compacted_count;
|
|
data->first_free_absolute_index = compacted_count;
|
|
match_free("c:\\halo\\SOURCE\\memory\\data.c", 447, compacted_data);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* ---------- private code */
|
|
|
|
/* port: whether an array gives out datums: one that is an array (its
|
|
signature, its elements) made valid for the map (data_make_valid). The
|
|
release game went on past the asserts, and an array never made valid, with
|
|
no identifier yet (data_delete_all seeds it), gave out identifier 0, which
|
|
marks a free datum: datum_get of it returned NULL to a caller that wrote
|
|
through it (light_new: Sentry NATIVE-7 and NATIVE-9). Each array is reported
|
|
once, to halo.log, with the first caller turned away. */
|
|
static boolean data_usable(
|
|
struct data_array *data,
|
|
void const *caller)
|
|
{
|
|
static struct data_array const *reported[32];
|
|
static long reported_count;
|
|
long index;
|
|
|
|
if (data->signature == 'd@t@' && data->data && data->valid && data->next_identifier)
|
|
return TRUE;
|
|
for (index = 0; index < reported_count; index++)
|
|
{
|
|
if (reported[index] == data)
|
|
return FALSE;
|
|
}
|
|
if (reported_count < (long)NUMBEROF(reported))
|
|
reported[reported_count++] = data;
|
|
platform_log("data: %.32s gives out no datum: signature %08lx, %s, next identifier %04x, count %d of %d "
|
|
"(asked from %p)",
|
|
data->signature == 'd@t@' ? data->name : "(not an array)", (unsigned long)data->signature,
|
|
data->valid ? "valid" : "not valid", (unsigned short)data->next_identifier, data->count,
|
|
data->maximum_count, caller);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void datum_initialize(
|
|
struct data_array *data,
|
|
struct datum_header *header)
|
|
{
|
|
csmemset(header, 0, data->size);
|
|
header->identifier = data->next_identifier;
|
|
data->next_identifier++;
|
|
if (!data->next_identifier)
|
|
{
|
|
data->next_identifier = 0x8000;
|
|
}
|
|
|
|
return;
|
|
}
|