winegstreamer: Add structure for gstreamer transform filters.
[wine] / dlls / mscoree / assembly.c
1 /*
2  * assembly parser
3  *
4  * Copyright 2008 James Hawkins
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winver.h"
28 #include "dbghelp.h"
29 #include "ole2.h"
30 #include "corhdr.h"
31 #include "metahost.h"
32 #include "mscoree_private.h"
33
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36
37 typedef struct
38 {
39     ULONG Signature;
40     USHORT MajorVersion;
41     USHORT MinorVersion;
42     ULONG Reserved;
43     ULONG VersionLength;
44     LPSTR Version;
45     BYTE Flags;
46     WORD Streams;
47 } METADATAHDR;
48
49 typedef struct
50 {
51     DWORD Offset;
52     DWORD Size;
53 } METADATASTREAMHDR;
54
55 typedef struct tagCLRTABLE
56 {
57     INT rows;
58     DWORD offset;
59 } CLRTABLE;
60
61 struct tagASSEMBLY
62 {
63     LPWSTR path;
64
65     HANDLE hfile;
66     HANDLE hmap;
67     BYTE *data;
68
69     IMAGE_NT_HEADERS *nthdr;
70     IMAGE_COR20_HEADER *corhdr;
71
72     METADATAHDR *metadatahdr;
73 };
74
75 static inline LPWSTR strdupW(LPCWSTR src)
76 {
77     LPWSTR dest;
78
79     if (!src)
80         return NULL;
81
82     dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR));
83     if (dest)
84         lstrcpyW(dest, src);
85
86     return dest;
87 }
88
89 static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz)
90 {
91     METADATAHDR *metadatahdr;
92     BYTE *ptr, *dest;
93     DWORD size, ofs;
94     ULONG rva;
95
96     rva = assembly->corhdr->MetaData.VirtualAddress;
97     ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL);
98     if (!ptr)
99         return E_FAIL;
100
101     metadatahdr = (METADATAHDR *)ptr;
102
103     assembly->metadatahdr = HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR));
104     if (!assembly->metadatahdr)
105         return E_OUTOFMEMORY;
106
107     size = FIELD_OFFSET(METADATAHDR, Version);
108     memcpy(assembly->metadatahdr, metadatahdr, size);
109
110     assembly->metadatahdr->Version = (LPSTR)&metadatahdr->Version;
111
112     ofs = FIELD_OFFSET(METADATAHDR, Flags);
113     ptr += FIELD_OFFSET(METADATAHDR, Version) + metadatahdr->VersionLength + 1;
114     dest = (BYTE *)assembly->metadatahdr + ofs;
115     memcpy(dest, ptr, sizeof(METADATAHDR) - ofs);
116
117     *hdrsz = sizeof(METADATAHDR) - sizeof(LPSTR) + metadatahdr->VersionLength + 1;
118
119     return S_OK;
120 }
121
122 static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
123 {
124     HRESULT hr;
125     DWORD hdrsz;
126
127     hr = parse_metadata_header(assembly, &hdrsz);
128     if (FAILED(hr))
129         return hr;
130
131     return S_OK;
132 }
133
134 static HRESULT parse_pe_header(ASSEMBLY *assembly)
135 {
136     IMAGE_DATA_DIRECTORY *datadirs;
137
138     assembly->nthdr = ImageNtHeader(assembly->data);
139     if (!assembly->nthdr)
140         return E_FAIL;
141
142     if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
143     {
144         IMAGE_OPTIONAL_HEADER64 *opthdr =
145                 (IMAGE_OPTIONAL_HEADER64 *)&assembly->nthdr->OptionalHeader;
146         datadirs = opthdr->DataDirectory;
147     }
148     else
149     {
150         IMAGE_OPTIONAL_HEADER32 *opthdr =
151                 (IMAGE_OPTIONAL_HEADER32 *)&assembly->nthdr->OptionalHeader;
152         datadirs = opthdr->DataDirectory;
153     }
154
155     if (!datadirs)
156         return E_FAIL;
157
158     if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||
159         !datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
160     {
161         return E_FAIL;
162     }
163
164     assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data,
165         datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL);
166     if (!assembly->corhdr)
167         return E_FAIL;
168
169     return S_OK;
170 }
171
172 HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
173 {
174     ASSEMBLY *assembly;
175     HRESULT hr;
176
177     *out = NULL;
178
179     assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY));
180     if (!assembly)
181         return E_OUTOFMEMORY;
182
183     assembly->path = strdupW(file);
184     if (!assembly->path)
185     {
186         hr = E_OUTOFMEMORY;
187         goto failed;
188     }
189
190     assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
191                                   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
192     if (assembly->hfile == INVALID_HANDLE_VALUE)
193     {
194         hr = HRESULT_FROM_WIN32(GetLastError());
195         goto failed;
196     }
197
198     assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
199                                         0, 0, NULL);
200     if (!assembly->hmap)
201     {
202         hr = HRESULT_FROM_WIN32(GetLastError());
203         goto failed;
204     }
205
206     assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
207     if (!assembly->data)
208     {
209         hr = HRESULT_FROM_WIN32(GetLastError());
210         goto failed;
211     }
212
213     hr = parse_pe_header(assembly);
214     if (FAILED(hr)) goto failed;
215
216     hr = parse_clr_metadata(assembly);
217     if (FAILED(hr)) goto failed;
218
219     *out = assembly;
220     return S_OK;
221
222 failed:
223     assembly_release(assembly);
224     return hr;
225 }
226
227 HRESULT assembly_release(ASSEMBLY *assembly)
228 {
229     if (!assembly)
230         return S_OK;
231
232     HeapFree(GetProcessHeap(), 0, assembly->metadatahdr);
233     HeapFree(GetProcessHeap(), 0, assembly->path);
234     UnmapViewOfFile(assembly->data);
235     CloseHandle(assembly->hmap);
236     CloseHandle(assembly->hfile);
237     HeapFree(GetProcessHeap(), 0, assembly);
238
239     return S_OK;
240 }
241
242 HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version)
243 {
244     *version = assembly->metadatahdr->Version;
245
246     return S_OK;
247 }