Global constructors using `.section .ctors' are bogus for NetBSD's
[wine/multimedia.git] / misc / ver.c
blob14296ac36be35aa189af2c3929a814376079d9f0
1 /*
2 * Implementation of VER.DLL
3 *
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
6 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <unistd.h>
11 #include "windows.h"
12 #include "win.h"
13 #include "winerror.h"
14 #include "heap.h"
15 #include "ver.h"
16 #include "lzexpand.h"
17 #include "module.h"
18 #include "neexe.h"
19 #include "debug.h"
20 #include "xmalloc.h"
21 #include "winreg.h"
23 #define LZREAD(what) \
24 if (sizeof(*what)!=LZRead32(lzfd,what,sizeof(*what))) return 0;
25 #define LZTELL(lzfd) LZSeek32(lzfd, 0, SEEK_CUR);
27 /******************************************************************************
29 * void ver_dstring(
30 * char const * prologue,
31 * char const * teststring,
32 * char const * epilogue )
34 * This function will print via dprintf[_]ver to stddeb the prologue string,
35 * followed by the address of teststring and the string it contains if
36 * teststring is non-null or "(null)" otherwise, and then the epilogue
37 * string followed by a new line.
39 * Revision history
40 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
41 * Original implementation as dprintf[_]ver_string
42 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
43 * Fixed problem that caused bug with tools/make_debug -- renaming
44 * this function should fix the problem.
45 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
46 * Modified it to make it print the message using only one
47 * dprintf[_]ver call.
49 *****************************************************************************/
51 static void ver_dstring(
52 char const * prologue,
53 char const * teststring,
54 char const * epilogue )
56 TRACE(ver, "%s %p (\"%s\") %s\n", prologue,
57 (void const *) teststring,
58 teststring ? teststring : "(null)",
59 epilogue);
62 /******************************************************************************
64 * This function will print via dprintf[_]ver to stddeb debug info regarding
65 * the file info structure vffi.
66 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
67 * Added this function to clean up the code.
69 *****************************************************************************/
70 static void print_vffi_debug(VS_FIXEDFILEINFO *vffi)
72 dbg_decl_str(ver, 1024);
74 TRACE(ver," structversion=%u.%u, fileversion=%u.%u.%u.%u, productversion=%u.%u.%u.%u, flagmask=0x%lx, flags=%s%s%s%s%s%s\n",
75 HIWORD(vffi->dwStrucVersion),LOWORD(vffi->dwStrucVersion),
76 HIWORD(vffi->dwFileVersionMS),LOWORD(vffi->dwFileVersionMS),
77 HIWORD(vffi->dwFileVersionLS),LOWORD(vffi->dwFileVersionLS),
78 HIWORD(vffi->dwProductVersionMS),LOWORD(vffi->dwProductVersionMS),
79 HIWORD(vffi->dwProductVersionLS),LOWORD(vffi->dwProductVersionLS),
80 vffi->dwFileFlagsMask,
81 (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "",
82 (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "",
83 (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "",
84 (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "",
85 (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "",
86 (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : ""
89 dsprintf(ver," OS=0x%x.0x%x ",
90 HIWORD(vffi->dwFileOS),
91 LOWORD(vffi->dwFileOS)
93 switch (vffi->dwFileOS&0xFFFF0000) {
94 case VOS_DOS:dsprintf(ver,"DOS,");break;
95 case VOS_OS216:dsprintf(ver,"OS/2-16,");break;
96 case VOS_OS232:dsprintf(ver,"OS/2-32,");break;
97 case VOS_NT:dsprintf(ver,"NT,");break;
98 case VOS_UNKNOWN:
99 default:
100 dsprintf(ver,"UNKNOWN(0x%lx),",vffi->dwFileOS&0xFFFF0000);break;
102 switch (LOWORD(vffi->dwFileOS)) {
103 case VOS__BASE:dsprintf(ver,"BASE");break;
104 case VOS__WINDOWS16:dsprintf(ver,"WIN16");break;
105 case VOS__WINDOWS32:dsprintf(ver,"WIN32");break;
106 case VOS__PM16:dsprintf(ver,"PM16");break;
107 case VOS__PM32:dsprintf(ver,"PM32");break;
108 default:dsprintf(ver,"UNKNOWN(0x%x)",LOWORD(vffi->dwFileOS));break;
110 TRACE(ver, "(%s)\n", dbg_str(ver));
112 dbg_reset_str(ver);
113 switch (vffi->dwFileType) {
114 default:
115 case VFT_UNKNOWN:
116 dsprintf(ver,"filetype=Unknown(0x%lx)",vffi->dwFileType);
117 break;
118 case VFT_APP:dsprintf(ver,"filetype=APP,");break;
119 case VFT_DLL:dsprintf(ver,"filetype=DLL,");break;
120 case VFT_DRV:
121 dsprintf(ver,"filetype=DRV,");
122 switch(vffi->dwFileSubtype) {
123 default:
124 case VFT2_UNKNOWN:
125 dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype);
126 break;
127 case VFT2_DRV_PRINTER:
128 dsprintf(ver,"PRINTER");
129 break;
130 case VFT2_DRV_KEYBOARD:
131 dsprintf(ver,"KEYBOARD");
132 break;
133 case VFT2_DRV_LANGUAGE:
134 dsprintf(ver,"LANGUAGE");
135 break;
136 case VFT2_DRV_DISPLAY:
137 dsprintf(ver,"DISPLAY");
138 break;
139 case VFT2_DRV_MOUSE:
140 dsprintf(ver,"MOUSE");
141 break;
142 case VFT2_DRV_NETWORK:
143 dsprintf(ver,"NETWORK");
144 break;
145 case VFT2_DRV_SYSTEM:
146 dsprintf(ver,"SYSTEM");
147 break;
148 case VFT2_DRV_INSTALLABLE:
149 dsprintf(ver,"INSTALLABLE");
150 break;
151 case VFT2_DRV_SOUND:
152 dsprintf(ver,"SOUND");
153 break;
154 case VFT2_DRV_COMM:
155 dsprintf(ver,"COMM");
156 break;
157 case VFT2_DRV_INPUTMETHOD:
158 dsprintf(ver,"INPUTMETHOD");
159 break;
161 break;
162 case VFT_FONT:
163 dsprintf(ver,"filetype=FONT.");
164 switch (vffi->dwFileSubtype) {
165 default:
166 dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype);
167 break;
168 case VFT2_FONT_RASTER:dsprintf(ver,"RASTER");break;
169 case VFT2_FONT_VECTOR:dsprintf(ver,"VECTOR");break;
170 case VFT2_FONT_TRUETYPE:dsprintf(ver,"TRUETYPE");break;
172 break;
173 case VFT_VXD:dsprintf(ver,"filetype=VXD");break;
174 case VFT_STATIC_LIB:dsprintf(ver,"filetype=STATIC_LIB");break;
176 TRACE(ver, "%s\n", dbg_str(ver));
178 TRACE(ver, " filedata=0x%lx.0x%lx\n",
179 vffi->dwFileDateMS,vffi->dwFileDateLS);
182 /******************************************************************************
184 * int testFileExistence(
185 * char const * path,
186 * char const * file )
188 * Tests whether a given path/file combination exists. If the file does
189 * not exist, the return value is zero. If it does exist, the return
190 * value is non-zero.
192 * Revision history
193 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
194 * Original implementation
196 *****************************************************************************/
198 static int testFileExistence(
199 char const * path,
200 char const * file )
202 char filename[1024];
203 int filenamelen;
204 OFSTRUCT fileinfo;
205 int retval;
207 fileinfo.cBytes = sizeof(OFSTRUCT);
209 strcpy(filename, path);
210 filenamelen = strlen(filename);
212 /* Add a trailing \ if necessary */
213 if(filenamelen) {
214 if(filename[filenamelen - 1] != '\\')
215 strcat(filename, "\\");
217 else /* specify the current directory */
218 strcpy(filename, ".\\");
220 /* Create the full pathname */
221 strcat(filename, file);
223 if(OpenFile32(filename, &fileinfo, OF_EXIST) == HFILE_ERROR32)
224 retval = 0;
225 else
226 retval = 1;
228 return retval;
231 /******************************************************************************
233 * int testFileExclusiveExistence(
234 * char const * path,
235 * char const * file )
237 * Tests whether a given path/file combination exists and ensures that no
238 * other programs have handles to the given file. If the file does not
239 * exist or is open, the return value is zero. If it does exist, the
240 * return value is non-zero.
242 * Revision history
243 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
244 * Original implementation
246 *****************************************************************************/
248 static int testFileExclusiveExistence(
249 char const * path,
250 char const * file )
252 char filename[1024];
253 int filenamelen;
254 OFSTRUCT fileinfo;
255 int retval;
257 fileinfo.cBytes = sizeof(OFSTRUCT);
259 strcpy(filename, path);
260 filenamelen = strlen(filename);
262 /* Add a trailing \ if necessary */
263 if(filenamelen) {
264 if(filename[filenamelen - 1] != '\\')
265 strcat(filename, "\\");
267 else /* specify the current directory */
268 strcpy(filename, ".\\");
270 /* Create the full pathname */
271 strcat(filename, file);
273 if(OpenFile32(filename, &fileinfo, OF_EXIST | OF_SHARE_EXCLUSIVE) ==
274 HFILE_ERROR32)
275 retval = 0;
276 else
277 retval = 1;
279 return retval;
283 static int read_xx_header(HFILE32 lzfd) {
284 IMAGE_DOS_HEADER mzh;
285 char magic[3];
287 LZSeek32(lzfd,0,SEEK_SET);
288 if (sizeof(mzh)!=LZRead32(lzfd,&mzh,sizeof(mzh)))
289 return 0;
290 if (mzh.e_magic!=IMAGE_DOS_SIGNATURE)
291 return 0;
292 LZSeek32(lzfd,mzh.e_lfanew,SEEK_SET);
293 if (2!=LZRead32(lzfd,magic,2))
294 return 0;
295 LZSeek32(lzfd,mzh.e_lfanew,SEEK_SET);
296 if (magic[0] == 'N' && magic[1] == 'E')
297 return IMAGE_OS2_SIGNATURE;
298 if (magic[0] == 'P' && magic[1] == 'E')
299 return IMAGE_NT_SIGNATURE;
300 magic[2]='\0';
301 WARN(ver,"Can't handle %s files.\n",magic);
302 return 0;
306 static int find_ne_resource(
307 HFILE32 lzfd,SEGPTR typeid,SEGPTR resid,
308 BYTE **resdata,int *reslen,DWORD *off
310 IMAGE_OS2_HEADER nehd;
311 NE_TYPEINFO ti;
312 NE_NAMEINFO ni;
313 int i;
314 WORD shiftcount;
315 DWORD nehdoffset;
317 nehdoffset = LZTELL(lzfd);
318 LZREAD(&nehd);
319 if (nehd.resource_tab_offset==nehd.rname_tab_offset) {
320 TRACE(ver,"no resources in NE dll\n");
321 return 0;
323 LZSeek32(lzfd,nehd.resource_tab_offset+nehdoffset,SEEK_SET);
324 LZREAD(&shiftcount);
325 TRACE(ver,"shiftcount is %d\n",shiftcount);
326 TRACE(ver,"reading resource typeinfo dir.\n");
328 if (!HIWORD(typeid)) typeid = (SEGPTR)(LOWORD(typeid) | 0x8000);
329 if (!HIWORD(resid)) resid = (SEGPTR)(LOWORD(resid) | 0x8000);
330 while (1) {
331 int skipflag;
333 LZREAD(&ti);
334 if (!ti.type_id)
335 return 0;
336 TRACE(ver," ti.typeid =%04x,count=%d\n",ti.type_id,ti.count);
338 skipflag=0;
339 if (!HIWORD(typeid)) {
340 if ((ti.type_id&0x8000)&&(typeid!=ti.type_id))
341 skipflag=1;
342 } else {
343 if (ti.type_id & 0x8000) {
344 skipflag=1;
345 } else {
346 BYTE len;
347 char *str;
348 DWORD whereleft;
350 whereleft = LZTELL(lzfd);
351 LZSeek32(
352 lzfd,
353 nehdoffset+nehd.resource_tab_offset+ti.type_id,
354 SEEK_SET
356 LZREAD(&len);
357 str=xmalloc(len);
358 if (len!=LZRead32(lzfd,str,len))
359 return 0;
360 TRACE(ver,"read %s to compare it with %s\n",
361 str,(char*)PTR_SEG_TO_LIN(typeid)
363 if (lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
364 skipflag=1;
365 free(str);
366 LZSeek32(lzfd,whereleft,SEEK_SET);
369 if (skipflag) {
370 LZSeek32(lzfd,ti.count*sizeof(ni),SEEK_CUR);
371 continue;
373 for (i=0;i<ti.count;i++) {
374 WORD *rdata;
375 int len;
377 LZREAD(&ni);
378 TRACE(ver," ni.id=%4x,offset=%d,length=%d\n",
379 ni.id,ni.offset,ni.length
381 skipflag=1;
382 if (!HIWORD(resid)) {
383 if (ni.id == resid)
384 skipflag=0;
385 } else {
386 if (!(ni.id & 0x8000)) {
387 BYTE len;
388 char *str;
389 DWORD whereleft;
391 whereleft = LZTELL(lzfd);
392 LZSeek32(
393 lzfd,
394 nehdoffset+nehd.resource_tab_offset+ni.id,
395 SEEK_SET
397 LZREAD(&len);
398 str=xmalloc(len);
399 if (len!=LZRead32(lzfd,str,len))
400 return 0;
401 TRACE(ver,"read %s to compare it with %s\n",
402 str,(char*)PTR_SEG_TO_LIN(typeid)
404 if (!lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
405 skipflag=0;
406 free(str);
407 LZSeek32(lzfd,whereleft,SEEK_SET);
410 if (skipflag)
411 continue;
412 LZSeek32(lzfd,((int)ni.offset<<shiftcount),SEEK_SET);
413 *off = (int)ni.offset<<shiftcount;
414 len = ni.length<<shiftcount;
415 rdata=(WORD*)xmalloc(len);
416 if (len!=LZRead32(lzfd,rdata,len)) {
417 free(rdata);
418 return 0;
420 TRACE(ver,"resource found.\n");
421 *resdata= (BYTE*)rdata;
422 *reslen = len;
423 return 1;
428 /* Loads the specified PE resource.
429 * FIXME: shouldn't load the whole image
431 static int
432 find_pe_resource(
433 HFILE32 lzfd,LPWSTR typeid,LPWSTR resid,
434 BYTE **resdata,int *reslen,DWORD *off
436 IMAGE_NT_HEADERS pehd;
437 int i;
438 UINT32 nrofsections;
439 DWORD imagesize,pehdoffset;
440 BYTE *image;
441 IMAGE_DATA_DIRECTORY resdir;
442 PIMAGE_RESOURCE_DIRECTORY resourcedir,xresdir;
443 PIMAGE_RESOURCE_DATA_ENTRY xresdata;
444 PIMAGE_SECTION_HEADER sections;
446 pehdoffset = LZTELL(lzfd);
447 LZREAD(&pehd);
448 resdir = pehd.OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
449 TRACE(ver,"(.,type=%p, id=%p, len=%u, off=%lu)\n",typeid,resid,*reslen,*off);
450 if (!resdir.Size) {
451 WARN(ver,"No resource directory found in PE file.\n");
452 return 0;
454 imagesize = pehd.OptionalHeader.SizeOfImage;
455 image = HeapAlloc(GetProcessHeap(),0,imagesize);
456 nrofsections = pehd.FileHeader.NumberOfSections;
458 sections = (PIMAGE_SECTION_HEADER)HeapAlloc(GetProcessHeap(),0,pehd.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
459 LZSeek32(lzfd,
460 pehdoffset+
461 sizeof(DWORD)+ /* Signature */
462 sizeof(IMAGE_FILE_HEADER)+
463 pehd.FileHeader.SizeOfOptionalHeader,
464 SEEK_SET
466 if ( nrofsections*sizeof(IMAGE_SECTION_HEADER)!=
467 LZRead32(lzfd,sections,nrofsections*sizeof(IMAGE_SECTION_HEADER))
469 HeapFree(GetProcessHeap(),0,image);
470 return 0;
472 for (i=0;i<nrofsections;i++) {
473 if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
474 continue;
475 LZSeek32(lzfd,sections[i].PointerToRawData,SEEK_SET);
476 if ( sections[i].SizeOfRawData!=
477 LZRead32(lzfd,image+sections[i].VirtualAddress,sections[i].SizeOfRawData)
479 HeapFree(GetProcessHeap(),0,image);
480 return 0;
483 resourcedir = (PIMAGE_RESOURCE_DIRECTORY)(image+resdir.VirtualAddress);
484 xresdir = GetResDirEntryW(resourcedir,typeid,(DWORD)resourcedir,FALSE);
485 if (!xresdir) {
486 TRACE(ver,"...no typeid entry found for %p\n",typeid);
487 HeapFree(GetProcessHeap(),0,image);
488 return 0;
490 xresdir = GetResDirEntryW(xresdir,resid,(DWORD)resourcedir,FALSE);
491 if (!xresdir) {
492 TRACE(ver,"...no resid entry found for %p\n",resid);
493 HeapFree(GetProcessHeap(),0,image);
494 return 0;
497 xresdir = GetResDirEntryW(xresdir,0,(DWORD)resourcedir,TRUE);
498 if (!xresdir) {
499 TRACE(ver,"...no 0 (default language) entry found for %p\n",resid);
500 HeapFree(GetProcessHeap(),0,image);
501 return 0;
503 xresdata = (PIMAGE_RESOURCE_DATA_ENTRY)xresdir;
504 *reslen = xresdata->Size;
505 *resdata= (LPBYTE)xmalloc(*reslen);
506 memcpy(*resdata,image+xresdata->OffsetToData,*reslen);
507 /* find physical address for virtual offset */
508 for (i=0;i<nrofsections;i++) {
509 if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
510 continue;
511 if ( (xresdata->OffsetToData >= sections[i].VirtualAddress)&&
512 (xresdata->OffsetToData < sections[i].VirtualAddress+sections[i].SizeOfRawData)
514 *off = (DWORD)(xresdata->OffsetToData)-(DWORD)(sections[i].VirtualAddress)+(DWORD)(sections[i].PointerToRawData);
515 break;
518 HeapFree(GetProcessHeap(),0,image);
519 HeapFree(GetProcessHeap(),0,sections);
520 TRACE(ver,"-- found at off=%lu\n",*off);
521 return 1;
524 /* GetFileResourceSize [VER.2] */
525 DWORD WINAPI GetFileResourceSize(LPCSTR filename,SEGPTR restype,SEGPTR resid,
526 LPDWORD off)
528 HFILE32 lzfd;
529 OFSTRUCT ofs;
530 BYTE *resdata = NULL;
531 int reslen=0;
532 int res=0;
534 TRACE(ver,"(%s,type=0x%lx,id=0x%lx,off=%p)\n",
535 filename,(LONG)restype,(LONG)resid,off
537 lzfd=LZOpenFile32A(filename,&ofs,OF_READ);
538 if (!lzfd)
539 return 0;
540 switch (read_xx_header(lzfd)) {
541 case 0:
542 res=0;
543 break;
544 case IMAGE_OS2_SIGNATURE:
545 res=find_ne_resource(lzfd,restype,resid,&resdata,&reslen,off);
546 break;
547 case IMAGE_NT_SIGNATURE:
548 res=find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,off);
549 break;
551 if (!res) {
552 LZClose32(lzfd);
553 return 0;
555 if (resdata)
556 free(resdata);
557 LZClose32(lzfd);
558 return reslen;
561 /* GetFileResource [VER.3] */
562 DWORD WINAPI GetFileResource(LPCSTR filename,SEGPTR restype,SEGPTR resid,
563 DWORD off,DWORD datalen,LPVOID data )
565 HFILE32 lzfd;
566 OFSTRUCT ofs;
567 BYTE *resdata=NULL;
568 int res=0;
569 int reslen=datalen;
571 TRACE(ver,"(%s,type=0x%lx,id=0x%lx,off=%ld,len=%ld,date=%p)\n",
572 filename,(LONG)restype,(LONG)resid,off,datalen,data
575 lzfd=LZOpenFile32A(filename,&ofs,OF_READ);
576 if (lzfd==0)
577 return 0;
578 if (!off) {
579 switch (read_xx_header(lzfd)) {
580 case 0: res=0;
581 break;
582 case IMAGE_OS2_SIGNATURE:
583 res= find_ne_resource(lzfd,restype,resid,&resdata,&reslen,&off);
584 break;
585 case IMAGE_NT_SIGNATURE:
586 res= find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,&off);
587 break;
589 LZClose32(lzfd);
590 if (!res)
591 return 0;
592 if (reslen>datalen) reslen = datalen;
593 memcpy(data,resdata,reslen);
594 free(resdata);
595 TRACE(ver,"--[1] len=%u\n", reslen);
596 return reslen;
598 LZSeek32(lzfd,off,SEEK_SET);
599 reslen = LZRead32(lzfd,data,datalen);
600 LZClose32(lzfd);
601 TRACE(ver,"--[2] len=%u\n", reslen);
602 return reslen;
605 /* GetFileVersionInfoSize [VER.6] */
606 DWORD WINAPI GetFileVersionInfoSize16(LPCSTR filename,LPDWORD handle)
608 DWORD len,ret,isuni=0;
609 BYTE buf[144];
610 VS_FIXEDFILEINFO *vffi;
612 TRACE(ver,"(%s,%p)\n",filename,handle);
613 len=GetFileResourceSize(filename,VS_FILE_INFO,VS_VERSION_INFO,handle);
614 if (!len)
615 return 0;
616 ret=GetFileResource(
617 filename,VS_FILE_INFO,VS_VERSION_INFO,*handle,sizeof(buf),buf
619 if (!ret)
620 return 0;
622 vffi=(VS_FIXEDFILEINFO*)(buf+0x14);
623 if (vffi->dwSignature != VS_FFI_SIGNATURE) {
624 /* unicode resource */
625 if (vffi->dwSignature == 0x004f0049) {
626 isuni = 1;
627 vffi = (VS_FIXEDFILEINFO*)(buf+0x28);
628 } else {
629 WARN(ver,"vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
630 vffi->dwSignature,VS_FFI_SIGNATURE
632 return 0;
635 if (*(WORD*)buf < len)
636 len = *(WORD*)buf;
638 if(TRACE_ON(ver))
639 print_vffi_debug(vffi);
641 return len;
644 /* GetFileVersionInfoSize32A [VERSION.1] */
645 DWORD WINAPI GetFileVersionInfoSize32A(LPCSTR filename,LPDWORD handle)
647 TRACE(ver,"(%s,%p)\n",filename,handle);
648 return GetFileVersionInfoSize16(filename,handle);
651 /* GetFileVersionInfoSize32W [VERSION.2] */
652 DWORD WINAPI GetFileVersionInfoSize32W( LPCWSTR filename, LPDWORD handle )
654 LPSTR xfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
655 DWORD ret = GetFileVersionInfoSize16( xfn, handle );
656 HeapFree( GetProcessHeap(), 0, xfn );
657 return ret;
660 /* GetFileVersionInfo [VER.7] */
661 DWORD WINAPI GetFileVersionInfo16(LPCSTR filename,DWORD handle,DWORD datasize,
662 LPVOID data)
664 TRACE(ver,"(%s,%ld,size=%ld,data=%p)\n",
665 filename,handle,datasize,data
667 return GetFileResource(
668 filename,VS_FILE_INFO,VS_VERSION_INFO,handle,datasize,data
672 /* GetFileVersionInfoA [VERSION.0] */
673 DWORD WINAPI GetFileVersionInfo32A(LPCSTR filename,DWORD handle,
674 DWORD datasize,LPVOID data)
676 return GetFileVersionInfo16(filename,handle,datasize,data);
679 /* GetFileVersionInfoW [VERSION.3] */
680 DWORD WINAPI GetFileVersionInfo32W( LPCWSTR filename, DWORD handle,
681 DWORD datasize, LPVOID data)
683 LPSTR fn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
684 DWORD ret = GetFileVersionInfo16( fn, handle, datasize, data );
685 HeapFree( GetProcessHeap(), 0, fn );
686 return ret;
689 /*****************************************************************************
691 * VerFindFile() [VER.8]
692 * Determines where to install a file based on whether it locates another
693 * version of the file in the system. The values VerFindFile returns are
694 * used in a subsequent call to the VerInstallFile function.
696 * Revision history:
697 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
698 * Reimplementation of VerFindFile from original stub.
700 ****************************************************************************/
702 DWORD WINAPI VerFindFile16(
703 UINT16 flags,
704 LPCSTR lpszFilename,
705 LPCSTR lpszWinDir,
706 LPCSTR lpszAppDir,
707 LPSTR lpszCurDir,
708 UINT16 *lpuCurDirLen,
709 LPSTR lpszDestDir,
710 UINT16 *lpuDestDirLen )
712 DWORD retval;
713 char curDir[256];
714 char destDir[256];
715 unsigned int curDirSizeReq;
716 unsigned int destDirSizeReq;
718 retval = 0;
720 /* Print out debugging information */
721 TRACE(ver, "called with parameters:\n"
722 "\tflags = %x", flags);
723 if(flags & VFFF_ISSHAREDFILE)
724 TRACE(ver, " (VFFF_ISSHAREDFILE)\n");
725 else
726 TRACE(ver, "\n");
728 ver_dstring("\tlpszFilename = ", lpszFilename, "");
729 ver_dstring("\tlpszWinDir = ", lpszWinDir, "");
730 ver_dstring("\tlpszAppDir = ", lpszAppDir, "");
732 TRACE(ver, "\tlpszCurDir = %p\n", lpszCurDir);
733 if(lpuCurDirLen)
734 TRACE(ver, "\tlpuCurDirLen = %p (%u)\n",
735 lpuCurDirLen, *lpuCurDirLen);
736 else
737 TRACE(ver, "\tlpuCurDirLen = (null)\n");
739 TRACE(ver, "\tlpszDestDir = %p\n", lpszDestDir);
740 if(lpuDestDirLen)
741 TRACE(ver, "\tlpuDestDirLen = %p (%u)\n",
742 lpuDestDirLen, *lpuDestDirLen);
744 /* Figure out where the file should go; shared files default to the
745 system directory */
747 strcpy(curDir, "");
748 strcpy(destDir, "");
750 if(flags & VFFF_ISSHAREDFILE) {
751 GetSystemDirectory32A(destDir, 256);
753 /* Were we given a filename? If so, try to find the file. */
754 if(lpszFilename) {
755 if(testFileExistence(destDir, lpszFilename)) {
756 strcpy(curDir, destDir);
758 if(!testFileExclusiveExistence(destDir, lpszFilename))
759 retval |= VFF_FILEINUSE;
761 else if(lpszAppDir && testFileExistence(lpszAppDir,
762 lpszFilename)) {
763 strcpy(curDir, lpszAppDir);
764 retval |= VFF_CURNEDEST;
766 if(!testFileExclusiveExistence(lpszAppDir, lpszFilename))
767 retval |= VFF_FILEINUSE;
771 else if(!(flags & VFFF_ISSHAREDFILE)) { /* not a shared file */
772 if(lpszAppDir) {
773 char systemDir[256];
774 GetSystemDirectory32A(systemDir, 256);
776 strcpy(destDir, lpszAppDir);
778 if(lpszFilename) {
779 if(testFileExistence(lpszAppDir, lpszFilename)) {
780 strcpy(curDir, lpszAppDir);
782 if(!testFileExclusiveExistence(lpszAppDir, lpszFilename))
783 retval |= VFF_FILEINUSE;
785 else if(testFileExistence(systemDir, lpszFilename)) {
786 strcpy(curDir, systemDir);
787 retval |= VFF_CURNEDEST;
789 if(!testFileExclusiveExistence(systemDir, lpszFilename))
790 retval |= VFF_FILEINUSE;
796 curDirSizeReq = strlen(curDir) + 1;
797 destDirSizeReq = strlen(destDir) + 1;
801 /* Make sure that the pointers to the size of the buffers are
802 valid; if not, do NOTHING with that buffer. If that pointer
803 is valid, then make sure that the buffer pointer is valid, too! */
805 if(lpuDestDirLen && lpszDestDir) {
806 if(*lpuDestDirLen < destDirSizeReq) {
807 retval |= VFF_BUFFTOOSMALL;
808 strncpy(lpszDestDir, destDir, *lpuDestDirLen - 1);
809 lpszDestDir[*lpuDestDirLen - 1] = '\0';
811 else
812 strcpy(lpszDestDir, destDir);
814 *lpuDestDirLen = destDirSizeReq;
817 if(lpuCurDirLen && lpszCurDir) {
818 if(*lpuCurDirLen < curDirSizeReq) {
819 retval |= VFF_BUFFTOOSMALL;
820 strncpy(lpszCurDir, curDir, *lpuCurDirLen - 1);
821 lpszCurDir[*lpuCurDirLen - 1] = '\0';
823 else
824 strcpy(lpszCurDir, curDir);
826 *lpuCurDirLen = curDirSizeReq;
829 TRACE(ver, "ret = %lu (%s%s%s)\n", retval,
830 (retval & VFF_CURNEDEST) ? "VFF_CURNEDEST " : "",
831 (retval & VFF_FILEINUSE) ? "VFF_FILEINUSE " : "",
832 (retval & VFF_BUFFTOOSMALL) ? "VFF_BUFFTOOSMALL " : "");
834 ver_dstring("\t(Exit) lpszCurDir = ", lpszCurDir, "");
835 if(lpuCurDirLen)
836 TRACE(ver, "\t(Exit) lpuCurDirLen = %p (%u)\n",
837 lpuCurDirLen, *lpuCurDirLen);
838 else
839 TRACE(ver, "\t(Exit) lpuCurDirLen = (null)\n");
841 ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir, "");
842 if(lpuDestDirLen)
843 TRACE(ver, "\t(Exit) lpuDestDirLen = %p (%u)\n",
844 lpuDestDirLen, *lpuDestDirLen);
846 return retval;
849 /* VerFindFileA [VERSION.5] */
850 DWORD WINAPI VerFindFile32A(
851 UINT32 flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir,
852 LPSTR curdir,UINT32 *pcurdirlen,LPSTR destdir,UINT32 *pdestdirlen )
854 UINT16 curdirlen, destdirlen;
855 DWORD ret;
857 curdirlen = (UINT16)*pcurdirlen;
858 destdirlen= (UINT16)*pdestdirlen;
860 ret = VerFindFile16(flags,filename,windir,appdir,
861 curdir,&curdirlen,destdir,&destdirlen);
862 *pcurdirlen = curdirlen;
863 *pdestdirlen = destdirlen;
864 return ret;
867 /* VerFindFileW [VERSION.6] */
868 DWORD WINAPI VerFindFile32W(
869 UINT32 flags,LPCWSTR filename,LPCWSTR windir,LPCWSTR appdir,
870 LPWSTR curdir,UINT32 *pcurdirlen,LPWSTR destdir,UINT32 *pdestdirlen )
872 UINT16 curdirlen, destdirlen;
873 LPSTR wfn,wwd,wad,wdd,wcd;
874 DWORD ret;
876 wfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
877 wwd = HEAP_strdupWtoA( GetProcessHeap(), 0, windir );
878 wad = HEAP_strdupWtoA( GetProcessHeap(), 0, appdir );
879 wcd = HeapAlloc( GetProcessHeap(), 0, *pcurdirlen );
880 wdd = HeapAlloc( GetProcessHeap(), 0, *pdestdirlen );
881 ret = VerFindFile16(flags,wfn,wwd,wad,wcd,&curdirlen,wdd,&destdirlen);
882 lstrcpynAtoW(curdir,wcd,*pcurdirlen);
883 lstrcpynAtoW(destdir,wdd,*pdestdirlen);
884 *pcurdirlen = strlen(wcd);
885 *pdestdirlen = strlen(wdd);
886 HeapFree( GetProcessHeap(), 0, wfn );
887 HeapFree( GetProcessHeap(), 0, wwd );
888 HeapFree( GetProcessHeap(), 0, wad );
889 HeapFree( GetProcessHeap(), 0, wcd );
890 HeapFree( GetProcessHeap(), 0, wdd );
891 return ret;
894 /* VerInstallFile [VER.9] */
895 DWORD WINAPI VerInstallFile16(
896 UINT16 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
897 LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT16 *tmpfilelen )
899 UINT32 filelen;
900 DWORD ret= VerInstallFile32A(flags,srcfilename,destfilename,srcdir,
901 destdir,curdir,tmpfile,&filelen);
903 *tmpfilelen = filelen;
904 return ret;
907 static LPBYTE
908 _fetch_versioninfo(LPSTR fn,VS_FIXEDFILEINFO **vffi) {
909 DWORD alloclen;
910 LPBYTE buf;
911 DWORD ret;
913 alloclen = 1000;
914 buf= xmalloc(alloclen);
915 while (1) {
916 ret = GetFileVersionInfo32A(fn,0,alloclen,buf);
917 if (!ret) {
918 free(buf);
919 return 0;
921 if (alloclen<*(WORD*)buf) {
922 free(buf);
923 alloclen = *(WORD*)buf;
924 buf = xmalloc(alloclen);
925 } else {
926 *vffi = (VS_FIXEDFILEINFO*)(buf+0x14);
927 if ((*vffi)->dwSignature == 0x004f0049) /* hack to detect unicode */
928 *vffi = (VS_FIXEDFILEINFO*)(buf+0x28);
929 if ((*vffi)->dwSignature != VS_FFI_SIGNATURE)
930 WARN(ver,"Bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi)->dwSignature);
931 return buf;
936 static DWORD
937 _error2vif(DWORD error) {
938 switch (error) {
939 case ERROR_ACCESS_DENIED:
940 return VIF_ACCESSVIOLATION;
941 case ERROR_SHARING_VIOLATION:
942 return VIF_SHARINGVIOLATION;
943 default:
944 return 0;
949 /******************************************************************************
950 * VerInstallFile32A [VERSION.7]
952 DWORD WINAPI VerInstallFile32A(
953 UINT32 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
954 LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT32 *tmpfilelen )
956 LPCSTR pdest;
957 char destfn[260],tmpfn[260],srcfn[260];
958 HFILE32 hfsrc,hfdst;
959 DWORD attr,ret,xret,tmplast;
960 LPBYTE buf1,buf2;
961 OFSTRUCT ofs;
963 TRACE(ver,"(%x,%s,%s,%s,%s,%s,%p,%d)\n",
964 flags,srcfilename,destfilename,srcdir,destdir,curdir,tmpfile,*tmpfilelen
966 xret = 0;
967 sprintf(srcfn,"%s\\%s",srcdir,srcfilename);
968 if (!destdir || !*destdir) pdest = srcdir;
969 else pdest = destdir;
970 sprintf(destfn,"%s\\%s",pdest,destfilename);
971 hfsrc=LZOpenFile32A(srcfn,&ofs,OF_READ);
972 if (hfsrc==HFILE_ERROR32)
973 return VIF_CANNOTREADSRC;
974 sprintf(tmpfn,"%s\\%s",pdest,destfilename);
975 tmplast=strlen(pdest)+1;
976 attr = GetFileAttributes32A(tmpfn);
977 if (attr!=-1) {
978 if (attr & FILE_ATTRIBUTE_READONLY) {
979 LZClose32(hfsrc);
980 return VIF_WRITEPROT;
982 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
984 attr = -1;
985 if (flags & VIFF_FORCEINSTALL) {
986 if (tmpfile[0]) {
987 sprintf(tmpfn,"%s\\%s",pdest,tmpfile);
988 tmplast = strlen(pdest)+1;
989 attr = GetFileAttributes32A(tmpfn);
990 /* if it exists, it has been copied by the call before.
991 * we jump over the copy part...
995 if (attr == -1) {
996 char *s;
998 GetTempFileName32A(pdest,"ver",0,tmpfn); /* should not fail ... */
999 s=strrchr(tmpfn,'\\');
1000 if (s)
1001 tmplast = s-tmpfn;
1002 else
1003 tmplast = 0;
1004 hfdst = OpenFile32(tmpfn,&ofs,OF_CREATE);
1005 if (hfdst == HFILE_ERROR32) {
1006 LZClose32(hfsrc);
1007 return VIF_CANNOTCREATE; /* | translated dos error */
1009 ret = LZCopy32(hfsrc,hfdst);
1010 _lclose32(hfdst);
1011 if (((long) ret) < 0) {
1012 /* translate LZ errors into VIF_xxx */
1013 switch (ret) {
1014 case LZERROR_BADINHANDLE:
1015 case LZERROR_READ:
1016 case LZERROR_BADVALUE:
1017 case LZERROR_UNKNOWNALG:
1018 ret = VIF_CANNOTREADSRC;
1019 break;
1020 case LZERROR_BADOUTHANDLE:
1021 case LZERROR_WRITE:
1022 ret = VIF_OUTOFMEMORY; /* FIXME: correct? */
1023 break;
1024 case LZERROR_GLOBALLOC:
1025 case LZERROR_GLOBLOCK:
1026 ret = VIF_OUTOFSPACE;
1027 break;
1028 default: /* unknown error, should not happen */
1029 ret = 0;
1030 break;
1032 if (ret) {
1033 LZClose32(hfsrc);
1034 return ret;
1038 xret = 0;
1039 if (!(flags & VIFF_FORCEINSTALL)) {
1040 VS_FIXEDFILEINFO *destvffi,*tmpvffi;
1041 buf1 = _fetch_versioninfo(destfn,&destvffi);
1042 if (buf1) {
1043 buf2 = _fetch_versioninfo(tmpfn,&tmpvffi);
1044 if (buf2) {
1045 char *tbuf1,*tbuf2;
1046 UINT32 len1,len2;
1048 len1=len2=40;
1050 /* compare file versions */
1051 if ((destvffi->dwFileVersionMS > tmpvffi->dwFileVersionMS)||
1052 ((destvffi->dwFileVersionMS==tmpvffi->dwFileVersionMS)&&
1053 (destvffi->dwFileVersionLS > tmpvffi->dwFileVersionLS)
1056 xret |= VIF_MISMATCH|VIF_SRCOLD;
1057 /* compare filetypes and filesubtypes */
1058 if ((destvffi->dwFileType!=tmpvffi->dwFileType) ||
1059 (destvffi->dwFileSubtype!=tmpvffi->dwFileSubtype)
1061 xret |= VIF_MISMATCH|VIF_DIFFTYPE;
1062 if (VerQueryValue32A(buf1,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf1,&len1) &&
1063 VerQueryValue32A(buf2,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf2,&len2)
1065 /* irgendwas mit tbuf1 und tbuf2 machen
1066 * generiert DIFFLANG|MISMATCH
1069 free(buf2);
1070 } else
1071 xret=VIF_MISMATCH|VIF_SRCOLD;
1072 free(buf1);
1075 if (xret) {
1076 if (*tmpfilelen<strlen(tmpfn+tmplast)) {
1077 xret|=VIF_BUFFTOOSMALL;
1078 DeleteFile32A(tmpfn);
1079 } else {
1080 strcpy(tmpfile,tmpfn+tmplast);
1081 *tmpfilelen = strlen(tmpfn+tmplast)+1;
1082 xret|=VIF_TEMPFILE;
1084 } else {
1085 if (-1!=GetFileAttributes32A(destfn))
1086 if (!DeleteFile32A(destfn)) {
1087 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETE;
1088 DeleteFile32A(tmpfn);
1089 LZClose32(hfsrc);
1090 return xret;
1092 if ((!(flags & VIFF_DONTDELETEOLD)) &&
1093 curdir &&
1094 *curdir &&
1095 lstrcmpi32A(curdir,pdest)
1097 char curfn[260];
1099 sprintf(curfn,"%s\\%s",curdir,destfilename);
1100 if (-1!=GetFileAttributes32A(curfn)) {
1101 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
1102 if (!DeleteFile32A(curfn))
1103 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR;
1106 if (!MoveFile32A(tmpfn,destfn)) {
1107 xret|=_error2vif(GetLastError())|VIF_CANNOTRENAME;
1108 DeleteFile32A(tmpfn);
1111 LZClose32(hfsrc);
1112 return xret;
1116 /* VerInstallFileW [VERSION.8] */
1117 DWORD WINAPI VerInstallFile32W(
1118 UINT32 flags,LPCWSTR srcfilename,LPCWSTR destfilename,LPCWSTR srcdir,
1119 LPCWSTR destdir,LPCWSTR curdir,LPWSTR tmpfile,UINT32 *tmpfilelen )
1121 LPSTR wsrcf,wsrcd,wdestf,wdestd,wtmpf,wcurd;
1122 DWORD ret;
1124 wsrcf = HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename );
1125 wsrcd = HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir );
1126 wdestf = HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename );
1127 wdestd = HEAP_strdupWtoA( GetProcessHeap(), 0, destdir );
1128 wtmpf = HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile );
1129 wcurd = HEAP_strdupWtoA( GetProcessHeap(), 0, curdir );
1130 ret = VerInstallFile32A(flags,wsrcf,wdestf,wsrcd,wdestd,wcurd,wtmpf,tmpfilelen);
1131 if (!ret)
1132 lstrcpynAtoW(tmpfile,wtmpf,*tmpfilelen);
1133 HeapFree( GetProcessHeap(), 0, wsrcf );
1134 HeapFree( GetProcessHeap(), 0, wsrcd );
1135 HeapFree( GetProcessHeap(), 0, wdestf );
1136 HeapFree( GetProcessHeap(), 0, wdestd );
1137 HeapFree( GetProcessHeap(), 0, wtmpf );
1138 if (wcurd)
1139 HeapFree( GetProcessHeap(), 0, wcurd );
1140 return ret;
1144 struct dbA {
1145 WORD nextoff;
1146 WORD datalen;
1147 /* in memory structure... */
1148 char name[1]; /* padded to dword alignment */
1149 /* ....
1150 char data[datalen]; padded to dword alignment
1151 BYTE subdirdata[]; until nextoff
1155 #define DATA_OFFSET_A(db) ((4+(strlen((db)->name)+4))&~3)
1157 struct dbW {
1158 WORD nextoff;
1159 WORD datalen;
1160 WORD btext; /* type of data */
1161 /* in memory structure... */
1162 WCHAR name[1]; /* padded to dword alignment */
1163 /* ....
1164 WCHAR data[datalen]; padded to dword alignment
1165 BYTE subdirdata[]; until nextoff
1169 /* WORD nextoffset;
1170 * WORD datalength;
1171 * WORD btype;
1172 * WCHAR szKey[]; (zero terminated)
1173 * PADDING (round up to nearest 32bit boundary)
1175 #define DATA_OFFSET_W(db) ((2+2+2+((lstrlen32W((db)->name)+1)*2+3))&~3)
1177 /* this one used for Win16 resources, which are always in ASCII format */
1178 static BYTE*
1179 _find_dataA(BYTE *block,LPCSTR str, int buff_remain) {
1180 char *nextslash;
1181 int substrlen, inc_size;
1182 struct dbA *db;
1184 while (*str && *str=='\\')
1185 str++;
1186 if (NULL!=(nextslash=strchr(str,'\\')))
1187 substrlen=nextslash-str;
1188 else
1189 substrlen=strlen(str);
1190 if (nextslash!=NULL) {
1191 while (*nextslash && *nextslash=='\\')
1192 nextslash++;
1193 if (!*nextslash)
1194 nextslash=NULL;
1195 } else if (*str == 0)
1196 return NULL;
1199 while (1) {
1200 db=(struct dbA*)block;
1201 TRACE(ver,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s\n",
1202 db,db->nextoff,db->datalen,db->name
1204 if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */
1205 return NULL;
1207 TRACE(ver,"comparing with %s\n",db->name);
1208 if (!lstrncmpi32A(db->name,str,substrlen)) {
1209 if (nextslash) {
1210 inc_size=DATA_OFFSET_A(db)+((db->datalen+3)&~3);
1211 return _find_dataA(block+inc_size,nextslash,
1212 db->nextoff-inc_size);
1213 } else
1214 return block;
1216 inc_size = ((db->nextoff+3)&~3);
1217 block += inc_size;
1218 buff_remain -= inc_size;
1222 /* this one used for Win32 resources, which are always in UNICODE format */
1223 extern LPWSTR __cdecl CRTDLL_wcschr(LPCWSTR str,WCHAR xchar);
1224 static BYTE*
1225 _find_dataW(BYTE *block,LPCWSTR str, int buff_remain) {
1226 LPWSTR nextslash;
1227 int substrlen, inc_size;
1228 struct dbW *db;
1231 while (*str && *str=='\\')
1232 str++;
1233 if (NULL!=(nextslash=CRTDLL_wcschr(str,'\\')))
1234 substrlen=nextslash-str;
1235 else
1236 substrlen=lstrlen32W(str);
1237 if (nextslash!=NULL) {
1238 while (*nextslash && *nextslash=='\\')
1239 nextslash++;
1240 if (!*nextslash)
1241 nextslash=NULL;
1242 } else if (*str == 0)
1243 return NULL;
1246 while (1) {
1247 char *xs,*vs;
1248 db=(struct dbW*)block;
1249 xs= HEAP_strdupWtoA(GetProcessHeap(),0,db->name);
1250 if (db->datalen) {
1251 if (db->btext)
1252 vs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)((block+DATA_OFFSET_W(db))));
1253 else
1254 vs = HEAP_strdupA(GetProcessHeap(),0,"not a string");
1255 } else
1256 vs = HEAP_strdupA(GetProcessHeap(),0,"no data");
1258 TRACE(ver,"db->nextoff=%d,db->name=%s,db->data=\"%s\"\n",
1259 db->nextoff,xs,vs
1261 HeapFree(GetProcessHeap(),0,vs);
1262 HeapFree(GetProcessHeap(),0,xs);
1263 if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */
1264 return NULL;
1266 if (!lstrncmpi32W(db->name,str,substrlen)) {
1267 if (nextslash) {
1268 /* DATA_OFFSET_W(db) (padded to 32bit already)
1269 * DATA[datalength]
1270 * PADDING (round up to nearest 32bit boundary)
1271 * --> next level structs
1273 inc_size=DATA_OFFSET_W(db)+((db->datalen+3)&~3);
1274 return _find_dataW( block+inc_size ,nextslash,
1275 db->nextoff-inc_size);
1276 } else
1277 return block;
1279 /* skip over this block, round up to nearest 32bit boundary */
1280 inc_size = ((db->nextoff+3)&~3);
1281 block += inc_size;
1282 buff_remain -= inc_size;
1286 /* VerQueryValue [VER.11] */
1287 /* take care, 'buffer' is NOT a SEGPTR, it just points to one */
1288 DWORD WINAPI VerQueryValue16(SEGPTR segblock,LPCSTR subblock,SEGPTR *buffer,
1289 UINT16 *buflen)
1291 LPSTR s;
1292 BYTE *block=PTR_SEG_TO_LIN(segblock),*b;
1294 TRACE(ver,"(%p,%s,%p,%d)\n",
1295 block,subblock,buffer,*buflen
1298 s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1);
1299 strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock);
1300 /* check for UNICODE version */
1301 if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) &&
1302 (*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE)
1304 struct dbW *db;
1305 LPWSTR wstr;
1306 LPSTR xs;
1308 wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s);
1309 b=_find_dataW(block,wstr,*(WORD*)block);
1310 HeapFree(GetProcessHeap(),0,wstr);
1311 if (!b) {
1312 WARN(ver,"key %s not found in versionresource.\n",s);
1313 *buflen=0;
1314 free (s);
1315 return 0;
1317 db=(struct dbW*)b;
1318 b = b+DATA_OFFSET_W(db);
1319 *buflen = db->datalen;
1320 if (db->btext) {
1321 xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
1322 TRACE(ver,"->%s\n",xs);
1323 HeapFree(GetProcessHeap(),0,xs);
1324 } else
1325 TRACE(ver,"->%p\n",b);
1326 } else {
1327 struct dbA *db;
1328 b=_find_dataA(block,s,*(WORD*)block);
1329 if (!b) {
1330 WARN(ver,"key %s not found in versionresource.\n",s);
1331 *buflen=0;
1332 free (s);
1333 return 0;
1335 db=(struct dbA*)b;
1336 b = b+DATA_OFFSET_A(db);
1337 *buflen = db->datalen;
1338 /* the string is only printable, if it is below \\StringFileInfo*/
1339 if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
1340 TRACE(ver," -> %s=%s\n",subblock,b);
1341 else
1342 TRACE(ver," -> %s=%p\n",subblock,b);
1344 *buffer = (b-block)+segblock;
1345 free(s);
1346 return 1;
1349 DWORD WINAPI VerQueryValue32A(LPVOID vblock,LPCSTR subblock,
1350 LPVOID *vbuffer,UINT32 *buflen)
1352 BYTE *b,*block=(LPBYTE)vblock,**buffer=(LPBYTE*)vbuffer;
1353 LPSTR s;
1355 TRACE(ver,"(%p,%s,%p,%d)\n",
1356 block,subblock,buffer,*buflen
1359 s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1);
1360 strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock);
1362 /* check for UNICODE version */
1363 if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) &&
1364 (*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE)
1366 LPWSTR wstr;
1367 LPSTR xs;
1368 struct dbW *db;
1370 wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s);
1371 b=_find_dataW(block,wstr,*(WORD*)block);
1372 HeapFree(GetProcessHeap(),0,wstr);
1373 if (!b) {
1374 WARN(ver,"key %s not found in versionresource.\n",s);
1375 *buflen=0;
1376 free (s);
1377 return 0;
1379 db = (struct dbW*)b;
1380 *buflen = db->datalen;
1381 b = b+DATA_OFFSET_W(db);
1382 if (db->btext) {
1383 xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
1384 TRACE(ver,"->%s\n",xs);
1385 HeapFree(GetProcessHeap(),0,xs);
1387 /* This is a leak. */
1388 b = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
1389 } else
1390 TRACE(ver,"->%p\n",b);
1391 } else {
1392 struct dbA *db;
1393 b=_find_dataA(block,s,*(WORD*)block);
1394 if (!b) {
1395 WARN(ver,"key %s not found in versionresource.\n",subblock);
1396 *buflen=0;
1397 free (s);
1398 return 0;
1400 db=(struct dbA*)b;
1401 *buflen = db->datalen;
1402 b = b+DATA_OFFSET_A(db);
1404 /* the string is only printable, if it is below \\StringFileInfo*/
1405 if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
1406 TRACE(ver," -> %s=%s\n",subblock,b);
1407 else
1408 TRACE(ver," -> %s=%p\n",subblock,b);
1410 *buffer = b;
1411 free(s);
1412 return 1;
1415 DWORD WINAPI VerQueryValue32W(LPVOID vblock,LPCWSTR subblock,LPVOID *vbuffer,
1416 UINT32 *buflen)
1418 LPSTR sb;
1419 DWORD ret;
1421 sb = HEAP_strdupWtoA( GetProcessHeap(), 0, subblock );
1422 ret = VerQueryValue32A(vblock,sb,vbuffer,buflen);
1423 HeapFree( GetProcessHeap(), 0, sb );
1424 return 1;
1426 /* 20 GETFILEVERSIONINFORAW */