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 *****************************************************************/
18 #include "../include/debug.h"
20 /* FUNCTIONS ****************************************************************/
22 /* Check whether a file is an OS/2 or a very old Windows executable
23 * by testing on import of KERNEL.
25 * FIXME: is reading the module imports the only way of discerning
26 * old Windows binaries from OS/2 ones ? At least it seems so...
29 InternalIsOS2OrOldWin(HANDLE hFile
, IMAGE_DOS_HEADER
*mz
, IMAGE_OS2_HEADER
*ne
)
38 CurPos
= SetFilePointer(hFile
, 0, NULL
, FILE_CURRENT
);
40 /* read modref table */
41 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_modtab
, NULL
, FILE_BEGIN
) == (DWORD
)-1) ||
42 (!(modtab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_cmod
* sizeof(WORD
)))) ||
43 (!(ReadFile(hFile
, modtab
, ne
->ne_cmod
* sizeof(WORD
), &Read
, NULL
))) ||
44 (Read
!= (DWORD
)ne
->ne_cmod
* sizeof(WORD
)))
49 /* read imported names table */
50 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_imptab
, NULL
, FILE_BEGIN
) == (DWORD
)-1) ||
51 (!(nametab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_enttab
- ne
->ne_imptab
))) ||
52 (!(ReadFile(hFile
, nametab
, ne
->ne_enttab
- ne
->ne_imptab
, &Read
, NULL
))) ||
53 (Read
!= (DWORD
)ne
->ne_enttab
- ne
->ne_imptab
))
58 for(i
= 0; i
< ne
->ne_cmod
; i
++)
61 module
= &nametab
[modtab
[i
]];
62 if(!strncmp(&module
[1], "KERNEL", module
[0]))
64 /* very old windows file */
71 DPRINT("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
74 HeapFree(GetProcessHeap(), 0, modtab
);
75 HeapFree(GetProcessHeap(), 0, nametab
);
76 SetFilePointer(hFile
, CurPos
, NULL
, FILE_BEGIN
);
81 InternalGetBinaryType(HANDLE hFile
)
87 unsigned char magic
[4];
88 unsigned char ignored
[12];
94 unsigned long cputype
;
95 unsigned long cpusubtype
;
96 unsigned long filetype
;
103 if((SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
) == (DWORD
)-1) ||
104 (!ReadFile(hFile
, &Header
, sizeof(Header
), &Read
, NULL
) ||
105 (Read
!= sizeof(Header
))))
107 return BINARY_UNKNOWN
;
110 if(!memcmp(Header
.elf
.magic
, "\177ELF", sizeof(Header
.elf
.magic
)))
112 /* FIXME: we don't bother to check byte order, architecture, etc. */
113 switch(Header
.elf
.type
)
116 return BINARY_UNIX_EXE
;
118 return BINARY_UNIX_LIB
;
120 return BINARY_UNKNOWN
;
123 /* Mach-o File with Endian set to Big Endian or Little Endian*/
124 if(Header
.macho
.magic
== 0xFEEDFACE ||
125 Header
.macho
.magic
== 0xCEFAEDFE)
127 switch(Header
.macho
.filetype
)
131 return BINARY_UNIX_LIB
;
133 return BINARY_UNKNOWN
;
136 /* Not ELF, try DOS */
137 if(Header
.mz
.e_magic
== IMAGE_DOS_SIGNATURE
)
139 /* We do have a DOS image so we will now try to seek into
140 * the file by the amount indicated by the field
141 * "Offset to extended header" and read in the
142 * "magic" field information at that location.
143 * This will tell us if there is more header information
146 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == (DWORD
)-1) ||
147 (!ReadFile(hFile
, magic
, sizeof(magic
), &Read
, NULL
) ||
148 (Read
!= sizeof(magic
))))
153 /* Reading the magic field succeeded so
154 * we will try to determine what type it is.
156 if(!memcmp(magic
, "PE\0\0", sizeof(magic
)))
158 IMAGE_FILE_HEADER FileHeader
;
159 if(!ReadFile(hFile
, &FileHeader
, sizeof(IMAGE_FILE_HEADER
), &Read
, NULL
) ||
160 (Read
== sizeof(IMAGE_FILE_HEADER
)))
165 /* FIXME - detect 32/64 bit */
167 if(FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
168 return BINARY_PE_DLL32
;
169 return BINARY_PE_EXE32
;
172 if(!memcmp(magic
, "NE", 1))
174 /* This is a Windows executable (NE) header. This can
175 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
176 * DOS program (running under a DOS extender). To decide
177 * which, we'll have to read the NE header.
180 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == 1) ||
181 !ReadFile(hFile
, &ne
, sizeof(IMAGE_OS2_HEADER
), &Read
, NULL
) ||
182 (Read
== sizeof(IMAGE_OS2_HEADER
)))
184 /* Couldn't read header, so abort. */
195 return InternalIsOS2OrOldWin(hFile
, &Header
.mz
, &ne
);
200 return BINARY_UNKNOWN
;
209 LPCWSTR lpApplicationName
,
216 if(!lpApplicationName
|| !lpBinaryType
)
218 SetLastError(ERROR_INVALID_PARAMETER
);
222 hFile
= CreateFileW(lpApplicationName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
223 OPEN_EXISTING
, 0, 0);
224 if(hFile
== INVALID_HANDLE_VALUE
)
229 BinType
= InternalGetBinaryType(hFile
);
239 * guess from filename
241 if(!(dot
= wcsrchr(lpApplicationName
, L
'.')))
245 if(!lstrcmpiW(dot
, L
".COM"))
247 *lpBinaryType
= SCS_DOS_BINARY
;
250 if(!lstrcmpiW(dot
, L
".PIF"))
252 *lpBinaryType
= SCS_PIF_BINARY
;
257 case BINARY_PE_EXE32
:
258 case BINARY_PE_DLL32
:
260 *lpBinaryType
= SCS_32BIT_BINARY
;
263 case BINARY_PE_EXE64
:
264 case BINARY_PE_DLL64
:
266 *lpBinaryType
= SCS_64BIT_BINARY
;
271 *lpBinaryType
= SCS_WOW_BINARY
;
276 *lpBinaryType
= SCS_OS216_BINARY
;
281 *lpBinaryType
= SCS_DOS_BINARY
;
284 case BINARY_UNIX_EXE
:
285 case BINARY_UNIX_LIB
:
291 DPRINT1("Invalid binary type returned!\n", BinType
);
302 LPCSTR lpApplicationName
,
306 PWCHAR ApplicationNameW
;
308 if(!lpApplicationName
|| !lpBinaryType
)
310 SetLastError(ERROR_INVALID_PARAMETER
);
314 if (!(ApplicationNameW
= FilenameA2W(lpApplicationName
, FALSE
)))
317 return GetBinaryTypeW(ApplicationNameW
, lpBinaryType
);