res16.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * Builtin dlls resource support
  3. *
  4. * Copyright 2000 Alexandre Julliard
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include "config.h"
  21. #include <assert.h>
  22. #include <ctype.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <stdarg.h>
  26. #include <stdio.h>
  27. #include "build.h"
  28. /* Unicode string or integer id */
  29. struct string_id
  30. {
  31. char *str; /* ptr to string */
  32. unsigned short id; /* integer id if str is NULL */
  33. };
  34. /* descriptor for a resource */
  35. struct resource
  36. {
  37. struct string_id type;
  38. struct string_id name;
  39. const void *data;
  40. unsigned int name_offset;
  41. unsigned int data_size;
  42. unsigned int memopt;
  43. };
  44. /* type level of the resource tree */
  45. struct res_type
  46. {
  47. const struct string_id *type; /* type name */
  48. struct resource *res; /* first resource of this type */
  49. unsigned int name_offset; /* name offset if string */
  50. unsigned int nb_names; /* total number of names */
  51. };
  52. /* top level of the resource tree */
  53. struct res_tree
  54. {
  55. struct res_type *types; /* types array */
  56. unsigned int nb_types; /* total number of types */
  57. };
  58. static inline struct resource *add_resource( DLLSPEC *spec )
  59. {
  60. spec->resources = xrealloc( spec->resources, (spec->nb_resources + 1) * sizeof(*spec->resources) );
  61. return &spec->resources[spec->nb_resources++];
  62. }
  63. static struct res_type *add_type( struct res_tree *tree, struct resource *res )
  64. {
  65. struct res_type *type;
  66. tree->types = xrealloc( tree->types, (tree->nb_types + 1) * sizeof(*tree->types) );
  67. type = &tree->types[tree->nb_types++];
  68. type->type = &res->type;
  69. type->res = res;
  70. type->nb_names = 0;
  71. return type;
  72. }
  73. /* get a string from the current resource file */
  74. static void get_string( struct string_id *str )
  75. {
  76. unsigned char c = get_byte();
  77. if (c == 0xff)
  78. {
  79. str->str = NULL;
  80. str->id = get_word();
  81. }
  82. else
  83. {
  84. str->str = (char *)input_buffer + input_buffer_pos - 1;
  85. str->id = 0;
  86. while (get_byte()) /* nothing */;
  87. }
  88. }
  89. /* load the next resource from the current file */
  90. static void load_next_resource( DLLSPEC *spec )
  91. {
  92. struct resource *res = add_resource( spec );
  93. get_string( &res->type );
  94. get_string( &res->name );
  95. res->memopt = get_word();
  96. res->data_size = get_dword();
  97. res->data = input_buffer + input_buffer_pos;
  98. input_buffer_pos += res->data_size;
  99. if (input_buffer_pos > input_buffer_size)
  100. fatal_error( "%s is a truncated/corrupted file\n", input_buffer_filename );
  101. }
  102. /* load a Win16 .res file */
  103. void load_res16_file( const char *name, DLLSPEC *spec )
  104. {
  105. init_input_buffer( name );
  106. while (input_buffer_pos < input_buffer_size) load_next_resource( spec );
  107. }
  108. /* compare two strings/ids */
  109. static int cmp_string( const struct string_id *str1, const struct string_id *str2 )
  110. {
  111. if (!str1->str)
  112. {
  113. if (!str2->str) return str1->id - str2->id;
  114. return 1; /* an id compares larger than a string */
  115. }
  116. if (!str2->str) return -1;
  117. return strcasecmp( str1->str, str2->str );
  118. }
  119. /* compare two resources for sorting the resource directory */
  120. /* resources are stored first by type, then by name */
  121. static int cmp_res( const void *ptr1, const void *ptr2 )
  122. {
  123. const struct resource *res1 = ptr1;
  124. const struct resource *res2 = ptr2;
  125. int ret;
  126. if ((ret = cmp_string( &res1->type, &res2->type ))) return ret;
  127. return cmp_string( &res1->name, &res2->name );
  128. }
  129. /* build the 2-level (type,name) resource tree */
  130. static struct res_tree *build_resource_tree( DLLSPEC *spec )
  131. {
  132. unsigned int i, j, offset;
  133. struct res_tree *tree;
  134. struct res_type *type = NULL;
  135. struct resource *res;
  136. qsort( spec->resources, spec->nb_resources, sizeof(*spec->resources), cmp_res );
  137. offset = 2; /* alignment */
  138. tree = xmalloc( sizeof(*tree) );
  139. tree->types = NULL;
  140. tree->nb_types = 0;
  141. for (i = 0; i < spec->nb_resources; i++)
  142. {
  143. if (!i || cmp_string( &spec->resources[i].type, &spec->resources[i-1].type )) /* new type */
  144. {
  145. type = add_type( tree, &spec->resources[i] );
  146. offset += 8;
  147. }
  148. type->nb_names++;
  149. offset += 12;
  150. }
  151. offset += 2; /* terminator */
  152. for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
  153. {
  154. if (type->type->str)
  155. {
  156. type->name_offset = offset;
  157. offset += strlen(type->type->str) + 1;
  158. }
  159. else type->name_offset = type->type->id | 0x8000;
  160. for (j = 0, res = type->res; j < type->nb_names; j++, res++)
  161. {
  162. if (res->name.str)
  163. {
  164. res->name_offset = offset;
  165. offset += strlen(res->name.str) + 1;
  166. }
  167. else res->name_offset = res->name.id | 0x8000;
  168. }
  169. }
  170. return tree;
  171. }
  172. /* free the resource tree */
  173. static void free_resource_tree( struct res_tree *tree )
  174. {
  175. free( tree->types );
  176. free( tree );
  177. }
  178. /* output a string preceded by its length */
  179. static void output_string( const char *str )
  180. {
  181. unsigned int i, len = strlen(str);
  182. output( "\t.byte 0x%02x", len );
  183. for (i = 0; i < len; i++) output( ",0x%02x", (unsigned char)str[i] );
  184. output( " /* %s */\n", str );
  185. }
  186. /* output a string preceded by its length in binary format*/
  187. static void output_bin_string( const char *str )
  188. {
  189. put_byte( strlen(str) );
  190. while (*str) put_byte( *str++ );
  191. }
  192. /* output the resource data */
  193. void output_res16_data( DLLSPEC *spec )
  194. {
  195. const struct resource *res;
  196. unsigned int i;
  197. for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
  198. {
  199. output( ".L__wine_spec_resource_%u:\n", i );
  200. dump_bytes( res->data, res->data_size );
  201. }
  202. }
  203. /* output the resource definitions */
  204. void output_res16_directory( DLLSPEC *spec )
  205. {
  206. unsigned int i, j;
  207. struct res_tree *tree;
  208. const struct res_type *type;
  209. const struct resource *res;
  210. tree = build_resource_tree( spec );
  211. output( "\n.L__wine_spec_ne_rsrctab:\n" );
  212. output( "\t.short 0\n" ); /* alignment */
  213. /* type and name structures */
  214. for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
  215. {
  216. output( "\t.short 0x%04x,%u,0,0\n", type->name_offset, type->nb_names );
  217. for (j = 0, res = type->res; j < type->nb_names; j++, res++)
  218. {
  219. output( "\t.short .L__wine_spec_resource_%lu-.L__wine_spec_dos_header,%u\n",
  220. (unsigned long)(res - spec->resources), res->data_size );
  221. output( "\t.short 0x%04x,0x%04x,0,0\n", res->memopt, res->name_offset );
  222. }
  223. }
  224. output( "\t.short 0\n" ); /* terminator */
  225. /* name strings */
  226. for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
  227. {
  228. if (type->type->str) output_string( type->type->str );
  229. for (j = 0, res = type->res; j < type->nb_names; j++, res++)
  230. if (res->name.str) output_string( res->name.str );
  231. }
  232. output( "\t.byte 0\n" ); /* names terminator */
  233. free_resource_tree( tree );
  234. }
  235. /* output the resource data in binary format */
  236. void output_bin_res16_data( DLLSPEC *spec )
  237. {
  238. const struct resource *res;
  239. unsigned int i;
  240. for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
  241. put_data( res->data, res->data_size );
  242. }
  243. /* output the resource definitions in binary format */
  244. void output_bin_res16_directory( DLLSPEC *spec, unsigned int data_offset )
  245. {
  246. unsigned int i, j;
  247. struct res_tree *tree;
  248. const struct res_type *type;
  249. const struct resource *res;
  250. tree = build_resource_tree( spec );
  251. put_word( 0 ); /* alignment */
  252. /* type and name structures */
  253. for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
  254. {
  255. put_word( type->name_offset );
  256. put_word( type->nb_names );
  257. put_word( 0 );
  258. put_word( 0 );
  259. for (j = 0, res = type->res; j < type->nb_names; j++, res++)
  260. {
  261. put_word( data_offset );
  262. put_word( res->data_size );
  263. put_word( res->memopt );
  264. put_word( res->name_offset );
  265. put_word( 0 );
  266. put_word( 0 );
  267. data_offset += res->data_size;
  268. }
  269. }
  270. put_word( 0 ); /* terminator */
  271. /* name strings */
  272. for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
  273. {
  274. if (type->type->str) output_bin_string( type->type->str );
  275. for (j = 0, res = type->res; j < type->nb_names; j++, res++)
  276. if (res->name.str) output_bin_string( res->name.str );
  277. }
  278. put_byte( 0 ); /* names terminator */
  279. free_resource_tree( tree );
  280. }