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