Use the correct rectangle for ETO_OPAQUE - spotted by James Hawkins.
[wine] / dlls / version / info.c
1 /*
2  * Implementation of VERSION.DLL - Version Info access
3  *
4  * Copyright 1996,1997 Marcus Meissner
5  * Copyright 1997 David Cuthbert
6  * Copyright 1999 Ulrich Weigand
7  * Copyright 2005 Paul Vriens
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winreg.h"
32 #include "winver.h"
33 #include "winternl.h"
34 #include "wine/winuser16.h"
35 #include "wine/unicode.h"
36 #include "winerror.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ver);
40
41 /******************************************************************************
42  *
43  *   This function will print via standard TRACE, debug info regarding
44  *   the file info structure vffi.
45  *      15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
46  *      Added this function to clean up the code.
47  *
48  *****************************************************************************/
49 static void print_vffi_debug(VS_FIXEDFILEINFO *vffi)
50 {
51     TRACE("structversion=%u.%u, fileversion=%u.%u.%u.%u, productversion=%u.%u.%u.%u, flagmask=0x%lx, flags=%s%s%s%s%s%s\n",
52           HIWORD(vffi->dwStrucVersion),LOWORD(vffi->dwStrucVersion),
53           HIWORD(vffi->dwFileVersionMS),LOWORD(vffi->dwFileVersionMS),
54           HIWORD(vffi->dwFileVersionLS),LOWORD(vffi->dwFileVersionLS),
55           HIWORD(vffi->dwProductVersionMS),LOWORD(vffi->dwProductVersionMS),
56           HIWORD(vffi->dwProductVersionLS),LOWORD(vffi->dwProductVersionLS),
57           vffi->dwFileFlagsMask,
58           (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "",
59           (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "",
60           (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "",
61           (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "",
62           (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "",
63           (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : "");
64
65     TRACE("(");
66
67     TRACE("OS=0x%x.0x%x ", HIWORD(vffi->dwFileOS), LOWORD(vffi->dwFileOS));
68
69     switch (vffi->dwFileOS&0xFFFF0000)
70     {
71     case VOS_DOS:TRACE("DOS,");break;
72     case VOS_OS216:TRACE("OS/2-16,");break;
73     case VOS_OS232:TRACE("OS/2-32,");break;
74     case VOS_NT:TRACE("NT,");break;
75     case VOS_UNKNOWN:
76     default:
77         TRACE("UNKNOWN(0x%lx),",vffi->dwFileOS&0xFFFF0000);break;
78     }
79
80     switch (LOWORD(vffi->dwFileOS))
81     {
82     case VOS__BASE:TRACE("BASE");break;
83     case VOS__WINDOWS16:TRACE("WIN16");break;
84     case VOS__WINDOWS32:TRACE("WIN32");break;
85     case VOS__PM16:TRACE("PM16");break;
86     case VOS__PM32:TRACE("PM32");break;
87     default:
88         TRACE("UNKNOWN(0x%x)",LOWORD(vffi->dwFileOS));break;
89     }
90
91     TRACE(")\n");
92
93     switch (vffi->dwFileType)
94     {
95     case VFT_APP:TRACE("filetype=APP");break;
96     case VFT_DLL:TRACE("filetype=DLL");break;
97     case VFT_DRV:
98         TRACE("filetype=DRV,");
99         switch(vffi->dwFileSubtype)
100         {
101         case VFT2_DRV_PRINTER:TRACE("PRINTER");break;
102         case VFT2_DRV_KEYBOARD:TRACE("KEYBOARD");break;
103         case VFT2_DRV_LANGUAGE:TRACE("LANGUAGE");break;
104         case VFT2_DRV_DISPLAY:TRACE("DISPLAY");break;
105         case VFT2_DRV_MOUSE:TRACE("MOUSE");break;
106         case VFT2_DRV_NETWORK:TRACE("NETWORK");break;
107         case VFT2_DRV_SYSTEM:TRACE("SYSTEM");break;
108         case VFT2_DRV_INSTALLABLE:TRACE("INSTALLABLE");break;
109         case VFT2_DRV_SOUND:TRACE("SOUND");break;
110         case VFT2_DRV_COMM:TRACE("COMM");break;
111         case VFT2_DRV_INPUTMETHOD:TRACE("INPUTMETHOD");break;
112         case VFT2_UNKNOWN:
113         default:
114             TRACE("UNKNOWN(0x%lx)",vffi->dwFileSubtype);break;
115         }
116         break;
117     case VFT_FONT:
118         TRACE("filetype=FONT,");
119         switch (vffi->dwFileSubtype)
120         {
121         case VFT2_FONT_RASTER:TRACE("RASTER");break;
122         case VFT2_FONT_VECTOR:TRACE("VECTOR");break;
123         case VFT2_FONT_TRUETYPE:TRACE("TRUETYPE");break;
124         default:TRACE("UNKNOWN(0x%lx)",vffi->dwFileSubtype);break;
125         }
126         break;
127     case VFT_VXD:TRACE("filetype=VXD");break;
128     case VFT_STATIC_LIB:TRACE("filetype=STATIC_LIB");break;
129     case VFT_UNKNOWN:
130     default:
131         TRACE("filetype=Unknown(0x%lx)",vffi->dwFileType);break;
132     }
133
134     TRACE("\n");
135     TRACE("filedate=0x%lx.0x%lx\n",vffi->dwFileDateMS,vffi->dwFileDateLS);
136 }
137
138 /***********************************************************************
139  * Version Info Structure
140  */
141
142 typedef struct
143 {
144     WORD  wLength;
145     WORD  wValueLength;
146     CHAR  szKey[1];
147 #if 0   /* variable length structure */
148     /* DWORD aligned */
149     BYTE  Value[];
150     /* DWORD aligned */
151     VS_VERSION_INFO_STRUCT16 Children[];
152 #endif
153 } VS_VERSION_INFO_STRUCT16;
154
155 typedef struct
156 {
157     WORD  wLength;
158     WORD  wValueLength;
159     WORD  wType;
160     WCHAR szKey[1];
161 #if 0   /* variable length structure */
162     /* DWORD aligned */
163     BYTE  Value[];
164     /* DWORD aligned */
165     VS_VERSION_INFO_STRUCT32 Children[];
166 #endif
167 } VS_VERSION_INFO_STRUCT32;
168
169 #define VersionInfoIs16( ver ) \
170     ( ((VS_VERSION_INFO_STRUCT16 *)ver)->szKey[0] >= ' ' )
171
172 #define DWORD_ALIGN( base, ptr ) \
173     ( (LPBYTE)(base) + ((((LPBYTE)(ptr) - (LPBYTE)(base)) + 3) & ~3) )
174
175 #define VersionInfo16_Value( ver )  \
176     DWORD_ALIGN( (ver), (ver)->szKey + strlen((ver)->szKey) + 1 )
177 #define VersionInfo32_Value( ver )  \
178     DWORD_ALIGN( (ver), (ver)->szKey + strlenW((ver)->szKey) + 1 )
179
180 #define VersionInfo16_Children( ver )  \
181     (VS_VERSION_INFO_STRUCT16 *)( VersionInfo16_Value( ver ) + \
182                            ( ( (ver)->wValueLength + 3 ) & ~3 ) )
183 #define VersionInfo32_Children( ver )  \
184     (VS_VERSION_INFO_STRUCT32 *)( VersionInfo32_Value( ver ) + \
185                            ( ( (ver)->wValueLength * \
186                                ((ver)->wType? 2 : 1) + 3 ) & ~3 ) )
187
188 #define VersionInfo16_Next( ver ) \
189     (VS_VERSION_INFO_STRUCT16 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
190 #define VersionInfo32_Next( ver ) \
191     (VS_VERSION_INFO_STRUCT32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
192
193 /***********************************************************************
194  *           VERSION_GetFileVersionInfo_PE             [internal]
195  *
196  *    NOTE: returns size of the PE VERSION resource or 0xFFFFFFFF
197  *    in the case the file is a PE module, but VERSION_INFO not found.
198  */
199 static DWORD VERSION_GetFileVersionInfo_PE( LPCWSTR filename, DWORD datasize, LPVOID data )
200 {
201     VS_FIXEDFILEINFO *vffi;
202     DWORD len;
203     BYTE *buf;
204     HMODULE hModule;
205     HRSRC hRsrc;
206     HGLOBAL hMem;
207
208     TRACE("%s\n", debugstr_w(filename));
209
210     hModule = GetModuleHandleW(filename);
211     if(!hModule)
212         hModule = LoadLibraryExW(filename, 0, LOAD_LIBRARY_AS_DATAFILE);
213     else
214         hModule = LoadLibraryExW(filename, 0, 0);
215     if(!hModule)
216     {
217         WARN("Could not load %s\n", debugstr_w(filename));
218         return 0;
219     }
220     hRsrc = FindResourceW(hModule,
221                           MAKEINTRESOURCEW(VS_VERSION_INFO),
222                           MAKEINTRESOURCEW(VS_FILE_INFO));
223     if(!hRsrc)
224     {
225         WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_w(filename));
226         FreeLibrary(hModule);
227         return 0xFFFFFFFF;
228     }
229     len = SizeofResource(hModule, hRsrc);
230     hMem = LoadResource(hModule, hRsrc);
231     if(!hMem)
232     {
233         WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_w(filename));
234         FreeLibrary(hModule);
235         return 0xFFFFFFFF;
236     }
237     buf = LockResource(hMem);
238
239     vffi = (VS_FIXEDFILEINFO *)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32 *)buf );
240
241     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
242     {
243         WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
244                    vffi->dwSignature, VS_FFI_SIGNATURE );
245         len = 0xFFFFFFFF;
246         goto END;
247     }
248
249     if ( TRACE_ON(ver) )
250         print_vffi_debug( vffi );
251
252     if(data)
253     {
254         if(datasize < len)
255             len = datasize; /* truncate data */
256         if(len)
257             memcpy(data, buf, len);
258         else
259             len = 0xFFFFFFFF;
260     }
261 END:
262     FreeResource(hMem);
263     FreeLibrary(hModule);
264
265     return len;
266 }
267
268 /***********************************************************************
269  *           VERSION_GetFileVersionInfo_16             [internal]
270  *
271  *    NOTE: returns size of the 16-bit VERSION resource or 0xFFFFFFFF
272  *    in the case the file exists, but VERSION_INFO not found.
273  */
274 static DWORD VERSION_GetFileVersionInfo_16( LPCSTR filename, DWORD datasize, LPVOID data )
275 {
276     VS_FIXEDFILEINFO *vffi;
277     DWORD len, offset;
278     BYTE *buf;
279     HMODULE16 hModule;
280     HRSRC16 hRsrc;
281     HGLOBAL16 hMem;
282     char dllname[20], owner[20], *p;
283     const char *basename;
284     BOOL is_builtin = FALSE;
285
286     TRACE("%s\n", debugstr_a(filename));
287
288     /* strip path information */
289
290     basename = filename;
291     if (basename[0] && basename[1] == ':') basename += 2;  /* strip drive specification */
292     if ((p = strrchr( basename, '\\' ))) basename = p + 1;
293     if ((p = strrchr( basename, '/' ))) basename = p + 1;
294
295     if (strlen(basename) < sizeof(dllname)-4)
296     {
297         int file_exists;
298
299         strcpy( dllname, basename );
300         p = strrchr( dllname, '.' );
301         if (!p) strcat( dllname, ".dll" );
302         for (p = dllname; *p; p++) if (*p >= 'A' && *p <= 'Z') *p += 32;
303
304         if (wine_dll_get_owner( dllname, owner, sizeof(owner), &file_exists ) == 0)
305             is_builtin = TRUE;
306     }
307
308     /* first try without loading a 16-bit module */
309     if (is_builtin)
310         len = 0;
311     else
312         len = GetFileResourceSize16( filename,
313                                      MAKEINTRESOURCEA(VS_FILE_INFO),
314                                      MAKEINTRESOURCEA(VS_VERSION_INFO),
315                                      &offset );
316     if (len)
317     {
318         if (!data) return len;
319
320         len = GetFileResource16( filename,
321                                  MAKEINTRESOURCEA(VS_FILE_INFO),
322                                  MAKEINTRESOURCEA(VS_VERSION_INFO),
323                                  offset, datasize, data );
324         if (len)
325         {
326             vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)data );
327
328             if ( vffi->dwSignature == VS_FFI_SIGNATURE )
329             {
330                 if ( ((VS_VERSION_INFO_STRUCT16 *)data)->wLength < len )
331                     len = ((VS_VERSION_INFO_STRUCT16 *)data)->wLength;
332
333                 if ( TRACE_ON(ver) )
334                     print_vffi_debug( vffi );
335
336                 return len;
337             }
338         }
339     }
340
341     /* this might be a builtin 16-bit module */
342     hModule = LoadLibrary16(filename);
343     if(hModule < 32)
344     {
345         WARN("Could not load %s\n", debugstr_a(filename));
346         return 0;
347     }
348     hRsrc = FindResource16(hModule,
349                           MAKEINTRESOURCEA(VS_VERSION_INFO),
350                           MAKEINTRESOURCEA(VS_FILE_INFO));
351     if(!hRsrc)
352     {
353         WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_a(filename));
354         FreeLibrary16(hModule);
355         return 0xFFFFFFFF;
356     }
357     len = SizeofResource16(hModule, hRsrc);
358     hMem = LoadResource16(hModule, hRsrc);
359     if(!hMem)
360     {
361         WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_a(filename));
362         FreeLibrary16(hModule);
363         return 0xFFFFFFFF;
364     }
365     buf = LockResource16(hMem);
366
367     if(!VersionInfoIs16(buf))
368     {
369         len = 0xFFFFFFFF;
370         goto END;
371     }
372
373     vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
374
375     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
376     {
377         WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
378                    vffi->dwSignature, VS_FFI_SIGNATURE );
379         len = 0xFFFFFFFF;
380         goto END;
381     }
382
383     if ( TRACE_ON(ver) )
384         print_vffi_debug( vffi );
385
386     if(data)
387     {
388         if(datasize < len)
389             len = datasize; /* truncate data */
390         if(len)
391             memcpy(data, buf, len);
392         else
393             len = 0xFFFFFFFF;
394     }
395 END:
396     FreeResource16(hMem);
397     FreeLibrary16(hModule);
398
399     return len;
400 }
401
402 /***********************************************************************
403  *           GetFileVersionInfoSizeW         [VERSION.@]
404  */
405 DWORD WINAPI GetFileVersionInfoSizeW( LPCWSTR filename, LPDWORD handle )
406 {
407     DWORD len;
408
409     TRACE("(%s,%p)\n", debugstr_w(filename), handle );
410
411     if (handle) *handle = 0;
412
413     if (!filename)
414     {
415         SetLastError(ERROR_INVALID_PARAMETER);
416         return 0;
417     }
418     if (!*filename)
419     {
420         SetLastError(ERROR_BAD_PATHNAME);
421         return 0;
422     }
423
424     len = VERSION_GetFileVersionInfo_PE(filename, 0, NULL);
425     /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
426     if(len == 0xFFFFFFFF)
427     {
428         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
429         return 0;
430     }
431
432     if (!len)
433     {
434         LPSTR filenameA;
435
436         len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
437         filenameA = HeapAlloc( GetProcessHeap(), 0, len );
438         WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
439
440         len = VERSION_GetFileVersionInfo_16(filenameA, 0, NULL);
441         HeapFree( GetProcessHeap(), 0, filenameA );
442         /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
443         if (!len)
444         {
445             SetLastError(ERROR_FILE_NOT_FOUND);
446             return 0;
447         }
448         if (len == 0xFFFFFFFF)
449         {
450             SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
451             return 0;
452         }
453     }
454
455     SetLastError(0);
456     return len;
457 }
458
459 /***********************************************************************
460  *           GetFileVersionInfoSizeA         [VERSION.@]
461  */
462 DWORD WINAPI GetFileVersionInfoSizeA( LPCSTR filename, LPDWORD handle )
463 {
464     UNICODE_STRING filenameW;
465     DWORD retval;
466
467     TRACE("(%s,%p)\n", debugstr_a(filename), handle );
468
469     if(filename)
470         RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
471     else
472         filenameW.Buffer = NULL;
473
474     retval = GetFileVersionInfoSizeW(filenameW.Buffer, handle);
475
476     RtlFreeUnicodeString(&filenameW);
477
478     return retval;
479 }
480
481 /***********************************************************************
482  *           GetFileVersionInfoW             [VERSION.@]
483  */
484 BOOL WINAPI GetFileVersionInfoW( LPCWSTR filename, DWORD handle,
485                                     DWORD datasize, LPVOID data )
486 {
487     DWORD len;
488
489     TRACE("(%s,%ld,size=%ld,data=%p)\n",
490                 debugstr_w(filename), handle, datasize, data );
491
492     if (!data)
493     {
494         SetLastError(ERROR_INVALID_DATA);
495         return FALSE;
496     }
497     len = VERSION_GetFileVersionInfo_PE(filename, datasize, data);
498     /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
499     if (len == 0xFFFFFFFF)
500     {
501         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
502         return FALSE;
503     }
504
505     if (!len)
506     {
507         LPSTR filenameA;
508
509         len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
510         filenameA = HeapAlloc( GetProcessHeap(), 0, len );
511         WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
512
513         len = VERSION_GetFileVersionInfo_16(filenameA, datasize, data);
514         HeapFree( GetProcessHeap(), 0, filenameA );
515         /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
516         if (!len || len == 0xFFFFFFFF)
517         {
518             SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
519             return FALSE;
520         }
521     }
522
523     /* If we end up here we have found either 16bit or 32bit
524      * version information
525      */
526
527     SetLastError(0);
528     return TRUE;
529 }
530
531 /***********************************************************************
532  *           GetFileVersionInfoA             [VERSION.@]
533  */
534 BOOL WINAPI GetFileVersionInfoA( LPCSTR filename, DWORD handle,
535                                     DWORD datasize, LPVOID data )
536 {
537     UNICODE_STRING filenameW;
538     BOOL retval;
539
540     TRACE("(%s,%ld,size=%ld,data=%p)\n",
541                 debugstr_a(filename), handle, datasize, data );
542
543     if(filename)
544         RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
545     else
546         filenameW.Buffer = NULL;
547
548     retval = GetFileVersionInfoW(filenameW.Buffer, handle, datasize, data);
549
550     RtlFreeUnicodeString(&filenameW);
551
552     return retval;
553 }
554
555 /***********************************************************************
556  *           VersionInfo16_FindChild             [internal]
557  */
558 static VS_VERSION_INFO_STRUCT16 *VersionInfo16_FindChild( VS_VERSION_INFO_STRUCT16 *info,
559                                             LPCSTR szKey, UINT cbKey )
560 {
561     VS_VERSION_INFO_STRUCT16 *child = VersionInfo16_Children( info );
562
563     while ( (DWORD)child < (DWORD)info + info->wLength )
564     {
565         if ( !strncasecmp( child->szKey, szKey, cbKey ) )
566             return child;
567
568         if (!(child->wLength)) return NULL;
569         child = VersionInfo16_Next( child );
570     }
571
572     return NULL;
573 }
574
575 /***********************************************************************
576  *           VersionInfo32_FindChild             [internal]
577  */
578 static VS_VERSION_INFO_STRUCT32 *VersionInfo32_FindChild( VS_VERSION_INFO_STRUCT32 *info,
579                                             LPCWSTR szKey, UINT cbKey )
580 {
581     VS_VERSION_INFO_STRUCT32 *child = VersionInfo32_Children( info );
582
583     while ( (DWORD)child < (DWORD)info + info->wLength )
584     {
585         if ( !strncmpiW( child->szKey, szKey, cbKey ) )
586             return child;
587
588         child = VersionInfo32_Next( child );
589     }
590
591     return NULL;
592 }
593
594 /***********************************************************************
595  *           VersionInfo16_QueryValue              [internal]
596  *
597  *    Gets a value from a 16-bit NE resource
598  */
599 static BOOL WINAPI VersionInfo16_QueryValue( VS_VERSION_INFO_STRUCT16 *info, LPCSTR lpSubBlock,
600                                LPVOID *lplpBuffer, UINT *puLen )
601 {
602     while ( *lpSubBlock )
603     {
604         /* Find next path component */
605         LPCSTR lpNextSlash;
606         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
607             if ( *lpNextSlash == '\\' )
608                 break;
609
610         /* Skip empty components */
611         if ( lpNextSlash == lpSubBlock )
612         {
613             lpSubBlock++;
614             continue;
615         }
616
617         /* We have a non-empty component: search info for key */
618         info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
619         if ( !info ) return FALSE;
620
621         /* Skip path component */
622         lpSubBlock = lpNextSlash;
623     }
624
625     /* Return value */
626     *lplpBuffer = VersionInfo16_Value( info );
627     if (puLen)
628         *puLen = info->wValueLength;
629
630     return TRUE;
631 }
632
633 /***********************************************************************
634  *           VersionInfo32_QueryValue              [internal]
635  *
636  *    Gets a value from a 32-bit PE resource
637  */
638 static BOOL WINAPI VersionInfo32_QueryValue( VS_VERSION_INFO_STRUCT32 *info, LPCWSTR lpSubBlock,
639                                LPVOID *lplpBuffer, UINT *puLen )
640 {
641     TRACE("lpSubBlock : (%s)\n", debugstr_w(lpSubBlock));
642
643     while ( *lpSubBlock )
644     {
645         /* Find next path component */
646         LPCWSTR lpNextSlash;
647         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
648             if ( *lpNextSlash == '\\' )
649                 break;
650
651         /* Skip empty components */
652         if ( lpNextSlash == lpSubBlock )
653         {
654             lpSubBlock++;
655             continue;
656         }
657
658         /* We have a non-empty component: search info for key */
659         info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
660         if ( !info ) return FALSE;
661
662         /* Skip path component */
663         lpSubBlock = lpNextSlash;
664     }
665
666     /* Return value */
667     *lplpBuffer = VersionInfo32_Value( info );
668     if (puLen)
669         *puLen = info->wValueLength;
670
671     return TRUE;
672 }
673
674 /***********************************************************************
675  *           VerQueryValueA              [VERSION.@]
676  */
677 BOOL WINAPI VerQueryValueA( LPVOID pBlock, LPCSTR lpSubBlock,
678                                LPVOID *lplpBuffer, UINT *puLen )
679 {
680     static const char rootA[] = "\\";
681     static const char varfileinfoA[] = "\\VarFileInfo\\Translation";
682     VS_VERSION_INFO_STRUCT16 *info = (VS_VERSION_INFO_STRUCT16 *)pBlock;
683
684     TRACE("(%p,%s,%p,%p)\n",
685                 pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen );
686
687     if ( !VersionInfoIs16( info ) )
688     {
689         BOOL ret;
690         INT len;
691         LPWSTR lpSubBlockW;
692
693         len  = MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, NULL, 0);
694         lpSubBlockW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
695
696         if (!lpSubBlockW)
697             return FALSE;
698
699         MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, lpSubBlockW, len);
700
701         ret = VersionInfo32_QueryValue(pBlock, lpSubBlockW, lplpBuffer, puLen);
702
703         HeapFree(GetProcessHeap(), 0, lpSubBlockW);
704
705         if (ret && strcasecmp( lpSubBlock, rootA ) && strcasecmp( lpSubBlock, varfileinfoA ))
706         {
707             LPSTR lplpBufferA;
708
709             len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)*lplpBuffer, -1, NULL, 0, NULL, NULL);
710             lplpBufferA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
711
712             if (!lplpBufferA)
713                 return FALSE;
714
715             WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)*lplpBuffer, -1, lplpBufferA, len, NULL, NULL);
716
717             memcpy(*lplpBuffer, lplpBufferA, len);
718             *puLen = len;
719
720             HeapFree(GetProcessHeap(), 0, lplpBufferA);
721         }
722         return ret;
723     }
724
725     return VersionInfo16_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
726 }
727
728 /***********************************************************************
729  *           VerQueryValueW              [VERSION.@]
730  */
731 BOOL WINAPI VerQueryValueW( LPVOID pBlock, LPCWSTR lpSubBlock,
732                                LPVOID *lplpBuffer, UINT *puLen )
733 {
734     static const WCHAR rootW[] = { '\\', 0 };
735     static const WCHAR varfileinfoW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
736                                           '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
737
738     VS_VERSION_INFO_STRUCT32 *info = (VS_VERSION_INFO_STRUCT32 *)pBlock;
739
740     TRACE("(%p,%s,%p,%p)\n",
741                 pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen );
742
743     if ( VersionInfoIs16( info ) )
744     {
745         BOOL ret;
746         int len;
747         LPSTR lpSubBlockA;
748
749         len = WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, NULL, 0, NULL, NULL);
750         lpSubBlockA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
751
752         if (!lpSubBlockA)
753             return FALSE;
754
755         WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, lpSubBlockA, len, NULL, NULL);
756
757         ret = VersionInfo16_QueryValue(pBlock, lpSubBlockA, lplpBuffer, puLen);
758
759         HeapFree(GetProcessHeap(), 0, lpSubBlockA);
760
761         if (ret && strcmpiW( lpSubBlock, rootW ) && strcmpiW( lpSubBlock, varfileinfoW ))
762         {
763             LPWSTR lplpBufferW;
764
765             len  = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*lplpBuffer, -1, NULL, 0);
766             lplpBufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
767
768             if (!lplpBufferW)
769                 return FALSE;
770
771             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*lplpBuffer, -1, lplpBufferW, len);
772
773             memcpy(*lplpBuffer, lplpBufferW, len * sizeof(WCHAR));
774             *puLen = len;
775
776             HeapFree(GetProcessHeap(), 0, lplpBufferW);
777         }
778         return ret;
779     }
780
781     return VersionInfo32_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
782 }