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
27 #include "wine/unicode.h"
29 #define NUM_ATTRIBUTES 28
31 static void WINAPI
SdbpSetDWORDAttr(PATTRINFO attr
, TAG tag
, DWORD value
)
34 attr
->flags
= ATTRIBUTE_AVAILABLE
;
38 static void WINAPI
SdbpSetQWORDAttr(PATTRINFO attr
, TAG tag
, QWORD value
)
41 attr
->flags
= ATTRIBUTE_AVAILABLE
;
45 static void WINAPI
SdbpSetStringAttr(PATTRINFO attr
, TAG tag
, WCHAR
*string
)
49 attr
->flags
= ATTRIBUTE_FAILED
;
54 attr
->flags
= ATTRIBUTE_AVAILABLE
;
55 attr
->lpattr
= SdbpStrDup(string
);
58 static void WINAPI
SdbpSetAttrFail(PATTRINFO attr
)
60 attr
->flags
= ATTRIBUTE_FAILED
;
63 static WCHAR
* WINAPI
SdbpGetStringAttr(LPWSTR translation
, LPCWSTR attr
, PVOID file_info
)
67 WCHAR value
[128] = {0};
72 snprintfW(value
, 128, translation
, attr
);
73 if (VerQueryValueW(file_info
, value
, &buffer
, &size
) && size
!= 0)
74 return (WCHAR
*)buffer
;
79 static void WINAPI
SdbpSetStringAttrFromAnsiString(PATTRINFO attr
, TAG tag
, PBYTE string
, BYTE len
)
84 attr
->flags
= ATTRIBUTE_FAILED
;
89 attr
->flags
= ATTRIBUTE_AVAILABLE
;
90 dest
= attr
->lpattr
= SdbpAlloc((len
+1) * sizeof(WCHAR
));
92 *(dest
++) = *(string
++);
96 static void WINAPI
SdbpSetStringAttrFromPascalString(PATTRINFO attr
, TAG tag
, PBYTE string
)
100 attr
->flags
= ATTRIBUTE_FAILED
;
104 SdbpSetStringAttrFromAnsiString(attr
, tag
, string
+ 1, *string
);
107 static void SdbpReadFileVersion(PATTRINFO attr_info
, PVOID file_info
)
109 static const WCHAR str_root
[] = {'\\',0};
111 VS_FIXEDFILEINFO
* fixed_info
;
113 if (file_info
&& VerQueryValueW(file_info
, str_root
, (LPVOID
*)&fixed_info
, &size
) && size
)
115 if (fixed_info
->dwSignature
== VS_FFI_SIGNATURE
)
117 LARGE_INTEGER version
;
118 version
.HighPart
= fixed_info
->dwFileVersionMS
;
119 version
.LowPart
= fixed_info
->dwFileVersionLS
;
120 SdbpSetQWORDAttr(&attr_info
[2], TAG_BIN_FILE_VERSION
, version
.QuadPart
);
121 SdbpSetQWORDAttr(&attr_info
[21], TAG_UPTO_BIN_FILE_VERSION
, version
.QuadPart
);
122 version
.HighPart
= fixed_info
->dwProductVersionMS
;
123 version
.LowPart
= fixed_info
->dwProductVersionLS
;
124 SdbpSetQWORDAttr(&attr_info
[3], TAG_BIN_PRODUCT_VERSION
, version
.QuadPart
);
125 SdbpSetQWORDAttr(&attr_info
[22], TAG_UPTO_BIN_PRODUCT_VERSION
, version
.QuadPart
);
127 SdbpSetDWORDAttr(&attr_info
[12], TAG_VERDATEHI
, fixed_info
->dwFileDateMS
);
128 SdbpSetDWORDAttr(&attr_info
[13], TAG_VERDATELO
, fixed_info
->dwFileDateLS
);
129 SdbpSetDWORDAttr(&attr_info
[14], TAG_VERFILEOS
, fixed_info
->dwFileOS
); /* 0x000, 0x4, 0x40004, 0x40000, 0x10004, 0x10001*/
130 SdbpSetDWORDAttr(&attr_info
[15], TAG_VERFILETYPE
, fixed_info
->dwFileType
); /* VFT_APP, VFT_DLL, .... */
135 SdbpSetAttrFail(&attr_info
[2]);
136 SdbpSetAttrFail(&attr_info
[3]);
137 SdbpSetAttrFail(&attr_info
[12]);
138 SdbpSetAttrFail(&attr_info
[13]);
139 SdbpSetAttrFail(&attr_info
[14]);
140 SdbpSetAttrFail(&attr_info
[15]);
141 SdbpSetAttrFail(&attr_info
[21]);
142 SdbpSetAttrFail(&attr_info
[22]);
145 static DWORD WINAPI
SdbpCalculateFileChecksum(PMEMMAPPED mapping
)
149 DWORD checks
= 0, carry
= 0;
151 if (mapping
->size
< 4)
154 if (mapping
->size
>= 0x1000)
157 if (mapping
->size
< 0x1200)
158 data
= (PDWORD
)(mapping
->view
+ mapping
->size
- size
);
160 data
= (PDWORD
)mapping
->view
+ (0x200 / 4);
164 data
= (PDWORD
)mapping
->view
;
165 size
= mapping
->size
;
168 for (n
= 0; n
< size
/ 4; ++n
)
171 carry
= (checks
& 1) ? 0x80000000 : 0;
179 static DWORD WINAPI
SdbpGetModuleType(PMEMMAPPED mapping
)
181 PIMAGE_DOS_HEADER dos
= (PIMAGE_DOS_HEADER
)mapping
->view
;
182 PIMAGE_OS2_HEADER os2
;
184 if (mapping
->size
< 2 || dos
->e_magic
!= IMAGE_DOS_SIGNATURE
)
187 if (mapping
->size
< sizeof(IMAGE_DOS_HEADER
) || mapping
->size
< (dos
->e_lfanew
+2))
190 os2
= (PIMAGE_OS2_HEADER
)((PBYTE
)dos
+ dos
->e_lfanew
);
191 if (os2
->ne_magic
== IMAGE_OS2_SIGNATURE
|| os2
->ne_magic
== IMAGE_OS2_SIGNATURE_LE
)
194 if (mapping
->size
>= (dos
->e_lfanew
+ 4) && ((PIMAGE_NT_HEADERS
)os2
)->Signature
== IMAGE_NT_SIGNATURE
)
201 * Frees attribute data allocated by SdbGetFileAttributes.
203 * @note Unlike Windows, this implementation will not crash if attr_info is NULL.
205 * @param [in] attr_info Pointer to array of ATTRINFO which will be freed.
207 * @return TRUE if it succeeds, FALSE if it fails.
209 BOOL WINAPI
SdbFreeFileAttributes(PATTRINFO attr_info
)
216 for (i
= 0; i
< NUM_ATTRIBUTES
; i
++)
217 if ((attr_info
[i
].type
& TAG_TYPE_MASK
) == TAG_TYPE_STRINGREF
)
218 SdbFree(attr_info
[i
].lpattr
);
224 * Retrieves attribute data shim database requires to match a file with database entry
226 * @note You must free the attr_info allocated by this function by calling SdbFreeFileAttributes.
228 * @param [in] path Path to the file.
229 * @param [out] attr_info_ret Pointer to array of ATTRINFO. Contains attribute data.
230 * @param [out] attr_count Number of attributes in attr_info.
232 * @return TRUE if it succeeds, FALSE if it fails.
234 BOOL WINAPI
SdbGetFileAttributes(LPCWSTR path
, PATTRINFO
*attr_info_ret
, LPDWORD attr_count
)
236 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};
237 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};
238 static const WCHAR str_CompanyName
[] = {'C','o','m','p','a','n','y','N','a','m','e',0};
239 static const WCHAR str_FileDescription
[] = {'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0};
240 static const WCHAR str_FileVersion
[] = {'F','i','l','e','V','e','r','s','i','o','n',0};
241 static const WCHAR str_InternalName
[] = {'I','n','t','e','r','n','a','l','N','a','m','e',0};
242 static const WCHAR str_LegalCopyright
[] = {'L','e','g','a','l','C','o','p','y','r','i','g','h','t',0};
243 static const WCHAR str_OriginalFilename
[] = {'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0};
244 static const WCHAR str_ProductName
[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
245 static const WCHAR str_ProductVersion
[] = {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
247 PIMAGE_NT_HEADERS headers
;
250 DWORD headersum
, checksum
, module_type
;
251 WCHAR translation
[128] = {0};
254 struct LANGANDCODEPAGE
{
259 if (!SdbpOpenMemMappedFile(path
, &mapped
))
261 SHIM_ERR("Error retrieving FILEINFO structure\n");
265 attr_info
= (PATTRINFO
)SdbAlloc(NUM_ATTRIBUTES
* sizeof(ATTRINFO
));
267 SdbpSetDWORDAttr(&attr_info
[0], TAG_SIZE
, mapped
.size
);
269 SdbpSetDWORDAttr(&attr_info
[1], TAG_CHECKSUM
, SdbpCalculateFileChecksum(&mapped
));
271 SdbpSetAttrFail(&attr_info
[1]);
272 module_type
= SdbpGetModuleType(&mapped
);
275 SdbpSetDWORDAttr(&attr_info
[16], TAG_MODULE_TYPE
, module_type
);
277 SdbpSetAttrFail(&attr_info
[16]); /* TAG_MODULE_TYPE */
279 headers
= CheckSumMappedFile(mapped
.view
, mapped
.size
, &headersum
, &checksum
);
283 SIZE_T export_dir_size
;
284 PIMAGE_EXPORT_DIRECTORY export_dir
;
286 info_size
= GetFileVersionInfoSizeW(path
, NULL
);
290 file_info
= SdbAlloc(info_size
);
291 GetFileVersionInfoW(path
, 0, info_size
, file_info
);
292 VerQueryValueW(file_info
, str_tinfo
, (LPVOID
)&lang_page
, &page_size
);
293 snprintfW(translation
, 128, str_trans
, lang_page
->language
, lang_page
->code_page
);
296 /* Handles 2, 3, 12, 13, 14, 15, 21, 22 */
297 SdbpReadFileVersion(attr_info
, file_info
);
299 SdbpSetStringAttr(&attr_info
[4], TAG_PRODUCT_VERSION
, SdbpGetStringAttr(translation
, str_ProductVersion
, file_info
));
300 SdbpSetStringAttr(&attr_info
[5], TAG_FILE_DESCRIPTION
, SdbpGetStringAttr(translation
, str_FileDescription
, file_info
));
301 SdbpSetStringAttr(&attr_info
[6], TAG_COMPANY_NAME
, SdbpGetStringAttr(translation
, str_CompanyName
, file_info
));
302 SdbpSetStringAttr(&attr_info
[7], TAG_PRODUCT_NAME
, SdbpGetStringAttr(translation
, str_ProductName
, file_info
));
303 SdbpSetStringAttr(&attr_info
[8], TAG_FILE_VERSION
, SdbpGetStringAttr(translation
, str_FileVersion
, file_info
));
304 SdbpSetStringAttr(&attr_info
[9], TAG_ORIGINAL_FILENAME
, SdbpGetStringAttr(translation
, str_OriginalFilename
, file_info
));
305 SdbpSetStringAttr(&attr_info
[10], TAG_INTERNAL_NAME
, SdbpGetStringAttr(translation
, str_InternalName
, file_info
));
306 SdbpSetStringAttr(&attr_info
[11], TAG_LEGAL_COPYRIGHT
, SdbpGetStringAttr(translation
, str_LegalCopyright
, file_info
));
308 /* http://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx */
310 SdbpSetDWORDAttr(&attr_info
[17], TAG_PE_CHECKSUM
, headers
->OptionalHeader
.CheckSum
);
312 SdbpSetDWORDAttr(&attr_info
[18], TAG_LINKER_VERSION
, /* mislabeled! */
313 ((DWORD
)headers
->OptionalHeader
.MajorImageVersion
) << 16 | headers
->OptionalHeader
.MinorImageVersion
);
314 SdbpSetAttrFail(&attr_info
[19]); /* TAG_16BIT_DESCRIPTION */
315 SdbpSetAttrFail(&attr_info
[20]); /* TAG_16BIT_MODULE_NAME */
317 SdbpSetDWORDAttr(&attr_info
[23], TAG_LINK_DATE
, headers
->FileHeader
.TimeDateStamp
);
318 SdbpSetDWORDAttr(&attr_info
[24], TAG_UPTO_LINK_DATE
, headers
->FileHeader
.TimeDateStamp
);
320 export_dir
= (PIMAGE_EXPORT_DIRECTORY
)ImageDirectoryEntryToData(mapped
.view
, FALSE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &export_dir_size
);
323 PIMAGE_SECTION_HEADER section
= NULL
;
324 PBYTE export_name
= ImageRvaToVa(headers
, mapped
.view
, export_dir
->Name
, §ion
);
326 SdbpSetStringAttrFromAnsiString(&attr_info
[25], TAG_EXPORT_NAME
, export_name
, strlen((char*)export_name
));
328 SdbpSetAttrFail(&attr_info
[25]); /* TAG_EXPORT_NAME */
332 SdbpSetAttrFail(&attr_info
[25]); /* TAG_EXPORT_NAME */
336 SdbpSetDWORDAttr(&attr_info
[26], TAG_VER_LANGUAGE
, lang_page
->language
);
338 SdbpSetDWORDAttr(&attr_info
[27], TAG_EXE_WRAPPER
, 0); /* boolean */
343 for (n
= 2; n
< NUM_ATTRIBUTES
; ++n
)
345 if (n
!= 16 && n
!= 26)
346 SdbpSetAttrFail(&attr_info
[n
]);
348 if (module_type
== 2)
350 PIMAGE_DOS_HEADER dos
= (PIMAGE_DOS_HEADER
)mapped
.view
;
351 PBYTE end
= mapped
.view
+ mapped
.size
, ptr
;
352 PIMAGE_OS2_HEADER os2
= (PIMAGE_OS2_HEADER
)((PBYTE
)dos
+ dos
->e_lfanew
);
353 if ((PBYTE
)(os2
+ 1) <= end
)
355 ptr
= (PBYTE
)dos
+ os2
->ne_nrestab
;
356 if (ptr
<= end
&& (ptr
+ 1 + *ptr
) <= end
)
357 SdbpSetStringAttrFromPascalString(&attr_info
[19], TAG_16BIT_DESCRIPTION
, ptr
);
358 ptr
= (PBYTE
)os2
+ os2
->ne_restab
;
359 if (ptr
<= end
&& (ptr
+ 1 + *ptr
) <= end
)
360 SdbpSetStringAttrFromPascalString(&attr_info
[20], TAG_16BIT_MODULE_NAME
, ptr
);
365 *attr_info_ret
= attr_info
;
366 *attr_count
= NUM_ATTRIBUTES
; /* As far as I know, this one is always 28 */
369 SdbpCloseMemMappedFile(&mapped
);