3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/bintype.c
6 * PURPOSE: Binary detection functions
7 * PROGRAMMER: Alexandre Julliard (WINE)
8 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
10 * 02/05/2004 - Ported/Adapted from WINE
13 /* INCLUDES *****************************************************************/
20 static ULONG gDebugChannel
= kernel32file
;
23 /* FUNCTIONS ****************************************************************/
25 /* Check whether a file is an OS/2 or a very old Windows executable
26 * by testing on import of KERNEL.
28 * FIXME: is reading the module imports the only way of discerning
29 * old Windows binaries from OS/2 ones ? At least it seems so...
32 InternalIsOS2OrOldWin(HANDLE hFile
, IMAGE_DOS_HEADER
*mz
, IMAGE_OS2_HEADER
*ne
)
41 CurPos
= SetFilePointer(hFile
, 0, NULL
, FILE_CURRENT
);
43 /* read modref table */
44 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_modtab
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
45 (!(modtab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_cmod
* sizeof(WORD
)))) ||
46 (!(ReadFile(hFile
, modtab
, ne
->ne_cmod
* sizeof(WORD
), &Read
, NULL
))) ||
47 (Read
!= (DWORD
)ne
->ne_cmod
* sizeof(WORD
)))
52 /* read imported names table */
53 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_imptab
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
54 (!(nametab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_enttab
- ne
->ne_imptab
))) ||
55 (!(ReadFile(hFile
, nametab
, ne
->ne_enttab
- ne
->ne_imptab
, &Read
, NULL
))) ||
56 (Read
!= (DWORD
)ne
->ne_enttab
- ne
->ne_imptab
))
61 for(i
= 0; i
< ne
->ne_cmod
; i
++)
64 module
= &nametab
[modtab
[i
]];
65 if(!strncmp(&module
[1], "KERNEL", module
[0]))
67 /* very old windows file */
74 WARN("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
77 HeapFree(GetProcessHeap(), 0, modtab
);
78 HeapFree(GetProcessHeap(), 0, nametab
);
79 SetFilePointer(hFile
, CurPos
, NULL
, FILE_BEGIN
);
84 InternalGetBinaryType(HANDLE hFile
)
90 unsigned char magic
[4];
91 unsigned char ignored
[12];
97 unsigned long cputype
;
98 unsigned long cpusubtype
;
99 unsigned long filetype
;
106 if((SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
107 (!ReadFile(hFile
, &Header
, sizeof(Header
), &Read
, NULL
) ||
108 (Read
!= sizeof(Header
))))
110 return BINARY_UNKNOWN
;
113 if(!memcmp(Header
.elf
.magic
, "\177ELF", sizeof(Header
.elf
.magic
)))
115 /* FIXME: we don't bother to check byte order, architecture, etc. */
116 switch(Header
.elf
.type
)
119 return BINARY_UNIX_EXE
;
121 return BINARY_UNIX_LIB
;
123 return BINARY_UNKNOWN
;
126 /* Mach-o File with Endian set to Big Endian or Little Endian*/
127 if(Header
.macho
.magic
== 0xFEEDFACE ||
128 Header
.macho
.magic
== 0xCEFAEDFE)
130 switch(Header
.macho
.filetype
)
134 return BINARY_UNIX_LIB
;
136 return BINARY_UNKNOWN
;
139 /* Not ELF, try DOS */
140 if(Header
.mz
.e_magic
== IMAGE_DOS_SIGNATURE
)
142 /* We do have a DOS image so we will now try to seek into
143 * the file by the amount indicated by the field
144 * "Offset to extended header" and read in the
145 * "magic" field information at that location.
146 * This will tell us if there is more header information
149 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
150 (!ReadFile(hFile
, magic
, sizeof(magic
), &Read
, NULL
) ||
151 (Read
!= sizeof(magic
))))
156 /* Reading the magic field succeeded so
157 * we will try to determine what type it is.
159 if(!memcmp(magic
, "PE\0\0", sizeof(magic
)))
161 IMAGE_FILE_HEADER FileHeader
;
162 if(!ReadFile(hFile
, &FileHeader
, sizeof(IMAGE_FILE_HEADER
), &Read
, NULL
) ||
163 (Read
!= sizeof(IMAGE_FILE_HEADER
)))
168 /* FIXME - detect 32/64 bit */
170 if(FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
171 return BINARY_PE_DLL32
;
172 return BINARY_PE_EXE32
;
175 if(!memcmp(magic
, "NE", 1))
177 /* This is a Windows executable (NE) header. This can
178 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
179 * DOS program (running under a DOS extender). To decide
180 * which, we'll have to read the NE header.
183 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == 1) ||
184 !ReadFile(hFile
, &ne
, sizeof(IMAGE_OS2_HEADER
), &Read
, NULL
) ||
185 (Read
!= sizeof(IMAGE_OS2_HEADER
)))
187 /* Couldn't read header, so abort. */
198 return InternalIsOS2OrOldWin(hFile
, &Header
.mz
, &ne
);
203 return BINARY_UNKNOWN
;
212 LPCWSTR lpApplicationName
,
219 if(!lpApplicationName
|| !lpBinaryType
)
221 SetLastError(ERROR_INVALID_PARAMETER
);
225 hFile
= CreateFileW(lpApplicationName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
226 OPEN_EXISTING
, 0, 0);
227 if(hFile
== INVALID_HANDLE_VALUE
)
232 BinType
= InternalGetBinaryType(hFile
);
242 * guess from filename
244 if(!(dot
= wcsrchr(lpApplicationName
, L
'.')))
248 if(!lstrcmpiW(dot
, L
".COM"))
250 *lpBinaryType
= SCS_DOS_BINARY
;
253 if(!lstrcmpiW(dot
, L
".PIF"))
255 *lpBinaryType
= SCS_PIF_BINARY
;
260 case BINARY_PE_EXE32
:
261 case BINARY_PE_DLL32
:
263 *lpBinaryType
= SCS_32BIT_BINARY
;
266 case BINARY_PE_EXE64
:
267 case BINARY_PE_DLL64
:
269 *lpBinaryType
= SCS_64BIT_BINARY
;
274 *lpBinaryType
= SCS_WOW_BINARY
;
279 *lpBinaryType
= SCS_OS216_BINARY
;
284 *lpBinaryType
= SCS_DOS_BINARY
;
287 case BINARY_UNIX_EXE
:
288 case BINARY_UNIX_LIB
:
294 ERR("Invalid binary type returned!\n", BinType
);
305 LPCSTR lpApplicationName
,
309 PWCHAR ApplicationNameW
;
311 if(!lpApplicationName
|| !lpBinaryType
)
313 SetLastError(ERROR_INVALID_PARAMETER
);
317 if (!(ApplicationNameW
= FilenameA2W(lpApplicationName
, FALSE
)))
320 return GetBinaryTypeW(ApplicationNameW
, lpBinaryType
);