resbin.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,388 行 · 第 1/4 页

C
2,388
字号
/* resbin.c -- manipulate the Windows binary resource format.   Copyright 1997, 1998, 1999 Free Software Foundation, Inc.   Written by Ian Lance Taylor, Cygnus Support.   This file is part of GNU Binutils.   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.   This program 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 General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA   02111-1307, USA.  *//* This file contains functions to convert between the binary resource   format and the internal structures that we want to use.  The same   binary resource format is used in both res and COFF files.  */#include "bfd.h"#include "bucomm.h"#include "libiberty.h"#include "windres.h"/* Macros to swap in values.  */#define get_16(be, s) ((be) ? bfd_getb16 (s) : bfd_getl16 (s))#define get_32(be, s) ((be) ? bfd_getb32 (s) : bfd_getl32 (s))/* Local functions.  */static void toosmall PARAMS ((const char *));static unichar *get_unicode  PARAMS ((const unsigned char *, unsigned long, int, int *));static int get_resid  PARAMS ((struct res_id *, const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_generic  PARAMS ((enum res_type, const unsigned char *, unsigned long));static struct res_resource *bin_to_res_cursor  PARAMS ((const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_menu  PARAMS ((const unsigned char *, unsigned long, int));static struct menuitem *bin_to_res_menuitems  PARAMS ((const unsigned char *, unsigned long, int, int *));static struct menuitem *bin_to_res_menuexitems  PARAMS ((const unsigned char *, unsigned long, int, int *));static struct res_resource *bin_to_res_dialog  PARAMS ((const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_string  PARAMS ((const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_fontdir  PARAMS ((const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_accelerators  PARAMS ((const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_rcdata  PARAMS ((const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_group_cursor  PARAMS ((const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_group_icon  PARAMS ((const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_version  PARAMS ((const unsigned char *, unsigned long, int));static struct res_resource *bin_to_res_userdata  PARAMS ((const unsigned char *, unsigned long, int));/* Given a resource type ID, a pointer to data, a length, return a   res_resource structure which represents that resource.  The caller   is responsible for initializing the res_info and coff_info fields   of the returned structure.  */struct res_resource *bin_to_res (type, data, length, big_endian)     struct res_id type;     const unsigned char *data;     unsigned long length;     int big_endian;{  if (type.named)    return bin_to_res_userdata (data, length, big_endian);  else    {      switch (type.u.id)	{	default:	  return bin_to_res_userdata (data, length, big_endian);	case RT_CURSOR:	  return bin_to_res_cursor (data, length, big_endian);	case RT_BITMAP:	  return bin_to_res_generic (RES_TYPE_BITMAP, data, length);	case RT_ICON:	  return bin_to_res_generic (RES_TYPE_ICON, data, length);	case RT_MENU:	  return bin_to_res_menu (data, length, big_endian);	case RT_DIALOG:	  return bin_to_res_dialog (data, length, big_endian);	case RT_STRING:	  return bin_to_res_string (data, length, big_endian);	case RT_FONTDIR:	  return bin_to_res_fontdir (data, length, big_endian);	case RT_FONT:	  return bin_to_res_generic (RES_TYPE_FONT, data, length);	case RT_ACCELERATOR:	  return bin_to_res_accelerators (data, length, big_endian);	case RT_RCDATA:	  return bin_to_res_rcdata (data, length, big_endian);	case RT_MESSAGETABLE:	  return bin_to_res_generic (RES_TYPE_MESSAGETABLE, data, length);	case RT_GROUP_CURSOR:	  return bin_to_res_group_cursor (data, length, big_endian);	case RT_GROUP_ICON:	  return bin_to_res_group_icon (data, length, big_endian);	case RT_VERSION:	  return bin_to_res_version (data, length, big_endian);	}    }}/* Give an error if the binary data is too small.  */static voidtoosmall (msg)     const char *msg;{  fatal (_("%s: not enough binary data"), msg);}/* Swap in a NULL terminated unicode string.  */static unichar *get_unicode (data, length, big_endian, retlen)     const unsigned char *data;     unsigned long length;     int big_endian;     int *retlen;{  int c, i;  unichar *ret;  c = 0;  while (1)    {      if (length < (unsigned long) c * 2 + 2)	toosmall (_("null terminated unicode string"));      if (get_16 (big_endian, data + c * 2) == 0)	break;      ++c;    }  ret = (unichar *) res_alloc ((c + 1) * sizeof (unichar));  for (i = 0; i < c; i++)    ret[i] = get_16 (big_endian, data + i * 2);  ret[i] = 0;  if (retlen != NULL)    *retlen = c;  return ret;}/* Get a resource identifier.  This returns the number of bytes used.  */static intget_resid (id, data, length, big_endian)     struct res_id *id;     const unsigned char *data;     unsigned long length;     int big_endian;{  int first;  if (length < 2)    toosmall (_("resource ID"));  first = get_16 (big_endian, data);  if (first == 0xffff)    {      if (length < 4)	toosmall (_("resource ID"));      id->named = 0;      id->u.id = get_16 (big_endian, data + 2);      return 4;    }  else    {      id->named = 1;      id->u.n.name = get_unicode (data, length, big_endian, &id->u.n.length);      return id->u.n.length * 2 + 2;    }}/* Convert a resource which just stores uninterpreted data from   binary.  */struct res_resource *bin_to_res_generic (type, data, length)     enum res_type type;     const unsigned char *data;     unsigned long length;{  struct res_resource *r;  r = (struct res_resource *) res_alloc (sizeof *r);  r->type = type;  r->u.data.data = data;  r->u.data.length = length;  return r;}/* Convert a cursor resource from binary.  */struct res_resource *bin_to_res_cursor (data, length, big_endian)     const unsigned char *data;     unsigned long length;     int big_endian;{  struct cursor *c;  struct res_resource *r;  if (length < 4)    toosmall (_("cursor"));  c = (struct cursor *) res_alloc (sizeof *c);  c->xhotspot = get_16 (big_endian, data);  c->yhotspot = get_16 (big_endian, data + 2);  c->length = length - 4;  c->data = data + 4;  r = (struct res_resource *) res_alloc (sizeof *r);  r->type = RES_TYPE_CURSOR;  r->u.cursor = c;  return r;}/* Convert a menu resource from binary.  */struct res_resource *bin_to_res_menu (data, length, big_endian)     const unsigned char *data;     unsigned long length;     int big_endian;{  struct res_resource *r;  struct menu *m;  int version, read;  r = (struct res_resource *) res_alloc (sizeof *r);  r->type = RES_TYPE_MENU;  m = (struct menu *) res_alloc (sizeof *m);  r->u.menu = m;  if (length < 2)    toosmall (_("menu header"));  version = get_16 (big_endian, data);  if (version == 0)    {      if (length < 4)	toosmall (_("menu header"));      m->help = 0;      m->items = bin_to_res_menuitems (data + 4, length - 4, big_endian,				       &read);    }  else if (version == 1)    {      unsigned int offset;      if (length < 8)	toosmall (_("menuex header"));      m->help = get_32 (big_endian, data + 4);      offset = get_16 (big_endian, data + 2);      if (offset + 4 >= length)	toosmall (_("menuex offset"));      m->items = bin_to_res_menuexitems (data + 4 + offset,					 length - (4 + offset),					 big_endian,					 &read);    }  else    fatal (_("unsupported menu version %d"), version);  return r;}/* Convert menu items from binary.  */static struct menuitem *bin_to_res_menuitems (data, length, big_endian, read)     const unsigned char *data;     unsigned long length;     int big_endian;     int *read;{  struct menuitem *first, **pp;  first = NULL;  pp = &first;  *read = 0;  while (length > 0)    {      int flags, slen, itemlen;      unsigned int stroff;      struct menuitem *mi;      if (length < 4)	toosmall (_("menuitem header"));      mi = (struct menuitem *) res_alloc (sizeof *mi);      mi->state = 0;      mi->help = 0;      flags = get_16 (big_endian, data);      mi->type = flags &~ (MENUITEM_POPUP | MENUITEM_ENDMENU);      if ((flags & MENUITEM_POPUP) == 0)	stroff = 4;      else	stroff = 2;      if (length < stroff + 2)	toosmall (_("menuitem header"));      if (get_16 (big_endian, data + stroff) == 0)	{	  slen = 0;	  mi->text = NULL;	}      else	mi->text = get_unicode (data + stroff, length - stroff, big_endian,				&slen);      itemlen = stroff + slen * 2 + 2;      if ((flags & MENUITEM_POPUP) == 0)	{	  mi->popup = NULL;	  mi->id = get_16 (big_endian, data + 2);	}      else	{	  int subread;	  mi->id = 0;	  mi->popup = bin_to_res_menuitems (data + itemlen, length - itemlen,					    big_endian, &subread);	  itemlen += subread;	}      mi->next = NULL;      *pp = mi;      pp = &mi->next;      data += itemlen;      length -= itemlen;      *read += itemlen;      if ((flags & MENUITEM_ENDMENU) != 0)	return first;    }  return first;}/* Convert menuex items from binary.  */static struct menuitem *bin_to_res_menuexitems (data, length, big_endian, read)     const unsigned char *data;     unsigned long length;     int big_endian;     int *read;{  struct menuitem *first, **pp;  first = NULL;  pp = &first;  *read = 0;  while (length > 0)    {      int flags, slen;      unsigned int itemlen;      struct menuitem *mi;      if (length < 14)	toosmall (_("menuitem header"));      mi = (struct menuitem *) res_alloc (sizeof *mi);      mi->type = get_32 (big_endian, data);      mi->state = get_32 (big_endian, data + 4);      mi->id = get_16 (big_endian, data + 8);      flags = get_16 (big_endian, data + 10);      if (get_16 (big_endian, data + 12) == 0)	{	  slen = 0;	  mi->text = NULL;	}      else	mi->text = get_unicode (data + 12, length - 12, big_endian, &slen);      itemlen = 12 + slen * 2 + 2;      itemlen = (itemlen + 3) &~ 3;      if ((flags & 1) == 0)	{	  mi->popup = NULL;	  mi->help = 0;	}      else	{	  int subread;	  if (length < itemlen + 4)	    toosmall (_("menuitem"));	  mi->help = get_32 (big_endian, data + itemlen);	  itemlen += 4;	  mi->popup = bin_to_res_menuexitems (data + itemlen,					      length - itemlen,					      big_endian, &subread);	  itemlen += subread;	}      mi->next = NULL;      *pp = mi;      pp = &mi->next;      data += itemlen;      length -= itemlen;      *read += itemlen;      if ((flags & 0x80) != 0)	return first;    }  return first;}/* Convert a dialog resource from binary.  */static struct res_resource *bin_to_res_dialog (data, length, big_endian)     const unsigned char *data;     unsigned long length;     int big_endian;{  int version;  struct dialog *d;  int c, sublen, i;  unsigned int off;  struct dialog_control **pp;  struct res_resource *r;  if (length < 18)    toosmall (_("dialog header"));  d = (struct dialog *) res_alloc (sizeof *d);  version = get_16 (big_endian, data);  if (version != 1)    {      d->ex = NULL;      d->style = get_32 (big_endian, data);      d->exstyle = get_32 (big_endian, data + 4);      off = 8;    }  else    {      int signature;      signature = get_16 (big_endian, data + 2);      if (signature != 0xffff)	fatal (_("unexpected dialog signature %d"), signature);      d->ex = (struct dialog_ex *) res_alloc (sizeof (struct dialog_ex));      d->ex->help = get_32 (big_endian, data + 4);      d->exstyle = get_32 (big_endian, data + 8);      d->style = get_32 (big_endian, data + 12);      off = 16;    }  if (length < off + 10)    toosmall (_("dialog header"));  c = get_16 (big_endian, data + off);  d->x = get_16  (big_endian, data + off + 2);  d->y = get_16 (big_endian, data + off + 4);  d->width = get_16 (big_endian, data + off + 6);  d->height = get_16 (big_endian, data + off + 8);  off += 10;  sublen = get_resid (&d->menu, data + off, length - off, big_endian);  off += sublen;  sublen = get_resid (&d->class, data + off, length - off, big_endian);  off += sublen;  d->caption = get_unicode (data + off, length - off, big_endian, &sublen);  off += sublen * 2 + 2;  if ((d->style & DS_SETFONT) == 0)    {      d->pointsize = 0;      d->font = NULL;      if (d->ex != NULL)	{	  d->ex->weight = 0;	  d->ex->italic = 0;	}    }  else    {      if (length < off + 2)	toosmall (_("dialog font point size"));      d->pointsize = get_16 (big_endian, data + off);      off += 2;      if (d->ex != NULL)	{	  if (length < off + 4)	    toosmall (_("dialogex font information"));	  d->ex->weight = get_16 (big_endian, data + off);	  d->ex->italic = get_16 (big_endian, data + off + 2);	  off += 4;	}      d->font = get_unicode (data + off, length - off, big_endian, &sublen);      off += sublen * 2 + 2;    }  d->controls = NULL;  pp = &d->controls;  for (i = 0; i < c; i++)    {      struct dialog_control *dc;      int datalen;      off = (off + 3) &~ 3;      dc = (struct dialog_control *) res_alloc (sizeof *dc);      if (d->ex == NULL)	{	  if (length < off + 8)	    toosmall (_("dialog control"));	  dc->style = get_32 (big_endian, data + off);	  dc->exstyle = get_32 (big_endian, data + off + 4);	  dc->help = 0;	  off += 8;	}      else	{	  if (length < off + 12)	    toosmall (_("dialogex control"));	  dc->help = get_32 (big_endian, data + off);	  dc->exstyle = get_32 (big_endian, data + off + 4);	  dc->style = get_32 (big_endian, data + off + 8);	  off += 12;	}      if (length < off + 10)	toosmall (_("dialog control"));      dc->x = get_16 (big_endian, data + off);      dc->y = get_16 (big_endian, data + off + 2);      dc->width = get_16 (big_endian, data + off + 4);      dc->height = get_16 (big_endian, data + off + 6);      if (d->ex != NULL)        dc->id = get_32 (big_endian, data + off + 8);      else        dc->id = get_16 (big_endian, data + off + 8);      off += 10 + (d->ex != NULL ? 2 : 0);      sublen = get_resid (&dc->class, data + off, length - off, big_endian);      off += sublen;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?