kernel32/tests: Add a few more tests, fix some failures on Windows.
[wine/wine-kai.git] / dlls / fusion / assembly.c
blob75ca048053cd6fc27bf47a7bbb03cda3d0e3c0dd
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"
32 #include "corhdr.h"
34 #include "fusionpriv.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
38 #define TableFromToken(tk) (TypeFromToken(tk) >> 24)
39 #define TokenFromTable(idx) (idx << 24)
41 #define MAX_CLR_TABLES 64
43 #define MD_STRINGS_BIT 0x1
44 #define MD_GUIDS_BIT 0x2
45 #define MD_BLOBS_BIT 0x4
47 typedef struct tagCLRTABLE
49 INT rows;
50 DWORD offset;
51 } CLRTABLE;
53 struct tagASSEMBLY
55 LPSTR path;
57 HANDLE hfile;
58 HANDLE hmap;
59 BYTE *data;
61 IMAGE_NT_HEADERS *nthdr;
62 IMAGE_COR20_HEADER *corhdr;
64 METADATAHDR *metadatahdr;
66 METADATATABLESHDR *tableshdr;
67 DWORD numtables;
68 DWORD *numrows;
69 CLRTABLE tables[MAX_CLR_TABLES];
71 DWORD stringsz;
72 DWORD guidsz;
73 DWORD blobsz;
75 BYTE *strings;
76 BYTE *blobs;
79 static LPSTR strdupWtoA(LPCWSTR str)
81 LPSTR ret = NULL;
82 DWORD len;
84 if (!str)
85 return ret;
87 len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
88 ret = HeapAlloc(GetProcessHeap(), 0, len);
89 if (ret)
90 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, len, NULL, NULL);
92 return ret;
95 static DWORD rva_to_offset(IMAGE_NT_HEADERS *nthdrs, DWORD rva)
97 DWORD offset = rva, limit;
98 IMAGE_SECTION_HEADER *img;
99 WORD i;
101 img = IMAGE_FIRST_SECTION(nthdrs);
103 if (rva < img->PointerToRawData)
104 return rva;
106 for (i = 0; i < nthdrs->FileHeader.NumberOfSections; i++)
108 if (img[i].SizeOfRawData)
109 limit = img[i].SizeOfRawData;
110 else
111 limit = img[i].Misc.VirtualSize;
113 if (rva >= img[i].VirtualAddress &&
114 rva < (img[i].VirtualAddress + limit))
116 if (img[i].PointerToRawData != 0)
118 offset -= img[i].VirtualAddress;
119 offset += img[i].PointerToRawData;
122 return offset;
126 return 0;
129 static BYTE *GetData(BYTE *pData, ULONG *pLength)
131 if ((*pData & 0x80) == 0x00)
133 *pLength = (*pData & 0x7f);
134 return pData + 1;
137 if ((*pData & 0xC0) == 0x80)
139 *pLength = ((*pData & 0x3f) << 8 | *(pData + 1));
140 return pData + 2;
143 if ((*pData & 0xE0) == 0xC0)
145 *pLength = ((*pData & 0x1f) << 24 | *(pData + 1) << 16 |
146 *(pData + 2) << 8 | *(pData + 3));
147 return pData + 4;
150 *pLength = (ULONG)-1;
151 return 0;
154 static VOID *assembly_data_offset(ASSEMBLY *assembly, ULONG offset)
156 return (VOID *)&assembly->data[offset];
159 #define MAX_TABLES_WORD 0xFFFF
160 #define MAX_TABLES_1BIT_ENCODE 32767
161 #define MAX_TABLES_2BIT_ENCODE 16383
162 #define MAX_TABLES_3BIT_ENCODE 8191
163 #define MAX_TABLES_5BIT_ENCODE 2047
165 static inline ULONG get_table_size(ASSEMBLY *assembly, DWORD index)
167 DWORD size;
168 INT tables;
170 switch (TokenFromTable(index))
172 case mdtModule:
174 size = sizeof(MODULETABLE) + (assembly->stringsz - sizeof(WORD)) +
175 2 * (assembly->guidsz - sizeof(WORD));
176 break;
178 case mdtTypeRef:
180 size = sizeof(TYPEREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD));
182 /* ResolutionScope:ResolutionScope */
183 tables = max(assembly->tables[TableFromToken(mdtModule)].rows,
184 assembly->tables[TableFromToken(mdtModuleRef)].rows);
185 tables = max(tables, assembly->tables[TableFromToken(mdtAssemblyRef)].rows);
186 tables = max(tables, assembly->tables[TableFromToken(mdtTypeRef)].rows);
187 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
188 break;
190 case mdtTypeDef:
192 size = sizeof(TYPEDEFTABLE) + 2 * (assembly->stringsz - sizeof(WORD));
194 /* Extends:TypeDefOrRef */
195 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
196 assembly->tables[TableFromToken(mdtTypeRef)].rows);
197 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
198 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
200 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
201 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
202 size += (assembly->tables[TableFromToken(mdtMethodDef)].rows >
203 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
204 break;
206 case mdtFieldDef:
208 size = sizeof(FIELDTABLE) + (assembly->stringsz - sizeof(WORD)) +
209 (assembly->blobsz - sizeof(WORD));
210 break;
212 case mdtMethodDef:
214 size = sizeof(METHODDEFTABLE) + (assembly->stringsz - sizeof(WORD)) +
215 (assembly->blobsz - sizeof(WORD));
217 size += (assembly->tables[TableFromToken(mdtParamDef)].rows >
218 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
219 break;
221 case mdtParamDef:
223 size = sizeof(PARAMTABLE) + (assembly->stringsz - sizeof(WORD));
224 break;
226 case mdtInterfaceImpl:
228 size = sizeof(INTERFACEIMPLTABLE);
230 /* Interface:TypeDefOrRef */
231 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
232 assembly->tables[TableFromToken(mdtTypeRef)].rows);
233 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
234 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
235 break;
237 case mdtMemberRef:
239 size = sizeof(MEMBERREFTABLE) + (assembly->stringsz - sizeof(WORD)) +
240 (assembly->blobsz - sizeof(WORD));
242 /* Class:MemberRefParent */
243 tables = max(assembly->tables[TableFromToken(mdtTypeRef)].rows,
244 assembly->tables[TableFromToken(mdtModuleRef)].rows);
245 tables = max(tables, assembly->tables[TableFromToken(mdtMethodDef)].rows);
246 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
247 tables = max(tables, assembly->tables[TableFromToken(mdtTypeDef)].rows);
248 size += (tables > MAX_TABLES_3BIT_ENCODE) ? sizeof(WORD) : 0;
249 break;
251 case 0x0B000000: /* FIXME */
253 size = sizeof(CONSTANTTABLE) + (assembly->blobsz - sizeof(WORD));
255 /* Parent:HasConstant */
256 tables = max(assembly->tables[TableFromToken(mdtParamDef)].rows,
257 assembly->tables[TableFromToken(mdtFieldDef)].rows);
258 tables = max(tables, assembly->tables[TableFromToken(mdtProperty)].rows);
259 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
260 break;
262 case mdtCustomAttribute:
264 size = sizeof(CUSTOMATTRIBUTETABLE) + (assembly->blobsz - sizeof(WORD));
266 /* Parent:HasCustomAttribute */
267 tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows,
268 assembly->tables[TableFromToken(mdtFieldDef)].rows);
269 tables = max(tables, assembly->tables[TableFromToken(mdtTypeRef)].rows);
270 tables = max(tables, assembly->tables[TableFromToken(mdtTypeDef)].rows);
271 tables = max(tables, assembly->tables[TableFromToken(mdtParamDef)].rows);
272 tables = max(tables, assembly->tables[TableFromToken(mdtInterfaceImpl)].rows);
273 tables = max(tables, assembly->tables[TableFromToken(mdtMemberRef)].rows);
274 tables = max(tables, assembly->tables[TableFromToken(mdtPermission)].rows);
275 tables = max(tables, assembly->tables[TableFromToken(mdtProperty)].rows);
276 tables = max(tables, assembly->tables[TableFromToken(mdtEvent)].rows);
277 tables = max(tables, assembly->tables[TableFromToken(mdtSignature)].rows);
278 tables = max(tables, assembly->tables[TableFromToken(mdtModuleRef)].rows);
279 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
280 tables = max(tables, assembly->tables[TableFromToken(mdtAssembly)].rows);
281 tables = max(tables, assembly->tables[TableFromToken(mdtFile)].rows);
282 tables = max(tables, assembly->tables[TableFromToken(mdtExportedType)].rows);
283 tables = max(tables, assembly->tables[TableFromToken(mdtManifestResource)].rows);
284 size += (tables > MAX_TABLES_5BIT_ENCODE) ? sizeof(WORD) : 0;
286 /* Type:CustomAttributeType */
287 tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows,
288 assembly->tables[TableFromToken(mdtMemberRef)].rows);
289 size += (tables > MAX_TABLES_3BIT_ENCODE) ? sizeof(WORD) : 0;
290 break;
292 case 0x0D000000: /* FIXME */
294 size = sizeof(FIELDMARSHALTABLE) + (assembly->blobsz - sizeof(WORD));
296 /* Parent:HasFieldMarshal */
297 tables = max(assembly->tables[TableFromToken(mdtFieldDef)].rows,
298 assembly->tables[TableFromToken(mdtParamDef)].rows);
299 size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0;
300 break;
302 case mdtPermission:
304 size = sizeof(DECLSECURITYTABLE) + (assembly->blobsz - sizeof(WORD));
306 /* Parent:HasDeclSecurity */
307 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
308 assembly->tables[TableFromToken(mdtMethodDef)].rows);
309 tables = max(tables, assembly->tables[TableFromToken(mdtAssembly)].rows);
310 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
311 break;
313 case 0x0F000000: /* FIXME */
315 size = sizeof(CLASSLAYOUTTABLE);
316 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
317 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
318 break;
320 case 0x10000000: /* FIXME */
322 size = sizeof(FIELDLAYOUTTABLE);
323 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
324 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
325 break;
327 case mdtSignature:
329 size = sizeof(STANDALONESIGTABLE) + (assembly->blobsz - sizeof(WORD));
330 break;
332 case 0x12000000: /* FIXME */
334 size = sizeof(EVENTMAPTABLE);
335 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
336 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
337 size += (assembly->tables[TableFromToken(mdtEvent)].rows >
338 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
339 break;
341 case mdtEvent:
343 size = sizeof(EVENTTABLE) + (assembly->stringsz - sizeof(WORD));
345 /* EventType:TypeDefOrRef */
346 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
347 assembly->tables[TableFromToken(mdtTypeRef)].rows);
348 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
349 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
350 break;
352 case 0x15000000:/* FIXME */
354 size = sizeof(PROPERTYMAPTABLE);
355 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
356 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
357 size += (assembly->tables[TableFromToken(mdtProperty)].rows >
358 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
359 break;
361 case mdtProperty:
363 size = sizeof(PROPERTYTABLE) + (assembly->stringsz - sizeof(WORD)) +
364 (assembly->blobsz - sizeof(WORD));
365 break;
367 case 0x18000000: /* FIXME */
369 size = sizeof(METHODSEMANTICSTABLE);
371 /* Association:HasSemantics */
372 tables = max(assembly->tables[TableFromToken(mdtEvent)].rows,
373 assembly->tables[TableFromToken(mdtProperty)].rows);
374 size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0;
376 size += (assembly->tables[TableFromToken(mdtMethodDef)].rows >
377 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
378 break;
380 case 0x19000000: /* FIXME */
382 size = sizeof(METHODIMPLTABLE);
384 /* MethodBody:MethodDefOrRef, MethodDeclaration:MethodDefOrRef */
385 tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows,
386 assembly->tables[TableFromToken(mdtMemberRef)].rows);
387 size += (tables > MAX_TABLES_1BIT_ENCODE) ? 2 * sizeof(WORD) : 0;
389 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
390 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
391 break;
393 case mdtModuleRef:
395 size = sizeof(MODULEREFTABLE) + (assembly->stringsz - sizeof(WORD));
396 break;
398 case mdtTypeSpec:
400 size = sizeof(TYPESPECTABLE) + (assembly->blobsz - sizeof(WORD));
401 break;
403 case 0x1C000000: /* FIXME */
405 size = sizeof(IMPLMAPTABLE) + (assembly->stringsz - sizeof(WORD));
407 /* MemberForwarded:MemberForwarded */
408 tables = max(assembly->tables[TableFromToken(mdtFieldDef)].rows,
409 assembly->tables[TableFromToken(mdtMethodDef)].rows);
410 size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0;
412 size += (assembly->tables[TableFromToken(mdtModuleRef)].rows >
413 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
414 break;
416 case 0x1D000000: /* FIXME */
418 size = sizeof(FIELDRVATABLE);
419 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
420 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
421 break;
423 case mdtAssembly:
425 size = sizeof(ASSEMBLYTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) +
426 (assembly->blobsz - sizeof(WORD));
427 break;
429 case 0x20000001: /* FIXME */
431 size = sizeof(ASSEMBLYPROCESSORTABLE);
432 break;
434 case 0x22000000: /* FIXME */
436 size = sizeof(ASSEMBLYOSTABLE);
437 break;
439 case mdtAssemblyRef:
441 size = sizeof(ASSEMBLYREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) +
442 2 * (assembly->blobsz - sizeof(WORD));
443 break;
445 case 0x24000000: /* FIXME */
447 size = sizeof(ASSEMBLYREFPROCESSORTABLE);
448 size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows >
449 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
450 break;
452 case 0x25000000: /* FIXME */
454 size = sizeof(ASSEMBLYREFOSTABLE);
455 size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows >
456 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
457 break;
459 case mdtFile:
461 size = sizeof(FILETABLE) + (assembly->stringsz - sizeof(WORD)) +
462 (assembly->blobsz - sizeof(WORD));
463 break;
465 case mdtExportedType:
467 size = sizeof(EXPORTEDTYPETABLE) + 2 * (assembly->stringsz - sizeof(WORD));
469 /* Implementation:Implementation */
470 tables = max(assembly->tables[TableFromToken(mdtFile)].rows,
471 assembly->tables[TableFromToken(mdtMethodDef)].rows);
472 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
473 break;
475 case mdtManifestResource:
477 size = sizeof(MANIFESTRESTABLE) + (assembly->stringsz - sizeof(WORD));
479 /* Implementation:Implementation */
480 tables = max(assembly->tables[TableFromToken(mdtFile)].rows,
481 assembly->tables[TableFromToken(mdtAssemblyRef)].rows);
482 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
483 break;
485 case 0x29000000: /* FIXME */
487 size = sizeof(NESTEDCLASSTABLE);
488 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
489 MAX_TABLES_WORD) ? 2 * sizeof(WORD) : 0;
490 break;
492 default:
493 return 0;
496 return size;
499 static HRESULT parse_clr_tables(ASSEMBLY *assembly, ULONG offset)
501 DWORD i, previ, offidx;
502 ULONG currofs;
504 currofs = offset;
505 assembly->tableshdr = (METADATATABLESHDR *)assembly_data_offset(assembly, currofs);
506 if (!assembly->tableshdr)
507 return E_FAIL;
509 assembly->stringsz = (assembly->tableshdr->HeapOffsetSizes & MD_STRINGS_BIT) ?
510 sizeof(DWORD) : sizeof(WORD);
511 assembly->guidsz = (assembly->tableshdr->HeapOffsetSizes & MD_GUIDS_BIT) ?
512 sizeof(DWORD) : sizeof(WORD);
513 assembly->blobsz = (assembly->tableshdr->HeapOffsetSizes & MD_BLOBS_BIT) ?
514 sizeof(DWORD) : sizeof(WORD);
516 currofs += sizeof(METADATATABLESHDR);
517 assembly->numrows = (DWORD *)assembly_data_offset(assembly, currofs);
518 if (!assembly->numrows)
519 return E_FAIL;
521 assembly->numtables = 0;
522 for (i = 0; i < MAX_CLR_TABLES; i++)
524 if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) ||
525 (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1))
527 assembly->numtables++;
531 currofs += assembly->numtables * sizeof(DWORD);
532 memset(assembly->tables, -1, MAX_CLR_TABLES * sizeof(CLRTABLE));
534 if (assembly->tableshdr->MaskValid.u.LowPart & 1)
535 assembly->tables[0].offset = currofs;
537 offidx = 0;
538 for (i = 0; i < MAX_CLR_TABLES; i++)
540 if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) ||
541 (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1))
543 assembly->tables[i].rows = assembly->numrows[offidx];
544 offidx++;
548 previ = 0;
549 offidx = 1;
550 for (i = 1; i < MAX_CLR_TABLES; i++)
552 if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) ||
553 (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1))
555 currofs += get_table_size(assembly, previ) * assembly->numrows[offidx - 1];
556 assembly->tables[i].offset = currofs;
557 offidx++;
558 previ = i;
562 return S_OK;
565 static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz)
567 METADATAHDR *metadatahdr;
568 BYTE *ptr, *dest;
569 DWORD size, ofs;
570 ULONG rva;
572 rva = assembly->corhdr->MetaData.VirtualAddress;
573 ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL);
574 if (!ptr)
575 return E_FAIL;
577 metadatahdr = (METADATAHDR *)ptr;
579 assembly->metadatahdr = HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR));
580 if (!assembly->metadatahdr)
581 return E_OUTOFMEMORY;
583 size = FIELD_OFFSET(METADATAHDR, Version);
584 memcpy(assembly->metadatahdr, metadatahdr, size);
586 /* we don't care about the version string */
588 ofs = FIELD_OFFSET(METADATAHDR, Flags);
589 ptr += FIELD_OFFSET(METADATAHDR, Version) + metadatahdr->VersionLength + 1;
590 dest = (BYTE *)assembly->metadatahdr + ofs;
591 memcpy(dest, ptr, sizeof(METADATAHDR) - ofs);
593 *hdrsz = sizeof(METADATAHDR) - sizeof(LPSTR) + metadatahdr->VersionLength + 1;
595 return S_OK;
598 static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
600 METADATASTREAMHDR *streamhdr;
601 ULONG rva, i, ofs;
602 LPSTR stream;
603 HRESULT hr;
604 DWORD hdrsz;
605 BYTE *ptr;
607 hr = parse_metadata_header(assembly, &hdrsz);
608 if (FAILED(hr))
609 return hr;
611 rva = assembly->corhdr->MetaData.VirtualAddress;
612 ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva + hdrsz, NULL);
613 if (!ptr)
614 return E_FAIL;
616 for (i = 0; i < assembly->metadatahdr->Streams; i++)
618 streamhdr = (METADATASTREAMHDR *)ptr;
619 ofs = rva_to_offset(assembly->nthdr, rva + streamhdr->Offset);
621 ptr += sizeof(METADATASTREAMHDR);
622 stream = (LPSTR)ptr;
624 if (!lstrcmpA(stream, "#~"))
626 hr = parse_clr_tables(assembly, ofs);
627 if (FAILED(hr))
628 return hr;
630 else if (!lstrcmpA(stream, "#Strings") || !lstrcmpA(stream, "Strings"))
631 assembly->strings = (BYTE *)assembly_data_offset(assembly, ofs);
632 else if (!lstrcmpA(stream, "#Blob") || !lstrcmpA(stream, "Blob"))
633 assembly->blobs = (BYTE *)assembly_data_offset(assembly, ofs);
635 ptr += lstrlenA(stream) + 1;
636 ptr = (BYTE *)(((UINT_PTR)ptr + 3) & ~3); /* align on DWORD boundary */
639 return S_OK;
642 static HRESULT parse_pe_header(ASSEMBLY *assembly)
644 IMAGE_DATA_DIRECTORY *datadirs;
646 assembly->nthdr = ImageNtHeader(assembly->data);
647 if (!assembly->nthdr)
648 return E_FAIL;
650 if (assembly->nthdr->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
652 IMAGE_OPTIONAL_HEADER64 *opthdr =
653 (IMAGE_OPTIONAL_HEADER64 *)&assembly->nthdr->OptionalHeader;
654 datadirs = opthdr->DataDirectory;
656 else
657 datadirs = assembly->nthdr->OptionalHeader.DataDirectory;
659 if (!datadirs)
660 return E_FAIL;
662 if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||
663 !datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
665 return E_FAIL;
668 assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data,
669 datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL);
670 if (!assembly->corhdr)
671 return E_FAIL;
673 return S_OK;
676 HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
678 ASSEMBLY *assembly;
679 HRESULT hr;
681 *out = NULL;
683 assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY));
684 if (!assembly)
685 return E_OUTOFMEMORY;
687 assembly->path = strdupWtoA(file);
688 if (!assembly->path)
690 hr = E_OUTOFMEMORY;
691 goto failed;
694 assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
695 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
696 if (assembly->hfile == INVALID_HANDLE_VALUE)
698 hr = HRESULT_FROM_WIN32(GetLastError());
699 goto failed;
702 assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
703 0, 0, NULL);
704 if (!assembly->hmap)
706 hr = HRESULT_FROM_WIN32(GetLastError());
707 goto failed;
710 assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
711 if (!assembly->data)
713 hr = HRESULT_FROM_WIN32(GetLastError());
714 goto failed;
717 hr = parse_pe_header(assembly);
718 if (FAILED(hr)) goto failed;
720 hr = parse_clr_metadata(assembly);
721 if (FAILED(hr)) goto failed;
723 *out = assembly;
724 return S_OK;
726 failed:
727 assembly_release(assembly);
728 return hr;
731 HRESULT assembly_release(ASSEMBLY *assembly)
733 if (!assembly)
734 return S_OK;
736 HeapFree(GetProcessHeap(), 0, assembly->metadatahdr);
737 HeapFree(GetProcessHeap(), 0, assembly->path);
738 UnmapViewOfFile(assembly->data);
739 CloseHandle(assembly->hmap);
740 CloseHandle(assembly->hfile);
741 HeapFree(GetProcessHeap(), 0, assembly);
743 return S_OK;
746 static LPSTR assembly_dup_str(ASSEMBLY *assembly, DWORD index)
748 LPSTR str = (LPSTR)&assembly->strings[index];
749 LPSTR cpy = HeapAlloc(GetProcessHeap(), 0, strlen(str)+1);
750 if (cpy)
751 strcpy(cpy, str);
752 return cpy;
755 HRESULT assembly_get_name(ASSEMBLY *assembly, LPSTR *name)
757 BYTE *ptr;
758 LONG offset;
759 DWORD stridx;
761 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
762 if (offset == -1)
763 return E_FAIL;
765 ptr = assembly_data_offset(assembly, offset);
766 if (!ptr)
767 return E_FAIL;
769 ptr += FIELD_OFFSET(ASSEMBLYTABLE, PublicKey) + assembly->blobsz;
770 if (assembly->stringsz == sizeof(DWORD))
771 stridx = *((DWORD *)ptr);
772 else
773 stridx = *((WORD *)ptr);
775 *name = assembly_dup_str(assembly, stridx);
776 if (!*name)
777 return E_OUTOFMEMORY;
779 return S_OK;
782 HRESULT assembly_get_path(ASSEMBLY *assembly, LPSTR *path)
784 LPSTR cpy = HeapAlloc(GetProcessHeap(), 0, strlen(assembly->path)+1);
785 *path = cpy;
786 if (cpy)
787 strcpy(cpy, assembly->path);
788 else
789 return E_OUTOFMEMORY;
791 return S_OK;
794 HRESULT assembly_get_version(ASSEMBLY *assembly, LPSTR *version)
796 LPSTR verdata;
797 VS_FIXEDFILEINFO *ffi;
798 HRESULT hr = S_OK;
799 DWORD size;
801 size = GetFileVersionInfoSizeA(assembly->path, NULL);
802 if (!size)
803 return HRESULT_FROM_WIN32(GetLastError());
805 verdata = HeapAlloc(GetProcessHeap(), 0, size);
806 if (!verdata)
807 return E_OUTOFMEMORY;
809 if (!GetFileVersionInfoA(assembly->path, 0, size, verdata))
811 hr = HRESULT_FROM_WIN32(GetLastError());
812 goto done;
815 if (!VerQueryValueA(verdata, "\\", (LPVOID *)&ffi, &size))
817 hr = HRESULT_FROM_WIN32(GetLastError());
818 goto done;
821 *version = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
822 if (!*version)
824 hr = E_OUTOFMEMORY;
825 goto done;
828 sprintf(*version, "%d.%d.%d.%d", HIWORD(ffi->dwFileVersionMS),
829 LOWORD(ffi->dwFileVersionMS), HIWORD(ffi->dwFileVersionLS),
830 LOWORD(ffi->dwFileVersionLS));
832 done:
833 HeapFree(GetProcessHeap(), 0, verdata);
834 return hr;
837 HRESULT assembly_get_architecture(ASSEMBLY *assembly, DWORD fixme)
839 /* FIXME */
840 return S_OK;
843 static BYTE *assembly_get_blob(ASSEMBLY *assembly, WORD index, ULONG *size)
845 return GetData(&assembly->blobs[index], size);
848 static void bytes_to_str(BYTE *bytes, DWORD len, LPSTR str)
850 DWORD i;
852 static const char hexval[16] = {
853 '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
856 for(i = 0; i < len; i++)
858 str[i * 2] = hexval[((bytes[i] >> 4) & 0xF)];
859 str[i * 2 + 1] = hexval[(bytes[i]) & 0x0F];
863 #define BYTES_PER_TOKEN 8
864 #define CHARS_PER_BYTE 2
865 #define TOKEN_LENGTH (BYTES_PER_TOKEN * CHARS_PER_BYTE + 1)
867 HRESULT assembly_get_pubkey_token(ASSEMBLY *assembly, LPSTR *token)
869 ASSEMBLYTABLE *asmtbl;
870 ULONG i, size;
871 LONG offset;
872 BYTE *hashdata;
873 HCRYPTPROV crypt;
874 HCRYPTHASH hash;
875 BYTE *pubkey;
876 BYTE tokbytes[BYTES_PER_TOKEN];
877 HRESULT hr = E_FAIL;
878 LPSTR tok;
880 *token = NULL;
882 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
883 if (offset == -1)
884 return E_FAIL;
886 asmtbl = (ASSEMBLYTABLE *)assembly_data_offset(assembly, offset);
887 if (!asmtbl)
888 return E_FAIL;
890 pubkey = assembly_get_blob(assembly, asmtbl->PublicKey, &size);
892 if (!CryptAcquireContextA(&crypt, NULL, NULL, PROV_RSA_FULL,
893 CRYPT_VERIFYCONTEXT))
894 return E_FAIL;
896 if (!CryptCreateHash(crypt, CALG_SHA1, 0, 0, &hash))
897 return E_FAIL;
899 if (!CryptHashData(hash, pubkey, size, 0))
900 return E_FAIL;
902 size = 0;
903 if (!CryptGetHashParam(hash, HP_HASHVAL, NULL, &size, 0))
904 return E_FAIL;
906 hashdata = HeapAlloc(GetProcessHeap(), 0, size);
907 if (!hashdata)
909 hr = E_OUTOFMEMORY;
910 goto done;
913 if (!CryptGetHashParam(hash, HP_HASHVAL, hashdata, &size, 0))
914 goto done;
916 for (i = size - 1; i >= size - 8; i--)
917 tokbytes[size - i - 1] = hashdata[i];
919 tok = HeapAlloc(GetProcessHeap(), 0, TOKEN_LENGTH);
920 if (!tok)
922 hr = E_OUTOFMEMORY;
923 goto done;
926 bytes_to_str(tokbytes, BYTES_PER_TOKEN, tok);
927 tok[TOKEN_LENGTH - 1] = '\0';
929 *token = tok;
930 hr = S_OK;
932 done:
933 HeapFree(GetProcessHeap(), 0, hashdata);
934 CryptDestroyHash(hash);
935 CryptReleaseContext(crypt, 0);
937 return hr;