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 / scc_char.c < prev    next >
Encoding:
C/C++ Source or Header  |  2008-02-19  |  8.1 KB  |  326 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 scc_char.c
  22.  * @ingroup scumm
  23.  * @brief SCUMM charset parser
  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 <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <fcntl.h>
  35.  
  36. #include "scc_util.h"
  37. #include "scc_fd.h"
  38. #include "scc_char.h"
  39.  
  40. scc_charmap_t* scc_parse_charmap(scc_fd_t* fd, unsigned size) {
  41.   uint32_t size2,unk,bpp,height,num_char;
  42.   uint8_t pal[15],byte,mask,bits,step;
  43.   off_t font_ptr;
  44.   uint32_t* char_off,x,i;
  45.   scc_charmap_t* chmap;
  46.   scc_char_t *ch;
  47.  
  48.   if(size < 25 ) {
  49.     scc_log(LOG_ERR,"CHAR block is too small.\n");
  50.     return NULL;
  51.   }
  52.  
  53.   // read the charset header
  54.   size2 = scc_fd_r32le(fd);
  55.   if(size2 != size-15)
  56.     scc_log(LOG_WARN,"Warning, size2 is invalid: %d != %d\n",size2,size-15);
  57.     
  58.   unk = scc_fd_r16le(fd);
  59.   if(scc_fd_read(fd,pal,15) != 15) {
  60.     scc_log(LOG_ERR,"Failed to read CHAR palette.\n");
  61.     return NULL;
  62.   }
  63.   
  64.   font_ptr = scc_fd_pos(fd);
  65.   bpp = scc_fd_r8(fd);
  66.   switch(bpp) {
  67.   case 1:
  68.     mask = 0x1;
  69.     break;
  70.   case 2:
  71.     mask = 0x3;
  72.     break;
  73.   case 4:
  74.     mask = 0xF;
  75.     break;
  76.   default:
  77.     scc_log(LOG_ERR,"Invalid CHAR bpp: %d\n",bpp);
  78.     return NULL;
  79.   }
  80.   height = scc_fd_r8(fd);
  81.   if(!height) {
  82.     scc_log(LOG_ERR,"Charset has 0 height??\n");
  83.     return NULL;
  84.   }
  85.   num_char = scc_fd_r16le(fd);
  86.   if(!num_char) {
  87.     scc_log(LOG_ERR,"Charset has no chars???\n");
  88.     return NULL;
  89.   }
  90.   if(size < 25 + 4*num_char) {
  91.     scc_log(LOG_ERR,"Charset is too small.\n");
  92.     return NULL;
  93.   }
  94.   // read the offset table
  95.   char_off = malloc(num_char*4);
  96.   for(i = 0 ; i < num_char ; i++)
  97.     char_off[i] = scc_fd_r32le(fd);
  98.   
  99.   chmap = calloc(1,sizeof(scc_charmap_t));
  100.   chmap->bpp = bpp;
  101.   chmap->height = height;
  102.   
  103.   // read the chars
  104.   scc_log(LOG_V,"Reading %d chars\n",num_char);
  105.   for(i = 0 ; i < num_char ; i++) {
  106.     if(!char_off[i]) continue;
  107.     scc_fd_seek(fd,font_ptr + char_off[i],SEEK_SET);
  108.     ch = &chmap->chars[i];
  109.     ch->w = scc_fd_r8(fd);
  110.     ch->h = scc_fd_r8(fd);
  111.     ch->x = scc_fd_r8(fd);
  112.     ch->y = scc_fd_r8(fd);
  113.     if(ch->w + ch->x > chmap->width) chmap->width = ch->w + ch->x;
  114.     if(!ch->w || !ch->h) continue;
  115.     ch->data = malloc(ch->w*ch->h);
  116.     bits = 0;
  117.     step = 8/bpp;
  118.     x = 0;
  119.     while(x < ch->w*ch->h) {
  120.       if(!bits) {
  121.         byte = scc_fd_r8(fd);
  122.         bits = 8;
  123.       }
  124.       ch->data[x] = (byte >> (8-bpp)) & mask;
  125.       byte <<= bpp;
  126.       bits -= bpp;
  127.       x++;
  128.     }
  129.     chmap->max_char = i;
  130.   }
  131.   return chmap; 
  132. }
  133.  
  134. static int decode_smush1(scc_fd_t* fd, unsigned size,
  135.                          unsigned w, unsigned h,
  136.                          uint8_t* dst, int dst_stride) {
  137.   unsigned x, y, line_size;
  138.  
  139.   for(y = 0 ; y < h && size > 1 ; y++) {
  140.     line_size = scc_fd_r16le(fd), size -= 2;
  141.     if(line_size > size) {
  142.         scc_log(LOG_WARN,"Too long line in smush1 image.\n");
  143.         line_size = size;
  144.     }
  145.     size -= line_size;
  146.     x = 0;
  147.     while(x < w && line_size > 1) {
  148.       uint8_t code = scc_fd_r8(fd);
  149.       uint8_t length = (code>>1)+1;
  150.       line_size--;
  151.       if(x + length > w) {
  152.         scc_log(LOG_WARN,"Too long block length in smush1 image.\n");
  153.         length = w-x;
  154.       }
  155.       if(code & 1) {
  156.         memset(dst+x,scc_fd_r8(fd),length);
  157.         line_size--, x += length;
  158.       } else {
  159.         if(length > line_size) {
  160.           scc_log(LOG_WARN,"Too long code length in smush1 image.\n");
  161.           length = line_size;
  162.         }
  163.         line_size -= length;
  164.         while(length > 0)
  165.           dst[x] = scc_fd_r8(fd), x++, length--;
  166.       }
  167.     }
  168.     if(x < w) memset(dst+x,0,w-x);
  169.     dst += dst_stride;
  170.   }
  171.  
  172.   while(y < h)
  173.     memset(dst,0,w), y++, dst += dst_stride;
  174.  
  175.   if(size > 0)
  176.     scc_fd_seek(fd,SEEK_CUR,size);
  177.  
  178.   return 1;
  179. }
  180.  
  181. static int decode_nut21(scc_fd_t* fd, unsigned size,
  182.                           unsigned w, unsigned h,
  183.                           uint8_t* dst, int dst_stride) {
  184.   unsigned x, y, line_size;
  185.  
  186.   for(y = 0 ; y < h && size > 1 ; y++) {
  187.     line_size = scc_fd_r16le(fd), size -= 2;
  188.     if(line_size > size) {
  189.         scc_log(LOG_WARN,"Too long line in smush21 image.\n");
  190.         line_size = size;
  191.     }
  192.     size -= line_size;
  193.     x = 0;
  194.     while(x < w && line_size >= 2) {
  195.       // Skip
  196.       unsigned len = scc_fd_r16le(fd);
  197.       line_size -= 2;
  198.       if(x + len > w) {
  199.         //scc_log(LOG_WARN,"Too long skip length in smush21 image.\n");
  200.         len = w-x;
  201.       }
  202.       if(len) {
  203.         memset(dst+x,0,len);
  204.         x += len;
  205.         if(x >= w) break;
  206.       }
  207.       // Draw
  208.       line_size -= 2;
  209.       if((len = scc_fd_r16le(fd)+1) > line_size) {
  210.         scc_log(LOG_WARN,"Too long draw code in smush21 image.\n");
  211.         len = line_size;
  212.       }
  213.       if(x + len > w) {
  214.         scc_log(LOG_WARN,"Too long draw length in smush21 image.\n");
  215.         len = w-x;
  216.       }
  217.       line_size -= len;
  218.       while(len > 0)
  219.         dst[x] = scc_fd_r8(fd), x++, len--;
  220.     }
  221.     if(line_size > 0)
  222.       scc_fd_seek(fd,line_size,SEEK_CUR);
  223.     if(x < w) memset(dst+x,0,w-x);
  224.     dst += dst_stride;
  225.   }
  226.  
  227.   while(y < h)
  228.     memset(dst,0,w), y++, dst += dst_stride;
  229.  
  230.   if(size > 0)
  231.     scc_fd_seek(fd,size,SEEK_CUR);
  232.  
  233.   return 1;
  234.  
  235. }
  236.  
  237. scc_charmap_t* scc_parse_nutmap(scc_fd_t* fd, unsigned block_size) {
  238.   uint32_t block, size;
  239.   uint8_t pal[3*256];
  240.   scc_charmap_t* chmap;
  241.   scc_char_t *ch;
  242.   unsigned num_char,i,codec;
  243.  
  244.   if(block_size < 8+3*2+3*256) {
  245.     scc_log(LOG_ERR,"Invalid ANIM block.\n");
  246.     return NULL;
  247.   }
  248.  
  249.   block = scc_fd_r32(fd);
  250.   size = scc_fd_r32be(fd);
  251.  
  252.   if(block != MKID('A','H','D','R') || size != 3*2 + 3*256) {
  253.     scc_log(LOG_ERR,"Invalid AHDR block.\n");
  254.     return NULL;
  255.   }
  256.  
  257.   scc_fd_r16(fd); // unk
  258.   num_char = scc_fd_r16le(fd);
  259.   scc_fd_r16(fd); // unk
  260.  
  261.   if(scc_fd_read(fd,pal,sizeof(pal)) != sizeof(pal)) {
  262.     scc_log(LOG_ERR,"Failed to read palette.\n");
  263.     return NULL;
  264.   }
  265.  
  266.   block_size -= 8 + 3*2 + 3*256;
  267.  
  268.   chmap = calloc(1,sizeof(scc_charmap_t));
  269.   chmap->bpp = 8;
  270.   chmap->rgb_pal = malloc(sizeof(pal));
  271.   memcpy(chmap->rgb_pal,pal,sizeof(pal));
  272.  
  273.   for(i = 0 ; i < num_char ; i++) {
  274.     block = scc_fd_r32(fd);
  275.     size = scc_fd_r32be(fd);
  276.     block_size -= 8;
  277.     if(block != MKID('F','R','M','E') ||
  278.        size > block_size || size < 4*2+7*2) {
  279.       scc_log(LOG_ERR,"Invalid FRME block (%d).\n",i);
  280.       return NULL;
  281.     }
  282.     block = scc_fd_r32(fd);
  283.     size = scc_fd_r32be(fd);
  284.     if(block != MKID('F','O','B','J') || size < 7*2) {
  285.       scc_log(LOG_ERR,"Invalid FOBJ block.\n");
  286.       return NULL;
  287.     }
  288.     // Read the header
  289.     ch = &chmap->chars[i];
  290.     codec  = scc_fd_r16le(fd);
  291.     ch->x  = scc_fd_r16le(fd);
  292.     ch->y  = scc_fd_r16le(fd);
  293.     ch->w  = scc_fd_r16le(fd);
  294.     ch->h  = scc_fd_r16le(fd);
  295.     /*unk*/  scc_fd_r32(fd);
  296.  
  297.     if(ch->w + ch->x > chmap->width) chmap->width = ch->w + ch->x;
  298.     if(ch->h + ch->y > chmap->height) chmap->height = ch->h + ch->y;
  299.     if(!ch->w || !ch->h) continue;
  300.  
  301.     // Decode the pic
  302.     ch->data = malloc(ch->w*ch->h);
  303.     switch(codec) {
  304.     case 1:
  305.       if(!decode_smush1(fd,size-7*2,ch->w,ch->h,ch->data,ch->w))
  306.         return NULL;
  307.       break;
  308.     case 21:
  309.     case 44:
  310.       if(!decode_nut21(fd,size-7*2,ch->w,ch->h,ch->data,ch->w))
  311.         return NULL;
  312.       break;
  313.     default:
  314.       scc_log(LOG_ERR,"Unknown NUT codec (%d) for char %d.\n",codec,i);
  315.       scc_fd_seek(fd,size-7*2,SEEK_CUR);
  316.       ch->w = ch->h = ch->x = ch->y = 0;
  317.       free(ch->data);
  318.       ch->data = NULL;
  319.       continue;
  320.     }
  321.     chmap->max_char = i;
  322.   }
  323.  
  324.   return chmap;
  325. }
  326.