[APPHELP][APPHELP_APITEST] Add SdbGetFileAttributes + tests, based on the work of Mislav Blažević CORE-10367

- Implement SdbGetFileAttributes (based on the work of Mislav Blažević)
- Add tests for SdbGetFileAttributes

svn path=/trunk/; revision=71226
This commit is contained in:
Mark Jansen 2016-05-01 19:12:06 +00:00
parent 535cdf4620
commit 78280ad21f
8 changed files with 1508 additions and 11 deletions

View file

@ -3,8 +3,9 @@ spec2def(apphelp.dll apphelp.spec ADD_IMPORTLIB)
list(APPEND SOURCE
apphelp.c
sdbapi.c
layer.c
sdbapi.c
sdbfileattr.c
apphelp.spec
apphelp.h
${CMAKE_CURRENT_BINARY_DIR}/apphelp_stubs.c)
@ -15,6 +16,7 @@ add_library(apphelp SHARED
set_module_type(apphelp win32dll)
target_link_libraries(apphelp wine)
#add_delay_importlibs(apphelp version imagehlp user32)
add_importlibs(apphelp msvcrt kernel32 ntdll)
# When binutils is fixed, we should move imagehlp to delay! CORE-6504
add_delay_importlibs(apphelp version)
add_importlibs(apphelp msvcrt imagehlp kernel32 ntdll)
add_cd_file(TARGET apphelp DESTINATION reactos/system32 FOR all)

View file

@ -32,6 +32,16 @@ typedef UINT64 QWORD;
#define TAGREF_NULL (0)
#define TAGREF_ROOT (0)
typedef struct tagATTRINFO {
TAG type;
DWORD flags;
union {
QWORD qwattr;
DWORD dwattr;
WCHAR *lpattr;
};
} ATTRINFO, *PATTRINFO;
typedef enum _SHIM_LOG_LEVEL {
SHIM_ERR = 1,
SHIM_WARN = 2,
@ -72,6 +82,19 @@ void SdbpFree(LPVOID mem);
#endif
typedef struct tagMEMMAPPED {
HANDLE file;
HANDLE section;
PBYTE view;
SIZE_T size;
SIZE_T mapped_size;
} MEMMAPPED, *PMEMMAPPED;
BOOL WINAPI SdbpOpenMemMappedFile(LPCWSTR path, PMEMMAPPED mapping);
void WINAPI SdbpCloseMemMappedFile(PMEMMAPPED mapping);
DWORD SdbpStrlen(LPCWSTR string);
PWSTR SdbpStrDup(LPCWSTR string);
/* layer.c */
BOOL WINAPI AllowPermLayer(PCWSTR path);
@ -79,6 +102,9 @@ BOOL WINAPI SdbGetPermLayerKeys(PCWSTR wszPath, PWSTR pwszLayers, PDWORD pdwByte
BOOL WINAPI SetPermLayerState(PCWSTR wszPath, PCWSTR wszLayer, DWORD dwFlags, BOOL bMachine, BOOL bEnable);
#define ATTRIBUTE_AVAILABLE 0x1
#define ATTRIBUTE_FAILED 0x2
#define TAGID_NULL 0x0
#define TAGID_ROOT 0x0

View file

@ -48,7 +48,7 @@
@ stub SdbFindNextTag
@ stub SdbFindNextTagRef
@ stub SdbFreeDatabaseInformation
@ stub SdbFreeFileAttributes
@ stdcall SdbFreeFileAttributes(ptr)
@ stub SdbFreeFileInfo
@ stub SdbFreeFlagInfo
@ stub SdbGetAppCompatDataSize
@ -61,7 +61,7 @@
@ stub SdbGetDatabaseVersion
@ stub SdbGetDllPath
@ stub SdbGetEntryFlags
@ stub SdbGetFileAttributes
@ stdcall SdbGetFileAttributes(wstr ptr ptr)
@ stub SdbGetFileImageType
@ stub SdbGetFileImageTypeEx
@ stub SdbGetFileInfo

View file

@ -155,11 +155,6 @@ void SdbpHeapDeinit(void)
HeapDestroy(g_Heap);
}
DWORD SdbpStrlen(PCWSTR string)
{
return (lstrlenW(string) + 1) * sizeof(WCHAR);
}
static HANDLE SdbpHeap(void)
{
return g_Heap;
@ -203,6 +198,94 @@ void SdbpFree(LPVOID mem
HeapFree(SdbpHeap(), 0, mem);
}
DWORD SdbpStrlen(PCWSTR string)
{
return (lstrlenW(string) + 1) * sizeof(WCHAR);
}
PWSTR SdbpStrDup(LPCWSTR string)
{
PWSTR ret = SdbpAlloc(SdbpStrlen(string));
lstrcpyW(ret, string);
return ret;
}
BOOL WINAPI SdbpOpenMemMappedFile(LPCWSTR path, PMEMMAPPED mapping)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
FILE_STANDARD_INFORMATION FileStandard;
UNICODE_STRING FileName;
RtlZeroMemory(mapping, sizeof(*mapping));
if(!RtlDosPathNameToNtPathName_U(path, &FileName, NULL, NULL))
{
RtlFreeUnicodeString(&FileName);
return FALSE;
}
InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenFile(&mapping->file, GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
RtlFreeUnicodeString(&FileName);
if (!NT_SUCCESS(Status))
{
SHIM_ERR("Failed to open file %S: 0x%lx\n", path, Status);
return FALSE;
}
Status = NtCreateSection(&mapping->section, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ, 0, 0, PAGE_READONLY, SEC_COMMIT, mapping->file);
if (!NT_SUCCESS(Status))
{
/* Special case */
if (Status == STATUS_MAPPED_FILE_SIZE_ZERO)
{
NtClose(mapping->file);
mapping->file = mapping->section = NULL;
return TRUE;
}
SHIM_ERR("Failed to create mapping for file: 0x%lx\n", Status);
goto err_out;
}
Status = NtQueryInformationFile(mapping->file, &IoStatusBlock, &FileStandard, sizeof(FileStandard), FileStandardInformation);
if (!NT_SUCCESS(Status))
{
SHIM_ERR("Failed to read file info for file: 0x%lx\n", Status);
goto err_out;
}
mapping->mapped_size = mapping->size = FileStandard.EndOfFile.LowPart;
Status = NtMapViewOfSection(mapping->section, NtCurrentProcess(), (PVOID*)&mapping->view, 0, 0, 0, &mapping->mapped_size, ViewUnmap, 0, PAGE_READONLY);
if (!NT_SUCCESS(Status))
{
SHIM_ERR("Failed to map view of file: 0x%lx\n", Status);
goto err_out;
}
return TRUE;
err_out:
if (!mapping->view)
{
if (mapping->section)
NtClose(mapping->section);
NtClose(mapping->file);
}
return FALSE;
}
void WINAPI SdbpCloseMemMappedFile(PMEMMAPPED mapping)
{
NtUnmapViewOfSection(NtCurrentProcess(), mapping->view);
NtClose(mapping->section);
NtClose(mapping->file);
RtlZeroMemory(mapping, sizeof(*mapping));
}
/**
* Converts specified tag into a string.
*

View file

@ -0,0 +1,371 @@
/*
* Copyright 2011 André Hentschel
* Copyright 2013 Mislav Blaževic
* Copyright 2015 Mark Jansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "windef.h"
#include "winbase.h"
#include "apphelp.h"
#include "imagehlp.h"
#include "winver.h"
#include "wine/unicode.h"
#define NUM_ATTRIBUTES 28
static void WINAPI SdbpSetDWORDAttr(PATTRINFO attr, TAG tag, DWORD value)
{
attr->type = tag;
attr->flags = ATTRIBUTE_AVAILABLE;
attr->dwattr = value;
}
static void WINAPI SdbpSetQWORDAttr(PATTRINFO attr, TAG tag, QWORD value)
{
attr->type = tag;
attr->flags = ATTRIBUTE_AVAILABLE;
attr->qwattr = value;
}
static void WINAPI SdbpSetStringAttr(PATTRINFO attr, TAG tag, WCHAR *string)
{
if (!string)
{
attr->flags = ATTRIBUTE_FAILED;
return;
}
attr->type = tag;
attr->flags = ATTRIBUTE_AVAILABLE;
attr->lpattr = SdbpStrDup(string);
}
static void WINAPI SdbpSetAttrFail(PATTRINFO attr)
{
attr->flags = ATTRIBUTE_FAILED;
}
static WCHAR* WINAPI SdbpGetStringAttr(LPWSTR translation, LPCWSTR attr, PVOID file_info)
{
UINT size = 0;
PVOID buffer;
WCHAR value[128] = {0};
if (!file_info)
return NULL;
snprintfW(value, 128, translation, attr);
if (VerQueryValueW(file_info, value, &buffer, &size) && size != 0)
return (WCHAR*)buffer;
return NULL;
}
static void WINAPI SdbpSetStringAttrFromAnsiString(PATTRINFO attr, TAG tag, PBYTE string, BYTE len)
{
WCHAR* dest;
if (!string)
{
attr->flags = ATTRIBUTE_FAILED;
return;
}
attr->type = tag;
attr->flags = ATTRIBUTE_AVAILABLE;
dest = attr->lpattr = SdbpAlloc((len+1) * sizeof(WCHAR));
while (len--)
*(dest++) = *(string++);
*dest = 0;
}
static void WINAPI SdbpSetStringAttrFromPascalString(PATTRINFO attr, TAG tag, PBYTE string)
{
if (!string)
{
attr->flags = ATTRIBUTE_FAILED;
return;
}
SdbpSetStringAttrFromAnsiString(attr, tag, string + 1, *string);
}
static void SdbpReadFileVersion(PATTRINFO attr_info, PVOID file_info)
{
static const WCHAR str_root[] = {'\\',0};
VS_FIXEDFILEINFO* fixed_info;
UINT size;
if (file_info && VerQueryValueW(file_info, str_root, (LPVOID*)&fixed_info, &size) && size)
{
if (fixed_info->dwSignature == VS_FFI_SIGNATURE)
{
LARGE_INTEGER version;
version.HighPart = fixed_info->dwFileVersionMS;
version.LowPart = fixed_info->dwFileVersionLS;
SdbpSetQWORDAttr(&attr_info[2], TAG_BIN_FILE_VERSION, version.QuadPart);
SdbpSetQWORDAttr(&attr_info[21], TAG_UPTO_BIN_FILE_VERSION, version.QuadPart);
version.HighPart = fixed_info->dwProductVersionMS;
version.LowPart = fixed_info->dwProductVersionLS;
SdbpSetQWORDAttr(&attr_info[3], TAG_BIN_PRODUCT_VERSION, version.QuadPart);
SdbpSetQWORDAttr(&attr_info[22], TAG_UPTO_BIN_PRODUCT_VERSION, version.QuadPart);
SdbpSetDWORDAttr(&attr_info[12], TAG_VERDATEHI, fixed_info->dwFileDateMS);
SdbpSetDWORDAttr(&attr_info[13], TAG_VERDATELO, fixed_info->dwFileDateLS);
SdbpSetDWORDAttr(&attr_info[14], TAG_VERFILEOS, fixed_info->dwFileOS); /* 0x000, 0x4, 0x40004, 0x40000, 0x10004, 0x10001*/
SdbpSetDWORDAttr(&attr_info[15], TAG_VERFILETYPE, fixed_info->dwFileType); /* VFT_APP, VFT_DLL, .... */
return;
}
}
SdbpSetAttrFail(&attr_info[2]);
SdbpSetAttrFail(&attr_info[3]);
SdbpSetAttrFail(&attr_info[12]);
SdbpSetAttrFail(&attr_info[13]);
SdbpSetAttrFail(&attr_info[14]);
SdbpSetAttrFail(&attr_info[15]);
SdbpSetAttrFail(&attr_info[21]);
SdbpSetAttrFail(&attr_info[22]);
}
static DWORD WINAPI SdbpCalculateFileChecksum(PMEMMAPPED mapping)
{
size_t n, size;
PDWORD data;
DWORD checks = 0, carry = 0;
if (mapping->size < 4)
return 0;
if (mapping->size >= 0x1000)
{
size = 0x1000;
if (mapping->size < 0x1200)
data = (PDWORD)(mapping->view + mapping->size - size);
else
data = (PDWORD)mapping->view + (0x200 / 4);
}
else
{
data = (PDWORD)mapping->view;
size = mapping->size;
}
for (n = 0; n < size / 4; ++n)
{
checks += *data;
carry = (checks & 1) ? 0x80000000 : 0;
checks >>= 1;
checks |= carry;
++data;
}
return checks;
}
static DWORD WINAPI SdbpGetModuleType(PMEMMAPPED mapping)
{
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)mapping->view;
PIMAGE_OS2_HEADER os2;
if (mapping->size < 2 || dos->e_magic != IMAGE_DOS_SIGNATURE)
return 0;
if (mapping->size < sizeof(IMAGE_DOS_HEADER) || mapping->size < (dos->e_lfanew+2))
return 1;
os2 = (PIMAGE_OS2_HEADER)((PBYTE)dos + dos->e_lfanew);
if (os2->ne_magic == IMAGE_OS2_SIGNATURE || os2->ne_magic == IMAGE_OS2_SIGNATURE_LE)
return 2;
if (mapping->size >= (dos->e_lfanew + 4) && ((PIMAGE_NT_HEADERS)os2)->Signature == IMAGE_NT_SIGNATURE)
return 3;
return 1;
}
/**
* Frees attribute data allocated by SdbGetFileAttributes.
*
* @note Unlike Windows, this implementation will not crash if attr_info is NULL.
*
* @param [in] attr_info Pointer to array of ATTRINFO which will be freed.
*
* @return TRUE if it succeeds, FALSE if it fails.
*/
BOOL WINAPI SdbFreeFileAttributes(PATTRINFO attr_info)
{
WORD i;
if (!attr_info)
return FALSE;
for (i = 0; i < NUM_ATTRIBUTES; i++)
if ((attr_info[i].type & TAG_TYPE_MASK) == TAG_TYPE_STRINGREF)
SdbFree(attr_info[i].lpattr);
SdbFree(attr_info);
return TRUE;
}
/**
* Retrieves attribute data shim database requires to match a file with database entry
*
* @note You must free the attr_info allocated by this function by calling SdbFreeFileAttributes.
*
* @param [in] path Path to the file.
* @param [out] attr_info_ret Pointer to array of ATTRINFO. Contains attribute data.
* @param [out] attr_count Number of attributes in attr_info.
*
* @return TRUE if it succeeds, FALSE if it fails.
*/
BOOL WINAPI SdbGetFileAttributes(LPCWSTR path, PATTRINFO *attr_info_ret, LPDWORD attr_count)
{
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};
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};
static const WCHAR str_CompanyName[] = {'C','o','m','p','a','n','y','N','a','m','e',0};
static const WCHAR str_FileDescription[] = {'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0};
static const WCHAR str_FileVersion[] = {'F','i','l','e','V','e','r','s','i','o','n',0};
static const WCHAR str_InternalName[] = {'I','n','t','e','r','n','a','l','N','a','m','e',0};
static const WCHAR str_LegalCopyright[] = {'L','e','g','a','l','C','o','p','y','r','i','g','h','t',0};
static const WCHAR str_OriginalFilename[] = {'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0};
static const WCHAR str_ProductName[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
static const WCHAR str_ProductVersion[] = {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
PIMAGE_NT_HEADERS headers;
MEMMAPPED mapped;
PVOID file_info = 0;
DWORD headersum, checksum, module_type;
WCHAR translation[128] = {0};
PATTRINFO attr_info;
struct LANGANDCODEPAGE {
WORD language;
WORD code_page;
} *lang_page;
if (!SdbpOpenMemMappedFile(path, &mapped))
{
SHIM_ERR("Error retrieving FILEINFO structure\n");
return FALSE;
}
attr_info = (PATTRINFO)SdbAlloc(NUM_ATTRIBUTES * sizeof(ATTRINFO));
SdbpSetDWORDAttr(&attr_info[0], TAG_SIZE, mapped.size);
if (mapped.size)
SdbpSetDWORDAttr(&attr_info[1], TAG_CHECKSUM, SdbpCalculateFileChecksum(&mapped));
else
SdbpSetAttrFail(&attr_info[1]);
module_type = SdbpGetModuleType(&mapped);
if (module_type)
SdbpSetDWORDAttr(&attr_info[16], TAG_MODULE_TYPE, module_type);
else
SdbpSetAttrFail(&attr_info[16]); /* TAG_MODULE_TYPE */
headers = CheckSumMappedFile(mapped.view, mapped.size, &headersum, &checksum);
if (headers)
{
DWORD info_size;
SIZE_T export_dir_size;
PIMAGE_EXPORT_DIRECTORY export_dir;
info_size = GetFileVersionInfoSizeW(path, NULL);
if (info_size != 0)
{
UINT page_size = 0;
file_info = SdbAlloc(info_size);
GetFileVersionInfoW(path, 0, info_size, file_info);
VerQueryValueW(file_info, str_tinfo, (LPVOID)&lang_page, &page_size);
snprintfW(translation, 128, str_trans, lang_page->language, lang_page->code_page);
}
/* Handles 2, 3, 12, 13, 14, 15, 21, 22 */
SdbpReadFileVersion(attr_info, file_info);
SdbpSetStringAttr(&attr_info[4], TAG_PRODUCT_VERSION, SdbpGetStringAttr(translation, str_ProductVersion, file_info));
SdbpSetStringAttr(&attr_info[5], TAG_FILE_DESCRIPTION, SdbpGetStringAttr(translation, str_FileDescription, file_info));
SdbpSetStringAttr(&attr_info[6], TAG_COMPANY_NAME, SdbpGetStringAttr(translation, str_CompanyName, file_info));
SdbpSetStringAttr(&attr_info[7], TAG_PRODUCT_NAME, SdbpGetStringAttr(translation, str_ProductName, file_info));
SdbpSetStringAttr(&attr_info[8], TAG_FILE_VERSION, SdbpGetStringAttr(translation, str_FileVersion, file_info));
SdbpSetStringAttr(&attr_info[9], TAG_ORIGINAL_FILENAME, SdbpGetStringAttr(translation, str_OriginalFilename, file_info));
SdbpSetStringAttr(&attr_info[10], TAG_INTERNAL_NAME, SdbpGetStringAttr(translation, str_InternalName, file_info));
SdbpSetStringAttr(&attr_info[11], TAG_LEGAL_COPYRIGHT, SdbpGetStringAttr(translation, str_LegalCopyright, file_info));
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx */
SdbpSetDWORDAttr(&attr_info[17], TAG_PE_CHECKSUM, headers->OptionalHeader.CheckSum);
SdbpSetDWORDAttr(&attr_info[18], TAG_LINKER_VERSION, /* mislabeled! */
((DWORD)headers->OptionalHeader.MajorImageVersion) << 16 | headers->OptionalHeader.MinorImageVersion);
SdbpSetAttrFail(&attr_info[19]); /* TAG_16BIT_DESCRIPTION */
SdbpSetAttrFail(&attr_info[20]); /* TAG_16BIT_MODULE_NAME */
SdbpSetDWORDAttr(&attr_info[23], TAG_LINK_DATE, headers->FileHeader.TimeDateStamp);
SdbpSetDWORDAttr(&attr_info[24], TAG_UPTO_LINK_DATE, headers->FileHeader.TimeDateStamp);
export_dir = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryEntryToData(mapped.view, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &export_dir_size);
if (export_dir)
{
PIMAGE_SECTION_HEADER section = NULL;
PBYTE export_name = ImageRvaToVa(headers, mapped.view, export_dir->Name, &section);
if (export_name)
SdbpSetStringAttrFromAnsiString(&attr_info[25], TAG_EXPORT_NAME, export_name, strlen((char*)export_name));
else
SdbpSetAttrFail(&attr_info[25]); /* TAG_EXPORT_NAME */
}
else
{
SdbpSetAttrFail(&attr_info[25]); /* TAG_EXPORT_NAME */
}
if (info_size)
SdbpSetDWORDAttr(&attr_info[26], TAG_VER_LANGUAGE, lang_page->language);
SdbpSetDWORDAttr(&attr_info[27], TAG_EXE_WRAPPER, 0); /* boolean */
}
else
{
int n;
for (n = 2; n < NUM_ATTRIBUTES; ++n)
{
if (n != 16 && n != 26)
SdbpSetAttrFail(&attr_info[n]);
}
if (module_type == 2)
{
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)mapped.view;
PBYTE end = mapped.view + mapped.size, ptr;
PIMAGE_OS2_HEADER os2 = (PIMAGE_OS2_HEADER)((PBYTE)dos + dos->e_lfanew);
if ((PBYTE)(os2 + 1) <= end)
{
ptr = (PBYTE)dos + os2->ne_nrestab;
if (ptr <= end && (ptr + 1 + *ptr) <= end)
SdbpSetStringAttrFromPascalString(&attr_info[19], TAG_16BIT_DESCRIPTION, ptr);
ptr = (PBYTE)os2 + os2->ne_restab;
if (ptr <= end && (ptr + 1 + *ptr) <= end)
SdbpSetStringAttrFromPascalString(&attr_info[20], TAG_16BIT_MODULE_NAME, ptr);
}
}
}
*attr_info_ret = attr_info;
*attr_count = NUM_ATTRIBUTES; /* As far as I know, this one is always 28 */
SdbFree(file_info);
SdbpCloseMemMappedFile(&mapped);
return TRUE;
}

View file

@ -2,8 +2,9 @@
add_definitions(-D__ROS_LONG64__)
list(APPEND SOURCE
layerapi.c
apphelp.c
data.c
layerapi.c
testlist.c)
add_executable(apphelp_apitest ${SOURCE})

View file

@ -35,6 +35,15 @@
#include "wine/test.h"
/* data.c */
void test_create_exe_imp(const char* name, int skip_rsrc_exports);
void test_create_file_imp(const char* name, const char* contents, size_t len);
void test_create_ne_imp(const char* name, int skip_names);
#define test_create_exe (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_create_exe_imp
#define test_create_file (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_create_file_imp
#define test_create_ne (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_create_ne_imp
static DWORD g_Version;
@ -48,6 +57,9 @@ static DWORD g_Version;
typedef WORD TAG;
typedef DWORD TAGID;
typedef DWORD TAGREF;
typedef UINT64 QWORD;
#define TAG_TYPE_MASK 0xF000
@ -60,10 +72,55 @@ typedef WORD TAG;
#define TAG_TYPE_LIST 0x7000
#define TAG_TYPE_STRING 0x8000
#define TAG_TYPE_BINARY 0x9000
#define TAG_NULL 0x0
#define TAG_SIZE (0x1 | TAG_TYPE_DWORD)
#define TAG_CHECKSUM (0x3 | TAG_TYPE_DWORD)
#define TAG_MODULE_TYPE (0x6 | TAG_TYPE_DWORD)
#define TAG_VERDATEHI (0x7 | TAG_TYPE_DWORD)
#define TAG_VERDATELO (0x8 | TAG_TYPE_DWORD)
#define TAG_VERFILEOS (0x9 | TAG_TYPE_DWORD)
#define TAG_VERFILETYPE (0xA | TAG_TYPE_DWORD)
#define TAG_PE_CHECKSUM (0xB | TAG_TYPE_DWORD)
#define TAG_VER_LANGUAGE (0x12 | TAG_TYPE_DWORD)
#define TAG_LINKER_VERSION (0x1C | TAG_TYPE_DWORD)
#define TAG_LINK_DATE (0x1D | TAG_TYPE_DWORD)
#define TAG_UPTO_LINK_DATE (0x1E | TAG_TYPE_DWORD)
#define TAG_EXE_WRAPPER (0x31 | TAG_TYPE_DWORD)
#define TAG_BIN_FILE_VERSION (0x2 | TAG_TYPE_QWORD)
#define TAG_BIN_PRODUCT_VERSION (0x3 | TAG_TYPE_QWORD)
#define TAG_UPTO_BIN_PRODUCT_VERSION (0x6 | TAG_TYPE_QWORD)
#define TAG_UPTO_BIN_FILE_VERSION (0xD | TAG_TYPE_QWORD)
#define TAG_NAME (0x1 | TAG_TYPE_STRINGREF)
#define TAG_COMPANY_NAME (0x9 | TAG_TYPE_STRINGREF)
#define TAG_PRODUCT_NAME (0x10 | TAG_TYPE_STRINGREF)
#define TAG_PRODUCT_VERSION (0x11 | TAG_TYPE_STRINGREF)
#define TAG_FILE_DESCRIPTION (0x12 | TAG_TYPE_STRINGREF)
#define TAG_FILE_VERSION (0x13 | TAG_TYPE_STRINGREF)
#define TAG_ORIGINAL_FILENAME (0x14 | TAG_TYPE_STRINGREF)
#define TAG_INTERNAL_NAME (0x15 | TAG_TYPE_STRINGREF)
#define TAG_LEGAL_COPYRIGHT (0x16 | TAG_TYPE_STRINGREF)
#define TAG_16BIT_DESCRIPTION (0x17 | TAG_TYPE_STRINGREF)
#define TAG_16BIT_MODULE_NAME (0x20 | TAG_TYPE_STRINGREF)
#define TAG_EXPORT_NAME (0x24 | TAG_TYPE_STRINGREF)
#define ATTRIBUTE_AVAILABLE 0x1
#define ATTRIBUTE_FAILED 0x2
typedef struct tagATTRINFO {
TAG type;
DWORD flags; /* ATTRIBUTE_AVAILABLE, ATTRIBUTE_FAILED */
union {
QWORD qwattr;
DWORD dwattr;
WCHAR *lpattr;
};
} ATTRINFO, *PATTRINFO;
static HMODULE hdll;
static LPCWSTR (WINAPI *pSdbTagToString)(TAG);
static BOOL (WINAPI *pSdbGetFileAttributes)(LPCWSTR, PATTRINFO *, LPDWORD);
static BOOL (WINAPI *pSdbFreeFileAttributes)(PATTRINFO);
static void test_SdbTagToString(void)
{
@ -368,6 +425,386 @@ static void test_SdbTagToStringAllTags(void)
}
}
static void expect_tag_skip_imp(PATTRINFO pattr, DWORD num)
{
PATTRINFO p = &pattr[num];
winetest_ok(p->type == TAG_NULL, "expected entry #%d to be TAG_NULL, was %x\n", num, p->type);
winetest_ok(p->flags == ATTRIBUTE_FAILED, "expected entry #%d to be failed, was %d\n", num, p->flags);
winetest_ok(p->qwattr == 0, "expected entry #%d to be 0, was 0x%I64x\n", num, p->qwattr);
}
static void expect_tag_empty_imp(PATTRINFO pattr, DWORD num)
{
PATTRINFO p = &pattr[num];
winetest_ok(p->type == TAG_NULL, "expected entry #%d to be TAG_NULL, was %x\n", num, p->type);
winetest_ok(p->flags == 0, "expected entry #%d to be 0, was %d\n", num, p->flags);
winetest_ok(p->qwattr == 0, "expected entry #%d to be 0, was 0x%I64x\n", num, p->qwattr);
}
static void expect_tag_dword_imp(PATTRINFO pattr, DWORD num, TAG tag, DWORD value)
{
PATTRINFO p = &pattr[num];
winetest_ok(p->type == tag, "expected entry #%d to be %x, was %x\n", num, tag, p->type);
winetest_ok(p->flags == ATTRIBUTE_AVAILABLE, "expected entry #%d to be available, was %d\n", num, p->flags);
winetest_ok(p->dwattr == value, "expected entry #%d to be 0x%x, was 0x%x\n", num, value, p->dwattr);
}
static void expect_tag_qword_imp(PATTRINFO pattr, DWORD num, TAG tag, QWORD value)
{
PATTRINFO p = &pattr[num];
winetest_ok(p->type == tag, "expected entry #%d to be %x, was %x\n", num, tag, p->type);
winetest_ok(p->flags == ATTRIBUTE_AVAILABLE, "expected entry #%d to be available, was %d\n", num, p->flags);
winetest_ok(p->qwattr == value, "expected entry #%d to be 0x%I64x, was 0x%I64x\n", num, value, p->qwattr);
}
static void expect_tag_str_imp(PATTRINFO pattr, DWORD num, TAG tag, const WCHAR* value)
{
PATTRINFO p = &pattr[num];
winetest_ok(p->type == tag, "expected entry #%d to be %x, was %x\n", num, tag, p->type);
winetest_ok(p->flags == ATTRIBUTE_AVAILABLE, "expected entry #%d to be available, was %d\n", num, p->flags);
winetest_ok(p->lpattr && wcscmp(p->lpattr, value) == 0, "expected entry #%d to be %s, was %s\n", num, wine_dbgstr_w(value), wine_dbgstr_w(p->lpattr));
}
#define expect_tag_skip (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_skip_imp
#define expect_tag_empty (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_empty_imp
#define expect_tag_dword (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_dword_imp
#define expect_tag_qword (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_qword_imp
#define expect_tag_str (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_str_imp
#define expect_tag_skip_range(ptr, from, to) \
do { \
int n = (from), n_end = (to); \
winetest_set_location(__FILE__, __LINE__); \
for ( ; n < n_end; ++n) \
expect_tag_skip_imp((ptr), n); \
} while (0)
#define test_crc (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_crc_imp
#define test_crc2 (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_crc2_imp
void test_onefile(WCHAR* filename)
{
PATTRINFO pattrinfo;
DWORD num;
if (!pSdbFreeFileAttributes)
{
hdll = LoadLibraryA("apphelp.dll");
pSdbTagToString = (void *)GetProcAddress(hdll, "SdbTagToString");
pSdbGetFileAttributes = (void *)GetProcAddress(hdll, "SdbGetFileAttributes");
pSdbFreeFileAttributes = (void *)GetProcAddress(hdll, "SdbFreeFileAttributes");
}
if (pSdbGetFileAttributes(filename, &pattrinfo, &num))
{
if (pattrinfo[16].flags == ATTRIBUTE_AVAILABLE)
{
if (pattrinfo[16].type != TAG_MODULE_TYPE)//SdbpSetAttrFail(&attr_info[16]); /* TAG_MODULE_TYPE (1: WIN16?) (3: WIN32?) (WIN64?), Win32VersionValue? */)
printf("FAIL TAG_MODULE_TYPE (%S)\n", filename);
if (pattrinfo[16].dwattr != 3 && pattrinfo[16].dwattr != 2)
printf("TAG_MODULE_TYPE(%S): %d\n", filename, pattrinfo[16].dwattr); // C:\Program Files (x86)\Windows Kits\8.1\Lib\win7\stub512.com
if (pattrinfo[16].dwattr == 2)
{
printf("TAG_MODULE_TYPE(%S): %d, %d\n", filename, pattrinfo[16].dwattr, pattrinfo[0].dwattr);
}
}
if (pattrinfo[27].flags == ATTRIBUTE_AVAILABLE)
{
if (pattrinfo[27].type != TAG_EXE_WRAPPER)
printf("FAIL TAG_EXE_WRAPPER (%S)\n", filename);
if (pattrinfo[27].dwattr != 0)
printf("TAG_EXE_WRAPPER(%S): %d\n", filename, pattrinfo[27].dwattr);
}
pSdbFreeFileAttributes(pattrinfo);
}
}
static void test_crc_imp(size_t len, DWORD expected)
{
static const WCHAR path[] = {'t','e','s','t','x','x','.','e','x','e',0};
static char crc_test[] = {4, 4, 4, 4, 1, 1, 1, 1, 4, 4, 4, 4, 2, 2, 2, 2};
PATTRINFO pattrinfo = (PATTRINFO)0xdead;
DWORD num = 333;
BOOL ret;
test_create_file_imp("testxx.exe", crc_test, len);
ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
winetest_ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
winetest_ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
winetest_ok(num == 28, "expected 28 items, got %d.\n", num);
if (num == 28 && ret)
{
expect_tag_dword_imp(pattrinfo, 1, TAG_CHECKSUM, expected);
}
if (ret)
pSdbFreeFileAttributes(pattrinfo);
}
static void test_crc2_imp(size_t len, int fill, DWORD expected)
{
static const WCHAR path[] = {'t','e','s','t','x','x','.','e','x','e',0};
PATTRINFO pattrinfo = (PATTRINFO)0xdead;
DWORD num = 333;
BOOL ret;
size_t n;
char* crc_test = malloc(len);
for (n = 0; n < len; ++n)
crc_test[n] = (char)(fill ? fill : n);
test_create_file_imp("testxx.exe", crc_test, len);
free(crc_test);
ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
winetest_ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
winetest_ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
winetest_ok(num == 28, "expected 28 items, got %d.\n", num);
if (num == 28 && ret)
{
expect_tag_dword_imp(pattrinfo, 0, TAG_SIZE, len);
expect_tag_dword_imp(pattrinfo, 1, TAG_CHECKSUM, expected);
}
if (ret)
pSdbFreeFileAttributes(pattrinfo);
}
static void test_ApplicationAttributes(void)
{
static const WCHAR path[] = {'t','e','s','t','x','x','.','e','x','e',0};
static const WCHAR PRODUCT_VERSION[] = {'1','.','0','.','0','.','1',0};
static const WCHAR FILE_DESCRIPTION[] = {'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0};
static const WCHAR COMPANY_NAME[] = {'C','o','m','p','a','n','y','N','a','m','e',0};
static const WCHAR PRODUCT_NAME[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
static const WCHAR FILE_VERSION[] = {'1','.','0','.','0','.','0',0};
static const WCHAR ORIGINAL_FILENAME[] = {'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0};
static const WCHAR INTERNAL_NAME[] = {'I','n','t','e','r','n','a','l','N','a','m','e',0};
static const WCHAR LEGAL_COPYRIGHT[] = {'L','e','g','a','l','C','o','p','y','r','i','g','h','t',0};
static const WCHAR EXPORT_NAME[] = {'T','e','S','t','2','.','e','x','e',0};
static const WCHAR OS2_DESCRIPTION[] = {'M','O','D',' ','D','E','S','C','R','I','P','T','I','O','N',' ','H','E','R','E',0};
static const WCHAR OS2_EXPORT_NAME[] = {'T','E','S','T','M','O','D','.','h','X','x',0};
static const WCHAR OS2_DESCRIPTION_broken[] = {'Z',0};
static const WCHAR OS2_EXPORT_NAME_broken[] = {'E',0};
PATTRINFO pattrinfo = (PATTRINFO)0xdead;
DWORD num = 333;
BOOL ret;
/* ensure the file is not there. */
DeleteFileA("testxx.exe");
ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
ok(ret == FALSE, "expected SdbGetFileAttributes to fail.\n");
ok(pattrinfo == (PATTRINFO)0xdead, "expected the pointer not to change.\n");
ok(num == 333, "expected the number of items not to change.\n");
if (ret)
pSdbFreeFileAttributes(pattrinfo);
/* Test a file with as much features as possible */
test_create_exe("testxx.exe", 0);
ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
ok(num == 28, "expected 28 items, got %d.\n", num);
if (num == 28 && ret)
{
expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0x800);
expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0x178bd629);
expect_tag_qword(pattrinfo, 2, TAG_BIN_FILE_VERSION, 0x1000000000000ull);
expect_tag_qword(pattrinfo, 3, TAG_BIN_PRODUCT_VERSION, 0x1000000000001ull);
expect_tag_str(pattrinfo, 4, TAG_PRODUCT_VERSION, PRODUCT_VERSION);
expect_tag_str(pattrinfo, 5, TAG_FILE_DESCRIPTION, FILE_DESCRIPTION);
expect_tag_str(pattrinfo, 6, TAG_COMPANY_NAME, COMPANY_NAME);
expect_tag_str(pattrinfo, 7, TAG_PRODUCT_NAME, PRODUCT_NAME);
expect_tag_str(pattrinfo, 8, TAG_FILE_VERSION, FILE_VERSION);
expect_tag_str(pattrinfo, 9, TAG_ORIGINAL_FILENAME, ORIGINAL_FILENAME);
expect_tag_str(pattrinfo, 10, TAG_INTERNAL_NAME, INTERNAL_NAME);
expect_tag_str(pattrinfo, 11, TAG_LEGAL_COPYRIGHT, LEGAL_COPYRIGHT);
expect_tag_dword(pattrinfo, 12, TAG_VERDATEHI, 0x1d1a019);
expect_tag_dword(pattrinfo, 13, TAG_VERDATELO, 0xac754c50);
expect_tag_dword(pattrinfo, 14, TAG_VERFILEOS, VOS__WINDOWS32);
expect_tag_dword(pattrinfo, 15, TAG_VERFILETYPE, VFT_APP);
expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x3); /* Win32 */
expect_tag_dword(pattrinfo, 17, TAG_PE_CHECKSUM, 0xBAAD);
expect_tag_dword(pattrinfo, 18, TAG_LINKER_VERSION, 0x40002);
expect_tag_skip(pattrinfo, 19); /* TAG_16BIT_DESCRIPTION */
expect_tag_skip(pattrinfo, 20); /* TAG_16BIT_MODULE_NAME */
expect_tag_qword(pattrinfo, 21, TAG_UPTO_BIN_FILE_VERSION, 0x1000000000000ull);
expect_tag_qword(pattrinfo, 22, TAG_UPTO_BIN_PRODUCT_VERSION, 0x1000000000001ull);
expect_tag_dword(pattrinfo, 23, TAG_LINK_DATE, 0x12345);
expect_tag_dword(pattrinfo, 24, TAG_UPTO_LINK_DATE, 0x12345);
expect_tag_str(pattrinfo, 25, TAG_EXPORT_NAME, EXPORT_NAME);
expect_tag_dword(pattrinfo, 26, TAG_VER_LANGUAGE, 0xffff);
expect_tag_dword(pattrinfo, 27, TAG_EXE_WRAPPER, 0x0);
}
if (ret)
pSdbFreeFileAttributes(pattrinfo);
/* Disable resource and exports */
test_create_exe("testxx.exe", 1);
ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
ok(num == 28, "expected 28 items, got %d.\n", num);
if (num == 28 && ret)
{
expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0x800);
expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0xea7caffd);
expect_tag_skip_range(pattrinfo, 2, 16);
expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x3); /* Win32 */
expect_tag_dword(pattrinfo, 17, TAG_PE_CHECKSUM, 0xBAAD);
expect_tag_dword(pattrinfo, 18, TAG_LINKER_VERSION, 0x40002);
expect_tag_skip_range(pattrinfo, 19, 23);
expect_tag_dword(pattrinfo, 23, TAG_LINK_DATE, 0x12345);
expect_tag_dword(pattrinfo, 24, TAG_UPTO_LINK_DATE, 0x12345);
expect_tag_skip(pattrinfo, 25); /* TAG_EXPORT_NAME */
expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
expect_tag_dword(pattrinfo, 27, TAG_EXE_WRAPPER, 0x0);
}
if (ret)
pSdbFreeFileAttributes(pattrinfo);
/* A file with just 'MZ' */
test_create_file("testxx.exe", "MZ", 2);
ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
ok(num == 28, "expected 28 items, got %d.\n", num);
if (num == 28 && ret)
{
expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0x2);
expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0);
expect_tag_skip_range(pattrinfo, 2, 16);
expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x1);
expect_tag_skip_range(pattrinfo, 17, 26);
expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
expect_tag_skip(pattrinfo, 27); /* TAG_EXE_WRAPPER */
}
if (ret)
pSdbFreeFileAttributes(pattrinfo);
/* Empty file */
test_create_file("testxx.exe", NULL, 0);
ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
ok(num == 28, "expected 28 items, got %d.\n", num);
if (num == 28 && ret)
{
expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0);
expect_tag_skip_range(pattrinfo, 1, 26);
expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
expect_tag_skip(pattrinfo, 27); /* TAG_EXE_WRAPPER */
}
if (ret)
pSdbFreeFileAttributes(pattrinfo);
/* minimal NE executable */
test_create_ne("testxx.exe", 0);
ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
ok(num == 28, "expected 28 items, got %d.\n", num);
if (num == 28 && ret)
{
expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0xa8);
expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0xf2abe4e9);
expect_tag_skip_range(pattrinfo, 2, 16);
expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x2);
expect_tag_skip(pattrinfo, 17); /* TAG_PE_CHECKSUM */
expect_tag_skip(pattrinfo, 18); /* TAG_LINKER_VERSION */
expect_tag_str(pattrinfo, 19, TAG_16BIT_DESCRIPTION, OS2_DESCRIPTION);
expect_tag_str(pattrinfo, 20, TAG_16BIT_MODULE_NAME, OS2_EXPORT_NAME);
expect_tag_skip_range(pattrinfo, 21, 26);
expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
expect_tag_skip(pattrinfo, 27); /* TAG_EXE_WRAPPER */
}
if (ret)
pSdbFreeFileAttributes(pattrinfo);
/* NE executable with description / module name pointers zero, to show they are always used */
test_create_ne("testxx.exe", 1);
ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
ok(num == 28, "expected 28 items, got %d.\n", num);
if (num == 28 && ret)
{
expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0xa8);
expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0xddcbe4c9);
expect_tag_skip_range(pattrinfo, 2, 16);
expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x2);
expect_tag_skip(pattrinfo, 17); /* TAG_PE_CHECKSUM */
expect_tag_skip(pattrinfo, 18); /* TAG_LINKER_VERSION */
expect_tag_str(pattrinfo, 19, TAG_16BIT_DESCRIPTION, OS2_DESCRIPTION_broken); /* the 'Z' from 'MZ' */
expect_tag_str(pattrinfo, 20, TAG_16BIT_MODULE_NAME, OS2_EXPORT_NAME_broken); /* the 'E' from 'NE' */
expect_tag_skip_range(pattrinfo, 21, 26);
expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
expect_tag_skip(pattrinfo, 27); /* TAG_EXE_WRAPPER */
}
if (ret)
pSdbFreeFileAttributes(pattrinfo);
test_crc(1, 0);
test_crc(2, 0);
test_crc(3, 0);
test_crc(4, 0x2020202);
test_crc(5, 0x2020202);
test_crc(6, 0x2020202);
test_crc(7, 0x2020202);
test_crc(8, 0x81818181);
test_crc(9, 0x81818181);
test_crc(10, 0x81818181);
test_crc(11, 0x81818181);
test_crc(12, 0xc2c2c2c2);
test_crc(16, 0x62626262);
/* This seems to be the cutoff point */
test_crc2(0xffc, 4, 0xfbfbfcfc);
test_crc2(0xffc, 8, 0x7070717);
test_crc2(0xffc, 0xcc, 0xc8eba002);
test_crc2(0xffc, 0, 0x4622028d);
test_crc2(0x1000, 4, 0x80);
test_crc2(0x1000, 8, 0x8787878f);
test_crc2(0x1000, 0xcc, 0x4adc3667);
test_crc2(0x1000, 0, 0xa3108044);
/* Here is another cutoff point */
test_crc2(0x11fc, 4, 0x80);
test_crc2(0x11fc, 8, 0x8787878f);
test_crc2(0x11fc, 0xcc, 0x4adc3667);
test_crc2(0x11fc, 0, 0xf03e0800);
test_crc2(0x1200, 4, 0x80);
test_crc2(0x1200, 8, 0x8787878f);
test_crc2(0x1200, 0xcc, 0x4adc3667);
test_crc2(0x1200, 0, 0xa3108044);
/* After that, it stays the same for all sizes */
test_crc2(0xf000, 4, 0x80);
test_crc2(0xf000, 8, 0x8787878f);
test_crc2(0xf000, 0xcc, 0x4adc3667);
test_crc2(0xf000, 0, 0xa3108044);
DeleteFileA("testxx.exe");
}
START_TEST(apphelp)
{
RTL_OSVERSIONINFOEXW rtlinfo;
@ -383,6 +820,10 @@ START_TEST(apphelp)
//SetEnvironmentVariable("DEBUGCHANNEL", "+apphelp");
hdll = LoadLibraryA("apphelp.dll");
pSdbTagToString = (void *) GetProcAddress(hdll, "SdbTagToString");
pSdbGetFileAttributes = (void *) GetProcAddress(hdll, "SdbGetFileAttributes");
pSdbFreeFileAttributes = (void *) GetProcAddress(hdll, "SdbFreeFileAttributes");
test_ApplicationAttributes();
test_SdbTagToString();
#ifdef __REACTOS__
if (g_Version < VERSION_WIN7)

View file

@ -0,0 +1,573 @@
/*
* Copyright 2015 Mark Jansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <exdisp.h>
#include <winbase.h>
#include "wine/test.h"
static IMAGE_DOS_HEADER dos_header =
{
IMAGE_DOS_SIGNATURE, /* e_magic */
144, /* e_cblp */
3, /* e_cp */
0, /* e_crlc */
4, /* e_cparhdr */
0, /* e_minalloc */
65535, /* e_maxalloc */
0, /* e_ss */
184, /* e_sp */
0, /* e_csum */
0, /* e_ip */
0, /* e_cs */
64, /* e_lfarlc */
0, /* e_ovno */
{ 0 }, /* e_res[4] */
0, /* e_oemid */
0, /* e_oeminfo */
{ 0 }, /* e_res2[10] */
0x80 /* e_lfanew */
};
static IMAGE_NT_HEADERS32 nt_header =
{
IMAGE_NT_SIGNATURE, /* Signature */
{
IMAGE_FILE_MACHINE_I386, /* Machine */
2, /* NumberOfSections */
0x12345, /* TimeDateStamp */
0, /* PointerToSymbolTable */
0, /* NumberOfSymbols */
sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_32BIT_MACHINE /* Characteristics */
},
{
IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
6, /* MajorLinkerVersion */
3, /* MinorLinkerVersion */
0, /* SizeOfCode */
0, /* SizeOfInitializedData */
0, /* SizeOfUninitializedData */
0x1000, /* AddressOfEntryPoint */
0x1000, /* BaseOfCode */
#ifndef _WIN64
0, /* BaseOfData */
#endif
0x400000, /* ImageBase */
0x1000, /* SectionAlignment */
0x200, /* FileAlignment */
4, /* MajorOperatingSystemVersion */
1, /* MinorOperatingSystemVersion */
4, /* MajorImageVersion */
2, /* MinorImageVersion */
4, /* MajorSubsystemVersion */
3, /* MinorSubsystemVersion */
0, /* Win32VersionValue */
0x3000, /* SizeOfImage */
0x200, /* SizeOfHeaders */
0xBAAD, /* CheckSum: This checksum is not the correct checksum, intentionally! */
IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
0, /* DllCharacteristics */
0x100000, /* SizeOfStackReserve */
0x1000, /* SizeOfStackCommit */
0x100000, /* SizeOfHeapReserve */
0x1000, /* SizeOfHeapCommit */
0, /* LoaderFlags */
0x10, /* NumberOfRvaAndSizes */
{
/* IMAGE_DIRECTORY_ENTRY_EXPORT */
{
0x2370, /* VirtualAddress */
76, /* Size */
},
{ 0 },
/* IMAGE_DIRECTORY_ENTRY_RESOURCE */
{
0x2000, /* VirtualAddress */
868, /* Size */
},
} /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
}
};
static IMAGE_SECTION_HEADER section_headers[] =
{
{
{ '.','t','e','x','t',0 }, /* Name */
{ 24 }, /* VirtualSize */
0x1000, /* VirtualAddress */
0x200, /* SizeOfRawData */
0x200, /* PointerToRawData */
0, /* PointerToRelocations */
0, /* PointerToLinenumbers */
0, /* NumberOfRelocations */
0, /* NumberOfLinenumbers */
IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ /* Characteristics */
},
{
{ '.','r','s','r','c',0 }, /* Name */
{ 880 }, /* VirtualSize */
0x2000, /* VirtualAddress */
0x400, /* SizeOfRawData */
0x400, /* PointerToRawData */
0, /* PointerToRelocations */
0, /* PointerToLinenumbers */
0, /* NumberOfRelocations */
0, /* NumberOfLinenumbers */
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ /* Characteristics */
}
};
static const unsigned char text_section[] =
{
0x33, 0xc0, /* xor eax, eax */
0xc3 /* ret */
};
/* taken from fusionpriv.h */
typedef struct
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[17];
VS_FIXEDFILEINFO Value;
} VS_VERSIONINFO;
typedef struct
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[15];
} STRINGFILEINFO;
typedef struct
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[9];
} STRINGTABLE;
typedef struct
{
WORD wLength;
WORD wValueLength;
WORD wType;
} STRINGHDR;
typedef struct
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[13];
} VARFILEINFO;
typedef struct
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[13];
DWORD Value;
} VAR;
typedef struct rsrc_section_t
{
IMAGE_RESOURCE_DIRECTORY header;
IMAGE_RESOURCE_DIRECTORY_ENTRY file_info_id;
IMAGE_RESOURCE_DIRECTORY file_info_header;
IMAGE_RESOURCE_DIRECTORY_ENTRY version_info_id;
IMAGE_RESOURCE_DIRECTORY version_info_header;
IMAGE_RESOURCE_DIRECTORY_ENTRY version_lang_id;
IMAGE_RESOURCE_DATA_ENTRY version_data_entry;
VS_VERSIONINFO version_info;
STRINGFILEINFO string_file_info;
STRINGTABLE string_table;
STRINGHDR FileVersion_hdr;
WCHAR FileVersion_key[13];
WCHAR FileVersion_val[8];
STRINGHDR ProductVersion_hdr;
WCHAR ProductVersion_key[15];
WCHAR ProductVersion_val[8];
STRINGHDR CompanyName_hdr;
WCHAR CompanyName_key[13];
WCHAR CompanyName_val[12];
STRINGHDR FileDescription_hdr;
WCHAR FileDescription_key[17];
WCHAR FileDescription_val[16];
STRINGHDR InternalName_hdr;
WCHAR InternalName_key[13];
WCHAR InternalName_val[14];
STRINGHDR LegalCopyright_hdr;
WCHAR LegalCopyright_key[15];
WCHAR LegalCopyright_val[16];
STRINGHDR LegalTrademarks_hdr;
WCHAR LegalTrademarks_key[17];
WCHAR LegalTrademarks_val[16];
STRINGHDR OriginalFilename_hdr;
WCHAR OriginalFilename_key[17];
WCHAR OriginalFilename_val[18];
STRINGHDR Productname_hdr;
WCHAR Productname_key[13];
WCHAR Productname_val[12];
VARFILEINFO file_info;
VAR translation;
} rsrc_section_t;
static const rsrc_section_t rsrc_section =
{
/* header */
{
0, /* Characteristics */
0x55FE8E21, /* TimeDateStamp, 20/09/2015 10:44:49 */
0, /* MajorVersion */
0, /* MinorVersion */
0, /* NumberOfNamedEntries */
1, /* NumberOfIdEntries */
},
/* file_info_id */
{
{{
(DWORD)VS_FILE_INFO, /* NameOffset:31 */
0 /* NameIsString:1 */
}},
{
0x80000018 /* OffsetToData */
}
},
/* file_info_header */
{
0, /* Characteristics */
0x55FE8E21, /* TimeDateStamp, 20/09/2015 10:44:49 */
0, /* MajorVersion */
0, /* MinorVersion */
0, /* NumberOfNamedEntries */
1, /* NumberOfIdEntries */
},
/* version_info_id */
{
{{
VS_VERSION_INFO, /* NameOffset:31 */
0 /* NameIsString:1 */
}},
{
0x80000030 /* OffsetToData */
},
},
/* version_info_header */
{
0, /* Characteristics */
0x55FE8E21, /* TimeDateStamp, 20/09/2015 10:44:49 */
0, /* MajorVersion */
0, /* MinorVersion */
0, /* NumberOfNamedEntries */
1, /* NumberOfIdEntries */
},
/* version_lang_id */
{
{{
1033, /* NameOffset:31 */
0 /* NameIsString:1 */
}},
{
0x48 /* OffsetToDirectory */
}
},
/* version_data_entry */
{
0x2058, /* OffsetToData */
0x30C, /* Size */
0, /* CodePage */
0, /* Reserved */
},
/* version_info */
{
0x30C, /* wLength */
0x34, /* wValueLength */
0, /* wType: Binary */
{ 'V','S','_','V','E','R','S','I','O','N','_','I','N','F','O','\0','\0' }, /* szKey[17] */
/* Value */
{
0xFEEF04BD, /* dwSignature */
0x10000, /* dwStrucVersion */
0x10000, /* dwFileVersionMS */
0, /* dwFileVersionLS */
0x10000, /* dwProductVersionMS */
1, /* dwProductVersionLS */
0, /* dwFileFlagsMask */
0, /* dwFileFlags */
VOS__WINDOWS32, /* dwFileOS */
VFT_APP, /* dwFileType */
0, /* dwFileSubtype */
0x01d1a019, /* dwFileDateMS */
0xac754c50 /* dwFileDateLS */
},
},
/* string_file_info */
{
0x26C, /* wLength */
0, /* wValueLength */
1, /* wType: Text */
{ 'S','t','r','i','n','g','F','i','l','e','I','n','f','o','\0' } /* szKey[15] */
},
/* string_table */
{
0x248, /* wLength */
0, /* wValueLength */
1, /* wType: Text */
{ 'F','F','F','F','0','0','0','0','\0' } /* szKey[9] */
},
/* FileVersion */
{
48, /* wLength */
8, /* wValueLength */
1, /* wType: Text */
},
{ 'F','i','l','e','V','e','r','s','i','o','n','\0' },
{ '1','.','0','.','0','.','0','\0' },
/* ProductVersion */
{
52, /* wLength */
8, /* wValueLength */
1, /* wType: Text */
},
{ 'P','r','o','d','u','c','t','V','e','r','s','i','o','n','\0' },
{ '1','.','0','.','0','.','1','\0' },
/* CompanyName */
{
56, /* wLength */
12, /* wValueLength */
1, /* wType: Text */
},
{ 'C','o','m','p','a','n','y','N','a','m','e','\0' },
{ 'C','o','m','p','a','n','y','N','a','m','e','\0' },
/* FileDescription */
{
72, /* wLength */
16, /* wValueLength */
1, /* wType: Text */
},
{ 'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n','\0' },
{ 'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n','\0' },
/* InternalName */
{
58, /* wLength */
13, /* wValueLength */
1, /* wType: Text */
},
{ 'I','n','t','e','r','n','a','l','N','a','m','e','\0' },
{ 'I','n','t','e','r','n','a','l','N','a','m','e','\0' },
/* LegalCopyright */
{
66, /* wLength */
15, /* wValueLength */
1, /* wType: Text */
},
{ 'L','e','g','a','l','C','o','p','y','r','i','g','h','t','\0' },
{ 'L','e','g','a','l','C','o','p','y','r','i','g','h','t','\0' },
/* LegalTrademarks */
{
72, /* wLength */
16, /* wValueLength */
1, /* wType: Text */
},
{ 'L','e','g','a','l','T','r','a','d','e','m','a','r','k','s','\0' },
{ 'L','e','g','a','l','T','r','a','d','e','m','a','r','k','s','\0' },
/* OriginalFilename */
{
74, /* wLength */
17, /* wValueLength */
1, /* wType: Text */
},
{ 'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e','\0' },
{ 'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e','\0' },
/* ProductName */
{
56, /* wLength */
12, /* wValueLength */
1, /* wType: Text */
},
{ 'P','r','o','d','u','c','t','N','a','m','e','\0' },
{ 'P','r','o','d','u','c','t','N','a','m','e','\0' },
/* file_info */
{
0x44, /* wLength */
0, /* wValueLength */
1, /* wType: Text */
{ 'V','a','r','F','i','l','e','I','n','f','o','\0' } /* szKey[13] */
},
/* translation */
{
0x24, /* wLength */
4, /* wValueLength */
0, /* wType: Binary */
{ 'T','r','a','n','s','l','a','t','i','o','n','\0' }, /* szKey[13] */
0xffff /* Value */
}
};
typedef struct export_section_t
{
IMAGE_EXPORT_DIRECTORY desc;
char binary_name[10];
} export_section_t;
/* This export section is not complete, but the Name RVA is only taken into account */
static export_section_t export_dir =
{
{
0, /* Characteristics */
0, /* TimeDateStamp */
0, /* MajorVersion */
0, /* MinorVersion */
0x2398, /* Name (RVA) */
1, /* Base */
0, /* NumberOfFunctions */
0, /* NumberOfNames */
0, /* AddressOfFunctions (RVA) */
0, /* AddressOfNames (RVA) */
0, /* AddressOfNameOrdinals (RVA) */
},
{ 'T','e','S','t','2','.','e','x','e',0 }, /* binary_name */
};
void test_create_exe_imp(const char* name, int skip_rsrc_exports)
{
HANDLE file;
char *buf, *cur;
DWORD size = 0x800;
buf = malloc(size);
file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
winetest_ok(file != INVALID_HANDLE_VALUE, "can't create file\n");
if(file == INVALID_HANDLE_VALUE)
return;
memset(buf, 0, size);
cur = buf;
cur = memcpy(buf, &dos_header, sizeof(dos_header));
cur += dos_header.e_lfanew;
memcpy(cur, &nt_header, sizeof(nt_header));
if (skip_rsrc_exports)
{
((IMAGE_NT_HEADERS32*)cur)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = 0;
((IMAGE_NT_HEADERS32*)cur)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = 0;
}
cur += sizeof(nt_header);
memcpy(cur, section_headers, sizeof(section_headers));
/* write code section: */
cur = buf + section_headers[0].PointerToRawData;
memcpy(cur, text_section, sizeof(text_section));
if (!skip_rsrc_exports)
{
/* write resource section: */
cur = buf + section_headers[1].PointerToRawData;
memcpy(cur, &rsrc_section, sizeof(rsrc_section));
/* write minimal export directory: */
cur += 0x370;
memcpy(cur, &export_dir, sizeof(export_dir));
}
WriteFile(file, buf, size, &size, NULL);
free(buf);
CloseHandle(file);
}
/* Almost everything in this filetype is ignored, only e_lfanew, ne_restab and ne_nrestab are relevant */
void test_create_ne_imp(const char* name, int skip_names)
{
HANDLE file;
DWORD size;
IMAGE_DOS_HEADER MZ_hdr = { IMAGE_DOS_SIGNATURE, 0 };
IMAGE_OS2_HEADER NE_hdr = { IMAGE_OS2_SIGNATURE, 0 };
static const BYTE NE_names[] =
{
/* Show that the length is used, not the nullterm*/
11,'T','E','S','T','M','O','D','.','h','X','x','x',0,0,0,
20,'M','O','D',' ','D','E','S','C','R','I','P','T','I','O','N',' ','H','E','R','E',0,0,0
};
file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
winetest_ok(file != INVALID_HANDLE_VALUE, "can't create file\n");
if(file == INVALID_HANDLE_VALUE)
return;
MZ_hdr.e_lfanew = sizeof(MZ_hdr);
if (!skip_names)
{
NE_hdr.ne_restab = sizeof(NE_hdr); /* First entry (pascal string + ordinal) = module name */
NE_hdr.ne_nrestab = sizeof(MZ_hdr) + sizeof(NE_hdr) + 16; /* First entry (pascal string + ordinal) = module description */
}
WriteFile(file, &MZ_hdr, sizeof(MZ_hdr), &size, NULL);
WriteFile(file, &NE_hdr, sizeof(NE_hdr), &size, NULL);
WriteFile(file, NE_names, sizeof(NE_names), &size, NULL);
CloseHandle(file);
}
void test_create_file_imp(const char* name, const char* contents, size_t len)
{
HANDLE file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
winetest_ok(file != INVALID_HANDLE_VALUE, "can't create file\n");
if (file != INVALID_HANDLE_VALUE)
{
if (contents && len)
{
DWORD size;
WriteFile(file, contents, len, &size, NULL);
}
CloseHandle(file);
}
}