Subversion Repositories Games.Carmageddon

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #include "resource.h"
  2.  
  3. #include "CORE/FW/brlists.h"
  4. #include "CORE/FW/diag.h"
  5. #include "CORE/FW/fwsetup.h"
  6. #include "CORE/FW/mem.h"
  7. #include "CORE/FW/scratch.h"
  8. #include "CORE/STD/brstdlib.h"
  9. #include "harness/trace.h"
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12.  
  13. #define RES_ALIGN 4
  14. #define RESOURCE_SIZE(RES) ((RES)->size_h << 18)  | ((RES)->size_m << 10) | ((RES)->size_l << 2)
  15.  
  16. #define PANIC_ON_INVALID_RESOURCE_HEADER(RES_HDR)                                                        \
  17.     do {                                                                                                 \
  18.         if ((RES_HDR)->magic_num != 0xdeadbeef) {                                                        \
  19.             LOG_PANIC("Bad resource header from user at %p. Was 0x%x", (RES_HDR), (RES_HDR)->magic_num); \
  20.         }                                                                                                \
  21.     } while (0)
  22.  
  23. // IDA: void* __usercall ResToUser@<EAX>(resource_header *r@<EAX>)
  24. void* ResToUser(resource_header* r) {
  25.     br_int_32 align;
  26.     LOG_TRACE9("(%p)", r);
  27.  
  28.     align = fw.resource_class_index[r->class]->alignment;
  29.     if (align <= 0) {
  30.         align = RES_ALIGN;
  31.     }
  32.     return (void *) (((br_size_t)r + sizeof(resource_header) + align - 1) & ~(align - 1)); // Pierre-Marie Baty -- added type cast
  33. }
  34.  
  35. // IDA: resource_header* __usercall UserToRes@<EAX>(void *r@<EAX>)
  36. resource_header* UserToRes(void* r) {
  37.     br_uint_8* p;
  38.     LOG_TRACE9("(%p)", r);
  39.  
  40.     p = (br_uint_8*)r - 1;
  41.     while (*p == 0) {
  42.         p--;
  43.     }
  44.     return (resource_header*)(p - (sizeof(resource_header) - 1));
  45. }
  46.  
  47. // IDA: void* __cdecl BrResAllocate(void *vparent, br_size_t size, br_uint_8 res_class)
  48. void* BrResAllocate(void* vparent, br_size_t size, br_uint_8 res_class) {
  49.     resource_header* res;
  50.     resource_header* parent;
  51.     br_int_32 malign;
  52.     br_int_32 calign;
  53.     br_int_32 pad;
  54.     br_int_32 actual_pad;
  55.     LOG_TRACE9("(%p, %d, %d)", vparent, size, res_class);
  56.  
  57.     size = (size + sizeof(resource_header) + RES_ALIGN - 1) & ~(RES_ALIGN - 1);
  58.  
  59.     malign = BrMemAlign(res_class);
  60.  
  61.     calign = fw.resource_class_index[res_class]->alignment;
  62.     if (calign <= 0) {
  63.         calign = RES_ALIGN;
  64.     }
  65.  
  66.     pad = (~(malign - 1)) & (calign - 1);
  67.     res = (resource_header*)BrMemAllocate(pad + size, res_class);
  68.     actual_pad = ((((br_size_t)res + calign - 1) & (~(calign - 1))) - (br_size_t)res);
  69.     if (actual_pad > pad) {
  70.         BrFailure("Memory allocator broke alignment");
  71.     }
  72.     res->class = res_class;
  73.     res->size_l = (br_uint_8) (size >> 2); // Pierre-Marie Baty -- added type cast
  74.     res->size_m = (br_uint_8) (size >> 10); // Pierre-Marie Baty -- added type cast
  75.     res->size_h = (br_uint_8) (size >> 18); // Pierre-Marie Baty -- added type cast
  76.     BrSimpleNewList(&res->children);
  77.     res->magic_num = 0xdeadbeef;
  78.     res->magic_ptr = res;
  79.  
  80.     if (vparent != NULL) {
  81.         // vparent points to a resource body, we track backwards to obtain its resource_header
  82.         parent = UserToRes(vparent);
  83.         PANIC_ON_INVALID_RESOURCE_HEADER(parent);
  84.         BrSimpleAddHead(&parent->children, &res->node);
  85.     }
  86.  
  87.     return ResToUser(res);
  88. }
  89.  
  90. // IDA: void __usercall BrResInternalFree(resource_header *res@<EAX>, br_boolean callback@<EDX>)
  91. void BrResInternalFree(resource_header* res, br_boolean callback) {
  92.     //int c; // Pierre-Marie Baty -- unused variable
  93.     void* r;
  94.     LOG_TRACE10("(%p, %d)", res, callback);
  95.  
  96.     if (res->class == BR_MEMORY_FREE) {
  97.         return;
  98.     }
  99.     if (callback != 0) {
  100.         if (fw.resource_class_index[res->class]->free_cb != NULL) {
  101.             fw.resource_class_index[res->class]->free_cb(ResToUser(res), res->class, RESOURCE_SIZE(res));
  102.         }
  103.     }
  104.  
  105.     while (res->children.head != NULL) {
  106.         r = BrSimpleRemove(res->children.head);
  107.         BrResInternalFree((resource_header*)r, 1);
  108.     }
  109.     if (res->node.prev != NULL) {
  110.         BrSimpleRemove(&res->node);
  111.     }
  112.     res->magic_num = 1;
  113.     res->magic_ptr = NULL;
  114.     BrMemFree(res);
  115. }
  116.  
  117. // IDA: void __cdecl BrResFree(void *vres)
  118. void BrResFree(void* vres) {
  119.     LOG_TRACE10("(%p)", vres);
  120.  
  121.     PANIC_ON_INVALID_RESOURCE_HEADER(UserToRes(vres));
  122.     BrResInternalFree(UserToRes(vres), 1);
  123. }
  124.  
  125. // IDA: void __cdecl BrResFreeNoCallback(void *vres)
  126. void BrResFreeNoCallback(void* vres) {
  127.     LOG_TRACE("(%p)", vres);
  128.  
  129.     PANIC_ON_INVALID_RESOURCE_HEADER(UserToRes(vres));
  130.     BrResInternalFree(UserToRes(vres), 0);
  131. }
  132.  
  133. // IDA: void* __cdecl BrResAdd(void *vparent, void *vres)
  134. void* BrResAdd(void* vparent, void* vres) {
  135.     resource_header* res;
  136.     resource_header* parent;
  137.     LOG_TRACE("(%p, %p)", vparent, vres);
  138.  
  139.     res = UserToRes(vres);
  140.     parent = UserToRes(vparent);
  141.  
  142.     PANIC_ON_INVALID_RESOURCE_HEADER(res);
  143.     PANIC_ON_INVALID_RESOURCE_HEADER(parent);
  144.  
  145.     if (res->node.prev != NULL) {
  146.         BrSimpleRemove(&res->node);
  147.     }
  148.     BrSimpleAddHead(&parent->children, &res->node);
  149.     return vres;
  150. }
  151.  
  152. // IDA: void* __cdecl BrResRemove(void *vres)
  153. void* BrResRemove(void* vres) {
  154.     resource_header* res;
  155.     LOG_TRACE("(%p)", vres);
  156.  
  157.     res = UserToRes(vres);
  158.     PANIC_ON_INVALID_RESOURCE_HEADER(res);
  159.  
  160.     BrSimpleRemove(&res->node);
  161.     return vres;
  162. }
  163.  
  164. // IDA: br_uint_8 __cdecl BrResClass(void *vres)
  165. br_uint_8 BrResClass(void* vres) {
  166.     resource_header* res;
  167.     LOG_TRACE("(%p)", vres);
  168.  
  169.     res = UserToRes(vres);
  170.     PANIC_ON_INVALID_RESOURCE_HEADER(res);
  171.     return res->class;
  172. }
  173.  
  174. // IDA: br_boolean __cdecl BrResIsChild(void *vparent, void *vchild)
  175. br_boolean BrResIsChild(void* vparent, void* vchild) {
  176.     resource_header* parent;
  177.     resource_header* child;
  178.     resource_header* cp;
  179.     LOG_TRACE("(%p, %p)", vparent, vchild);
  180.  
  181.     parent = UserToRes(vparent);
  182.     child = UserToRes(vchild);
  183.     PANIC_ON_INVALID_RESOURCE_HEADER(parent);
  184.     PANIC_ON_INVALID_RESOURCE_HEADER(child);
  185.  
  186.     for (cp = (resource_header*)parent->children.head; cp != NULL; cp = (resource_header*)cp->node.next) {
  187.         if (cp == child) {
  188.             return 1;
  189.         }
  190.     }
  191.     return 0;
  192. }
  193.  
  194. // IDA: br_uint_32 __cdecl BrResSize(void *vres)
  195. br_uint_32 BrResSize(void* vres) {
  196.     resource_header* res;
  197.     LOG_TRACE("(%p)", vres);
  198.  
  199.     res = UserToRes(vres);
  200.     PANIC_ON_INVALID_RESOURCE_HEADER(res);
  201.  
  202.     return RESOURCE_SIZE(res);
  203. }
  204.  
  205. // IDA: br_uint_32 __cdecl ResSizeTotal(void *vres, br_uint_32 *ptotal)
  206. br_uint_32 ResSizeTotal(void* vres, br_uint_32* ptotal) {
  207.     LOG_TRACE("(%p, %p)", vres, ptotal);
  208.  
  209.     *ptotal += BrResSize(vres);
  210.     BrResChildEnum(vres, (br_resenum_cbfn*)ResSizeTotal, ptotal);
  211.     return 0;
  212. }
  213.  
  214. // IDA: br_uint_32 __cdecl BrResSizeTotal(void *vres)
  215. br_uint_32 BrResSizeTotal(void* vres) {
  216.     br_uint_32 total;
  217.     LOG_TRACE("(%p)", vres);
  218.  
  219.     total = BrResSize(vres);
  220.     BrResChildEnum(vres, (br_resenum_cbfn*)ResSizeTotal, &total);
  221.     return total;
  222. }
  223.  
  224. // IDA: br_uint_32 __cdecl BrResChildEnum(void *vres, br_resenum_cbfn *callback, void *arg)
  225. br_uint_32 BrResChildEnum(void* vres, br_resenum_cbfn* callback, void* arg) {
  226.     resource_header* res;
  227.     resource_header* rp;
  228.     br_uint_32 r;
  229.     LOG_TRACE("(%p, %p, %p)", vres, callback, arg);
  230.  
  231.     res = UserToRes(vres);
  232.     PANIC_ON_INVALID_RESOURCE_HEADER(res);
  233.     r = 0;
  234.     for (rp = (resource_header*)res->children.head; rp != NULL; rp = (resource_header*)rp->node.next) {
  235.         r = callback(ResToUser(rp), arg);
  236.         if (r != 0) {
  237.             break;
  238.         }
  239.     }
  240.     return r;
  241. }
  242.  
  243. // IDA: br_uint_32 __cdecl BrResCheck(void *vres, int no_tag)
  244. br_uint_32 BrResCheck(void* vres, int no_tag) {
  245.     resource_header* res;
  246.     LOG_TRACE("(%p, %d)", vres, no_tag);
  247.  
  248.     res = UserToRes(vres);
  249.     // No PANIC_ON_INVALID_RESOURCE_HEADER check
  250.  
  251.     return res->magic_ptr == res && res->magic_num == 0xdeadbeef;
  252. }
  253.  
  254. // IDA: char* __cdecl BrResStrDup(void *vparent, char *str)
  255. char* BrResStrDup(void* vparent, char* str) {
  256.     int l;
  257.     char* nstr;
  258.  
  259.     l = BrStrLen(str);
  260.     nstr = (char*)BrResAllocate(vparent, l + 1, BR_MEMORY_STRING);
  261.     BrStrCpy(nstr, str);
  262.     return nstr;
  263. }
  264.  
  265. // IDA: void __usercall InternalResourceDump(resource_header *res@<EAX>, br_putline_cbfn *putline@<EDX>, void *arg@<EBX>, int level@<ECX>)
  266. void InternalResourceDump(resource_header* res, br_putline_cbfn* putline, void* arg, int level) {
  267.     int i;
  268.     char* cp;
  269.     resource_header* child;
  270.     br_resource_class* rclass;
  271.     LOG_TRACE9("(%p, %p, %p, %d)", res, putline, arg, level);
  272.  
  273.     rclass = fw.resource_class_index[res->class];
  274.     cp = BrScratchString();
  275.     for (i = 0; i < level; i++) {
  276.         *cp = ' ';
  277.         cp++;
  278.     }
  279.     sprintf(cp, "%p [%s] size=%u", res, rclass->identifier, RESOURCE_SIZE(res));
  280.     putline(BrScratchString(), arg);
  281.     for (child = (resource_header*)res->children.head; child != NULL; child = (resource_header*)child->node.next) {
  282.         InternalResourceDump(child, putline, arg, level + 1);
  283.     }
  284. }
  285.  
  286. // IDA: void __cdecl BrResDump(void *vres, br_putline_cbfn *putline, void *arg)
  287. void BrResDump(void* vres, br_putline_cbfn* putline, void* arg) {
  288.     resource_header* res;
  289.     LOG_TRACE("(%p, %p, %p)", vres, putline, arg);
  290.  
  291.     res = UserToRes(vres);
  292.     PANIC_ON_INVALID_RESOURCE_HEADER(res);
  293.     InternalResourceDump(res, putline, arg, 0);
  294. }
  295.  
  296. // IDA: char* __cdecl BrResClassIdentifier(br_uint_8 res_class)
  297. char* BrResClassIdentifier(br_uint_8 res_class) {
  298.     br_resource_class* rclass;
  299.     LOG_TRACE("(%d)", res_class);
  300.  
  301.     rclass = fw.resource_class_index[res_class];
  302.     if (rclass == NULL) {
  303.         return "<NULL>";
  304.     }
  305.     return rclass->identifier;
  306. }
  307.