fusion: Fix a number of leaks in assembly_create.
[wine/multimedia.git] / dlls / fusion / assembly.c
blob024e611d6e023a2770a82e6d5271d8f070c3553c
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 #include <stdarg.h>
22 #include <stdio.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winver.h"
28 #include "wincrypt.h"
29 #include "dbghelp.h"
30 #include "ole2.h"
31 #include "fusion.h"
33 #include "fusionpriv.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 #define MAX_CLR_TABLES 64
39 typedef struct tagCLRTABLE
41 DWORD rows;
42 DWORD offset;
43 } CLRTABLE;
45 struct tagASSEMBLY
47 LPSTR path;
49 HANDLE hfile;
50 HANDLE hmap;
51 BYTE *data;
53 IMAGE_NT_HEADERS32 *nthdr;
54 IMAGE_COR20_HEADER *corhdr;
56 METADATAHDR *metadatahdr;
58 METADATATABLESHDR *tableshdr;
59 DWORD numtables;
60 DWORD *numrows;
61 CLRTABLE tables[MAX_CLR_TABLES];
63 BYTE *strings;
64 BYTE *blobs;
67 /* FIXME: fill in */
68 const DWORD COR_TABLE_SIZES[64] =
70 sizeof(MODULETABLE),
71 sizeof(TYPEREFTABLE),
72 sizeof(TYPEDEFTABLE),
102 sizeof(ASSEMBLYTABLE),
110 sizeof(MANIFESTRESTABLE),
136 static LPSTR strdupWtoA(LPCWSTR str)
138 LPSTR ret = NULL;
139 DWORD len;
141 if (!str)
142 return ret;
144 len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
145 ret = HeapAlloc(GetProcessHeap(), 0, len);
146 if (ret)
147 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, len, NULL, NULL);
149 return ret;
152 static DWORD rva_to_offset(IMAGE_NT_HEADERS *nthdrs, DWORD rva)
154 DWORD offset = rva, limit;
155 IMAGE_SECTION_HEADER *img;
156 WORD i;
158 img = IMAGE_FIRST_SECTION(nthdrs);
160 if (rva < img->PointerToRawData)
161 return rva;
163 for (i = 0; i < nthdrs->FileHeader.NumberOfSections; i++)
165 if (img[i].SizeOfRawData)
166 limit = img[i].SizeOfRawData;
167 else
168 limit = img[i].Misc.VirtualSize;
170 if (rva >= img[i].VirtualAddress &&
171 rva < (img[i].VirtualAddress + limit))
173 if (img[i].PointerToRawData != 0)
175 offset -= img[i].VirtualAddress;
176 offset += img[i].PointerToRawData;
179 return offset;
183 return 0;
186 static BYTE *GetData(BYTE *pData, ULONG *pLength)
188 if ((*pData & 0x80) == 0x00)
190 *pLength = (*pData & 0x7f);
191 return pData + 1;
194 if ((*pData & 0xC0) == 0x80)
196 *pLength = ((*pData & 0x3f) << 8 | *(pData + 1));
197 return pData + 2;
200 if ((*pData & 0xE0) == 0xC0)
202 *pLength = ((*pData & 0x1f) << 24 | *(pData + 1) << 16 |
203 *(pData + 2) << 8 | *(pData + 3));
204 return pData + 4;
207 *pLength = (ULONG)-1;
208 return 0;
211 static VOID *assembly_data_offset(ASSEMBLY *assembly, ULONG offset)
213 return (VOID *)&assembly->data[offset];
216 static HRESULT parse_clr_tables(ASSEMBLY *assembly, ULONG offset)
218 DWORD i, previ, offidx;
219 ULONG currofs;
221 currofs = offset;
222 assembly->tableshdr = (METADATATABLESHDR *)assembly_data_offset(assembly, currofs);
223 if (!assembly->tableshdr)
224 return E_FAIL;
226 currofs += sizeof(METADATATABLESHDR);
227 assembly->numrows = (DWORD *)assembly_data_offset(assembly, currofs);
228 if (!assembly->numrows)
229 return E_FAIL;
231 assembly->numtables = 0;
232 for (i = 0; i < MAX_CLR_TABLES; i++)
234 if ((i < 32 && (assembly->tableshdr->MaskValid.LowPart >> i) & 1) ||
235 (i >= 32 && (assembly->tableshdr->MaskValid.HighPart >> i) & 1))
237 assembly->numtables++;
241 currofs += assembly->numtables * sizeof(DWORD);
242 memset(assembly->tables, -1, MAX_CLR_TABLES * sizeof(CLRTABLE));
244 if (assembly->tableshdr->MaskValid.LowPart & 1)
246 assembly->tables[0].offset = currofs;
247 assembly->tables[0].rows = assembly->numrows[0];
250 previ = 0;
251 offidx = 1;
252 for (i = 1; i < MAX_CLR_TABLES; i++)
254 if ((i < 32 && (assembly->tableshdr->MaskValid.LowPart >> i) & 1) ||
255 (i >= 32 && (assembly->tableshdr->MaskValid.HighPart >> i) & 1))
257 currofs += COR_TABLE_SIZES[previ] * assembly->numrows[offidx - 1];
258 assembly->tables[i].offset = currofs;
259 assembly->tables[i].rows = assembly->numrows[offidx];
260 offidx++;
261 previ = i;
265 return S_OK;
268 static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
270 METADATASTREAMHDR *streamhdr;
271 ULONG rva, i, ofs;
272 LPSTR stream;
273 HRESULT hr;
274 BYTE *ptr;
276 rva = assembly->corhdr->MetaData.VirtualAddress;
277 assembly->metadatahdr = ImageRvaToVa(assembly->nthdr, assembly->data,
278 rva, NULL);
279 if (!assembly->metadatahdr)
280 return E_FAIL;
282 ptr = ImageRvaToVa(assembly->nthdr, assembly->data,
283 rva + sizeof(METADATAHDR), NULL);
284 if (!ptr)
285 return E_FAIL;
287 for (i = 0; i < assembly->metadatahdr->Streams; i++)
289 streamhdr = (METADATASTREAMHDR *)ptr;
290 ofs = rva_to_offset(assembly->nthdr, rva + streamhdr->Offset);
292 ptr += sizeof(METADATASTREAMHDR);
293 stream = (LPSTR)ptr;
295 if (!lstrcmpA(stream, "#~"))
297 hr = parse_clr_tables(assembly, ofs);
298 if (FAILED(hr))
299 return hr;
301 else if (!lstrcmpA(stream, "#Strings"))
302 assembly->strings = (BYTE *)assembly_data_offset(assembly, ofs);
303 else if (!lstrcmpA(stream, "#Blob"))
304 assembly->blobs = (BYTE *)assembly_data_offset(assembly, ofs);
306 ptr += lstrlenA(stream);
307 while (!*ptr) ptr++;
310 return S_OK;
313 static HRESULT parse_pe_header(ASSEMBLY *assembly)
315 IMAGE_DATA_DIRECTORY *datadirs;
317 assembly->nthdr = ImageNtHeader(assembly->data);
318 if (!assembly->nthdr)
319 return E_FAIL;
321 datadirs = assembly->nthdr->OptionalHeader.DataDirectory;
322 if (!datadirs)
323 return E_FAIL;
325 if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||
326 !datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
328 return E_FAIL;
331 assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data,
332 datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL);
333 if (!assembly->corhdr)
334 return E_FAIL;
336 return S_OK;
339 HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
341 ASSEMBLY *assembly;
342 HRESULT hr;
344 *out = NULL;
346 assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY));
347 if (!assembly)
348 return E_OUTOFMEMORY;
350 assembly->path = strdupWtoA(file);
351 if (!assembly->path)
353 hr = E_OUTOFMEMORY;
354 goto failed;
357 assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
358 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
359 if (assembly->hfile == INVALID_HANDLE_VALUE)
361 hr = HRESULT_FROM_WIN32(GetLastError());
362 goto failed;
365 assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
366 0, 0, NULL);
367 if (!assembly->hmap)
369 hr = HRESULT_FROM_WIN32(GetLastError());
370 goto failed;
373 assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
374 if (!assembly->data)
376 hr = HRESULT_FROM_WIN32(GetLastError());
377 goto failed;
380 hr = parse_pe_header(assembly);
381 if (FAILED(hr)) goto failed;
383 hr = parse_clr_metadata(assembly);
384 if (FAILED(hr)) goto failed;
386 *out = assembly;
387 return S_OK;
389 failed:
390 assembly_release( assembly );
391 return hr;
394 HRESULT assembly_release(ASSEMBLY *assembly)
396 if (!assembly)
397 return S_OK;
399 HeapFree(GetProcessHeap(), 0, assembly->path);
400 UnmapViewOfFile(assembly->data);
401 CloseHandle(assembly->hmap);
402 CloseHandle(assembly->hfile);
403 HeapFree(GetProcessHeap(), 0, assembly);
405 return S_OK;
408 static LPSTR assembly_dup_str(ASSEMBLY *assembly, WORD index)
410 return strdup((LPSTR)&assembly->strings[index]);
413 HRESULT assembly_get_name(ASSEMBLY *assembly, LPSTR *name)
415 ASSEMBLYTABLE *asmtbl;
416 ULONG offset;
418 offset = assembly->tables[0x20].offset; /* FIXME: add constants */
419 if (offset < 0)
420 return E_FAIL;
422 asmtbl = (ASSEMBLYTABLE *)assembly_data_offset(assembly, offset);
423 if (!asmtbl)
424 return E_FAIL;
426 *name = assembly_dup_str(assembly, asmtbl->Name);
427 if (!*name)
428 return E_OUTOFMEMORY;
430 return S_OK;
433 HRESULT assembly_get_path(ASSEMBLY *assembly, LPSTR *path)
435 *path = strdup(assembly->path);
436 if (!*path)
437 return E_OUTOFMEMORY;
439 return S_OK;
442 HRESULT assembly_get_version(ASSEMBLY *assembly, LPSTR *version)
444 LPSTR verdata;
445 VS_FIXEDFILEINFO *ffi;
446 HRESULT hr = S_OK;
447 DWORD size;
449 size = GetFileVersionInfoSizeA(assembly->path, NULL);
450 if (!size)
451 return HRESULT_FROM_WIN32(GetLastError());
453 verdata = HeapAlloc(GetProcessHeap(), 0, size);
454 if (!verdata)
455 return E_OUTOFMEMORY;
457 if (!GetFileVersionInfoA(assembly->path, 0, size, verdata))
459 hr = HRESULT_FROM_WIN32(GetLastError());
460 goto done;
463 if (!VerQueryValueA(verdata, "\\", (LPVOID *)&ffi, &size))
465 hr = HRESULT_FROM_WIN32(GetLastError());
466 goto done;
469 *version = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
470 if (!*version)
472 hr = E_OUTOFMEMORY;
473 goto done;
476 sprintf(*version, "%d.%d.%d.%d", HIWORD(ffi->dwFileVersionMS),
477 LOWORD(ffi->dwFileVersionMS), HIWORD(ffi->dwFileVersionLS),
478 LOWORD(ffi->dwFileVersionLS));
480 done:
481 HeapFree(GetProcessHeap(), 0, verdata);
482 return hr;
485 HRESULT assembly_get_architecture(ASSEMBLY *assembly, DWORD fixme)
487 /* FIXME */
488 return S_OK;
491 static BYTE *assembly_get_blob(ASSEMBLY *assembly, WORD index, ULONG *size)
493 return GetData(&assembly->blobs[index], size);
496 static void bytes_to_str(BYTE *bytes, DWORD len, LPSTR str)
498 int i;
500 static const char hexval[16] = {
501 '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
504 for(i = 0; i < len; i++)
506 str[i * 2] = hexval[((bytes[i] >> 4) & 0xF)];
507 str[i * 2 + 1] = hexval[(bytes[i]) & 0x0F];
511 #define BYTES_PER_TOKEN 8
512 #define CHARS_PER_BYTE 2
513 #define TOKEN_LENGTH (BYTES_PER_TOKEN * CHARS_PER_BYTE + 1)
515 HRESULT assembly_get_pubkey_token(ASSEMBLY *assembly, LPSTR *token)
517 ASSEMBLYTABLE *asmtbl;
518 ULONG i, offset, size;
519 BYTE *hashdata;
520 HCRYPTPROV crypt;
521 HCRYPTHASH hash;
522 BYTE *pubkey;
523 BYTE tokbytes[BYTES_PER_TOKEN];
524 HRESULT hr = E_FAIL;
525 LPSTR tok;
527 *token = NULL;
529 offset = assembly->tables[0x20].offset; /* FIXME: add constants */
530 if (offset < 0)
531 return E_FAIL;
533 asmtbl = (ASSEMBLYTABLE *)assembly_data_offset(assembly, offset);
534 if (!asmtbl)
535 return E_FAIL;
537 pubkey = assembly_get_blob(assembly, asmtbl->PublicKey, &size);
539 if (!CryptAcquireContextA(&crypt, NULL, NULL, PROV_RSA_FULL,
540 CRYPT_VERIFYCONTEXT))
541 return E_FAIL;
543 if (!CryptCreateHash(crypt, CALG_SHA1, 0, 0, &hash))
544 return E_FAIL;
546 if (!CryptHashData(hash, pubkey, size, 0))
547 return E_FAIL;
549 size = 0;
550 if (!CryptGetHashParam(hash, HP_HASHVAL, NULL, &size, 0))
551 return E_FAIL;
553 hashdata = HeapAlloc(GetProcessHeap(), 0, size);
554 if (!hashdata)
556 hr = E_OUTOFMEMORY;
557 goto done;
560 if (!CryptGetHashParam(hash, HP_HASHVAL, hashdata, &size, 0))
561 goto done;
563 for (i = size - 1; i >= size - 8; i--)
564 tokbytes[size - i - 1] = hashdata[i];
566 tok = HeapAlloc(GetProcessHeap(), 0, TOKEN_LENGTH);
567 if (!tok)
569 hr = E_OUTOFMEMORY;
570 goto done;
573 bytes_to_str(tokbytes, BYTES_PER_TOKEN, tok);
574 tok[TOKEN_LENGTH - 1] = '\0';
576 *token = tok;
577 hr = S_OK;
579 done:
580 HeapFree(GetProcessHeap(), 0, hashdata);
581 CryptDestroyHash(hash);
582 CryptReleaseContext(crypt, 0);
584 return hr;