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"
21 /* FUNCTIONS ****************************************************************/
23 /* Check whether a file is an OS/2 or a very old Windows executable
24 * by testing on import of KERNEL.
26 * FIXME: is reading the module imports the only way of discerning
27 * old Windows binaries from OS/2 ones ? At least it seems so...
30 InternalIsOS2OrOldWin(HANDLE hFile
, IMAGE_DOS_HEADER
*mz
, IMAGE_OS2_HEADER
*ne
)
39 CurPos
= SetFilePointer(hFile
, 0, NULL
, FILE_CURRENT
);
41 /* read modref table */
42 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_modtab
, NULL
, FILE_BEGIN
) == (DWORD
)-1) ||
43 (!(modtab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_cmod
* sizeof(WORD
)))) ||
44 (!(ReadFile(hFile
, modtab
, ne
->ne_cmod
* sizeof(WORD
), &Read
, NULL
))) ||
45 (Read
!= (DWORD
)ne
->ne_cmod
* sizeof(WORD
)))
50 /* read imported names table */
51 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_imptab
, NULL
, FILE_BEGIN
) == (DWORD
)-1) ||
52 (!(nametab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_enttab
- ne
->ne_imptab
))) ||
53 (!(ReadFile(hFile
, nametab
, ne
->ne_enttab
- ne
->ne_imptab
, &Read
, NULL
))) ||
54 (Read
!= (DWORD
)ne
->ne_enttab
- ne
->ne_imptab
))
59 for(i
= 0; i
< ne
->ne_cmod
; i
++)
62 module
= &nametab
[modtab
[i
]];
63 if(!strncmp(&module
[1], "KERNEL", module
[0]))
65 /* very old windows file */
72 DPRINT("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
75 HeapFree(GetProcessHeap(), 0, modtab
);
76 HeapFree(GetProcessHeap(), 0, nametab
);
77 SetFilePointer(hFile
, CurPos
, NULL
, FILE_BEGIN
);
82 InternalGetBinaryType(HANDLE hFile
)
88 unsigned char magic
[4];
89 unsigned char ignored
[12];
95 unsigned long cputype
;
96 unsigned long cpusubtype
;
97 unsigned long filetype
;
104 if((SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
) == (DWORD
)-1) ||
105 (!ReadFile(hFile
, &Header
, sizeof(Header
), &Read
, NULL
) ||
106 (Read
!= sizeof(Header
))))
108 return BINARY_UNKNOWN
;
111 if(!memcmp(Header
.elf
.magic
, "\177ELF", sizeof(Header
.elf
.magic
)))
113 /* FIXME: we don't bother to check byte order, architecture, etc. */
114 switch(Header
.elf
.type
)
117 return BINARY_UNIX_EXE
;
119 return BINARY_UNIX_LIB
;
121 return BINARY_UNKNOWN
;
124 /* Mach-o File with Endian set to Big Endian or Little Endian*/
125 if(Header
.macho
.magic
== 0xFEEDFACE ||
126 Header
.macho
.magic
== 0xECAFDEEF)
128 switch(Header
.macho
.filetype
)
132 return BINARY_UNIX_LIB
;
134 return BINARY_UNKNOWN
;
137 /* Not ELF, try DOS */
138 if(Header
.mz
.e_magic
== IMAGE_DOS_SIGNATURE
)
140 /* We do have a DOS image so we will now try to seek into
141 * the file by the amount indicated by the field
142 * "Offset to extended header" and read in the
143 * "magic" field information at that location.
144 * This will tell us if there is more header information
147 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == (DWORD
)-1) ||
148 (!ReadFile(hFile
, magic
, sizeof(magic
), &Read
, NULL
) ||
149 (Read
!= sizeof(magic
))))
154 /* Reading the magic field succeeded so
155 * we will try to determine what type it is.
157 if(!memcmp(magic
, "PE\0\0", sizeof(magic
)))
159 IMAGE_FILE_HEADER FileHeader
;
160 if(!ReadFile(hFile
, &FileHeader
, sizeof(IMAGE_FILE_HEADER
), &Read
, NULL
) ||
161 (Read
== sizeof(IMAGE_FILE_HEADER
)))
166 /* FIXME - detect 32/64 bit */
168 if(FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
169 return BINARY_PE_DLL32
;
170 return BINARY_PE_EXE32
;
173 if(!memcmp(magic
, "NE", 1))
175 /* This is a Windows executable (NE) header. This can
176 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
177 * DOS program (running under a DOS extender). To decide
178 * which, we'll have to read the NE header.
181 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == 1) ||
182 !ReadFile(hFile
, &ne
, sizeof(IMAGE_OS2_HEADER
), &Read
, NULL
) ||
183 (Read
== sizeof(IMAGE_OS2_HEADER
)))
185 /* Couldn't read header, so abort. */
196 return InternalIsOS2OrOldWin(hFile
, &Header
.mz
, &ne
);
201 return BINARY_UNKNOWN
;
210 LPCWSTR lpApplicationName
,
217 if(!lpApplicationName
|| !lpBinaryType
)
219 SetLastError(ERROR_INVALID_PARAMETER
);
223 hFile
= CreateFileW(lpApplicationName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
224 OPEN_EXISTING
, 0, 0);
225 if(hFile
== INVALID_HANDLE_VALUE
)
230 BinType
= InternalGetBinaryType(hFile
);
240 * guess from filename
242 if(!(dot
= wcsrchr(lpApplicationName
, L
'.')))
246 if(!lstrcmpiW(dot
, L
".COM"))
248 *lpBinaryType
= SCS_DOS_BINARY
;
251 if(!lstrcmpiW(dot
, L
".PIF"))
253 *lpBinaryType
= SCS_PIF_BINARY
;
258 case BINARY_PE_EXE32
:
259 case BINARY_PE_DLL32
:
261 *lpBinaryType
= SCS_32BIT_BINARY
;
264 case BINARY_PE_EXE64
:
265 case BINARY_PE_DLL64
:
267 *lpBinaryType
= SCS_64BIT_BINARY
;
272 *lpBinaryType
= SCS_WOW_BINARY
;
277 *lpBinaryType
= SCS_OS216_BINARY
;
282 *lpBinaryType
= SCS_DOS_BINARY
;
285 case BINARY_UNIX_EXE
:
286 case BINARY_UNIX_LIB
:
292 DPRINT1("Invalid binary type returned!\n", BinType
);
303 LPCSTR lpApplicationName
,
307 PWCHAR ApplicationNameW
;
309 if(!lpApplicationName
|| !lpBinaryType
)
311 SetLastError(ERROR_INVALID_PARAMETER
);
315 if (!(ApplicationNameW
= FilenameA2W(lpApplicationName
, FALSE
)))
318 return GetBinaryTypeW(ApplicationNameW
, lpBinaryType
);