2 * Implementation of VERSION.DLL - Resource Access routines
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
6 * Copyright 1999 Ulrich Weigand
11 #include <sys/types.h>
14 #include "wine/unicode.h"
21 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(ver);
26 /**********************************************************************
29 * Find an entry by id in a resource directory
30 * Copied from loader/pe_resource.c
32 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
33 WORD id, const void *root )
35 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
38 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
39 min = dir->NumberOfNamedEntries;
40 max = min + dir->NumberOfIdEntries - 1;
43 pos = (min + max) / 2;
44 if (entry[pos].u1.Id == id)
45 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s2.OffsetToDirectory);
46 if (entry[pos].u1.Id > id) max = pos - 1;
53 /**********************************************************************
56 * Find a default entry in a resource directory
57 * Copied from loader/pe_resource.c
59 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
62 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
64 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
65 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s2.OffsetToDirectory);
69 /**********************************************************************
72 * Find an entry by name in a resource directory
73 * Copied from loader/pe_resource.c
75 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( const IMAGE_RESOURCE_DIRECTORY *dir,
76 LPCSTR name, const void *root )
78 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
81 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
84 return find_entry_by_id( dir, atoi(name+1), root );
87 if ((nameW = HEAP_strdupAtoW( GetProcessHeap(), 0, name )))
89 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
90 const IMAGE_RESOURCE_DIR_STRING_U *str;
91 int min, max, res, pos, namelen = strlenW(nameW);
93 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
95 max = dir->NumberOfNamedEntries - 1;
98 pos = (min + max) / 2;
99 str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
100 res = strncmpiW( nameW, str->NameString, str->Length );
101 if (!res && namelen == str->Length)
103 ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s2.OffsetToDirectory);
106 if (res < 0) max = pos - 1;
109 HeapFree( GetProcessHeap(), 0, nameW );
115 /***********************************************************************
116 * read_xx_header [internal]
118 static int read_xx_header( HFILE lzfd )
120 IMAGE_DOS_HEADER mzh;
123 LZSeek( lzfd, 0, SEEK_SET );
124 if ( sizeof(mzh) != LZRead( lzfd, &mzh, sizeof(mzh) ) )
126 if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
129 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
130 if ( 2 != LZRead( lzfd, magic, 2 ) )
133 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
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;
141 WARN("Can't handle %s files.\n", magic );
145 /***********************************************************************
146 * load_ne_resource [internal]
148 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
149 DWORD *resLen, DWORD *resOff )
151 IMAGE_OS2_HEADER nehd;
152 NE_TYPEINFO *typeInfo;
153 NE_NAMEINFO *nameInfo;
158 /* Read in NE header */
159 nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
160 if ( sizeof(nehd) != LZRead( lzfd, &nehd, sizeof(nehd) ) ) return 0;
162 resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
165 TRACE("No resources in NE dll\n" );
169 /* Read in resource table */
170 resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
171 if ( !resTab ) return FALSE;
173 LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
174 if ( resTabSize != LZRead( lzfd, resTab, resTabSize ) )
176 HeapFree( GetProcessHeap(), 0, resTab );
181 typeInfo = (NE_TYPEINFO *)(resTab + 2);
182 typeInfo = NE_FindTypeSection( resTab, typeInfo, typeid );
185 TRACE("No typeid entry found for %p\n", typeid );
186 HeapFree( GetProcessHeap(), 0, resTab );
189 nameInfo = NE_FindResourceFromType( resTab, typeInfo, resid );
192 TRACE("No resid entry found for %p\n", typeid );
193 HeapFree( GetProcessHeap(), 0, resTab );
197 /* Return resource data */
198 if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
199 if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
201 HeapFree( GetProcessHeap(), 0, resTab );
205 /***********************************************************************
206 * load_pe_resource [internal]
208 static BOOL find_pe_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
209 DWORD *resLen, DWORD *resOff )
211 IMAGE_NT_HEADERS pehd;
213 PIMAGE_DATA_DIRECTORY resDataDir;
214 PIMAGE_SECTION_HEADER sections;
216 DWORD resSectionSize;
218 const IMAGE_RESOURCE_DIRECTORY *resPtr;
219 const IMAGE_RESOURCE_DATA_ENTRY *resData;
223 /* Read in PE header */
224 pehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
225 if ( sizeof(pehd) != LZRead( lzfd, &pehd, sizeof(pehd) ) ) return 0;
227 resDataDir = pehd.OptionalHeader.DataDirectory+IMAGE_FILE_RESOURCE_DIRECTORY;
228 if ( !resDataDir->Size )
230 TRACE("No resources in PE dll\n" );
234 /* Read in section table */
235 nSections = pehd.FileHeader.NumberOfSections;
236 sections = HeapAlloc( GetProcessHeap(), 0,
237 nSections * sizeof(IMAGE_SECTION_HEADER) );
238 if ( !sections ) return FALSE;
240 LZSeek( lzfd, pehdoffset +
241 sizeof(DWORD) + /* Signature */
242 sizeof(IMAGE_FILE_HEADER) +
243 pehd.FileHeader.SizeOfOptionalHeader, SEEK_SET );
245 if ( nSections * sizeof(IMAGE_SECTION_HEADER) !=
246 LZRead( lzfd, sections, nSections * sizeof(IMAGE_SECTION_HEADER) ) )
248 HeapFree( GetProcessHeap(), 0, sections );
252 /* Find resource section */
253 for ( i = 0; i < nSections; i++ )
254 if ( resDataDir->VirtualAddress >= sections[i].VirtualAddress
255 && resDataDir->VirtualAddress < sections[i].VirtualAddress +
256 sections[i].SizeOfRawData )
259 if ( i == nSections )
261 HeapFree( GetProcessHeap(), 0, sections );
262 TRACE("Couldn't find resource section\n" );
266 /* Read in resource section */
267 resSectionSize = sections[i].SizeOfRawData;
268 resSection = HeapAlloc( GetProcessHeap(), 0, resSectionSize );
271 HeapFree( GetProcessHeap(), 0, sections );
275 LZSeek( lzfd, sections[i].PointerToRawData, SEEK_SET );
276 if ( resSectionSize != LZRead( lzfd, resSection, resSectionSize ) ) goto done;
279 resDir = resSection + (resDataDir->VirtualAddress - sections[i].VirtualAddress);
281 resPtr = (PIMAGE_RESOURCE_DIRECTORY)resDir;
282 resPtr = find_entry_by_name( resPtr, typeid, resDir );
285 TRACE("No typeid entry found for %p\n", typeid );
288 resPtr = find_entry_by_name( resPtr, resid, resDir );
291 TRACE("No resid entry found for %p\n", resid );
294 resPtr = find_entry_default( resPtr, resDir );
297 TRACE("No default language entry found for %p\n", resid );
301 /* Find resource data section */
302 resData = (PIMAGE_RESOURCE_DATA_ENTRY)resPtr;
303 for ( i = 0; i < nSections; i++ )
304 if ( resData->OffsetToData >= sections[i].VirtualAddress
305 && resData->OffsetToData < sections[i].VirtualAddress +
306 sections[i].SizeOfRawData )
309 if ( i == nSections )
311 TRACE("Couldn't find resource data section\n" );
315 /* Return resource data */
316 if ( resLen ) *resLen = resData->Size;
317 if ( resOff ) *resOff = resData->OffsetToData - sections[i].VirtualAddress
318 + sections[i].PointerToRawData;
322 HeapFree( GetProcessHeap(), 0, resSection );
323 HeapFree( GetProcessHeap(), 0, sections );
328 /*************************************************************************
329 * GetFileResourceSize16 [VER.2]
331 DWORD WINAPI GetFileResourceSize16( LPCSTR lpszFileName, LPCSTR lpszResType,
332 LPCSTR lpszResId, LPDWORD lpdwFileOffset )
339 TRACE("(%s,type=0x%lx,id=0x%lx,off=%p)\n",
340 debugstr_a(lpszFileName), (LONG)lpszResType, (LONG)lpszResId,
343 lzfd = LZOpenFileA( lpszFileName, &ofs, OF_READ );
344 if ( !lzfd ) return 0;
346 switch ( read_xx_header( lzfd ) )
348 case IMAGE_OS2_SIGNATURE:
349 retv = find_ne_resource( lzfd, lpszResType, lpszResId,
350 &reslen, lpdwFileOffset );
353 case IMAGE_NT_SIGNATURE:
354 retv = find_pe_resource( lzfd, lpszResType, lpszResId,
355 &reslen, lpdwFileOffset );
360 return retv? reslen : 0;
364 /*************************************************************************
365 * GetFileResource16 [VER.3]
367 DWORD WINAPI GetFileResource16( LPCSTR lpszFileName, LPCSTR lpszResType,
368 LPCSTR lpszResId, DWORD dwFileOffset,
369 DWORD dwResLen, LPVOID lpvData )
374 DWORD reslen = dwResLen;
376 TRACE("(%s,type=0x%lx,id=0x%lx,off=%ld,len=%ld,data=%p)\n",
377 debugstr_a(lpszFileName), (LONG)lpszResType, (LONG)lpszResId,
378 dwFileOffset, dwResLen, lpvData );
380 lzfd = LZOpenFileA( lpszFileName, &ofs, OF_READ );
381 if ( lzfd == 0 ) return 0;
385 switch ( read_xx_header( lzfd ) )
387 case IMAGE_OS2_SIGNATURE:
388 retv = find_ne_resource( lzfd, lpszResType, lpszResId,
389 &reslen, &dwFileOffset );
392 case IMAGE_NT_SIGNATURE:
393 retv = find_pe_resource( lzfd, lpszResType, lpszResId,
394 &reslen, &dwFileOffset );
405 LZSeek( lzfd, dwFileOffset, SEEK_SET );
406 reslen = LZRead( lzfd, lpvData, min( reslen, dwResLen ) );