Logo Search packages:      
Sourcecode: wine-unstable version File versions  Download package

readres.c

/*
 * Read a .res file and create a resource-tree
 *
 * Copyright 1998 Bertho A. Stultiens
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"
#include "wine/port.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "wrc.h"
#include "readres.h"
#include "newstruc.h"
#include "utils.h"
#include "genres.h"

static const struct resheader32 {
      DWORD ressize;    /* 0 */
      DWORD hdrsize;    /* 0x20 */
      WORD  restype1;   /* 0xffff */
      WORD  restype2;   /* 0 */
      WORD  resname1;   /* 0xffff */
      WORD  resname2;   /* 0 */
      DWORD dversion;   /* 0 */
      WORD  memopt;           /* 0 */
      WORD  language;   /* 0 */
      DWORD version;    /* 0 */
      DWORD characts;   /* 0 */
} emptyheader           = {0, 0x20, 0xffff, 0, 0xffff, 0, 0, 0, 0, 0, 0},
  emptyheaderSWAPPED    = {0, BYTESWAP_DWORD(0x20), 0xffff, 0, 0xffff, 0, 0, 0, 0, 0, 0};

/*
 *****************************************************************************
 * Function :
 * Syntax   :
 * Input    :
 * Output   :
 * Description    :
 * Remarks  :
 *****************************************************************************
*/
/*
 *****************************************************************************
 * Function :
 * Syntax   :
 * Input    :
 * Output   :
 * Description    :
 * Remarks  :
 *****************************************************************************
*/
/*
 *****************************************************************************
 * Function :
 * Syntax   :
 * Input    :
 * Output   :
 * Description    :
 * Remarks  :
 *****************************************************************************
*/
static int read_data(FILE *fp, size_t size, void *buf)
{
      unsigned int r;
      int pos = ftell(fp);
      r = fread(buf, 1, size, fp);
      if(r == size)
            return 0;
      if(r == 0 && ftell(fp) - pos > 0)
            return 1;
      else
            return -1;
}

/*
 *****************************************************************************
 * Function :
 * Syntax   :
 * Input    :
 * Output   :
 * Description    :
 * Remarks  :
 *****************************************************************************
*/
static enum res_e res_type_from_id(const name_id_t *nid)
{
      if(nid->type == name_str)
            return res_usr;

      if(nid->type != name_ord)
            internal_error(__FILE__, __LINE__, "Invalid name_id descriptor %d\n", nid->type);

      switch(nid->name.i_name)
      {
      case WRC_RT_CURSOR:           return res_cur;
      case WRC_RT_BITMAP:           return res_bmp;
      case WRC_RT_ICON:       return res_ico;
      case WRC_RT_MENU:       return res_men;
      case WRC_RT_DIALOG:           return res_dlg;
      case WRC_RT_STRING:           return res_stt;
      case WRC_RT_FONTDIR:          return res_fntdir;
      case WRC_RT_FONT:       return res_fnt;
      case WRC_RT_ACCELERATOR:      return res_acc;
      case WRC_RT_RCDATA:           return res_rdt;
      case WRC_RT_MESSAGETABLE:     return res_msg;
      case WRC_RT_GROUP_CURSOR:     return res_curg;
      case WRC_RT_GROUP_ICON:       return res_icog;
      case WRC_RT_VERSION:          return res_ver;
      case WRC_RT_TOOLBAR:          return res_toolbar;

      default:
      case WRC_RT_DLGINCLUDE:
      case WRC_RT_PLUGPLAY:
      case WRC_RT_VXD:
      case WRC_RT_ANICURSOR:
      case WRC_RT_ANIICON:
            warning("Cannot be sure of resource type, using usertype settings\n");
            return res_usr;
      }
}

/*
 *****************************************************************************
 * Function :
 * Syntax   :
 * Input    :
 * Output   :
 * Description    :
 * Remarks  :
 *****************************************************************************
*/
#define get_word(idx)   (*((WORD *)(&res->data[idx])))
#define get_dword(idx)  (*((DWORD *)(&res->data[idx])))

