[CMAKE]
[reactos.git] / dll / win32 / version / resource.c
1 /*
2 * Implementation of VERSION.DLL - Resource Access routines
3 *
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
6 * Copyright 1999 Ulrich Weigand
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "lzexpand.h"
39 #include "winuser.h"
40 #include "winver.h"
41 #undef VS_FILE_INFO
42 #define VS_FILE_INFO 16
43
44 #include "wine/unicode.h"
45
46 #include "wine/debug.h"
47
48 typedef struct
49 {
50 WORD offset;
51 WORD length;
52 WORD flags;
53 WORD id;
54 WORD handle;
55 WORD usage;
56 } NE_NAMEINFO;
57
58 typedef struct
59 {
60 WORD type_id;
61 WORD count;
62 DWORD resloader;
63 } NE_TYPEINFO;
64
65 WINE_DEFAULT_DEBUG_CHANNEL(ver);
66
67
68 /**********************************************************************
69 * find_entry_by_id
70 *
71 * Find an entry by id in a resource directory
72 * Copied from loader/pe_resource.c
73 */
74 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
75 WORD id, const void *root )
76 {
77 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
78 int min, max, pos;
79
80 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
81 min = dir->NumberOfNamedEntries;
82 max = min + dir->NumberOfIdEntries - 1;
83 while (min <= max)
84 {
85 pos = (min + max) / 2;
86 if (entry[pos].u1.Id == id)
87 return (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + entry[pos].u2.s3.OffsetToDirectory);
88 if (entry[pos].u1.Id > id) max = pos - 1;
89 else min = pos + 1;
90 }
91 return NULL;
92 }
93
94
95 /**********************************************************************
96 * find_entry_default
97 *
98 * Find a default entry in a resource directory
99 * Copied from loader/pe_resource.c
100 */
101 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
102 const void *root )
103 {
104 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
105
106 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
107 return (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + entry->u2.s3.OffsetToDirectory);
108 }
109
110
111 /***********************************************************************
112 * read_xx_header [internal]
113 */
114 static int read_xx_header( HFILE lzfd )
115 {
116 IMAGE_DOS_HEADER mzh;
117 char magic[3];
118
119 LZSeek( lzfd, 0, SEEK_SET );
120 if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
121 return 0;
122 if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
123 {
124 if (!memcmp( &mzh, "\177ELF", 4 )) return 1; /* ELF */
125 if (*(UINT *)&mzh == 0xfeedface || *(UINT *)&mzh == 0xcefaedfe) return 1; /* Mach-O */
126 return 0;
127 }
128
129 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
130 if ( 2 != LZRead( lzfd, magic, 2 ) )
131 return 0;
132
133 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
134
135 if ( magic[0] == 'N' && magic[1] == 'E' )
136 return IMAGE_OS2_SIGNATURE;
137 if ( magic[0] == 'P' && magic[1] == 'E' )
138 return IMAGE_NT_SIGNATURE;
139
140 magic[2] = '\0';
141 WARN("Can't handle %s files.\n", magic );
142 return 0;
143 }
144
145 /***********************************************************************
146 * find_ne_resource [internal]
147 */
148 static BOOL find_ne_resource( HFILE lzfd, DWORD *resLen, DWORD *resOff )
149 {
150 const WORD typeid = VS_FILE_INFO | 0x8000;
151 const WORD resid = VS_VERSION_INFO | 0x8000;
152 IMAGE_OS2_HEADER nehd;
153 NE_TYPEINFO *typeInfo;
154 NE_NAMEINFO *nameInfo;
155 DWORD nehdoffset;
156 LPBYTE resTab;
157 DWORD resTabSize;
158 int count;
159
160 /* Read in NE header */
161 nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
162 if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;
163
164 resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
165 if ( !resTabSize )
166 {
167 TRACE("No resources in NE dll\n" );
168 return FALSE;
169 }
170
171 /* Read in resource table */
172 resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
173 if ( !resTab ) return FALSE;
174
175 LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
176 if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
177 {
178 HeapFree( GetProcessHeap(), 0, resTab );
179 return FALSE;
180 }
181
182 /* Find resource */
183 typeInfo = (NE_TYPEINFO *)(resTab + 2);
184 while (typeInfo->type_id)
185 {
186 if (typeInfo->type_id == typeid) goto found_type;
187 typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
188 typeInfo->count * sizeof(NE_NAMEINFO));
189 }
190 TRACE("No typeid entry found\n" );
191 HeapFree( GetProcessHeap(), 0, resTab );
192 return FALSE;
193
194 found_type:
195 nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
196
197 for (count = typeInfo->count; count > 0; count--, nameInfo++)
198 if (nameInfo->id == resid) goto found_name;
199
200 TRACE("No resid entry found\n" );
201 HeapFree( GetProcessHeap(), 0, resTab );
202 return FALSE;
203
204 found_name:
205 /* Return resource data */
206 if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
207 if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
208
209 HeapFree( GetProcessHeap(), 0, resTab );
210 return TRUE;
211 }
212
213 /***********************************************************************
214 * find_pe_resource [internal]
215 */
216 static BOOL find_pe_resource( HFILE lzfd, DWORD *resLen, DWORD *resOff )
217 {
218 union
219 {
220 IMAGE_NT_HEADERS32 nt32;
221 IMAGE_NT_HEADERS64 nt64;
222 } pehd;
223 DWORD pehdoffset;
224 PIMAGE_DATA_DIRECTORY resDataDir;
225 PIMAGE_SECTION_HEADER sections;
226 LPBYTE resSection;
227 DWORD resSectionSize;
228 const void *resDir;
229 const IMAGE_RESOURCE_DIRECTORY *resPtr;
230 const IMAGE_RESOURCE_DATA_ENTRY *resData;
231 int i, len, nSections;
232 BOOL ret = FALSE;
233
234 /* Read in PE header */
235 pehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
236 len = LZRead( lzfd, (LPSTR)&pehd, sizeof(pehd) );
237 if (len < sizeof(pehd.nt32.FileHeader)) return 0;
238 if (len < sizeof(pehd)) memset( (char *)&pehd + len, 0, sizeof(pehd) - len );
239
240 switch (pehd.nt32.OptionalHeader.Magic)
241 {
242 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
243 resDataDir = pehd.nt32.OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_RESOURCE;
244 break;
245 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
246 resDataDir = pehd.nt64.OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_RESOURCE;
247 break;
248 default:
249 return 0;
250 }
251
252 if ( !resDataDir->Size )
253 {
254 TRACE("No resources in PE dll\n" );
255 return FALSE;
256 }
257
258 /* Read in section table */
259 nSections = pehd.nt32.FileHeader.NumberOfSections;
260 sections = HeapAlloc( GetProcessHeap(), 0,
261 nSections * sizeof(IMAGE_SECTION_HEADER) );
262 if ( !sections ) return FALSE;
263
264 len = FIELD_OFFSET( IMAGE_NT_HEADERS32, OptionalHeader ) + pehd.nt32.FileHeader.SizeOfOptionalHeader;
265 LZSeek( lzfd, pehdoffset + len, SEEK_SET );
266
267 if ( nSections * sizeof(IMAGE_SECTION_HEADER) !=
268 LZRead( lzfd, (LPSTR)sections, nSections * sizeof(IMAGE_SECTION_HEADER) ) )
269 {
270 HeapFree( GetProcessHeap(), 0, sections );
271 return FALSE;
272 }
273
274 /* Find resource section */
275 for ( i = 0; i < nSections; i++ )
276 if ( resDataDir->VirtualAddress >= sections[i].VirtualAddress
277 && resDataDir->VirtualAddress < sections[i].VirtualAddress +
278 sections[i].SizeOfRawData )
279 break;
280
281 if ( i == nSections )
282 {
283 HeapFree( GetProcessHeap(), 0, sections );
284 TRACE("Couldn't find resource section\n" );
285 return FALSE;
286 }
287
288 /* Read in resource section */
289 resSectionSize = sections[i].SizeOfRawData;
290 resSection = HeapAlloc( GetProcessHeap(), 0, resSectionSize );
291 if ( !resSection )
292 {
293 HeapFree( GetProcessHeap(), 0, sections );
294 return FALSE;
295 }
296
297 LZSeek( lzfd, sections[i].PointerToRawData, SEEK_SET );
298 if ( resSectionSize != LZRead( lzfd, (char*)resSection, resSectionSize ) ) goto done;
299
300 /* Find resource */
301 resDir = resSection + (resDataDir->VirtualAddress - sections[i].VirtualAddress);
302
303 resPtr = resDir;
304 resPtr = find_entry_by_id( resPtr, VS_FILE_INFO, resDir );
305 if ( !resPtr )
306 {
307 TRACE("No typeid entry found\n" );
308 goto done;
309 }
310 resPtr = find_entry_by_id( resPtr, VS_VERSION_INFO, resDir );
311 if ( !resPtr )
312 {
313 TRACE("No resid entry found\n" );
314 goto done;
315 }
316 resPtr = find_entry_default( resPtr, resDir );
317 if ( !resPtr )
318 {
319 TRACE("No default language entry found\n" );
320 goto done;
321 }
322
323 /* Find resource data section */
324 resData = (const IMAGE_RESOURCE_DATA_ENTRY*)resPtr;
325 for ( i = 0; i < nSections; i++ )
326 if ( resData->OffsetToData >= sections[i].VirtualAddress
327 && resData->OffsetToData < sections[i].VirtualAddress +
328 sections[i].SizeOfRawData )
329 break;
330
331 if ( i == nSections )
332 {
333 TRACE("Couldn't find resource data section\n" );
334 goto done;
335 }
336
337 /* Return resource data */
338 if ( resLen ) *resLen = resData->Size;
339 if ( resOff ) *resOff = resData->OffsetToData - sections[i].VirtualAddress
340 + sections[i].PointerToRawData;
341 ret = TRUE;
342
343 done:
344 HeapFree( GetProcessHeap(), 0, resSection );
345 HeapFree( GetProcessHeap(), 0, sections );
346 return ret;
347 }
348
349
350 /***********************************************************************
351 * find_version_resource [internal]
352 */
353 DWORD find_version_resource( HFILE lzfd, DWORD *reslen, DWORD *offset )
354 {
355 DWORD magic = read_xx_header( lzfd );
356
357 switch (magic)
358 {
359 case IMAGE_OS2_SIGNATURE:
360 if (!find_ne_resource( lzfd, reslen, offset )) magic = 0;
361 break;
362 case IMAGE_NT_SIGNATURE:
363 if (!find_pe_resource( lzfd, reslen, offset )) magic = 0;
364 break;
365 }
366 return magic;
367 }