kernel32/nls: Added LOCALE_SNAN entries.
[wine.git] / dlls / mscoree / assembly.c
blobb6535561ca0e49fc95af7415c23479597c65c40b
1 /*
2 * assembly parser
4 * Copyright 2008 James Hawkins
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
21 #define NONAMELESSUNION
23 #include <stdarg.h>
24 #include <stdio.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winver.h"
30 #include "dbghelp.h"
31 #include "ole2.h"
32 #include "mscoree.h"
33 #include "corhdr.h"
34 #include "metahost.h"
35 #include "cordebug.h"
36 #include "wine/list.h"
37 #include "mscoree_private.h"
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
42 typedef struct
44 ULONG Signature;
45 USHORT MajorVersion;
46 USHORT MinorVersion;
47 ULONG Reserved;
48 ULONG VersionLength;
49 LPSTR Version;
50 BYTE Flags;
51 WORD Streams;
52 } METADATAHDR;
54 typedef struct
56 DWORD Offset;
57 DWORD Size;
58 } METADATASTREAMHDR;
60 typedef struct tagCLRTABLE
62 INT rows;
63 DWORD offset;
64 } CLRTABLE;
66 struct tagASSEMBLY
68 BOOL is_mapped_file;
70 /* mapped files */
71 LPWSTR path;
72 HANDLE hfile;
73 HANDLE hmap;
75 BYTE *data;
77 IMAGE_NT_HEADERS *nthdr;
78 IMAGE_COR20_HEADER *corhdr;
80 METADATAHDR *metadatahdr;
83 static inline LPWSTR strdupW(LPCWSTR src)
85 LPWSTR dest;
87 if (!src)
88 return NULL;
90 dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR));
91 if (dest)
92 lstrcpyW(dest, src);
94 return dest;
97 static void* assembly_rva_to_va(ASSEMBLY *assembly, ULONG rva)
99 if (assembly->is_mapped_file)
100 return ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL);
101 else
102 return assembly->data + rva;
105 static ULONG assembly_datadir_get_data(ASSEMBLY *assembly,
106 IMAGE_DATA_DIRECTORY *datadir, void **data)
108 if (!datadir->VirtualAddress || !datadir->Size)
110 *data = NULL;
111 return 0;
113 else
115 *data = assembly_rva_to_va(assembly, datadir->VirtualAddress);
116 return datadir->Size;
120 static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz)
122 METADATAHDR *metadatahdr;
123 BYTE *ptr, *dest;
124 DWORD size, ofs;
125 ULONG rva;
127 rva = assembly->corhdr->MetaData.VirtualAddress;
128 ptr = assembly_rva_to_va(assembly, rva);
129 if (!ptr)
130 return E_FAIL;
132 metadatahdr = (METADATAHDR *)ptr;
134 assembly->metadatahdr = HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR));
135 if (!assembly->metadatahdr)
136 return E_OUTOFMEMORY;
138 size = FIELD_OFFSET(METADATAHDR, Version);
139 memcpy(assembly->metadatahdr, metadatahdr, size);
141 assembly->metadatahdr->Version = (LPSTR)&metadatahdr->Version;
143 ofs = FIELD_OFFSET(METADATAHDR, Flags);
144 ptr += FIELD_OFFSET(METADATAHDR, Version) + metadatahdr->VersionLength + 1;
145 dest = (BYTE *)assembly->metadatahdr + ofs;
146 memcpy(dest, ptr, sizeof(METADATAHDR) - ofs);
148 *hdrsz = sizeof(METADATAHDR) - sizeof(LPSTR) + metadatahdr->VersionLength + 1;
150 return S_OK;
153 static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
155 HRESULT hr;
156 DWORD hdrsz;
158 hr = parse_metadata_header(assembly, &hdrsz);
159 if (FAILED(hr))
160 return hr;
162 return S_OK;
165 static HRESULT parse_pe_header(ASSEMBLY *assembly)
167 IMAGE_DATA_DIRECTORY *datadirs;
169 assembly->nthdr = ImageNtHeader(assembly->data);
170 if (!assembly->nthdr)
171 return E_FAIL;
173 if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
175 IMAGE_OPTIONAL_HEADER64 *opthdr =
176 (IMAGE_OPTIONAL_HEADER64 *)&assembly->nthdr->OptionalHeader;
177 datadirs = opthdr->DataDirectory;
179 else
181 IMAGE_OPTIONAL_HEADER32 *opthdr =
182 (IMAGE_OPTIONAL_HEADER32 *)&assembly->nthdr->OptionalHeader;
183 datadirs = opthdr->DataDirectory;
186 if (!datadirs)
187 return E_FAIL;
189 if (!assembly_datadir_get_data(assembly, &datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR], (void**)&assembly->corhdr))
190 return E_FAIL;
192 return S_OK;
195 static HRESULT parse_headers(ASSEMBLY *assembly)
197 HRESULT hr;
199 hr = parse_pe_header(assembly);
201 if (SUCCEEDED(hr))
202 hr = parse_clr_metadata(assembly);
204 return hr;
207 HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
209 ASSEMBLY *assembly;
210 HRESULT hr;
212 *out = NULL;
214 assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY));
215 if (!assembly)
216 return E_OUTOFMEMORY;
218 assembly->is_mapped_file = TRUE;
220 assembly->path = strdupW(file);
221 if (!assembly->path)
223 hr = E_OUTOFMEMORY;
224 goto failed;
227 assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
228 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
229 if (assembly->hfile == INVALID_HANDLE_VALUE)
231 hr = HRESULT_FROM_WIN32(GetLastError());
232 goto failed;
235 assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
236 0, 0, NULL);
237 if (!assembly->hmap)
239 hr = HRESULT_FROM_WIN32(GetLastError());
240 goto failed;
243 assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
244 if (!assembly->data)
246 hr = HRESULT_FROM_WIN32(GetLastError());
247 goto failed;
250 hr = parse_headers(assembly);
251 if (FAILED(hr)) goto failed;
253 *out = assembly;
254 return S_OK;
256 failed:
257 assembly_release(assembly);
258 return hr;
261 HRESULT assembly_from_hmodule(ASSEMBLY **out, HMODULE hmodule)
263 ASSEMBLY *assembly;
264 HRESULT hr;
266 *out = NULL;
268 assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY));
269 if (!assembly)
270 return E_OUTOFMEMORY;
272 assembly->is_mapped_file = FALSE;
274 assembly->data = (BYTE*)hmodule;
276 hr = parse_headers(assembly);
277 if (SUCCEEDED(hr))
278 *out = assembly;
279 else
280 assembly_release(assembly);
282 return hr;
285 HRESULT assembly_release(ASSEMBLY *assembly)
287 if (!assembly)
288 return S_OK;
290 if (assembly->is_mapped_file)
292 UnmapViewOfFile(assembly->data);
293 CloseHandle(assembly->hmap);
294 CloseHandle(assembly->hfile);
296 HeapFree(GetProcessHeap(), 0, assembly->metadatahdr);
297 HeapFree(GetProcessHeap(), 0, assembly->path);
298 HeapFree(GetProcessHeap(), 0, assembly);
300 return S_OK;
303 HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version)
305 *version = assembly->metadatahdr->Version;
307 return S_OK;
310 HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count)
312 ULONG size;
314 size = assembly_datadir_get_data(assembly, &assembly->corhdr->VTableFixups, (void**)fixups);
315 *count = size / sizeof(VTableFixup);
317 return S_OK;
320 HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func)
322 if (assembly->corhdr->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)
324 *func = assembly_rva_to_va(assembly, assembly->corhdr->u.EntryPointRVA);
325 return S_OK;
327 else
329 *func = NULL;
330 return S_FALSE;