Simulates DPMI memory map by converting lower-MB segment base
[wine/hacks.git] / misc / ver.c
blob00d98153d7551b42f2ac1628efc55cb78cbd2334
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=0x%lx.0x%lx, fileversion=0x%lx.0x%lx, productversion=0x%lx.0x%lx, flagmask=0x%lx, flags=%s%s%s%s%s%s\n",
75 (vffi->dwStrucVersion>>16),vffi->dwStrucVersion&0xFFFF,
76 vffi->dwFileVersionMS,vffi->dwFileVersionLS,
77 vffi->dwProductVersionMS,vffi->dwProductVersionLS,
78 vffi->dwFileFlagsMask,
79 (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "",
80 (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "",
81 (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "",
82 (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "",
83 (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "",
84 (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : ""
87 dsprintf(ver," OS=0x%lx.0x%lx ",
88 (vffi->dwFileOS&0xFFFF0000)>>16,
89 vffi->dwFileOS&0x0000FFFF
91 switch (vffi->dwFileOS&0xFFFF0000) {
92 case VOS_DOS:dsprintf(ver,"DOS,");break;
93 case VOS_OS216:dsprintf(ver,"OS/2-16,");break;
94 case VOS_OS232:dsprintf(ver,"OS/2-32,");break;
95 case VOS_NT:dsprintf(ver,"NT,");break;
96 case VOS_UNKNOWN:
97 default:
98 dsprintf(ver,"UNKNOWN(0x%lx),",vffi->dwFileOS&0xFFFF0000);break;
100 switch (vffi->dwFileOS & 0xFFFF) {
101 case VOS__BASE:dsprintf(ver,"BASE");break;
102 case VOS__WINDOWS16:dsprintf(ver,"WIN16");break;
103 case VOS__WINDOWS32:dsprintf(ver,"WIN32");break;
104 case VOS__PM16:dsprintf(ver,"PM16");break;
105 case VOS__PM32:dsprintf(ver,"PM32");break;
106 default:dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileOS&0xFFFF);break;
108 TRACE(ver, "(%s)\n", dbg_str(ver));
110 dbg_reset_str(ver);
111 switch (vffi->dwFileType) {
112 default:
113 case VFT_UNKNOWN:
114 dsprintf(ver,"filetype=Unknown(0x%lx)",vffi->dwFileType);
115 break;
116 case VFT_APP:dsprintf(ver,"filetype=APP,");break;
117 case VFT_DLL:dsprintf(ver,"filetype=DLL,");break;
118 case VFT_DRV:
119 dsprintf(ver,"filetype=DRV,");
120 switch(vffi->dwFileSubtype) {
121 default:
122 case VFT2_UNKNOWN:
123 dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype);
124 break;
125 case VFT2_DRV_PRINTER:
126 dsprintf(ver,"PRINTER");
127 break;
128 case VFT2_DRV_KEYBOARD:
129 dsprintf(ver,"KEYBOARD");
130 break;
131 case VFT2_DRV_LANGUAGE:
132 dsprintf(ver,"LANGUAGE");
133 break;
134 case VFT2_DRV_DISPLAY:
135 dsprintf(ver,"DISPLAY");
136 break;
137 case VFT2_DRV_MOUSE:
138 dsprintf(ver,"MOUSE");
139 break;
140 case VFT2_DRV_NETWORK:
141 dsprintf(ver,"NETWORK");
142 break;
143 case VFT2_DRV_SYSTEM:
144 dsprintf(ver,"SYSTEM");
145 break;
146 case VFT2_DRV_INSTALLABLE:
147 dsprintf(ver,"INSTALLABLE");
148 break;
149 case VFT2_DRV_SOUND:
150 dsprintf(ver,"SOUND");
151 break;
152 case VFT2_DRV_COMM:
153 dsprintf(ver,"COMM");
154 break;
155 case VFT2_DRV_INPUTMETHOD:
156 dsprintf(ver,"INPUTMETHOD");
157 break;
159 break;
160 case VFT_FONT:
161 dsprintf(ver,"filetype=FONT.");
162 switch (vffi->dwFileSubtype) {
163 default:
164 dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype);
165 break;
166 case VFT2_FONT_RASTER:dsprintf(ver,"RASTER");break;
167 case VFT2_FONT_VECTOR:dsprintf(ver,"VECTOR");break;
168 case VFT2_FONT_TRUETYPE:dsprintf(ver,"TRUETYPE");break;
170 break;
171 case VFT_VXD:dsprintf(ver,"filetype=VXD");break;
172 case VFT_STATIC_LIB:dsprintf(ver,"filetype=STATIC_LIB");break;
174 TRACE(ver, "%s\n", dbg_str(ver));
176 TRACE(ver, " filedata=0x%lx.0x%lx\n",
177 vffi->dwFileDateMS,vffi->dwFileDateLS);
180 /******************************************************************************
182 * int testFileExistence(
183 * char const * path,
184 * char const * file )
186 * Tests whether a given path/file combination exists. If the file does
187 * not exist, the return value is zero. If it does exist, the return
188 * value is non-zero.
190 * Revision history
191 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
192 * Original implementation
194 *****************************************************************************/
196 static int testFileExistence(
197 char const * path,
198 char const * file )
200 char filename[1024];
201 int filenamelen;
202 OFSTRUCT fileinfo;
203 int retval;
205 fileinfo.cBytes = sizeof(OFSTRUCT);
207 strcpy(filename, path);
208 filenamelen = strlen(filename);
210 /* Add a trailing \ if necessary */
211 if(filenamelen) {
212 if(filename[filenamelen - 1] != '\\')
213 strcat(filename, "\\");
215 else /* specify the current directory */
216 strcpy(filename, ".\\");
218 /* Create the full pathname */
219 strcat(filename, file);
221 if(OpenFile32(filename, &fileinfo, OF_EXIST) == HFILE_ERROR32)
222 retval = 0;
223 else
224 retval = 1;
226 return retval;
229 /******************************************************************************
231 * int testFileExclusiveExistence(
232 * char const * path,
233 * char const * file )
235 * Tests whether a given path/file combination exists and ensures that no
236 * other programs have handles to the given file. If the file does not
237 * exist or is open, the return value is zero. If it does exist, the
238 * return value is non-zero.
240 * Revision history
241 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
242 * Original implementation
244 *****************************************************************************/
246 static int testFileExclusiveExistence(
247 char const * path,
248 char const * file )
250 char filename[1024];
251 int filenamelen;
252 OFSTRUCT fileinfo;
253 int retval;
255 fileinfo.cBytes = sizeof(OFSTRUCT);
257 strcpy(filename, path);
258 filenamelen = strlen(filename);
260 /* Add a trailing \ if necessary */
261 if(filenamelen) {
262 if(filename[filenamelen - 1] != '\\')
263 strcat(filename, "\\");
265 else /* specify the current directory */
266 strcpy(filename, ".\\");
268 /* Create the full pathname */
269 strcat(filename, file);
271 if(OpenFile32(filename, &fileinfo, OF_EXIST | OF_SHARE_EXCLUSIVE) ==
272 HFILE_ERROR32)
273 retval = 0;
274 else
275 retval = 1;
277 return retval;
281 static int read_xx_header(HFILE32 lzfd) {
282 IMAGE_DOS_HEADER mzh;
283 char magic[3];
285 LZSeek32(lzfd,0,SEEK_SET);
286 if (sizeof(mzh)!=LZRead32(lzfd,&mzh,sizeof(mzh)))
287 return 0;
288 if (mzh.e_magic!=IMAGE_DOS_SIGNATURE)
289 return 0;
290 LZSeek32(lzfd,mzh.e_lfanew,SEEK_SET);
291 if (2!=LZRead32(lzfd,magic,2))
292 return 0;
293 LZSeek32(lzfd,mzh.e_lfanew,SEEK_SET);
294 if (magic[0] == 'N' && magic[1] == 'E')
295 return IMAGE_OS2_SIGNATURE;
296 if (magic[0] == 'P' && magic[1] == 'E')
297 return IMAGE_NT_SIGNATURE;
298 magic[2]='\0';
299 WARN(ver,"Can't handle %s files.\n",magic);
300 return 0;
304 static int find_ne_resource(
305 HFILE32 lzfd,SEGPTR typeid,SEGPTR resid,
306 BYTE **resdata,int *reslen,DWORD *off
308 IMAGE_OS2_HEADER nehd;
309 NE_TYPEINFO ti;
310 NE_NAMEINFO ni;
311 int i;
312 WORD shiftcount;
313 DWORD nehdoffset;
315 nehdoffset = LZTELL(lzfd);
316 LZREAD(&nehd);
317 if (nehd.resource_tab_offset==nehd.rname_tab_offset) {
318 TRACE(ver,"no resources in NE dll\n");
319 return 0;
321 LZSeek32(lzfd,nehd.resource_tab_offset+nehdoffset,SEEK_SET);
322 LZREAD(&shiftcount);
323 TRACE(ver,"shiftcount is %d\n",shiftcount);
324 TRACE(ver,"reading resource typeinfo dir.\n");
326 if (!HIWORD(typeid)) typeid = (SEGPTR)(LOWORD(typeid) | 0x8000);
327 if (!HIWORD(resid)) resid = (SEGPTR)(LOWORD(resid) | 0x8000);
328 while (1) {
329 int skipflag;
331 LZREAD(&ti);
332 if (!ti.type_id)
333 return 0;
334 TRACE(ver," ti.typeid =%04x,count=%d\n",ti.type_id,ti.count);
336 skipflag=0;
337 if (!HIWORD(typeid)) {
338 if ((ti.type_id&0x8000)&&(typeid!=ti.type_id))
339 skipflag=1;
340 } else {
341 if (ti.type_id & 0x8000) {
342 skipflag=1;
343 } else {
344 BYTE len;
345 char *str;
346 DWORD whereleft;
348 whereleft = LZTELL(lzfd);
349 LZSeek32(
350 lzfd,
351 nehdoffset+nehd.resource_tab_offset+ti.type_id,
352 SEEK_SET
354 LZREAD(&len);
355 str=xmalloc(len);
356 if (len!=LZRead32(lzfd,str,len))
357 return 0;
358 TRACE(ver,"read %s to compare it with %s\n",
359 str,(char*)PTR_SEG_TO_LIN(typeid)
361 if (lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
362 skipflag=1;
363 free(str);
364 LZSeek32(lzfd,whereleft,SEEK_SET);
367 if (skipflag) {
368 LZSeek32(lzfd,ti.count*sizeof(ni),SEEK_CUR);
369 continue;
371 for (i=0;i<ti.count;i++) {
372 WORD *rdata;
373 int len;
375 LZREAD(&ni);
376 TRACE(ver," ni.id=%4x,offset=%d,length=%d\n",
377 ni.id,ni.offset,ni.length
379 skipflag=1;
380 if (!HIWORD(resid)) {
381 if (ni.id == resid)
382 skipflag=0;
383 } else {
384 if (!(ni.id & 0x8000)) {
385 BYTE len;
386 char *str;
387 DWORD whereleft;
389 whereleft = LZTELL(lzfd);
390 LZSeek32(
391 lzfd,
392 nehdoffset+nehd.resource_tab_offset+ni.id,
393 SEEK_SET
395 LZREAD(&len);
396 str=xmalloc(len);
397 if (len!=LZRead32(lzfd,str,len))
398 return 0;
399 TRACE(ver,"read %s to compare it with %s\n",
400 str,(char*)PTR_SEG_TO_LIN(typeid)
402 if (!lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
403 skipflag=0;
404 free(str);
405 LZSeek32(lzfd,whereleft,SEEK_SET);
408 if (skipflag)
409 continue;
410 LZSeek32(lzfd,((int)ni.offset<<shiftcount),SEEK_SET);
411 *off = (int)ni.offset<<shiftcount;
412 len = ni.length<<shiftcount;
413 rdata=(WORD*)xmalloc(len);
414 if (len!=LZRead32(lzfd,rdata,len)) {
415 free(rdata);
416 return 0;
418 TRACE(ver,"resource found.\n");
419 *resdata= (BYTE*)rdata;
420 *reslen = len;
421 return 1;
426 /* Loads the specified PE resource.
427 * FIXME: shouldn't load the whole image
429 static int
430 find_pe_resource(
431 HFILE32 lzfd,LPWSTR typeid,LPWSTR resid,
432 BYTE **resdata,int *reslen,DWORD *off
434 IMAGE_NT_HEADERS pehd;
435 int i;
436 UINT32 nrofsections;
437 DWORD imagesize,pehdoffset;
438 BYTE *image;
439 IMAGE_DATA_DIRECTORY resdir;
440 LPIMAGE_RESOURCE_DIRECTORY resourcedir,xresdir;
441 LPIMAGE_RESOURCE_DATA_ENTRY xresdata;
442 LPIMAGE_SECTION_HEADER sections;
444 pehdoffset = LZTELL(lzfd);
445 LZREAD(&pehd);
446 resdir = pehd.OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
447 TRACE(ver,"(.,%p,%p,....)\n",typeid,resid);
448 if (!resdir.Size) {
449 WARN(ver,"No resource directory found in PE file.\n");
450 return 0;
452 imagesize = pehd.OptionalHeader.SizeOfImage;
453 image = HeapAlloc(GetProcessHeap(),0,imagesize);
454 nrofsections = pehd.FileHeader.NumberOfSections;
456 sections = (LPIMAGE_SECTION_HEADER)HeapAlloc(GetProcessHeap(),0,pehd.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
457 LZSeek32(lzfd,
458 pehdoffset+
459 sizeof(DWORD)+ /* Signature */
460 sizeof(IMAGE_FILE_HEADER)+
461 pehd.FileHeader.SizeOfOptionalHeader,
462 SEEK_SET
464 if ( nrofsections*sizeof(IMAGE_SECTION_HEADER)!=
465 LZRead32(lzfd,sections,nrofsections*sizeof(IMAGE_SECTION_HEADER))
467 HeapFree(GetProcessHeap(),0,image);
468 return 0;
470 for (i=0;i<nrofsections;i++) {
471 if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
472 continue;
473 LZSeek32(lzfd,sections[i].PointerToRawData,SEEK_SET);
474 if ( sections[i].SizeOfRawData!=
475 LZRead32(lzfd,image+sections[i].VirtualAddress,sections[i].SizeOfRawData)
477 HeapFree(GetProcessHeap(),0,image);
478 return 0;
481 resourcedir = (LPIMAGE_RESOURCE_DIRECTORY)(image+resdir.VirtualAddress);
482 xresdir = GetResDirEntryW(resourcedir,typeid,(DWORD)resourcedir,FALSE);
483 if (!xresdir) {
484 TRACE(ver,"...no typeid entry found for %p\n",typeid);
485 HeapFree(GetProcessHeap(),0,image);
486 return 0;
488 xresdir = GetResDirEntryW(xresdir,resid,(DWORD)resourcedir,FALSE);
489 if (!xresdir) {
490 TRACE(ver,"...no resid entry found for %p\n",resid);
491 HeapFree(GetProcessHeap(),0,image);
492 return 0;
495 xresdir = GetResDirEntryW(xresdir,0,(DWORD)resourcedir,TRUE);
496 if (!xresdir) {
497 TRACE(ver,"...no 0 (default language) entry found for %p\n",resid);
498 HeapFree(GetProcessHeap(),0,image);
499 return 0;
501 xresdata = (LPIMAGE_RESOURCE_DATA_ENTRY)xresdir;
502 *reslen = xresdata->Size;
503 *resdata= (LPBYTE)xmalloc(*reslen);
504 memcpy(*resdata,image+xresdata->OffsetToData,*reslen);
505 /* find physical address for virtual offset */
506 for (i=0;i<nrofsections;i++) {
507 if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
508 continue;
509 if ( (xresdata->OffsetToData >= sections[i].VirtualAddress)&&
510 (xresdata->OffsetToData < sections[i].VirtualAddress+sections[i].SizeOfRawData)
512 *off = (DWORD)(xresdata->OffsetToData)-(DWORD)(sections[i].VirtualAddress)+(DWORD)(sections[i].PointerToRawData);
513 break;
516 HeapFree(GetProcessHeap(),0,image);
517 HeapFree(GetProcessHeap(),0,sections);
518 return 1;
521 /* GetFileResourceSize [VER.2] */
522 DWORD WINAPI GetFileResourceSize(LPCSTR filename,SEGPTR restype,SEGPTR resid,
523 LPDWORD off)
525 HFILE32 lzfd;
526 OFSTRUCT ofs;
527 BYTE *resdata = NULL;
528 int reslen=0;
529 int res=0;
531 TRACE(ver,"(%s,%lx,%lx,%p)\n",
532 filename,(LONG)restype,(LONG)resid,off
534 lzfd=LZOpenFile32A(filename,&ofs,OF_READ);
535 if (!lzfd)
536 return 0;
537 switch (read_xx_header(lzfd)) {
538 case 0:
539 res=0;
540 break;
541 case IMAGE_OS2_SIGNATURE:
542 res=find_ne_resource(lzfd,restype,resid,&resdata,&reslen,off);
543 break;
544 case IMAGE_NT_SIGNATURE:
545 res=find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,off);
546 break;
548 if (!res) {
549 LZClose32(lzfd);
550 return 0;
552 if (resdata)
553 free(resdata);
554 LZClose32(lzfd);
555 return reslen;
558 /* GetFileResource [VER.3] */
559 DWORD WINAPI GetFileResource(LPCSTR filename,SEGPTR restype,SEGPTR resid,
560 DWORD off,DWORD datalen,LPVOID data )
562 HFILE32 lzfd;
563 OFSTRUCT ofs;
564 BYTE *resdata=NULL;
565 int res=0;
566 int reslen=datalen;
568 TRACE(ver,"(%s,%lx,%lx,%ld,%ld,%p)\n",
569 filename,(LONG)restype,(LONG)resid,off,datalen,data
572 lzfd=LZOpenFile32A(filename,&ofs,OF_READ);
573 if (lzfd==0)
574 return 0;
575 if (!off) {
576 switch (read_xx_header(lzfd)) {
577 case 0: res=0;
578 break;
579 case IMAGE_OS2_SIGNATURE:
580 res= find_ne_resource(lzfd,restype,resid,&resdata,&reslen,&off);
581 break;
582 case IMAGE_NT_SIGNATURE:
583 res= find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,&off);
584 break;
586 LZClose32(lzfd);
587 if (!res)
588 return 0;
589 if (reslen>datalen) reslen = datalen;
590 memcpy(data,resdata,reslen);
591 free(resdata);
592 return reslen;
594 LZSeek32(lzfd,off,SEEK_SET);
595 reslen = LZRead32(lzfd,data,datalen);
596 LZClose32(lzfd);
597 return reslen;
600 /* GetFileVersionInfoSize [VER.6] */
601 DWORD WINAPI GetFileVersionInfoSize16(LPCSTR filename,LPDWORD handle)
603 DWORD len,ret,isuni=0;
604 BYTE buf[144];
605 VS_FIXEDFILEINFO *vffi;
607 TRACE(ver,"(%s,%p)\n",filename,handle);
608 len=GetFileResourceSize(filename,VS_FILE_INFO,VS_VERSION_INFO,handle);
609 if (!len)
610 return 0;
611 ret=GetFileResource(
612 filename,VS_FILE_INFO,VS_VERSION_INFO,*handle,sizeof(buf),buf
614 if (!ret)
615 return 0;
617 vffi=(VS_FIXEDFILEINFO*)(buf+0x14);
618 if (vffi->dwSignature != VS_FFI_SIGNATURE) {
619 /* unicode resource */
620 if (vffi->dwSignature == 0x004f0049) {
621 isuni = 1;
622 vffi = (VS_FIXEDFILEINFO*)(buf+0x28);
623 } else {
624 WARN(ver,"vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
625 vffi->dwSignature,VS_FFI_SIGNATURE
627 return 0;
630 if (*(WORD*)buf < len)
631 len = *(WORD*)buf;
633 if(TRACE_ON(ver))
634 print_vffi_debug(vffi);
636 return len;
639 /* GetFileVersionInfoSize32A [VERSION.1] */
640 DWORD WINAPI GetFileVersionInfoSize32A(LPCSTR filename,LPDWORD handle)
642 TRACE(ver,"(%s,%p)\n",filename,handle);
643 return GetFileVersionInfoSize16(filename,handle);
646 /* GetFileVersionInfoSize32W [VERSION.2] */
647 DWORD WINAPI GetFileVersionInfoSize32W( LPCWSTR filename, LPDWORD handle )
649 LPSTR xfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
650 DWORD ret = GetFileVersionInfoSize16( xfn, handle );
651 HeapFree( GetProcessHeap(), 0, xfn );
652 return ret;
655 /* GetFileVersionInfo [VER.7] */
656 DWORD WINAPI GetFileVersionInfo16(LPCSTR filename,DWORD handle,DWORD datasize,
657 LPVOID data)
659 TRACE(ver,"(%s,%ld,%ld,%p)\n",
660 filename,handle,datasize,data
662 return GetFileResource(
663 filename,VS_FILE_INFO,VS_VERSION_INFO,handle,datasize,data
667 /* GetFileVersionInfoA [VERSION.0] */
668 DWORD WINAPI GetFileVersionInfo32A(LPCSTR filename,DWORD handle,
669 DWORD datasize,LPVOID data)
671 return GetFileVersionInfo16(filename,handle,datasize,data);
674 /* GetFileVersionInfoW [VERSION.3] */
675 DWORD WINAPI GetFileVersionInfo32W( LPCWSTR filename, DWORD handle,
676 DWORD datasize, LPVOID data)
678 LPSTR fn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
679 DWORD ret = GetFileVersionInfo16( fn, handle, datasize, data );
680 HeapFree( GetProcessHeap(), 0, fn );
681 return ret;
684 /*****************************************************************************
686 * VerFindFile() [VER.8]
687 * Determines where to install a file based on whether it locates another
688 * version of the file in the system. The values VerFindFile returns are
689 * used in a subsequent call to the VerInstallFile function.
691 * Revision history:
692 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
693 * Reimplementation of VerFindFile from original stub.
695 ****************************************************************************/
697 DWORD WINAPI VerFindFile16(
698 UINT16 flags,
699 LPCSTR lpszFilename,
700 LPCSTR lpszWinDir,
701 LPCSTR lpszAppDir,
702 LPSTR lpszCurDir,
703 UINT16 *lpuCurDirLen,
704 LPSTR lpszDestDir,
705 UINT16 *lpuDestDirLen )
707 DWORD retval;
708 char curDir[256];
709 char destDir[256];
710 unsigned int curDirSizeReq;
711 unsigned int destDirSizeReq;
713 retval = 0;
715 /* Print out debugging information */
716 TRACE(ver, "called with parameters:\n"
717 "\tflags = %x", flags);
718 if(flags & VFFF_ISSHAREDFILE)
719 TRACE(ver, " (VFFF_ISSHAREDFILE)\n");
720 else
721 TRACE(ver, "\n");
723 ver_dstring("\tlpszFilename = ", lpszFilename, "");
724 ver_dstring("\tlpszWinDir = ", lpszWinDir, "");
725 ver_dstring("\tlpszAppDir = ", lpszAppDir, "");
727 TRACE(ver, "\tlpszCurDir = %p\n", lpszCurDir);
728 if(lpuCurDirLen)
729 TRACE(ver, "\tlpuCurDirLen = %p (%u)\n",
730 lpuCurDirLen, *lpuCurDirLen);
731 else
732 TRACE(ver, "\tlpuCurDirLen = (null)\n");
734 TRACE(ver, "\tlpszDestDir = %p\n", lpszDestDir);
735 if(lpuDestDirLen)
736 TRACE(ver, "\tlpuDestDirLen = %p (%u)\n",
737 lpuDestDirLen, *lpuDestDirLen);
739 /* Figure out where the file should go; shared files default to the
740 system directory */
742 strcpy(curDir, "");
743 strcpy(destDir, "");
745 if(flags & VFFF_ISSHAREDFILE) {
746 GetSystemDirectory32A(destDir, 256);
748 /* Were we given a filename? If so, try to find the file. */
749 if(lpszFilename) {
750 if(testFileExistence(destDir, lpszFilename)) {
751 strcpy(curDir, destDir);
753 if(!testFileExclusiveExistence(destDir, lpszFilename))
754 retval |= VFF_FILEINUSE;
756 else if(lpszAppDir && testFileExistence(lpszAppDir,
757 lpszFilename)) {
758 strcpy(curDir, lpszAppDir);
759 retval |= VFF_CURNEDEST;
761 if(!testFileExclusiveExistence(lpszAppDir, lpszFilename))
762 retval |= VFF_FILEINUSE;
766 else if(!(flags & VFFF_ISSHAREDFILE)) { /* not a shared file */
767 if(lpszAppDir) {
768 char systemDir[256];
769 GetSystemDirectory32A(systemDir, 256);
771 strcpy(destDir, lpszAppDir);
773 if(lpszFilename) {
774 if(testFileExistence(lpszAppDir, lpszFilename)) {
775 strcpy(curDir, lpszAppDir);
777 if(!testFileExclusiveExistence(lpszAppDir, lpszFilename))
778 retval |= VFF_FILEINUSE;
780 else if(testFileExistence(systemDir, lpszFilename)) {
781 strcpy(curDir, systemDir);
782 retval |= VFF_CURNEDEST;
784 if(!testFileExclusiveExistence(systemDir, lpszFilename))
785 retval |= VFF_FILEINUSE;
791 curDirSizeReq = strlen(curDir) + 1;
792 destDirSizeReq = strlen(destDir) + 1;
796 /* Make sure that the pointers to the size of the buffers are
797 valid; if not, do NOTHING with that buffer. If that pointer
798 is valid, then make sure that the buffer pointer is valid, too! */
800 if(lpuDestDirLen && lpszDestDir) {
801 if(*lpuDestDirLen < destDirSizeReq) {
802 retval |= VFF_BUFFTOOSMALL;
803 strncpy(lpszDestDir, destDir, *lpuDestDirLen - 1);
804 lpszDestDir[*lpuDestDirLen - 1] = '\0';
806 else
807 strcpy(lpszDestDir, destDir);
809 *lpuDestDirLen = destDirSizeReq;
812 if(lpuCurDirLen && lpszCurDir) {
813 if(*lpuCurDirLen < curDirSizeReq) {
814 retval |= VFF_BUFFTOOSMALL;
815 strncpy(lpszCurDir, curDir, *lpuCurDirLen - 1);
816 lpszCurDir[*lpuCurDirLen - 1] = '\0';
818 else
819 strcpy(lpszCurDir, curDir);
821 *lpuCurDirLen = curDirSizeReq;
824 TRACE(ver, "ret = %lu (%s%s%s)\n", retval,
825 (retval & VFF_CURNEDEST) ? "VFF_CURNEDEST " : "",
826 (retval & VFF_FILEINUSE) ? "VFF_FILEINUSE " : "",
827 (retval & VFF_BUFFTOOSMALL) ? "VFF_BUFFTOOSMALL " : "");
829 ver_dstring("\t(Exit) lpszCurDir = ", lpszCurDir, "");
830 if(lpuCurDirLen)
831 TRACE(ver, "\t(Exit) lpuCurDirLen = %p (%u)\n",
832 lpuCurDirLen, *lpuCurDirLen);
833 else
834 TRACE(ver, "\t(Exit) lpuCurDirLen = (null)\n");
836 ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir, "");
837 if(lpuDestDirLen)
838 TRACE(ver, "\t(Exit) lpuDestDirLen = %p (%u)\n",
839 lpuDestDirLen, *lpuDestDirLen);
841 return retval;
844 /* VerFindFileA [VERSION.5] */
845 DWORD WINAPI VerFindFile32A(
846 UINT32 flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir,
847 LPSTR curdir,UINT32 *pcurdirlen,LPSTR destdir,UINT32 *pdestdirlen )
849 UINT16 curdirlen, destdirlen;
850 DWORD ret;
852 curdirlen = (UINT16)*pcurdirlen;
853 destdirlen= (UINT16)*pdestdirlen;
855 ret = VerFindFile16(flags,filename,windir,appdir,
856 curdir,&curdirlen,destdir,&destdirlen);
857 *pcurdirlen = curdirlen;
858 *pdestdirlen = destdirlen;
859 return ret;
862 /* VerFindFileW [VERSION.6] */
863 DWORD WINAPI VerFindFile32W(
864 UINT32 flags,LPCWSTR filename,LPCWSTR windir,LPCWSTR appdir,
865 LPWSTR curdir,UINT32 *pcurdirlen,LPWSTR destdir,UINT32 *pdestdirlen )
867 UINT16 curdirlen, destdirlen;
868 LPSTR wfn,wwd,wad,wdd,wcd;
869 DWORD ret;
871 wfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
872 wwd = HEAP_strdupWtoA( GetProcessHeap(), 0, windir );
873 wad = HEAP_strdupWtoA( GetProcessHeap(), 0, appdir );
874 wcd = HeapAlloc( GetProcessHeap(), 0, *pcurdirlen );
875 wdd = HeapAlloc( GetProcessHeap(), 0, *pdestdirlen );
876 ret = VerFindFile16(flags,wfn,wwd,wad,wcd,&curdirlen,wdd,&destdirlen);
877 lstrcpynAtoW(curdir,wcd,*pcurdirlen);
878 lstrcpynAtoW(destdir,wdd,*pdestdirlen);
879 *pcurdirlen = strlen(wcd);
880 *pdestdirlen = strlen(wdd);
881 HeapFree( GetProcessHeap(), 0, wfn );
882 HeapFree( GetProcessHeap(), 0, wwd );
883 HeapFree( GetProcessHeap(), 0, wad );
884 HeapFree( GetProcessHeap(), 0, wcd );
885 HeapFree( GetProcessHeap(), 0, wdd );
886 return ret;
889 /* VerInstallFile [VER.9] */
890 DWORD WINAPI VerInstallFile16(
891 UINT16 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
892 LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT16 *tmpfilelen )
894 UINT32 filelen;
895 DWORD ret= VerInstallFile32A(flags,srcfilename,destfilename,srcdir,
896 destdir,curdir,tmpfile,&filelen);
898 *tmpfilelen = filelen;
899 return ret;
902 static LPBYTE
903 _fetch_versioninfo(LPSTR fn,VS_FIXEDFILEINFO **vffi) {
904 DWORD alloclen;
905 LPBYTE buf;
906 DWORD ret;
908 alloclen = 1000;
909 buf= xmalloc(alloclen);
910 while (1) {
911 ret = GetFileVersionInfo32A(fn,0,alloclen,buf);
912 if (!ret) {
913 free(buf);
914 return 0;
916 if (alloclen<*(WORD*)buf) {
917 free(buf);
918 alloclen = *(WORD*)buf;
919 buf = xmalloc(alloclen);
920 } else {
921 *vffi = (VS_FIXEDFILEINFO*)(buf+0x14);
922 if ((*vffi)->dwSignature == 0x004f0049) /* hack to detect unicode */
923 *vffi = (VS_FIXEDFILEINFO*)(buf+0x28);
924 if ((*vffi)->dwSignature != VS_FFI_SIGNATURE)
925 WARN(ver,"Bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi)->dwSignature);
926 return buf;
931 static DWORD
932 _error2vif(DWORD error) {
933 switch (error) {
934 case ERROR_ACCESS_DENIED:
935 return VIF_ACCESSVIOLATION;
936 case ERROR_SHARING_VIOLATION:
937 return VIF_SHARINGVIOLATION;
938 default:
939 return 0;
944 /******************************************************************************
945 * VerInstallFile32A [VERSION.7]
947 DWORD WINAPI VerInstallFile32A(
948 UINT32 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
949 LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT32 *tmpfilelen )
951 LPCSTR pdest;
952 char destfn[260],tmpfn[260],srcfn[260];
953 HFILE32 hfsrc,hfdst;
954 DWORD attr,ret,xret,tmplast;
955 LPBYTE buf1,buf2;
956 OFSTRUCT ofs;
958 TRACE(ver,"(%x,%s,%s,%s,%s,%s,%p,%d)\n",
959 flags,srcfilename,destfilename,srcdir,destdir,curdir,tmpfile,*tmpfilelen
961 xret = 0;
962 sprintf(srcfn,"%s\\%s",srcdir,srcfilename);
963 if (!destdir || !*destdir) pdest = srcdir;
964 else pdest = destdir;
965 sprintf(destfn,"%s\\%s",pdest,destfilename);
966 hfsrc=LZOpenFile32A(srcfn,&ofs,OF_READ);
967 if (hfsrc==HFILE_ERROR32)
968 return VIF_CANNOTREADSRC;
969 sprintf(tmpfn,"%s\\%s",pdest,destfilename);
970 tmplast=strlen(pdest)+1;
971 attr = GetFileAttributes32A(tmpfn);
972 if (attr!=-1) {
973 if (attr & FILE_ATTRIBUTE_READONLY) {
974 LZClose32(hfsrc);
975 return VIF_WRITEPROT;
977 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
979 attr = -1;
980 if (flags & VIFF_FORCEINSTALL) {
981 if (tmpfile[0]) {
982 sprintf(tmpfn,"%s\\%s",pdest,tmpfile);
983 tmplast = strlen(pdest)+1;
984 attr = GetFileAttributes32A(tmpfn);
985 /* if it exists, it has been copied by the call before.
986 * we jump over the copy part...
990 if (attr == -1) {
991 char *s;
993 GetTempFileName32A(pdest,"ver",0,tmpfn); /* should not fail ... */
994 s=strrchr(tmpfn,'\\');
995 if (s)
996 tmplast = s-tmpfn;
997 else
998 tmplast = 0;
999 hfdst = OpenFile32(tmpfn,&ofs,OF_CREATE);
1000 if (hfdst == HFILE_ERROR32) {
1001 LZClose32(hfsrc);
1002 return VIF_CANNOTCREATE; /* | translated dos error */
1004 ret = LZCopy32(hfsrc,hfdst);
1005 _lclose32(hfdst);
1006 if (((long) ret) < 0) {
1007 /* translate LZ errors into VIF_xxx */
1008 switch (ret) {
1009 case LZERROR_BADINHANDLE:
1010 case LZERROR_READ:
1011 case LZERROR_BADVALUE:
1012 case LZERROR_UNKNOWNALG:
1013 ret = VIF_CANNOTREADSRC;
1014 break;
1015 case LZERROR_BADOUTHANDLE:
1016 case LZERROR_WRITE:
1017 ret = VIF_OUTOFMEMORY; /* FIXME: correct? */
1018 break;
1019 case LZERROR_GLOBALLOC:
1020 case LZERROR_GLOBLOCK:
1021 ret = VIF_OUTOFSPACE;
1022 break;
1023 default: /* unknown error, should not happen */
1024 ret = 0;
1025 break;
1027 if (ret) {
1028 LZClose32(hfsrc);
1029 return ret;
1033 xret = 0;
1034 if (!(flags & VIFF_FORCEINSTALL)) {
1035 VS_FIXEDFILEINFO *destvffi,*tmpvffi;
1036 buf1 = _fetch_versioninfo(destfn,&destvffi);
1037 if (buf1) {
1038 buf2 = _fetch_versioninfo(tmpfn,&tmpvffi);
1039 if (buf2) {
1040 char *tbuf1,*tbuf2;
1041 UINT32 len1,len2;
1043 len1=len2=40;
1045 /* compare file versions */
1046 if ((destvffi->dwFileVersionMS > tmpvffi->dwFileVersionMS)||
1047 ((destvffi->dwFileVersionMS==tmpvffi->dwFileVersionMS)&&
1048 (destvffi->dwFileVersionLS > tmpvffi->dwFileVersionLS)
1051 xret |= VIF_MISMATCH|VIF_SRCOLD;
1052 /* compare filetypes and filesubtypes */
1053 if ((destvffi->dwFileType!=tmpvffi->dwFileType) ||
1054 (destvffi->dwFileSubtype!=tmpvffi->dwFileSubtype)
1056 xret |= VIF_MISMATCH|VIF_DIFFTYPE;
1057 if (VerQueryValue32A(buf1,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf1,&len1) &&
1058 VerQueryValue32A(buf2,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf2,&len2)
1060 /* irgendwas mit tbuf1 und tbuf2 machen
1061 * generiert DIFFLANG|MISMATCH
1064 free(buf2);
1065 } else
1066 xret=VIF_MISMATCH|VIF_SRCOLD;
1067 free(buf1);
1070 if (xret) {
1071 if (*tmpfilelen<strlen(tmpfn+tmplast)) {
1072 xret|=VIF_BUFFTOOSMALL;
1073 DeleteFile32A(tmpfn);
1074 } else {
1075 strcpy(tmpfile,tmpfn+tmplast);
1076 *tmpfilelen = strlen(tmpfn+tmplast)+1;
1077 xret|=VIF_TEMPFILE;
1079 } else {
1080 if (-1!=GetFileAttributes32A(destfn))
1081 if (!DeleteFile32A(destfn)) {
1082 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETE;
1083 DeleteFile32A(tmpfn);
1084 LZClose32(hfsrc);
1085 return xret;
1087 if ((!(flags & VIFF_DONTDELETEOLD)) &&
1088 curdir &&
1089 *curdir &&
1090 lstrcmpi32A(curdir,pdest)
1092 char curfn[260];
1094 sprintf(curfn,"%s\\%s",curdir,destfilename);
1095 if (-1!=GetFileAttributes32A(curfn)) {
1096 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
1097 if (!DeleteFile32A(curfn))
1098 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR;
1101 if (!MoveFile32A(tmpfn,destfn)) {
1102 xret|=_error2vif(GetLastError())|VIF_CANNOTRENAME;
1103 DeleteFile32A(tmpfn);
1106 LZClose32(hfsrc);
1107 return xret;
1111 /* VerInstallFileW [VERSION.8] */
1112 DWORD WINAPI VerInstallFile32W(
1113 UINT32 flags,LPCWSTR srcfilename,LPCWSTR destfilename,LPCWSTR srcdir,
1114 LPCWSTR destdir,LPCWSTR curdir,LPWSTR tmpfile,UINT32 *tmpfilelen )
1116 LPSTR wsrcf,wsrcd,wdestf,wdestd,wtmpf,wcurd;
1117 DWORD ret;
1119 wsrcf = HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename );
1120 wsrcd = HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir );
1121 wdestf = HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename );
1122 wdestd = HEAP_strdupWtoA( GetProcessHeap(), 0, destdir );
1123 wtmpf = HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile );
1124 wcurd = HEAP_strdupWtoA( GetProcessHeap(), 0, curdir );
1125 ret = VerInstallFile32A(flags,wsrcf,wdestf,wsrcd,wdestd,wcurd,wtmpf,tmpfilelen);
1126 if (!ret)
1127 lstrcpynAtoW(tmpfile,wtmpf,*tmpfilelen);
1128 HeapFree( GetProcessHeap(), 0, wsrcf );
1129 HeapFree( GetProcessHeap(), 0, wsrcd );
1130 HeapFree( GetProcessHeap(), 0, wdestf );
1131 HeapFree( GetProcessHeap(), 0, wdestd );
1132 HeapFree( GetProcessHeap(), 0, wtmpf );
1133 if (wcurd)
1134 HeapFree( GetProcessHeap(), 0, wcurd );
1135 return ret;
1139 struct dbA {
1140 WORD nextoff;
1141 WORD datalen;
1142 /* in memory structure... */
1143 char name[1]; /* padded to dword alignment */
1144 /* ....
1145 char data[datalen]; padded to dword alignment
1146 BYTE subdirdata[]; until nextoff
1150 #define DATA_OFFSET_A(db) ((4+(strlen((db)->name)+4))&~3)
1152 struct dbW {
1153 WORD nextoff;
1154 WORD datalen;
1155 WORD btext; /* type of data */
1156 /* in memory structure... */
1157 WCHAR name[1]; /* padded to dword alignment */
1158 /* ....
1159 WCHAR data[datalen]; padded to dword alignment
1160 BYTE subdirdata[]; until nextoff
1164 /* WORD nextoffset;
1165 * WORD datalength;
1166 * WORD btype;
1167 * WCHAR szKey[]; (zero terminated)
1168 * PADDING (round up to nearest 32bit boundary)
1170 #define DATA_OFFSET_W(db) ((2+2+2+((lstrlen32W((db)->name)+1)*2+3))&~3)
1172 /* this one used for Win16 resources, which are always in ASCII format */
1173 static BYTE*
1174 _find_dataA(BYTE *block,LPCSTR str, int buff_remain) {
1175 char *nextslash;
1176 int substrlen, inc_size;
1177 struct dbA *db;
1179 while (*str && *str=='\\')
1180 str++;
1181 if (NULL!=(nextslash=strchr(str,'\\')))
1182 substrlen=nextslash-str;
1183 else
1184 substrlen=strlen(str);
1185 if (nextslash!=NULL) {
1186 while (*nextslash && *nextslash=='\\')
1187 nextslash++;
1188 if (!*nextslash)
1189 nextslash=NULL;
1190 } else if (*str == 0)
1191 return NULL;
1194 while (1) {
1195 db=(struct dbA*)block;
1196 TRACE(ver,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s\n",
1197 db,db->nextoff,db->datalen,db->name
1199 if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */
1200 return NULL;
1202 TRACE(ver,"comparing with %s\n",db->name);
1203 if (!lstrncmpi32A(db->name,str,substrlen)) {
1204 if (nextslash) {
1205 inc_size=DATA_OFFSET_A(db)+((db->datalen+3)&~3);
1206 return _find_dataA(block+inc_size,nextslash,
1207 db->nextoff-inc_size);
1208 } else
1209 return block;
1211 inc_size = ((db->nextoff+3)&~3);
1212 block += inc_size;
1213 buff_remain -= inc_size;
1217 /* this one used for Win32 resources, which are always in UNICODE format */
1218 extern LPWSTR __cdecl CRTDLL_wcschr(LPCWSTR str,WCHAR xchar);
1219 static BYTE*
1220 _find_dataW(BYTE *block,LPCWSTR str, int buff_remain) {
1221 LPWSTR nextslash;
1222 int substrlen, inc_size;
1223 struct dbW *db;
1226 while (*str && *str=='\\')
1227 str++;
1228 if (NULL!=(nextslash=CRTDLL_wcschr(str,'\\')))
1229 substrlen=nextslash-str;
1230 else
1231 substrlen=lstrlen32W(str);
1232 if (nextslash!=NULL) {
1233 while (*nextslash && *nextslash=='\\')
1234 nextslash++;
1235 if (!*nextslash)
1236 nextslash=NULL;
1237 } else if (*str == 0)
1238 return NULL;
1241 while (1) {
1242 char *xs,*vs;
1243 db=(struct dbW*)block;
1244 xs= HEAP_strdupWtoA(GetProcessHeap(),0,db->name);
1245 if (db->datalen) {
1246 if (db->btext)
1247 vs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)((block+DATA_OFFSET_W(db))));
1248 else
1249 vs = HEAP_strdupA(GetProcessHeap(),0,"not a string");
1250 } else
1251 vs = HEAP_strdupA(GetProcessHeap(),0,"no data");
1253 TRACE(ver,"db->nextoff=%d,db->name=%s,db->data=\"%s\"\n",
1254 db->nextoff,xs,vs
1256 HeapFree(GetProcessHeap(),0,vs);
1257 HeapFree(GetProcessHeap(),0,xs);
1258 if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */
1259 return NULL;
1261 if (!lstrncmpi32W(db->name,str,substrlen)) {
1262 if (nextslash) {
1263 /* DATA_OFFSET_W(db) (padded to 32bit already)
1264 * DATA[datalength]
1265 * PADDING (round up to nearest 32bit boundary)
1266 * --> next level structs
1268 inc_size=DATA_OFFSET_W(db)+((db->datalen+3)&~3);
1269 return _find_dataW( block+inc_size ,nextslash,
1270 db->nextoff-inc_size);
1271 } else
1272 return block;
1274 /* skip over this block, round up to nearest 32bit boundary */
1275 inc_size = ((db->nextoff+3)&~3);
1276 block += inc_size;
1277 buff_remain -= inc_size;
1281 /* VerQueryValue [VER.11] */
1282 /* take care, 'buffer' is NOT a SEGPTR, it just points to one */
1283 DWORD WINAPI VerQueryValue16(SEGPTR segblock,LPCSTR subblock,SEGPTR *buffer,
1284 UINT16 *buflen)
1286 LPSTR s;
1287 BYTE *block=PTR_SEG_TO_LIN(segblock),*b;
1289 TRACE(ver,"(%p,%s,%p,%d)\n",
1290 block,subblock,buffer,*buflen
1293 s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1);
1294 strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock);
1295 /* check for UNICODE version */
1296 if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) &&
1297 (*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE)
1299 struct dbW *db;
1300 LPWSTR wstr;
1301 LPSTR xs;
1303 wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s);
1304 b=_find_dataW(block,wstr,*(WORD*)block);
1305 HeapFree(GetProcessHeap(),0,wstr);
1306 if (!b) {
1307 WARN(ver,"key %s not found in versionresource.\n",s);
1308 *buflen=0;
1309 free (s);
1310 return 0;
1312 db=(struct dbW*)b;
1313 b = b+DATA_OFFSET_W(db);
1314 *buflen = db->datalen;
1315 if (db->btext) {
1316 xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
1317 TRACE(ver,"->%s\n",xs);
1318 HeapFree(GetProcessHeap(),0,xs);
1319 } else
1320 TRACE(ver,"->%p\n",b);
1321 } else {
1322 struct dbA *db;
1323 b=_find_dataA(block,s,*(WORD*)block);
1324 if (!b) {
1325 WARN(ver,"key %s not found in versionresource.\n",s);
1326 *buflen=0;
1327 free (s);
1328 return 0;
1330 db=(struct dbA*)b;
1331 b = b+DATA_OFFSET_A(db);
1332 *buflen = db->datalen;
1333 /* the string is only printable, if it is below \\StringFileInfo*/
1334 if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
1335 TRACE(ver," -> %s=%s\n",subblock,b);
1336 else
1337 TRACE(ver," -> %s=%p\n",subblock,b);
1339 *buffer = (b-block)+segblock;
1340 free(s);
1341 return 1;
1344 DWORD WINAPI VerQueryValue32A(LPVOID vblock,LPCSTR subblock,
1345 LPVOID *vbuffer,UINT32 *buflen)
1347 BYTE *b,*block=(LPBYTE)vblock,**buffer=(LPBYTE*)vbuffer;
1348 LPSTR s;
1350 TRACE(ver,"(%p,%s,%p,%d)\n",
1351 block,subblock,buffer,*buflen
1354 s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1);
1355 strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock);
1357 /* check for UNICODE version */
1358 if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) &&
1359 (*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE)
1361 LPWSTR wstr;
1362 LPSTR xs;
1363 struct dbW *db;
1365 wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s);
1366 b=_find_dataW(block,wstr,*(WORD*)block);
1367 HeapFree(GetProcessHeap(),0,wstr);
1368 if (!b) {
1369 WARN(ver,"key %s not found in versionresource.\n",s);
1370 *buflen=0;
1371 free (s);
1372 return 0;
1374 db = (struct dbW*)b;
1375 *buflen = db->datalen;
1376 b = b+DATA_OFFSET_W(db);
1377 if (db->btext) {
1378 xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
1379 TRACE(ver,"->%s\n",xs);
1380 HeapFree(GetProcessHeap(),0,xs);
1381 } else
1382 TRACE(ver,"->%p\n",b);
1383 /* This is a leak. */
1384 b = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
1385 } else {
1386 struct dbA *db;
1387 b=_find_dataA(block,s,*(WORD*)block);
1388 if (!b) {
1389 WARN(ver,"key %s not found in versionresource.\n",subblock);
1390 *buflen=0;
1391 free (s);
1392 return 0;
1394 db=(struct dbA*)b;
1395 *buflen = db->datalen;
1396 b = b+DATA_OFFSET_A(db);
1398 /* the string is only printable, if it is below \\StringFileInfo*/
1399 if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
1400 TRACE(ver," -> %s=%s\n",subblock,b);
1401 else
1402 TRACE(ver," -> %s=%p\n",subblock,b);
1404 *buffer = b;
1405 free(s);
1406 return 1;
1409 DWORD WINAPI VerQueryValue32W(LPVOID vblock,LPCWSTR subblock,LPVOID *vbuffer,
1410 UINT32 *buflen)
1412 LPSTR sb;
1413 DWORD ret;
1415 sb = HEAP_strdupWtoA( GetProcessHeap(), 0, subblock );
1416 ret = VerQueryValue32A(vblock,sb,vbuffer,buflen);
1417 HeapFree( GetProcessHeap(), 0, sb );
1418 return 1;
1420 /* 20 GETFILEVERSIONINFORAW */