static resource_t *read_res32(FILE *fp)
{
      static const char wrong_format[] = "Wrong resfile format (32bit)";
      DWORD ressize;
      DWORD hdrsize;
      DWORD totsize;
      WORD memopt;
      WORD language;
      int err;
      res_t *res;
      resource_t *rsc;
      resource_t *tail = NULL;
      resource_t *list = NULL;
      name_id_t *type = NULL;
      name_id_t *name = NULL;
      int idx;
      enum res_e res_type;
      user_t *usrres;

      while(1)
      {
            /* Get headersize and resource size */
            err = read_data(fp, sizeof(ressize), &ressize);
            if(err < 0)
                  break;
            else if(err > 0)
                  error(wrong_format);
            err = read_data(fp, sizeof(hdrsize), &hdrsize);
            if(err)
                  error(wrong_format);

            /* Align sizes and compute total size */
            totsize = hdrsize;
            if(hdrsize & 3)
            {
                  warning("Hu? .res header needed alignment (anything can happen now)\n");
                  totsize += 4 - (hdrsize & 3);
            }
            totsize += ressize;
            if(ressize & 3)
                  totsize += 4 - (ressize & 3);

            /* Read in entire data-block */
            fseek(fp, -8, SEEK_CUR);
            res = new_res();
            if(res->allocsize < totsize)
                  grow_res(res, totsize - res->allocsize + 8);
            err = read_data(fp, totsize, res->data);
            if(err)
                  error(wrong_format);

            res->dataidx = hdrsize;
            res->size = hdrsize + ressize;

            /* Analyse the content of the header */
            idx = 8;
            /* Get restype */
            if(get_word(idx) == 0xffff)
            {
                  idx += sizeof(WORD);
                  type = new_name_id();
                  type->type = name_ord;
                  type->name.i_name = get_word(idx);
                  idx += sizeof(WORD);
            }
            else if(get_word(idx) == 0)
            {
                  error("ResType name has zero length (32 bit)\n");
            }
            else
            {
                  int tag = idx;
                  string_t *str;
                  while(1)
                  {
                        idx += sizeof(WORD);
                        if(!get_word(idx))
                              break;
                  }
                  idx += sizeof(WORD);
                  str = new_string();
                  str->type = str_unicode;
                  str->size = (idx - tag) / 2;
                  str->str.wstr = xmalloc(idx-tag+2);
                  memcpy(str->str.wstr, &res->data[tag], idx-tag);
                  str->str.wstr[str->size] = 0;
                  type = new_name_id();
                  type->type = name_str;
                  type->name.s_name = str;
            }
            /* Get resname */
            if(get_word(idx) == 0xffff)
            {
                  idx += sizeof(WORD);
                  name = new_name_id();
                  name->type = name_ord;
                  name->name.i_name = get_word(idx);
                  idx += sizeof(WORD);
            }
            else if(get_word(idx) == 0)
            {
                  error("ResName name has zero length (32 bit)\n");
            }
            else
            {
                  int tag = idx;
                  string_t *str;
                  while(1)
                  {
                        idx += sizeof(WORD);
                        if(!get_word(idx))
                              break;
                  }
                  idx += sizeof(WORD);
                  str = new_string();
                  str->type = str_unicode;
                  str->size = (idx - tag) / 2;
                  str->str.wstr = xmalloc(idx-tag+2);
                  memcpy(str->str.wstr, &res->data[tag], idx-tag);
                  str->str.wstr[str->size] = 0;
                  name = new_name_id();
                  name->type = name_str;
                  name->name.s_name = str;
            }

            /* align */
            if(idx & 0x3)
                  idx += 4 - (idx & 3);

            idx += sizeof(DWORD);   /* Skip DataVersion */
            memopt = get_word(idx);
            idx += sizeof(WORD);
            language = get_word(idx);

            /* Build a resource_t list */
            res_type = res_type_from_id(type);
            if(res_type == res_usr)
            {
                  /* User-type has custom ResType for .[s|h] generation */
                  usrres = new_user(type, NULL, new_int(memopt));
            }
            else
            {
                  free (type);
                  usrres = NULL;
            }
            rsc = new_resource(res_type,
                           usrres,
                           memopt,
                           new_language(PRIMARYLANGID(language),
                                    SUBLANGID(language)));
            rsc->binres = res;
            rsc->name = name;
            rsc->c_name = make_c_name(get_c_typename(res_type), name, rsc->lan);
            if(!list)
            {
                  list = rsc;
                  tail = rsc;
            }
            else
            {
                  rsc->prev = tail;
                  tail->next = rsc;
                  tail = rsc;
            }
      }
      return list;
}

/*
 *****************************************************************************
 * Function :
 * Syntax   :
 * Input    :
 * Output   :
 * Description    :
 * Remarks  :
 *****************************************************************************
*/
static resource_t *read_res16(FILE *fp)
{
      internal_error(__FILE__, __LINE__, "Can't yet read 16 bit .res files\n");
      return NULL;
}

/*
 *****************************************************************************
 * Function : read_resfile
 * Syntax   : resource_t *read_resfile(char *inname)
 * Input    :
 * Output   :
 * Description    :
 * Remarks  :
 *****************************************************************************
*/
resource_t *read_resfile(char *inname)
{
      FILE *fp;
      struct resheader32 rh;
      int is32bit = 1;
      resource_t *top;

      fp = fopen(inname, "rb");
      if(!fp)
            fatal_perror("Could not open %s", inname);

      /* Determine 16 or 32 bit .res file */
      if(fread(&rh, 1, sizeof(rh), fp) != sizeof(rh))
            is32bit = 0;
      else
      {
            if(!memcmp(&emptyheader, &rh, sizeof(rh)))
                  is32bit = 1;
            else if(!memcmp(&emptyheaderSWAPPED, &rh, sizeof(rh)))
                  error("Binary .res-file has its byteorder swapped\n");
            else
                  is32bit = 0;
      }

      if(is32bit && !win32)
            error("Cannot convert 32-bit .res-file into 16-bit resources (and will, hopefully never, implement it)\n");

      if(!is32bit && win32)
            error("Cannot (yet) convert 16-bit .res-file into 32-bit resources\n");

      if(!is32bit)
      {
            fseek(fp, 0, SEEK_SET);
            top = read_res16(fp);
      }
      else
      {
            top = read_res32(fp);
      }

      fclose(fp);

      return top;
}

Generated by  Doxygen 1.6.0   Back to index