#include "resource.h"
#include "CORE/FW/brlists.h"
#include "CORE/FW/diag.h"
#include "CORE/FW/fwsetup.h"
#include "CORE/FW/mem.h"
#include "CORE/FW/scratch.h"
#include "CORE/STD/brstdlib.h"
#include "harness/trace.h"
#include <stdio.h>
#include <stdlib.h>
#define RES_ALIGN 4
#define RESOURCE_SIZE(RES) ((RES)->size_h << 18) | ((RES)->size_m << 10) | ((RES)->size_l << 2)
#define PANIC_ON_INVALID_RESOURCE_HEADER(RES_HDR) \
do { \
if ((RES_HDR)->magic_num != 0xdeadbeef) { \
LOG_PANIC("Bad resource header from user at %p. Was 0x%x", (RES_HDR), (RES_HDR)->magic_num); \
} \
} while (0)
// IDA: void* __usercall ResToUser@<EAX>(resource_header *r@<EAX>)
void* ResToUser(resource_header* r) {
br_int_32 align;
LOG_TRACE9("(%p)", r);
align = fw.resource_class_index[r->class]->alignment;
if (align <= 0) {
align = RES_ALIGN;
}
return (void *) (((br_size_t)r + sizeof(resource_header) + align - 1) & ~(align - 1)); // Pierre-Marie Baty -- added type cast
}
// IDA: resource_header* __usercall UserToRes@<EAX>(void *r@<EAX>)
resource_header* UserToRes(void* r) {
br_uint_8* p;
LOG_TRACE9("(%p)", r);
p = (br_uint_8*)r - 1;
while (*p == 0) {
p--;
}
return (resource_header*)(p - (sizeof(resource_header) - 1));
}
// IDA: void* __cdecl BrResAllocate(void *vparent, br_size_t size, br_uint_8 res_class)
void* BrResAllocate(void* vparent, br_size_t size, br_uint_8 res_class) {
resource_header* res;
resource_header* parent;
br_int_32 malign;
br_int_32 calign;
br_int_32 pad;
br_int_32 actual_pad;
LOG_TRACE9("(%p, %d, %d)", vparent, size, res_class);
size = (size + sizeof(resource_header) + RES_ALIGN - 1) & ~(RES_ALIGN - 1);
malign = BrMemAlign(res_class);
calign = fw.resource_class_index[res_class]->alignment;
if (calign <= 0) {
calign = RES_ALIGN;
}
pad = (~(malign - 1)) & (calign - 1);
res = (resource_header*)BrMemAllocate(pad + size, res_class);
actual_pad = ((((br_size_t)res + calign - 1) & (~(calign - 1))) - (br_size_t)res);
if (actual_pad > pad) {
BrFailure("Memory allocator broke alignment");
}
res->class = res_class;
res->size_l = (br_uint_8) (size >> 2); // Pierre-Marie Baty -- added type cast
res->size_m = (br_uint_8) (size >> 10); // Pierre-Marie Baty -- added type cast
res->size_h = (br_uint_8) (size >> 18); // Pierre-Marie Baty -- added type cast
BrSimpleNewList(&res->children);
res->magic_num = 0xdeadbeef;
res->magic_ptr = res;
if (vparent != NULL) {
// vparent points to a resource body, we track backwards to obtain its resource_header
parent = UserToRes(vparent);
PANIC_ON_INVALID_RESOURCE_HEADER(parent);
BrSimpleAddHead(&parent->children, &res->node);
}
return ResToUser(res);
}
// IDA: void __usercall BrResInternalFree(resource_header *res@<EAX>, br_boolean callback@<EDX>)
void BrResInternalFree(resource_header* res, br_boolean callback) {
//int c; // Pierre-Marie Baty -- unused variable
void* r;
LOG_TRACE10("(%p, %d)", res, callback);
if (res->class == BR_MEMORY_FREE) {
return;
}
if (callback != 0) {
if (fw.resource_class_index[res->class]->free_cb != NULL) {
fw.resource_class_index[res->class]->free_cb(ResToUser(res), res->class, RESOURCE_SIZE(res));
}
}
while (res->children.head != NULL) {
r = BrSimpleRemove(res->children.head);
BrResInternalFree((resource_header*)r, 1);
}
if (res->node.prev != NULL) {
BrSimpleRemove(&res->node);
}
res->magic_num = 1;
res->magic_ptr = NULL;
BrMemFree(res);
}
// IDA: void __cdecl BrResFree(void *vres)
void BrResFree(void* vres) {
LOG_TRACE10("(%p)", vres);
PANIC_ON_INVALID_RESOURCE_HEADER(UserToRes(vres));
BrResInternalFree(UserToRes(vres), 1);
}
// IDA: void __cdecl BrResFreeNoCallback(void *vres)
void BrResFreeNoCallback(void* vres) {
LOG_TRACE("(%p)", vres);
PANIC_ON_INVALID_RESOURCE_HEADER(UserToRes(vres));
BrResInternalFree(UserToRes(vres), 0);
}
// IDA: void* __cdecl BrResAdd(void *vparent, void *vres)
void* BrResAdd(void* vparent, void* vres) {
resource_header* res;
resource_header* parent;
LOG_TRACE("(%p, %p)", vparent, vres);
res = UserToRes(vres);
parent = UserToRes(vparent);
PANIC_ON_INVALID_RESOURCE_HEADER(res);
PANIC_ON_INVALID_RESOURCE_HEADER(parent);
if (res->node.prev != NULL) {
BrSimpleRemove(&res->node);
}
BrSimpleAddHead(&parent->children, &res->node);
return vres;
}
// IDA: void* __cdecl BrResRemove(void *vres)
void* BrResRemove(void* vres) {
resource_header* res;
LOG_TRACE("(%p)", vres);
res = UserToRes(vres);
PANIC_ON_INVALID_RESOURCE_HEADER(res);
BrSimpleRemove(&res->node);
return vres;
}
// IDA: br_uint_8 __cdecl BrResClass(void *vres)
br_uint_8 BrResClass(void* vres) {
resource_header* res;
LOG_TRACE("(%p)", vres);
res = UserToRes(vres);
PANIC_ON_INVALID_RESOURCE_HEADER(res);
return res->class;
}
// IDA: br_boolean __cdecl BrResIsChild(void *vparent, void *vchild)
br_boolean BrResIsChild(void* vparent, void* vchild) {
resource_header* parent;
resource_header* child;
resource_header* cp;
LOG_TRACE("(%p, %p)", vparent, vchild);
parent = UserToRes(vparent);
child = UserToRes(vchild);
PANIC_ON_INVALID_RESOURCE_HEADER(parent);
PANIC_ON_INVALID_RESOURCE_HEADER(child);
for (cp = (resource_header*)parent->children.head; cp != NULL; cp = (resource_header*)cp->node.next) {
if (cp == child) {
return 1;
}
}
return 0;
}
// IDA: br_uint_32 __cdecl BrResSize(void *vres)
br_uint_32 BrResSize(void* vres) {
resource_header* res;
LOG_TRACE("(%p)", vres);
res = UserToRes(vres);
PANIC_ON_INVALID_RESOURCE_HEADER(res);
return RESOURCE_SIZE(res);
}
// IDA: br_uint_32 __cdecl ResSizeTotal(void *vres, br_uint_32 *ptotal)
br_uint_32 ResSizeTotal(void* vres, br_uint_32* ptotal) {
LOG_TRACE("(%p, %p)", vres, ptotal);
*ptotal += BrResSize(vres);
BrResChildEnum(vres, (br_resenum_cbfn*)ResSizeTotal, ptotal);
return 0;
}
// IDA: br_uint_32 __cdecl BrResSizeTotal(void *vres)
br_uint_32 BrResSizeTotal(void* vres) {
br_uint_32 total;
LOG_TRACE("(%p)", vres);
total = BrResSize(vres);
BrResChildEnum(vres, (br_resenum_cbfn*)ResSizeTotal, &total);
return total;
}
// IDA: br_uint_32 __cdecl BrResChildEnum(void *vres, br_resenum_cbfn *callback, void *arg)
br_uint_32 BrResChildEnum(void* vres, br_resenum_cbfn* callback, void* arg) {
resource_header* res;
resource_header* rp;
br_uint_32 r;
LOG_TRACE("(%p, %p, %p)", vres, callback, arg);
res = UserToRes(vres);
PANIC_ON_INVALID_RESOURCE_HEADER(res);
r = 0;
for (rp = (resource_header*)res->children.head; rp != NULL; rp = (resource_header*)rp->node.next) {
r = callback(ResToUser(rp), arg);
if (r != 0) {
break;
}
}
return r;
}
// IDA: br_uint_32 __cdecl BrResCheck(void *vres, int no_tag)
br_uint_32 BrResCheck(void* vres, int no_tag) {
resource_header* res;
LOG_TRACE("(%p, %d)", vres, no_tag);
res = UserToRes(vres);
// No PANIC_ON_INVALID_RESOURCE_HEADER check
return res->magic_ptr == res && res->magic_num == 0xdeadbeef;
}
// IDA: char* __cdecl BrResStrDup(void *vparent, char *str)
char* BrResStrDup(void* vparent, char* str) {
int l;
char* nstr;
l = BrStrLen(str);
nstr = (char*)BrResAllocate(vparent, l + 1, BR_MEMORY_STRING);
BrStrCpy(nstr, str);
return nstr;
}
// IDA: void __usercall InternalResourceDump(resource_header *res@<EAX>, br_putline_cbfn *putline@<EDX>, void *arg@<EBX>, int level@<ECX>)
void InternalResourceDump(resource_header* res, br_putline_cbfn* putline, void* arg, int level) {
int i;
char* cp;
resource_header* child;
br_resource_class* rclass;
LOG_TRACE9("(%p, %p, %p, %d)", res, putline, arg, level);
rclass = fw.resource_class_index[res->class];
cp = BrScratchString();
for (i = 0; i < level; i++) {
*cp = ' ';
cp++;
}
sprintf(cp
, "%p [%s] size=%u", res
, rclass
->identifier
, RESOURCE_SIZE
(res
));
putline(BrScratchString(), arg);
for (child = (resource_header*)res->children.head; child != NULL; child = (resource_header*)child->node.next) {
InternalResourceDump(child, putline, arg, level + 1);
}
}
// IDA: void __cdecl BrResDump(void *vres, br_putline_cbfn *putline, void *arg)
void BrResDump(void* vres, br_putline_cbfn* putline, void* arg) {
resource_header* res;
LOG_TRACE("(%p, %p, %p)", vres, putline, arg);
res = UserToRes(vres);
PANIC_ON_INVALID_RESOURCE_HEADER(res);
InternalResourceDump(res, putline, arg, 0);
}
// IDA: char* __cdecl BrResClassIdentifier(br_uint_8 res_class)
char* BrResClassIdentifier(br_uint_8 res_class) {
br_resource_class* rclass;
LOG_TRACE("(%d)", res_class);
rclass = fw.resource_class_index[res_class];
if (rclass == NULL) {
return "<NULL>";
}
return rclass->identifier;
}