Converted to the new debugging interface (done with the help of the
[wine] / dlls / 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
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "peexe.h"
13 #include "neexe.h"
14 #include "module.h"
15 #include "winver.h"
16 #include "ver.h"
17 #include "heap.h"
18 #include "lzexpand.h"
19 #include "peexe.h"
20 #include "debug.h"
21
22 DEFAULT_DEBUG_CHANNEL(ver)
23
24
25 /***********************************************************************
26  *           read_xx_header         [internal]
27  */
28 static int read_xx_header( HFILE lzfd )
29 {
30     IMAGE_DOS_HEADER mzh;
31     char magic[3];
32
33     LZSeek( lzfd, 0, SEEK_SET );
34     if ( sizeof(mzh) != LZRead( lzfd, &mzh, sizeof(mzh) ) )
35         return 0;
36     if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
37         return 0;
38
39     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
40     if ( 2 != LZRead( lzfd, magic, 2 ) )
41         return 0;
42
43     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
44
45     if ( magic[0] == 'N' && magic[1] == 'E' )
46         return IMAGE_OS2_SIGNATURE;
47     if ( magic[0] == 'P' && magic[1] == 'E' )
48         return IMAGE_NT_SIGNATURE;
49
50     magic[2] = '\0';
51     WARN( ver, "Can't handle %s files.\n", magic );
52     return 0;
53 }
54
55 /***********************************************************************
56  *           load_ne_resource         [internal]
57  */
58 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
59                                 DWORD *resLen, DWORD *resOff )
60 {
61     IMAGE_OS2_HEADER nehd;
62     NE_TYPEINFO *typeInfo;
63     NE_NAMEINFO *nameInfo;
64     DWORD nehdoffset;
65     LPBYTE resTab;
66     DWORD resTabSize;
67
68     /* Read in NE header */ 
69     nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
70     if ( sizeof(nehd) != LZRead( lzfd, &nehd, sizeof(nehd) ) ) return 0;
71
72     resTabSize = nehd.rname_tab_offset - nehd.resource_tab_offset; 
73     if ( !resTabSize )
74     {
75         TRACE( ver, "No resources in NE dll\n" );
76         return FALSE;
77     }
78
79     /* Read in resource table */ 
80     resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
81     if ( !resTab ) return FALSE;
82
83     LZSeek( lzfd, nehd.resource_tab_offset + nehdoffset, SEEK_SET );
84     if ( resTabSize != LZRead( lzfd, resTab, resTabSize ) )
85     {
86         HeapFree( GetProcessHeap(), 0, resTab );
87         return FALSE;
88     }
89
90     /* Find resource */
91     typeInfo = (NE_TYPEINFO *)(resTab + 2);
92     typeInfo = NE_FindTypeSection( resTab, typeInfo, typeid );
93     if ( !typeInfo )
94     {
95         TRACE( ver, "No typeid entry found for %p\n", typeid );
96         HeapFree( GetProcessHeap(), 0, resTab );
97         return FALSE;
98     }
99     nameInfo = NE_FindResourceFromType( resTab, typeInfo, resid );
100     if ( !nameInfo )
101     {
102         TRACE( ver, "No resid entry found for %p\n", typeid );
103         HeapFree( GetProcessHeap(), 0, resTab );
104         return FALSE;
105     }
106
107     /* Return resource data */
108     if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
109     if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
110
111     HeapFree( GetProcessHeap(), 0, resTab );
112     return TRUE;
113 }
114
115 /***********************************************************************
116  *           load_pe_resource         [internal]
117  */
118 static BOOL find_pe_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
119                                 DWORD *resLen, DWORD *resOff )
120 {
121     IMAGE_NT_HEADERS pehd;
122     DWORD pehdoffset;
123     PIMAGE_DATA_DIRECTORY resDataDir;
124     PIMAGE_SECTION_HEADER sections;
125     LPBYTE resSection;
126     DWORD resSectionSize;
127     DWORD resDir;
128     PIMAGE_RESOURCE_DIRECTORY resPtr;
129     PIMAGE_RESOURCE_DATA_ENTRY resData;
130     int i, nSections;
131
132
133     /* Read in PE header */
134     pehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
135     if ( sizeof(pehd) != LZRead( lzfd, &pehd, sizeof(pehd) ) ) return 0;
136
137     resDataDir = pehd.OptionalHeader.DataDirectory+IMAGE_FILE_RESOURCE_DIRECTORY;
138     if ( !resDataDir->Size )
139     {
140         TRACE( ver, "No resources in PE dll\n" );
141         return FALSE;
142     }
143
144     /* Read in section table */
145     nSections = pehd.FileHeader.NumberOfSections; 
146     sections = HeapAlloc( GetProcessHeap(), 0, 
147                           nSections * sizeof(IMAGE_SECTION_HEADER) );
148     if ( !sections ) return FALSE;
149
150     LZSeek( lzfd, pehdoffset +
151                     sizeof(DWORD) + /* Signature */
152                     sizeof(IMAGE_FILE_HEADER) +
153                     pehd.FileHeader.SizeOfOptionalHeader, SEEK_SET );
154
155     if ( nSections * sizeof(IMAGE_SECTION_HEADER) !=
156          LZRead( lzfd, sections, nSections * sizeof(IMAGE_SECTION_HEADER) ) )
157     {
158         HeapFree( GetProcessHeap(), 0, sections );
159         return FALSE;
160     }
161
162     /* Find resource section */
163     for ( i = 0; i < nSections; i++ )
164         if (    resDataDir->VirtualAddress >= sections[i].VirtualAddress
165              && resDataDir->VirtualAddress <  sections[i].VirtualAddress +
166                                               sections[i].SizeOfRawData )
167             break;
168
169     if ( i == nSections )
170     {
171         HeapFree( GetProcessHeap(), 0, sections );
172         TRACE( ver, "Couldn't find resource section\n" );
173         return FALSE;
174     }
175
176     /* Read in resource section */
177     resSectionSize = sections[i].SizeOfRawData; 
178     resSection = HeapAlloc( GetProcessHeap(), 0, resSectionSize );
179     if ( !resSection ) 
180     {
181         HeapFree( GetProcessHeap(), 0, sections );
182         return FALSE;
183     }
184
185     LZSeek( lzfd, sections[i].PointerToRawData, SEEK_SET );
186     if ( resSectionSize != LZRead( lzfd, resSection, resSectionSize ) )
187     {
188         HeapFree( GetProcessHeap(), 0, resSection );
189         HeapFree( GetProcessHeap(), 0, sections );
190         return FALSE;
191     }
192
193     /* Find resource */
194     resDir = (DWORD)resSection + 
195              (resDataDir->VirtualAddress - sections[i].VirtualAddress);
196
197     resPtr = (PIMAGE_RESOURCE_DIRECTORY)resDir;
198     resPtr = GetResDirEntryA( resPtr, typeid, resDir, FALSE );
199     if ( !resPtr )
200     {
201         TRACE( ver, "No typeid entry found for %p\n", typeid );
202         HeapFree( GetProcessHeap(), 0, resSection );
203         HeapFree( GetProcessHeap(), 0, sections );
204         return FALSE;
205     }
206     resPtr = GetResDirEntryA( resPtr, resid, resDir, FALSE );
207     if ( !resPtr )
208     {
209         TRACE( ver, "No resid entry found for %p\n", resid );
210         HeapFree( GetProcessHeap(), 0, resSection );
211         HeapFree( GetProcessHeap(), 0, sections );
212         return FALSE;
213     }
214     resPtr = GetResDirEntryA( resPtr, 0, resDir, TRUE );
215     if ( !resPtr )
216     {
217         TRACE( ver, "No default language entry found for %p\n", resid );
218         HeapFree( GetProcessHeap(), 0, resSection );
219         HeapFree( GetProcessHeap(), 0, sections );
220         return FALSE;
221     }
222
223     /* Find resource data section */
224     resData = (PIMAGE_RESOURCE_DATA_ENTRY)resPtr;
225     for ( i = 0; i < nSections; i++ )
226         if (    resData->OffsetToData >= sections[i].VirtualAddress
227              && resData->OffsetToData <  sections[i].VirtualAddress +
228                                          sections[i].SizeOfRawData )
229             break;
230
231     if ( i == nSections )
232     {
233         TRACE( ver, "Couldn't find resource data section\n" );
234         HeapFree( GetProcessHeap(), 0, resSection );
235         HeapFree( GetProcessHeap(), 0, sections );
236         return FALSE;
237     }
238
239     /* Return resource data */
240     if ( resLen ) *resLen = resData->Size;
241     if ( resOff ) *resOff = resData->OffsetToData - sections[i].VirtualAddress
242                             + sections[i].PointerToRawData;
243
244     HeapFree( GetProcessHeap(), 0, resSection );
245     HeapFree( GetProcessHeap(), 0, sections );
246     return TRUE;
247 }
248
249 /***********************************************************************
250  *           GetFileResourceSize32         [internal]
251  */
252 DWORD WINAPI GetFileResourceSize( LPCSTR lpszFileName,
253                                     LPCSTR lpszResType, LPCSTR lpszResId,
254                                     LPDWORD lpdwFileOffset )
255 {
256     BOOL retv = FALSE;
257     HFILE lzfd;
258     OFSTRUCT ofs;
259     DWORD reslen;
260
261     TRACE( ver, "(%s,type=0x%lx,id=0x%lx,off=%p)\n",
262                 debugstr_a(lpszFileName), (LONG)lpszResType, (LONG)lpszResId, 
263                 lpszResId );
264
265     lzfd = LZOpenFileA( lpszFileName, &ofs, OF_READ );
266     if ( !lzfd ) return 0;
267
268     switch ( read_xx_header( lzfd ) )
269     {
270     case IMAGE_OS2_SIGNATURE:
271         retv = find_ne_resource( lzfd, lpszResType, lpszResId, 
272                                  &reslen, lpdwFileOffset );
273         break;
274
275     case IMAGE_NT_SIGNATURE:
276         retv = find_pe_resource( lzfd, lpszResType, lpszResId, 
277                                  &reslen, lpdwFileOffset );
278         break;
279     }
280
281     LZClose( lzfd );
282     return retv? reslen : 0;
283 }
284
285 /***********************************************************************
286  *           GetFileResource32         [internal]
287  */
288 DWORD WINAPI GetFileResource( LPCSTR lpszFileName,
289                                 LPCSTR lpszResType, LPCSTR lpszResId,
290                                 DWORD dwFileOffset,
291                                 DWORD dwResLen, LPVOID lpvData )
292 {
293     BOOL retv = FALSE;
294     HFILE lzfd;
295     OFSTRUCT ofs;
296     DWORD reslen = dwResLen;
297
298     TRACE( ver, "(%s,type=0x%lx,id=0x%lx,off=%ld,len=%ld,data=%p)\n",
299                 debugstr_a(lpszFileName), (LONG)lpszResType, (LONG)lpszResId, 
300                 dwFileOffset, dwResLen, lpvData );
301
302     lzfd = LZOpenFileA( lpszFileName, &ofs, OF_READ );
303     if ( lzfd == 0 ) return 0;
304
305     if ( !dwFileOffset )
306     {
307         switch ( read_xx_header( lzfd ) ) 
308         {
309         case IMAGE_OS2_SIGNATURE:
310             retv = find_ne_resource( lzfd, lpszResType, lpszResId, 
311                                      &reslen, &dwFileOffset );
312             break;
313
314         case IMAGE_NT_SIGNATURE:
315             retv = find_pe_resource( lzfd, lpszResType, lpszResId, 
316                                      &reslen, &dwFileOffset );
317             break;
318         }
319
320         if ( !retv ) 
321         {
322             LZClose( lzfd );
323             return 0;
324         }
325     }
326
327     LZSeek( lzfd, dwFileOffset, SEEK_SET );
328     reslen = LZRead( lzfd, lpvData, min( reslen, dwResLen ) );
329     LZClose( lzfd );
330
331     return reslen;
332 }
333