home *** CD-ROM | disk | FTP | other *** search
/ hobbes.nmsu.edu 2008 / 2008-06-02_hobbes.nmsu.edu.zip / new / scummc-0.2.0-os2.zip / ScummC / src / scvm_res.c < prev    next >
Encoding:
C/C++ Source or Header  |  2008-01-14  |  19.8 KB  |  672 lines

  1. /* ScummC
  2.  * Copyright (C) 2006  Alban Bedel
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17.  *
  18.  */
  19.  
  20. /**
  21.  * @file scvm_res.c
  22.  * @ingroup scvm
  23.  * @brief SCVM ressources management
  24.  */
  25.  
  26. #include "config.h"
  27.  
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <inttypes.h>
  32. #include <errno.h>
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #include <fcntl.h>
  36.  
  37. #include "scc_fd.h"
  38. #include "scc_util.h"
  39. #include "scc_cost.h"
  40. #include "scc_char.h"
  41. #include "scc_codec.h"
  42. #include "scc_box.h"
  43.  
  44. #include "scvm_res.h"
  45. #include "scvm_thread.h"
  46. #include "scvm.h"
  47.  
  48. scc_fd_t* scvm_open_file(scvm_t* vm,unsigned num) {
  49.   if(num >= vm->num_file) {
  50.     scc_log(LOG_ERR,"Invalid file number %d\n",num);
  51.     return NULL;
  52.   }
  53.   if(!vm->file[num]) {
  54.     int l = strlen(vm->path) + strlen(vm->basename) + 32;
  55.     char name[l+1];
  56.     sprintf(name,"%s/%s.%03d",vm->path,vm->basename,num);
  57.     vm->file[num] = new_scc_fd(name,O_RDONLY,vm->file_key);
  58.     if(!vm->file[num])
  59.       scc_log(LOG_ERR,"Failed to open %s: %s\n",name,strerror(errno));
  60.   }
  61.   return vm->file[num];
  62. }
  63.  
  64. void scvm_close_file(scvm_t* vm,unsigned num) {
  65.   if(num >= vm->num_file) {
  66.     scc_log(LOG_ERR,"Invalid file number %d\n",num);
  67.     return;
  68.   }
  69.   if(vm->file[num]) {
  70.     scc_fd_close(vm->file[num]);
  71.     vm->file[num] = NULL;
  72.   }
  73. }
  74.  
  75.  
  76. void scvm_res_init(scvm_res_type_t* res, char* name, unsigned num,
  77.                    scvm_res_load_f load, scvm_res_nuke_f nuke) {
  78.   res->name = strdup(name);
  79.   res->load = load;
  80.   res->nuke = nuke;
  81.   res->num = num;
  82.   if(num > 0) res->idx = calloc(num,sizeof(scvm_res_t));
  83. }
  84.  
  85. int scvm_res_load_index(scvm_t* vm, scvm_res_type_t* res,scc_fd_t* fd,
  86.                         uint32_t ref_type) {
  87.   int i,num;
  88.   uint32_t type, len;
  89.   
  90.   type = scc_fd_r32(fd);
  91.   len = scc_fd_r32be(fd);
  92.   if(type != ref_type || len < 8+2 ||
  93.      (num = scc_fd_r16le(fd))*5+2+8 != len ||
  94.      num != res->num) {
  95.     scc_log(LOG_ERR,"Invalid index file, bad %c%c%c%c block.\n",UNMKID(ref_type));
  96.     return 0;
  97.   }
  98.   
  99.   for(i = 0 ; i < res->num ; i++) {
  100.     res->idx[i].room = scc_fd_r8(fd);
  101.     if(res->idx[i].room >= vm->res[SCVM_RES_ROOM].num) {
  102.       scc_log(LOG_WARN,"Invalid room number in index: %d.\n",res->idx[i].room);
  103.       res->idx[i].room = 0;
  104.       continue;
  105.     }
  106.     res->idx[i].file = vm->res[SCVM_RES_ROOM].idx[res->idx[i].room].file;
  107.   }
  108.   for(i = 0 ; i < res->num ; i++)
  109.     res->idx[i].offset = scc_fd_r32le(fd) + 
  110.     vm->res[SCVM_RES_ROOM].idx[res->idx[i].room].offset;
  111.   return 1;
  112. }
  113.  
  114. int scvm_lock_res(scvm_t* vm, unsigned type, unsigned num) {
  115.   // check type and num
  116.   if(type >= SCVM_RES_MAX) {
  117.     scc_log(LOG_ERR,"Invalid resource type: %d\n",type);
  118.     return 0;
  119.   }
  120.   if(num >= vm->res[type].num) {
  121.     scc_log(LOG_ERR,"Invalid %s number: %d\n",vm->res[type].name,num);
  122.     return 0;
  123.   }
  124.   vm->res[type].idx[num].flags |= SCVM_RES_LOCKED;
  125.   return 1;
  126. }
  127.  
  128. int scvm_unlock_res(scvm_t* vm, unsigned type, unsigned num) {
  129.   // check type and num
  130.   if(type >= SCVM_RES_MAX) {
  131.     scc_log(LOG_ERR,"Invalid resource type: %d\n",type);
  132.     return 0;
  133.   }
  134.   if(num >= vm->res[type].num) {
  135.     scc_log(LOG_ERR,"Invalid %s number: %d\n",vm->res[type].name,num);
  136.     return 0;
  137.   }
  138.   vm->res[type].idx[num].flags &= ~SCVM_RES_LOCKED;
  139.   return 1;
  140. }
  141.  
  142.  
  143. void* scvm_load_res(scvm_t* vm, unsigned type, unsigned num) {
  144.   // check type and num
  145.   if(type >= SCVM_RES_MAX) {
  146.     scc_log(LOG_ERR,"Invalid resource type: %d\n",type);
  147.     return NULL;
  148.   }
  149.   if(num >= vm->res[type].num) {
  150.     scc_log(LOG_ERR,"Invalid %s number: %d\n",vm->res[type].name,num);
  151.     return NULL;
  152.   }
  153.   if(!vm->res[type].load && !vm->res[type].idx[num].data) {
  154.     scc_log(LOG_ERR,"The %s loader is missing. Implement it!\n",
  155.             vm->res[type].name);
  156.     return NULL;
  157.   }
  158.   // load if needed
  159.   if(!vm->res[type].idx[num].data) {
  160.     scc_fd_t* fd = scvm_open_file(vm,vm->res[type].idx[num].file);
  161.     unsigned offset = vm->res[type].idx[num].offset;
  162.     if(!fd) return NULL;
  163.     if(scc_fd_seek(fd,offset,SEEK_SET) != offset) {
  164.       scc_log(LOG_ERR,"Failed to seek to %d in %s.\n",offset,fd->filename);
  165.       scvm_close_file(vm,vm->res[type].idx[num].file);
  166.       return NULL;
  167.     }
  168.     vm->res[type].idx[num].data = vm->res[type].load(vm,fd,num);
  169.     if(!vm->res[type].idx[num].data)
  170.       scc_log(LOG_ERR,"Failed to load %s %d\n",vm->res[type].name,num);
  171.   }
  172.   return vm->res[type].idx[num].data;
  173. }
  174.  
  175. void* scvm_load_script(scvm_t* vm,scc_fd_t* fd, unsigned num) {
  176.   uint32_t type,len;
  177.   scvm_script_t* scrp;
  178.   
  179.   type = scc_fd_r32(fd);
  180.   len = scc_fd_r32be(fd);
  181.   if(type != MKID('S','C','R','P') || len < 8) {
  182.     scc_log(LOG_ERR,"Bad script block %d: %c%c%c%c %d\n",num,
  183.             UNMKID(type),len);
  184.     return NULL;
  185.   }
  186.   scrp = malloc(sizeof(scvm_script_t)+len-8);
  187.   scrp->id = num;
  188.   scrp->size = len-8;
  189.   if(scrp->size > 0) {
  190.     int total = 0, r;
  191.     while(total < scrp->size) {
  192.       r = scc_fd_read(fd,scrp->code+total,scrp->size-total);
  193.       if(r < 0) {
  194.         scc_log(LOG_ERR,"Error loading script %d: %s\n",num,strerror(errno));
  195.         free(scrp);
  196.         return NULL;
  197.       }
  198.       total += r;
  199.     }
  200.   }
  201.   return scrp;
  202. }
  203.  
  204. int scvm_load_image(unsigned width, unsigned height, unsigned num_zplane,
  205.                     scvm_image_t* img,scc_fd_t* fd) {
  206.   int i;
  207.   uint32_t type = scc_fd_r32(fd);
  208.   uint32_t size = scc_fd_r32be(fd);
  209.   if(type != MKID('S','M','A','P') ||
  210.      size < 8+(width/8)*4) return 0;
  211.   else {
  212.     uint8_t smap[size-8];
  213.     if(scc_fd_read(fd,smap,size-8) != size-8)
  214.       return 0;
  215.     img->data = calloc(1,width*height);
  216.     if(!(i = scc_decode_image(img->data,width,
  217.                               width,height,
  218.                               smap,size-8,-1)))
  219.       return 0;
  220.     img->have_trans = i-1;
  221.   }
  222.   if(!num_zplane) return 1;
  223.   img->zplane = calloc(num_zplane+1,sizeof(uint8_t*));
  224.   for(i = 1 ; i <= num_zplane ; i++) {
  225.     char buf[8];
  226.     sprintf(buf,"%02x",i);
  227.     type = scc_fd_r32(fd);
  228.     size = scc_fd_r32be(fd);
  229.     if(type != MKID('Z','P',buf[0],buf[1]) ||
  230.        size < 8+(width/8)*4) return 0;
  231.     else {
  232.       uint8_t zmap[size-8];
  233.       uint8_t zbit[width/8*height];
  234.       int j;
  235.       if(scc_fd_read(fd,zmap,size-8) != size-8)
  236.         return 0;
  237.       if(!scc_decode_zbuf(zbit,width/8,
  238.                           width,height,
  239.                           zmap,size-8,0))
  240.         return 0;
  241.       img->zplane[i] = malloc(width*height);
  242.       for(j = 0 ; j < width*height ; j++)
  243.         img->zplane[i][j] = (zbit[j/8] & (1<<(7-(j%8))) ? 1 : 0);
  244.         //img->zplane[i][j] = ((zbit[j>>3] << (j&7)) & 0x80) >> 7;
  245.     }
  246.   }
  247.   return 1;
  248. }
  249.  
  250. scvm_object_t* scvm_load_obim(scvm_t* vm, scvm_room_t* room, scc_fd_t* fd) {
  251.   uint32_t type = scc_fd_r32(fd);
  252.   uint32_t size = scc_fd_r32be(fd);
  253.   scvm_object_t* obj;
  254.   unsigned id;
  255.   int i;
  256.   if(type != MKID('I','M','H','D') ||
  257.      size < 8+20) return NULL;
  258.   
  259.   id = scc_fd_r16le(fd);
  260.   if(id >= vm->num_object) return NULL;
  261.   if(vm->res[SCVM_RES_OBJECT].idx[id].data)
  262.     obj = vm->res[SCVM_RES_OBJECT].idx[id].data;
  263.   else {
  264.     obj = calloc(1,sizeof(scvm_object_t));
  265.     obj->id = id;
  266.     obj->pdata = &vm->object_pdata[id];
  267.     vm->res[SCVM_RES_OBJECT].idx[id].data = obj;
  268.   }
  269.   // already loaded
  270.   if(obj->loaded & SCVM_OBJ_OBIM) return obj;
  271.   obj->loaded |= SCVM_OBJ_OBIM;
  272.   
  273.   obj->num_image = scc_fd_r16le(fd);
  274.   obj->num_zplane = scc_fd_r16le(fd);
  275.   scc_fd_r16le(fd); // unknown
  276.   obj->x = scc_fd_r16le(fd);
  277.   obj->y = scc_fd_r16le(fd);
  278.   obj->width = scc_fd_r16le(fd);
  279.   obj->height = scc_fd_r16le(fd);
  280.   obj->num_hotspot = scc_fd_r16le(fd);
  281.   if(obj->num_hotspot > 0) {
  282.     obj->hotspot = malloc(2*sizeof(int)*obj->num_hotspot);
  283.     for(i = 0 ; i < obj->num_hotspot ; i++) {
  284.       obj->hotspot[2*i] = scc_fd_r16le(fd);
  285.       obj->hotspot[2*i+1] = scc_fd_r16le(fd);
  286.     }
  287.   }
  288.   
  289.   // load the images
  290.   if(!obj->num_image) return obj;
  291.   
  292.   obj->image = calloc(sizeof(scvm_image_t),obj->num_image+1);
  293.   for(i = 1 ; i <= obj->num_image ; i++) {
  294.     type = scc_fd_r32le(fd);
  295.     size = scc_fd_r32be(fd);
  296.     if((type & 0xFFFF) != ('I'|'M'<<8) ||
  297.        size < 8) return 0;
  298.     if(!scvm_load_image(obj->width,obj->height,obj->num_zplane,
  299.                         &obj->image[i],fd)) return NULL;
  300.   }
  301.   
  302.   return obj;
  303. }
  304.  
  305. scvm_object_t* scvm_load_obcd(scvm_t* vm, scvm_room_t* room, scc_fd_t* fd) {
  306.   uint32_t type = scc_fd_r32(fd);
  307.   uint32_t size = scc_fd_r32be(fd);
  308.   scvm_object_t* obj;
  309.   unsigned id;
  310.   
  311.   if(type != MKID('C','D','H','D') ||
  312.      size < 8+17) return NULL;
  313.   
  314.   id = scc_fd_r16le(fd);
  315.   if(id >= vm->num_object) return NULL;
  316.   if(vm->res[SCVM_RES_OBJECT].idx[id].data)
  317.     obj = vm->res[SCVM_RES_OBJECT].idx[id].data;
  318.   else {
  319.     obj = calloc(1,sizeof(scvm_object_t));
  320.     obj->id = id;
  321.     obj->pdata = &vm->object_pdata[id];
  322.     vm->res[SCVM_RES_OBJECT].idx[id].data = obj;
  323.   }
  324.   // already loaded
  325.   if(obj->loaded & SCVM_OBJ_OBCD) return obj;
  326.   obj->loaded |= SCVM_OBJ_OBCD;
  327.   
  328.   if(!(obj->loaded & SCVM_OBJ_OBIM)) {
  329.     obj->x = scc_fd_r16le(fd);
  330.     obj->y = scc_fd_r16le(fd);
  331.     obj->width = scc_fd_r16le(fd);
  332.     obj->height = scc_fd_r16le(fd);
  333.   } else
  334.     scc_fd_seek(fd,8,SEEK_CUR);
  335.   obj->flags = scc_fd_r8(fd);
  336.   // hack, the real pointer get resolved when all
  337.   // object are loaded.
  338.   obj->parent = (scvm_object_t*)((intptr_t)scc_fd_r8(fd));
  339.   scc_fd_r32(fd); // unknown
  340.   obj->actor_dir = scc_fd_r8(fd);
  341.  
  342.   type = scc_fd_r32(fd);
  343.   size = scc_fd_r32be(fd);
  344.  
  345.   if(type == MKID('V','E','R','B')) {
  346.     unsigned entries[0x200];
  347.     unsigned num_entries = 0,verb;
  348.     if(size < 8+1) return NULL;
  349.     size -= 8;
  350.     while(1) {
  351.       verb = entries[2*num_entries] = scc_fd_r8(fd);
  352.       size--;
  353.       if(!verb) break;
  354.       entries[2*num_entries+1] = scc_fd_r16le(fd);
  355.       size -= 2;
  356.       num_entries++;
  357.     }
  358.     if(num_entries) {
  359.       obj->verb_entries = malloc(2*num_entries*sizeof(unsigned));
  360.       obj->num_verb_entries = num_entries;
  361.       memcpy(obj->verb_entries,entries,2*num_entries*sizeof(unsigned));
  362.     }
  363.     if(size > 0) {
  364.       obj->script = malloc(sizeof(scvm_script_t)+size);
  365.       if(scc_fd_read(fd,obj->script->code,size) != size)
  366.         return 0;
  367.       obj->script->id = obj->id | 0x10000;
  368.       obj->script->size = size;
  369.     }
  370.     
  371.     type = scc_fd_r32(fd);
  372.     size = scc_fd_r32be(fd);
  373.   }
  374.   
  375.   if(type == MKID('O','B','N','A') &&
  376.      !obj->pdata->name) {
  377.     if(size < 8+1) return 0;
  378.     size -= 8;
  379.     obj->pdata->name = malloc(size);
  380.     if(scc_fd_read(fd,obj->pdata->name,size));
  381.     // it should be 0 terminated but make sure it is
  382.     obj->pdata->name[size-1] = 0;
  383.   }  
  384.   
  385.   return obj;
  386. }
  387.  
  388. void* scvm_load_room(scvm_t* vm,scc_fd_t* fd, unsigned num) {
  389.   uint32_t type,size,block_size,sub_block_size;
  390.   unsigned len = 8,num_obim = 0, num_obcd = 0, num_lscr = 0;
  391.   int i,j;
  392.   scvm_room_t* room;
  393.   off_t next_block;
  394.   scvm_object_t *objlist[vm->num_local_object],*obj;
  395.  
  396.   memset(objlist,0,sizeof(scvm_object_t*)*vm->num_local_object);
  397.   
  398.   type = scc_fd_r32(fd);
  399.   size = scc_fd_r32be(fd);
  400.   if(type != MKID('R','O','O','M') || size < 16) {
  401.     scc_log(LOG_ERR,"Bad ROOM block %d: %c%c%c%c %d\n",num,
  402.             UNMKID(type),size);
  403.     return NULL;
  404.   }
  405.   room = calloc(1,sizeof(scvm_room_t));
  406.   room->id = num;
  407.   while(len < size) {
  408.     type = scc_fd_r32(fd);
  409.     block_size = scc_fd_r32be(fd);
  410.     next_block = scc_fd_pos(fd)-8+block_size;
  411.     len += block_size;
  412.     switch(type) {
  413.     case MKID('R','M','H','D'):
  414.       if(block_size != 6+8) goto bad_block;
  415.       room->width = scc_fd_r16le(fd);
  416.       room->height = scc_fd_r16le(fd);
  417.       room->num_object = scc_fd_r16le(fd);
  418.       break;
  419.       
  420.     case MKID('C','Y','C','L'):
  421.       if(block_size < 1+8) goto bad_block;
  422.       room->num_cycle = 17;
  423.       room->cycle = calloc(room->num_cycle,sizeof(scvm_cycle_t));
  424.       while(1) {
  425.         unsigned freq,id = scc_fd_r8(fd);
  426.         if(!id) break;
  427.         if(id >= room->num_cycle) goto bad_block;
  428.         room->cycle[id].id = id;
  429.         scc_fd_r16(fd); // unknown
  430.         freq = scc_fd_r16be(fd);
  431.         room->cycle[id].delay = freq ? 0x4000/freq : 0;
  432.         room->cycle[id].flags = scc_fd_r16be(fd);
  433.         room->cycle[id].start = scc_fd_r8(fd);
  434.         room->cycle[id].end = scc_fd_r8(fd);
  435.       }
  436.       break;
  437.       
  438.     case MKID('T','R','N','S'):
  439.       if(block_size != 2+8) goto bad_block;
  440.       room->trans = scc_fd_r16le(fd);
  441.       break;
  442.  
  443.     case MKID('P','A','L','S'):
  444.       if(block_size < 16) goto bad_block;
  445.       type = scc_fd_r32(fd);
  446.       sub_block_size = scc_fd_r32be(fd);
  447.       if(type != MKID('W','R','A','P') ||
  448.          sub_block_size != block_size-8) goto bad_block;
  449.       type = scc_fd_r32(fd);
  450.       sub_block_size = scc_fd_r32be(fd);
  451.       if(type != MKID('O','F','F','S') || sub_block_size<8) goto bad_block;
  452.       else {
  453.         off_t base_ptr = scc_fd_pos(fd)-8;
  454.         int npal = (sub_block_size-8)/4;
  455.         off_t offset[npal];
  456.         for(i = 0 ; i < npal ; i++)
  457.           offset[i] = base_ptr + scc_fd_r32le(fd);
  458.         room->num_palette = npal;
  459.         room->palette = malloc(npal*sizeof(scvm_palette_t));
  460.         for(i = 0 ; i < npal ; i++) {
  461.           int c;
  462.           scc_fd_seek(fd,offset[i],SEEK_SET);
  463.           type = scc_fd_r32(fd);
  464.           sub_block_size = scc_fd_r32be(fd);
  465.           if(type != MKID('A','P','A','L') ||
  466.              sub_block_size-8!= SCVM_PALETTE_SIZE*3) goto bad_block;
  467.           for(c = 0 ; c < SCVM_PALETTE_SIZE ; c++) {
  468.             room->palette[i][c].r = scc_fd_r8(fd);
  469.             room->palette[i][c].g = scc_fd_r8(fd);
  470.             room->palette[i][c].b = scc_fd_r8(fd);
  471.           }
  472.         }
  473.       }
  474.       break;
  475.       
  476.     case MKID('R','M','I','M'):
  477.       if(block_size < 8+8+2+8+8+(room->width/8)*4) goto bad_block;
  478.       type = scc_fd_r32(fd);
  479.       sub_block_size = scc_fd_r32be(fd);
  480.       if(type != MKID('R','M','I','H') ||
  481.          sub_block_size != 8+2) goto bad_block;
  482.       room->num_zplane = scc_fd_r16le(fd);
  483.       type = scc_fd_r32(fd);
  484.       sub_block_size = scc_fd_r32be(fd);
  485.       if(type != MKID('I','M','0','0') ||
  486.          sub_block_size < 8+8) goto bad_block;
  487.       if(!scvm_load_image(room->width,room->height,room->num_zplane,
  488.                           &room->image,fd))
  489.         goto bad_block;
  490.       break;
  491.       
  492.     case MKID('O','B','I','M'):
  493.       if(num_obim >= vm->num_local_object) {
  494.         scc_log(LOG_ERR,"Too many objects in room.\n");
  495.         goto bad_block;
  496.       }
  497.       if(block_size < 8+8+20 ||
  498.          !(obj = scvm_load_obim(vm,room,fd))) goto bad_block;
  499.       if(!objlist[num_obim])
  500.         objlist[num_obim] = obj;
  501.       else if(objlist[num_obim] != obj) {
  502.         scc_log(LOG_ERR,"OBIM and OBCD are badly ordered.\n");
  503.         goto bad_block;
  504.       }
  505.       num_obim++;
  506.       break;
  507.       
  508.     case MKID('O','B','C','D'):
  509.       if(num_obcd >= vm->num_local_object) {
  510.         scc_log(LOG_ERR,"Too many objects in room.\n");
  511.         goto bad_block;
  512.       }
  513.       if(block_size < 8+8+17 ||
  514.          !(obj = scvm_load_obcd(vm,room,fd))) goto bad_block;
  515.       if(!objlist[num_obcd])
  516.         objlist[num_obcd] = obj;
  517.       else if(objlist[num_obcd] != obj) {
  518.         scc_log(LOG_ERR,"OBIM and OBCD are badly ordered.\n");
  519.         goto bad_block;
  520.       }
  521.       num_obcd++;
  522.       break;
  523.       
  524.     case MKID('E','X','C','D'):
  525.       if(block_size <= 8) {
  526.         scc_log(LOG_WARN,"Ignoring empty EXCD.\n");
  527.         break;
  528.       }
  529.       block_size -= 8;
  530.       room->exit = malloc(sizeof(scvm_script_t)+block_size);
  531.       room->exit->id = 0x1ECD0000;
  532.       room->exit->size = block_size;
  533.       if(scc_fd_read(fd,room->exit->code,block_size) != block_size)
  534.         goto bad_block;
  535.       break;
  536.  
  537.     case MKID('E','N','C','D'):
  538.       if(block_size <= 8) {
  539.         scc_log(LOG_WARN,"Ignoring empty ENCD.\n");
  540.         break;
  541.       }
  542.       block_size -= 8;
  543.       room->entry = malloc(sizeof(scvm_script_t)+block_size);
  544.       room->entry->id = 0x0ECD0000;
  545.       room->entry->size = block_size;
  546.       if(scc_fd_read(fd,room->entry->code,block_size) != block_size)
  547.         goto bad_block;
  548.       break;
  549.  
  550.     case MKID('N','L','S','C'):
  551.       if(block_size != 8+2)
  552.         goto bad_block;
  553.       room->num_script = scc_fd_r16le(fd);
  554.       if(room->num_script)
  555.         room->script = calloc(room->num_script,sizeof(scvm_script_t*));
  556.       break;
  557.       
  558.     case MKID('L','S','C','R'):
  559.       if(num_lscr >= room->num_script) {
  560.         scc_log(LOG_ERR,"Too many local scripts in room.\n");
  561.         goto bad_block;
  562.       }
  563.       if(block_size <= 8+1) {
  564.         scc_log(LOG_WARN,"Ignoring empty LSCR.\n");
  565.         break;
  566.       }
  567.       block_size -= 8+1;
  568.       i = scc_fd_r8(fd);
  569.       if(i < 200 || i-200 >= room->num_script)
  570.         goto bad_block;
  571.       i -= 200;
  572.       room->script[i] = malloc(sizeof(scvm_script_t)+block_size);
  573.       room->script[i]->id = i+200;
  574.       room->script[i]->size = block_size;
  575.       if(scc_fd_read(fd,room->script[i]->code,block_size) != block_size)
  576.         goto bad_block;
  577.       num_lscr++;
  578.       break;
  579.  
  580.     case MKID('B','O','X','D'):
  581.       if(room->box) break;
  582.       if(block_size < 8+2) goto bad_block;
  583.       room->num_box = scc_fd_r16le(fd);
  584.       if(!room->num_box) break;
  585.       if(block_size != 8+2+(4*2*2+1+1+2)*room->num_box) goto bad_block;
  586.       room->box = calloc(room->num_box,sizeof(scc_box_t));
  587.       for(i = 0 ; i < room->num_box ; i++) {
  588.         if(i+1 < room->num_box)
  589.           room->box[i].next = &room->box[i+1];
  590.         room->box[i].id = i;
  591.         room->box[i].npts = 4;
  592.         for(j = 0 ; j < 4 ; j++) {
  593.           room->box[i].pts[j].x = scc_fd_r16le(fd);
  594.           room->box[i].pts[j].y = scc_fd_r16le(fd);
  595.         }
  596.         room->box[i].mask = scc_fd_r8(fd);
  597.         room->box[i].flags = scc_fd_r8(fd);
  598.         room->box[i].scale = scc_fd_r16le(fd);
  599.       }
  600.       // Compute the matrix
  601.       scc_box_get_matrix(room->box+1,&room->boxm);
  602.       break;
  603.  
  604.     default:
  605.       scc_log(LOG_WARN,"Unhandled room block: %c%c%c%c %d\n",
  606.               UNMKID(type),block_size);
  607.     }
  608.     scc_fd_seek(fd,next_block,SEEK_SET);
  609.   }
  610.   
  611.   if(num_lscr < room->num_script)
  612.     scc_log(LOG_WARN,"Room %d is missing some local scripts?\n",num);
  613.  
  614.   // Resolve the object parent
  615.   for(i=0 ; i < num_obim ; i++) {
  616.     uint8_t num = (uint8_t)((uintptr_t)objlist[i]->parent);
  617.     if(!num) continue;
  618.     if(num > num_obim) {
  619.       scc_log(LOG_WARN,"Object %d has an invalid parent.\n",obj->id);
  620.       continue;
  621.     }
  622.     objlist[i]->parent = objlist[num-1];
  623.   }
  624.   if(num_obcd > num_obim) num_obim = num_obcd;
  625.   room->num_object = num_obim;
  626.   room->object = malloc(num_obim*sizeof(scvm_object_t*));
  627.   for(i=0 ; i < num_obim ; i++)
  628.     room->object[i] = objlist[i];
  629.   
  630.   return room;
  631.   
  632. bad_block:
  633.   scc_log(LOG_ERR,"Bad ROOM subblock %d: %c%c%c%c %d\n",num,
  634.           UNMKID(type),block_size);
  635.   free(room);
  636.   return NULL;
  637. }
  638.  
  639. void* scvm_load_costume(scvm_t* vm,scc_fd_t* fd, unsigned num) {
  640.   uint32_t size,fmt;
  641.   scc_cost_t* cost;
  642.   fmt = scc_fd_r32(fd);
  643.   size = scc_fd_r32be(fd);
  644.   
  645.   if(fmt != MKID('C','O','S','T') || size < 8+32 ) { // put the right size here
  646.     scc_log(LOG_ERR,"Bad COST block %d: %c%c%c%c %d\n",num,
  647.             UNMKID(fmt),size);
  648.     return NULL;
  649.   }
  650.   cost = scc_parse_cost(fd,size-8);
  651.   if(cost) cost->id = num;
  652.   return cost;
  653. }
  654.  
  655.  
  656. void* scvm_load_charset(scvm_t* vm,scc_fd_t* fd, unsigned num) {
  657.   uint32_t size,fmt;
  658.   scc_charmap_t* ch;
  659.   // read the scumm block header
  660.   fmt = scc_fd_r32(fd);
  661.   size = scc_fd_r32be(fd);
  662.   
  663.   if(fmt != MKID('C','H','A','R') || size < 8+25 ) {
  664.     scc_log(LOG_ERR,"Bad CHAR block %d: %c%c%c%c %d\n",num,
  665.             UNMKID(fmt),size);
  666.     return NULL;
  667.   }
  668.   ch = scc_parse_charmap(fd,size-8);
  669.   if(ch) ch->id = num;
  670.   return ch;
  671. }
  672.