2 * Copyright 2011 André Hentschel
3 * Copyright 2013 Mislav Bla\9eevic
4 * Copyright 2015 Mark Jansen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define WIN32_NO_STATUS
29 #include "wine/unicode.h"
31 #define NUM_ATTRIBUTES 28
32 enum APPHELP_MODULETYPE
41 static void WINAPI
SdbpSetDWORDAttr(PATTRINFO attr
, TAG tag
, DWORD value
)
44 attr
->flags
= ATTRIBUTE_AVAILABLE
;
48 static void WINAPI
SdbpSetQWORDAttr(PATTRINFO attr
, TAG tag
, QWORD value
)
51 attr
->flags
= ATTRIBUTE_AVAILABLE
;
55 static void WINAPI
SdbpSetStringAttr(PATTRINFO attr
, TAG tag
, WCHAR
*string
)
59 attr
->flags
= ATTRIBUTE_FAILED
;
64 attr
->flags
= ATTRIBUTE_AVAILABLE
;
65 attr
->lpattr
= SdbpStrDup(string
);
68 static void WINAPI
SdbpSetAttrFail(PATTRINFO attr
)
70 attr
->flags
= ATTRIBUTE_FAILED
;
73 static WCHAR
* WINAPI
SdbpGetStringAttr(LPWSTR translation
, LPCWSTR attr
, PVOID file_info
)
77 WCHAR value
[128] = {0};
82 snprintfW(value
, 128, translation
, attr
);
83 if (VerQueryValueW(file_info
, value
, &buffer
, &size
) && size
!= 0)
84 return (WCHAR
*)buffer
;
89 static void WINAPI
SdbpSetStringAttrFromAnsiString(PATTRINFO attr
, TAG tag
, PBYTE string
, BYTE len
)
94 attr
->flags
= ATTRIBUTE_FAILED
;
99 attr
->flags
= ATTRIBUTE_AVAILABLE
;
100 dest
= attr
->lpattr
= SdbpAlloc((len
+1) * sizeof(WCHAR
));
102 *(dest
++) = *(string
++);
106 static void WINAPI
SdbpSetStringAttrFromPascalString(PATTRINFO attr
, TAG tag
, PBYTE string
)
110 attr
->flags
= ATTRIBUTE_FAILED
;
114 SdbpSetStringAttrFromAnsiString(attr
, tag
, string
+ 1, *string
);
117 static void SdbpReadFileVersion(PATTRINFO attr_info
, PVOID file_info
)
119 static const WCHAR str_root
[] = {'\\',0};
121 VS_FIXEDFILEINFO
* fixed_info
;
123 if (file_info
&& VerQueryValueW(file_info
, str_root
, (LPVOID
*)&fixed_info
, &size
) && size
)
125 if (fixed_info
->dwSignature
== VS_FFI_SIGNATURE
)
127 LARGE_INTEGER version
;
128 version
.HighPart
= fixed_info
->dwFileVersionMS
;
129 version
.LowPart
= fixed_info
->dwFileVersionLS
;
130 SdbpSetQWORDAttr(&attr_info
[2], TAG_BIN_FILE_VERSION
, version
.QuadPart
);
131 SdbpSetQWORDAttr(&attr_info
[21], TAG_UPTO_BIN_FILE_VERSION
, version
.QuadPart
);
132 version
.HighPart
= fixed_info
->dwProductVersionMS
;
133 version
.LowPart
= fixed_info
->dwProductVersionLS
;
134 SdbpSetQWORDAttr(&attr_info
[3], TAG_BIN_PRODUCT_VERSION
, version
.QuadPart
);
135 SdbpSetQWORDAttr(&attr_info
[22], TAG_UPTO_BIN_PRODUCT_VERSION
, version
.QuadPart
);
137 SdbpSetDWORDAttr(&attr_info
[12], TAG_VERDATEHI
, fixed_info
->dwFileDateMS
);
138 SdbpSetDWORDAttr(&attr_info
[13], TAG_VERDATELO
, fixed_info
->dwFileDateLS
);
139 SdbpSetDWORDAttr(&attr_info
[14], TAG_VERFILEOS
, fixed_info
->dwFileOS
); /* 0x000, 0x4, 0x40004, 0x40000, 0x10004, 0x10001*/
140 SdbpSetDWORDAttr(&attr_info
[15], TAG_VERFILETYPE
, fixed_info
->dwFileType
); /* VFT_APP, VFT_DLL, .... */
145 SdbpSetAttrFail(&attr_info
[2]);
146 SdbpSetAttrFail(&attr_info
[3]);
147 SdbpSetAttrFail(&attr_info
[12]);
148 SdbpSetAttrFail(&attr_info
[13]);
149 SdbpSetAttrFail(&attr_info
[14]);
150 SdbpSetAttrFail(&attr_info
[15]);
151 SdbpSetAttrFail(&attr_info
[21]);
152 SdbpSetAttrFail(&attr_info
[22]);
155 static DWORD WINAPI
SdbpCalculateFileChecksum(PMEMMAPPED mapping
)
159 DWORD checks
= 0, carry
= 0;
161 if (mapping
->size
< 4)
164 if (mapping
->size
>= 0x1000)
167 if (mapping
->size
< 0x1200)
168 data
= (PDWORD
)(mapping
->view
+ mapping
->size
- size
);
170 data
= (PDWORD
)mapping
->view
+ (0x200 / 4);
174 data
= (PDWORD
)mapping
->view
;
175 size
= mapping
->size
;
178 for (n
= 0; n
< size
/ 4; ++n
)
181 carry
= (checks
& 1) ? 0x80000000 : 0;
189 static DWORD WINAPI
SdbpGetModuleType(PMEMMAPPED mapping
, PIMAGE_NT_HEADERS
* nt_headers
)
191 PIMAGE_DOS_HEADER dos
= (PIMAGE_DOS_HEADER
)mapping
->view
;
192 PIMAGE_OS2_HEADER os2
;
196 if (mapping
->size
< 2 || dos
->e_magic
!= IMAGE_DOS_SIGNATURE
)
197 return MODTYPE_UNKNOWN
;
199 if (mapping
->size
< sizeof(IMAGE_DOS_HEADER
) || mapping
->size
< (dos
->e_lfanew
+2))
202 os2
= (PIMAGE_OS2_HEADER
)((PBYTE
)dos
+ dos
->e_lfanew
);
203 if (os2
->ne_magic
== IMAGE_OS2_SIGNATURE
|| os2
->ne_magic
== IMAGE_OS2_SIGNATURE_LE
)
205 *nt_headers
= (PIMAGE_NT_HEADERS
)os2
;
209 if (mapping
->size
>= (dos
->e_lfanew
+ 4) && ((PIMAGE_NT_HEADERS
)os2
)->Signature
== IMAGE_NT_SIGNATURE
)
211 *nt_headers
= (PIMAGE_NT_HEADERS
)os2
;
219 * Frees attribute data allocated by SdbGetFileAttributes.
221 * @note Unlike Windows, this implementation will not crash if attr_info is NULL.
223 * @param [in] attr_info Pointer to array of ATTRINFO which will be freed.
225 * @return TRUE if it succeeds, FALSE if it fails.
227 BOOL WINAPI
SdbFreeFileAttributes(PATTRINFO attr_info
)
234 for (i
= 0; i
< NUM_ATTRIBUTES
; i
++)
235 if ((attr_info
[i
].type
& TAG_TYPE_MASK
) == TAG_TYPE_STRINGREF
)
236 SdbFree(attr_info
[i
].lpattr
);
242 * Retrieves attribute data shim database requires to match a file with database entry
244 * @note You must free the attr_info allocated by this function by calling SdbFreeFileAttributes.
246 * @param [in] path Path to the file.
247 * @param [out] attr_info_ret Pointer to array of ATTRINFO. Contains attribute data.
248 * @param [out] attr_count Number of attributes in attr_info.
250 * @return TRUE if it succeeds, FALSE if it fails.
252 BOOL WINAPI
SdbGetFileAttributes(LPCWSTR path
, PATTRINFO
*attr_info_ret
, LPDWORD attr_count
)
254 static const WCHAR str_tinfo
[] = {'\\','V','a','r','F','i','l','e','I','n','f','o','\\','T','r','a','n','s','l','a','t','i','o','n',0};
255 static const WCHAR str_trans
[] = {'\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o','\\','%','0','4','x','%','0','4','x','\\','%','%','s',0};
256 static const WCHAR str_CompanyName
[] = {'C','o','m','p','a','n','y','N','a','m','e',0};
257 static const WCHAR str_FileDescription
[] = {'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0};
258 static const WCHAR str_FileVersion
[] = {'F','i','l','e','V','e','r','s','i','o','n',0};
259 static const WCHAR str_InternalName
[] = {'I','n','t','e','r','n','a','l','N','a','m','e',0};
260 static const WCHAR str_LegalCopyright
[] = {'L','e','g','a','l','C','o','p','y','r','i','g','h','t',0};
261 static const WCHAR str_OriginalFilename
[] = {'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0};
262 static const WCHAR str_ProductName
[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
263 static const WCHAR str_ProductVersion
[] = {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
265 PIMAGE_NT_HEADERS headers
;
270 WCHAR translation
[128] = {0};
273 struct LANGANDCODEPAGE
{
278 if (!SdbpOpenMemMappedFile(path
, &mapped
))
280 SHIM_ERR("Error retrieving FILEINFO structure\n");
283 mapping_end
= mapped
.view
+ mapped
.size
;
285 attr_info
= (PATTRINFO
)SdbAlloc(NUM_ATTRIBUTES
* sizeof(ATTRINFO
));
287 SdbpSetDWORDAttr(&attr_info
[0], TAG_SIZE
, mapped
.size
);
289 SdbpSetDWORDAttr(&attr_info
[1], TAG_CHECKSUM
, SdbpCalculateFileChecksum(&mapped
));
291 SdbpSetAttrFail(&attr_info
[1]);
292 module_type
= SdbpGetModuleType(&mapped
, &headers
);
294 if (module_type
!= MODTYPE_UNKNOWN
)
295 SdbpSetDWORDAttr(&attr_info
[16], TAG_MODULE_TYPE
, module_type
);
297 SdbpSetAttrFail(&attr_info
[16]); /* TAG_MODULE_TYPE */
299 if (headers
&& module_type
== MODTYPE_PE
&& ((PBYTE
)(headers
+1) <= mapping_end
))
302 SIZE_T export_dir_size
;
303 PIMAGE_EXPORT_DIRECTORY export_dir
;
305 info_size
= GetFileVersionInfoSizeW(path
, NULL
);
309 file_info
= SdbAlloc(info_size
);
310 GetFileVersionInfoW(path
, 0, info_size
, file_info
);
311 VerQueryValueW(file_info
, str_tinfo
, (LPVOID
)&lang_page
, &page_size
);
312 snprintfW(translation
, 128, str_trans
, lang_page
->language
, lang_page
->code_page
);
315 /* Handles 2, 3, 12, 13, 14, 15, 21, 22 */
316 SdbpReadFileVersion(attr_info
, file_info
);
318 SdbpSetStringAttr(&attr_info
[4], TAG_PRODUCT_VERSION
, SdbpGetStringAttr(translation
, str_ProductVersion
, file_info
));
319 SdbpSetStringAttr(&attr_info
[5], TAG_FILE_DESCRIPTION
, SdbpGetStringAttr(translation
, str_FileDescription
, file_info
));
320 SdbpSetStringAttr(&attr_info
[6], TAG_COMPANY_NAME
, SdbpGetStringAttr(translation
, str_CompanyName
, file_info
));
321 SdbpSetStringAttr(&attr_info
[7], TAG_PRODUCT_NAME
, SdbpGetStringAttr(translation
, str_ProductName
, file_info
));
322 SdbpSetStringAttr(&attr_info
[8], TAG_FILE_VERSION
, SdbpGetStringAttr(translation
, str_FileVersion
, file_info
));
323 SdbpSetStringAttr(&attr_info
[9], TAG_ORIGINAL_FILENAME
, SdbpGetStringAttr(translation
, str_OriginalFilename
, file_info
));
324 SdbpSetStringAttr(&attr_info
[10], TAG_INTERNAL_NAME
, SdbpGetStringAttr(translation
, str_InternalName
, file_info
));
325 SdbpSetStringAttr(&attr_info
[11], TAG_LEGAL_COPYRIGHT
, SdbpGetStringAttr(translation
, str_LegalCopyright
, file_info
));
327 /* http://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx */
329 SdbpSetDWORDAttr(&attr_info
[17], TAG_PE_CHECKSUM
, headers
->OptionalHeader
.CheckSum
);
331 SdbpSetDWORDAttr(&attr_info
[18], TAG_LINKER_VERSION
, /* mislabeled! */
332 ((DWORD
)headers
->OptionalHeader
.MajorImageVersion
) << 16 | headers
->OptionalHeader
.MinorImageVersion
);
333 SdbpSetAttrFail(&attr_info
[19]); /* TAG_16BIT_DESCRIPTION */
334 SdbpSetAttrFail(&attr_info
[20]); /* TAG_16BIT_MODULE_NAME */
336 SdbpSetDWORDAttr(&attr_info
[23], TAG_LINK_DATE
, headers
->FileHeader
.TimeDateStamp
);
337 SdbpSetDWORDAttr(&attr_info
[24], TAG_UPTO_LINK_DATE
, headers
->FileHeader
.TimeDateStamp
);
339 export_dir
= (PIMAGE_EXPORT_DIRECTORY
)RtlImageDirectoryEntryToData(mapped
.view
, FALSE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &export_dir_size
);
340 if (export_dir
&& ((PBYTE
)(export_dir
+1) <= mapping_end
))
342 PIMAGE_SECTION_HEADER section
= NULL
;
343 PBYTE export_name
= RtlImageRvaToVa(headers
, mapped
.view
, export_dir
->Name
, §ion
);
345 SdbpSetStringAttrFromAnsiString(&attr_info
[25], TAG_EXPORT_NAME
, export_name
, strlen((char*)export_name
));
347 SdbpSetAttrFail(&attr_info
[25]); /* TAG_EXPORT_NAME */
351 SdbpSetAttrFail(&attr_info
[25]); /* TAG_EXPORT_NAME */
355 SdbpSetDWORDAttr(&attr_info
[26], TAG_VER_LANGUAGE
, lang_page
->language
);
357 SdbpSetDWORDAttr(&attr_info
[27], TAG_EXE_WRAPPER
, 0); /* boolean */
362 for (n
= 2; n
< NUM_ATTRIBUTES
; ++n
)
364 if (n
!= 16 && n
!= 26)
365 SdbpSetAttrFail(&attr_info
[n
]);
367 if (module_type
== MODTYPE_NE
)
370 PIMAGE_OS2_HEADER os2
= (PIMAGE_OS2_HEADER
)headers
;
371 if ((PBYTE
)(os2
+ 1) <= mapping_end
)
373 ptr
= mapped
.view
+ os2
->ne_nrestab
;
374 if (ptr
<= mapping_end
&& (ptr
+ 1 + *ptr
) <= mapping_end
)
375 SdbpSetStringAttrFromPascalString(&attr_info
[19], TAG_16BIT_DESCRIPTION
, ptr
);
376 ptr
= (PBYTE
)os2
+ os2
->ne_restab
;
377 if (ptr
<= mapping_end
&& (ptr
+ 1 + *ptr
) <= mapping_end
)
378 SdbpSetStringAttrFromPascalString(&attr_info
[20], TAG_16BIT_MODULE_NAME
, ptr
);
383 *attr_info_ret
= attr_info
;
384 *attr_count
= NUM_ATTRIBUTES
; /* As far as I know, this one is always 28 */
387 SdbpCloseMemMappedFile(&mapped
);