ntdll: Reimplement bsearch to avoid redundant and possibly out of bounds comparisons.
[wine/hramrach.git] / dlls / fusion / assembly.c
blobbc187ac91cd9df44cc35ac69dfe90014ede2a0f7
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 LPWSTR 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 DWORD rva_to_offset(IMAGE_NT_HEADERS *nthdrs, DWORD rva)
81 DWORD offset = rva, limit;
82 IMAGE_SECTION_HEADER *img;
83 WORD i;
85 img = IMAGE_FIRST_SECTION(nthdrs);
87 if (rva < img->PointerToRawData)
88 return rva;
90 for (i = 0; i < nthdrs->FileHeader.NumberOfSections; i++)
92 if (img[i].SizeOfRawData)
93 limit = img[i].SizeOfRawData;
94 else
95 limit = img[i].Misc.VirtualSize;
97 if (rva >= img[i].VirtualAddress &&
98 rva < (img[i].VirtualAddress + limit))
100 if (img[i].PointerToRawData != 0)
102 offset -= img[i].VirtualAddress;
103 offset += img[i].PointerToRawData;
106 return offset;
110 return 0;
113 static BYTE *GetData(BYTE *pData, ULONG *pLength)
115 if ((*pData & 0x80) == 0x00)
117 *pLength = (*pData & 0x7f);
118 return pData + 1;
121 if ((*pData & 0xC0) == 0x80)
123 *pLength = ((*pData & 0x3f) << 8 | *(pData + 1));
124 return pData + 2;
127 if ((*pData & 0xE0) == 0xC0)
129 *pLength = ((*pData & 0x1f) << 24 | *(pData + 1) << 16 |
130 *(pData + 2) << 8 | *(pData + 3));
131 return pData + 4;
134 *pLength = (ULONG)-1;
135 return 0;
138 static VOID *assembly_data_offset(ASSEMBLY *assembly, ULONG offset)
140 return &assembly->data[offset];
143 #define MAX_TABLES_WORD 0xFFFF
144 #define MAX_TABLES_1BIT_ENCODE 32767
145 #define MAX_TABLES_2BIT_ENCODE 16383
146 #define MAX_TABLES_3BIT_ENCODE 8191
147 #define MAX_TABLES_5BIT_ENCODE 2047
149 static inline ULONG get_table_size(ASSEMBLY *assembly, DWORD index)
151 DWORD size;
152 INT tables;
154 switch (TokenFromTable(index))
156 case mdtModule:
158 size = sizeof(MODULETABLE) + (assembly->stringsz - sizeof(WORD)) +
159 2 * (assembly->guidsz - sizeof(WORD));
160 break;
162 case mdtTypeRef:
164 size = sizeof(TYPEREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD));
166 /* ResolutionScope:ResolutionScope */
167 tables = max(assembly->tables[TableFromToken(mdtModule)].rows,
168 assembly->tables[TableFromToken(mdtModuleRef)].rows);
169 tables = max(tables, assembly->tables[TableFromToken(mdtAssemblyRef)].rows);
170 tables = max(tables, assembly->tables[TableFromToken(mdtTypeRef)].rows);
171 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
172 break;
174 case mdtTypeDef:
176 size = sizeof(TYPEDEFTABLE) + 2 * (assembly->stringsz - sizeof(WORD));
178 /* Extends:TypeDefOrRef */
179 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
180 assembly->tables[TableFromToken(mdtTypeRef)].rows);
181 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
182 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
184 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
185 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
186 size += (assembly->tables[TableFromToken(mdtMethodDef)].rows >
187 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
188 break;
190 case mdtFieldDef:
192 size = sizeof(FIELDTABLE) + (assembly->stringsz - sizeof(WORD)) +
193 (assembly->blobsz - sizeof(WORD));
194 break;
196 case mdtMethodDef:
198 size = sizeof(METHODDEFTABLE) + (assembly->stringsz - sizeof(WORD)) +
199 (assembly->blobsz - sizeof(WORD));
201 size += (assembly->tables[TableFromToken(mdtParamDef)].rows >
202 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
203 break;
205 case mdtParamDef:
207 size = sizeof(PARAMTABLE) + (assembly->stringsz - sizeof(WORD));
208 break;
210 case mdtInterfaceImpl:
212 size = sizeof(INTERFACEIMPLTABLE);
214 /* Interface:TypeDefOrRef */
215 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
216 assembly->tables[TableFromToken(mdtTypeRef)].rows);
217 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
218 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
219 break;
221 case mdtMemberRef:
223 size = sizeof(MEMBERREFTABLE) + (assembly->stringsz - sizeof(WORD)) +
224 (assembly->blobsz - sizeof(WORD));
226 /* Class:MemberRefParent */
227 tables = max(assembly->tables[TableFromToken(mdtTypeRef)].rows,
228 assembly->tables[TableFromToken(mdtModuleRef)].rows);
229 tables = max(tables, assembly->tables[TableFromToken(mdtMethodDef)].rows);
230 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
231 tables = max(tables, assembly->tables[TableFromToken(mdtTypeDef)].rows);
232 size += (tables > MAX_TABLES_3BIT_ENCODE) ? sizeof(WORD) : 0;
233 break;
235 case 0x0B000000: /* FIXME */
237 size = sizeof(CONSTANTTABLE) + (assembly->blobsz - sizeof(WORD));
239 /* Parent:HasConstant */
240 tables = max(assembly->tables[TableFromToken(mdtParamDef)].rows,
241 assembly->tables[TableFromToken(mdtFieldDef)].rows);
242 tables = max(tables, assembly->tables[TableFromToken(mdtProperty)].rows);
243 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
244 break;
246 case mdtCustomAttribute:
248 size = sizeof(CUSTOMATTRIBUTETABLE) + (assembly->blobsz - sizeof(WORD));
250 /* Parent:HasCustomAttribute */
251 tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows,
252 assembly->tables[TableFromToken(mdtFieldDef)].rows);
253 tables = max(tables, assembly->tables[TableFromToken(mdtTypeRef)].rows);
254 tables = max(tables, assembly->tables[TableFromToken(mdtTypeDef)].rows);
255 tables = max(tables, assembly->tables[TableFromToken(mdtParamDef)].rows);
256 tables = max(tables, assembly->tables[TableFromToken(mdtInterfaceImpl)].rows);
257 tables = max(tables, assembly->tables[TableFromToken(mdtMemberRef)].rows);
258 tables = max(tables, assembly->tables[TableFromToken(mdtPermission)].rows);
259 tables = max(tables, assembly->tables[TableFromToken(mdtProperty)].rows);
260 tables = max(tables, assembly->tables[TableFromToken(mdtEvent)].rows);
261 tables = max(tables, assembly->tables[TableFromToken(mdtSignature)].rows);
262 tables = max(tables, assembly->tables[TableFromToken(mdtModuleRef)].rows);
263 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
264 tables = max(tables, assembly->tables[TableFromToken(mdtAssembly)].rows);
265 tables = max(tables, assembly->tables[TableFromToken(mdtFile)].rows);
266 tables = max(tables, assembly->tables[TableFromToken(mdtExportedType)].rows);
267 tables = max(tables, assembly->tables[TableFromToken(mdtManifestResource)].rows);
268 size += (tables > MAX_TABLES_5BIT_ENCODE) ? sizeof(WORD) : 0;
270 /* Type:CustomAttributeType */
271 tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows,
272 assembly->tables[TableFromToken(mdtMemberRef)].rows);
273 size += (tables > MAX_TABLES_3BIT_ENCODE) ? sizeof(WORD) : 0;
274 break;
276 case 0x0D000000: /* FIXME */
278 size = sizeof(FIELDMARSHALTABLE) + (assembly->blobsz - sizeof(WORD));
280 /* Parent:HasFieldMarshal */
281 tables = max(assembly->tables[TableFromToken(mdtFieldDef)].rows,
282 assembly->tables[TableFromToken(mdtParamDef)].rows);
283 size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0;
284 break;
286 case mdtPermission:
288 size = sizeof(DECLSECURITYTABLE) + (assembly->blobsz - sizeof(WORD));
290 /* Parent:HasDeclSecurity */
291 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
292 assembly->tables[TableFromToken(mdtMethodDef)].rows);
293 tables = max(tables, assembly->tables[TableFromToken(mdtAssembly)].rows);
294 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
295 break;
297 case 0x0F000000: /* FIXME */
299 size = sizeof(CLASSLAYOUTTABLE);
300 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
301 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
302 break;
304 case 0x10000000: /* FIXME */
306 size = sizeof(FIELDLAYOUTTABLE);
307 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
308 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
309 break;
311 case mdtSignature:
313 size = sizeof(STANDALONESIGTABLE) + (assembly->blobsz - sizeof(WORD));
314 break;
316 case 0x12000000: /* FIXME */
318 size = sizeof(EVENTMAPTABLE);
319 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
320 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
321 size += (assembly->tables[TableFromToken(mdtEvent)].rows >
322 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
323 break;
325 case mdtEvent:
327 size = sizeof(EVENTTABLE) + (assembly->stringsz - sizeof(WORD));
329 /* EventType:TypeDefOrRef */
330 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
331 assembly->tables[TableFromToken(mdtTypeRef)].rows);
332 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
333 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
334 break;
336 case 0x15000000:/* FIXME */
338 size = sizeof(PROPERTYMAPTABLE);
339 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
340 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
341 size += (assembly->tables[TableFromToken(mdtProperty)].rows >
342 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
343 break;
345 case mdtProperty:
347 size = sizeof(PROPERTYTABLE) + (assembly->stringsz - sizeof(WORD)) +
348 (assembly->blobsz - sizeof(WORD));
349 break;
351 case 0x18000000: /* FIXME */
353 size = sizeof(METHODSEMANTICSTABLE);
355 /* Association:HasSemantics */
356 tables = max(assembly->tables[TableFromToken(mdtEvent)].rows,
357 assembly->tables[TableFromToken(mdtProperty)].rows);
358 size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0;
360 size += (assembly->tables[TableFromToken(mdtMethodDef)].rows >
361 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
362 break;
364 case 0x19000000: /* FIXME */
366 size = sizeof(METHODIMPLTABLE);
368 /* MethodBody:MethodDefOrRef, MethodDeclaration:MethodDefOrRef */
369 tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows,
370 assembly->tables[TableFromToken(mdtMemberRef)].rows);
371 size += (tables > MAX_TABLES_1BIT_ENCODE) ? 2 * sizeof(WORD) : 0;
373 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
374 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
375 break;
377 case mdtModuleRef:
379 size = sizeof(MODULEREFTABLE) + (assembly->stringsz - sizeof(WORD));
380 break;
382 case mdtTypeSpec:
384 size = sizeof(TYPESPECTABLE) + (assembly->blobsz - sizeof(WORD));
385 break;
387 case 0x1C000000: /* FIXME */
389 size = sizeof(IMPLMAPTABLE) + (assembly->stringsz - sizeof(WORD));
391 /* MemberForwarded:MemberForwarded */
392 tables = max(assembly->tables[TableFromToken(mdtFieldDef)].rows,
393 assembly->tables[TableFromToken(mdtMethodDef)].rows);
394 size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0;
396 size += (assembly->tables[TableFromToken(mdtModuleRef)].rows >
397 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
398 break;
400 case 0x1D000000: /* FIXME */
402 size = sizeof(FIELDRVATABLE);
403 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
404 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
405 break;
407 case mdtAssembly:
409 size = sizeof(ASSEMBLYTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) +
410 (assembly->blobsz - sizeof(WORD));
411 break;
413 case 0x20000001: /* FIXME */
415 size = sizeof(ASSEMBLYPROCESSORTABLE);
416 break;
418 case 0x22000000: /* FIXME */
420 size = sizeof(ASSEMBLYOSTABLE);
421 break;
423 case mdtAssemblyRef:
425 size = sizeof(ASSEMBLYREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) +
426 2 * (assembly->blobsz - sizeof(WORD));
427 break;
429 case 0x24000000: /* FIXME */
431 size = sizeof(ASSEMBLYREFPROCESSORTABLE);
432 size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows >
433 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
434 break;
436 case 0x25000000: /* FIXME */
438 size = sizeof(ASSEMBLYREFOSTABLE);
439 size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows >
440 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
441 break;
443 case mdtFile:
445 size = sizeof(FILETABLE) + (assembly->stringsz - sizeof(WORD)) +
446 (assembly->blobsz - sizeof(WORD));
447 break;
449 case mdtExportedType:
451 size = sizeof(EXPORTEDTYPETABLE) + 2 * (assembly->stringsz - sizeof(WORD));
453 /* Implementation:Implementation */
454 tables = max(assembly->tables[TableFromToken(mdtFile)].rows,
455 assembly->tables[TableFromToken(mdtMethodDef)].rows);
456 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
457 break;
459 case mdtManifestResource:
461 size = sizeof(MANIFESTRESTABLE) + (assembly->stringsz - sizeof(WORD));
463 /* Implementation:Implementation */
464 tables = max(assembly->tables[TableFromToken(mdtFile)].rows,
465 assembly->tables[TableFromToken(mdtAssemblyRef)].rows);
466 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
467 break;
469 case 0x29000000: /* FIXME */
471 size = sizeof(NESTEDCLASSTABLE);
472 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
473 MAX_TABLES_WORD) ? 2 * sizeof(WORD) : 0;
474 break;
476 default:
477 return 0;
480 return size;
483 static HRESULT parse_clr_tables(ASSEMBLY *assembly, ULONG offset)
485 DWORD i, previ, offidx;
486 ULONG currofs;
488 currofs = offset;
489 assembly->tableshdr = assembly_data_offset(assembly, currofs);
490 if (!assembly->tableshdr)
491 return E_FAIL;
493 assembly->stringsz = (assembly->tableshdr->HeapOffsetSizes & MD_STRINGS_BIT) ?
494 sizeof(DWORD) : sizeof(WORD);
495 assembly->guidsz = (assembly->tableshdr->HeapOffsetSizes & MD_GUIDS_BIT) ?
496 sizeof(DWORD) : sizeof(WORD);
497 assembly->blobsz = (assembly->tableshdr->HeapOffsetSizes & MD_BLOBS_BIT) ?
498 sizeof(DWORD) : sizeof(WORD);
500 currofs += sizeof(METADATATABLESHDR);
501 assembly->numrows = assembly_data_offset(assembly, currofs);
502 if (!assembly->numrows)
503 return E_FAIL;
505 assembly->numtables = 0;
506 for (i = 0; i < MAX_CLR_TABLES; i++)
508 if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) ||
509 (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1))
511 assembly->numtables++;
515 currofs += assembly->numtables * sizeof(DWORD);
516 memset(assembly->tables, -1, MAX_CLR_TABLES * sizeof(CLRTABLE));
518 if (assembly->tableshdr->MaskValid.u.LowPart & 1)
519 assembly->tables[0].offset = currofs;
521 offidx = 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->tables[i].rows = assembly->numrows[offidx];
528 offidx++;
532 previ = 0;
533 offidx = 1;
534 for (i = 1; i < MAX_CLR_TABLES; i++)
536 if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) ||
537 (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1))
539 currofs += get_table_size(assembly, previ) * assembly->numrows[offidx - 1];
540 assembly->tables[i].offset = currofs;
541 offidx++;
542 previ = i;
546 return S_OK;
549 static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz)
551 METADATAHDR *metadatahdr;
552 BYTE *ptr, *dest;
553 DWORD size, ofs;
554 ULONG rva;
556 rva = assembly->corhdr->MetaData.VirtualAddress;
557 ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL);
558 if (!ptr)
559 return E_FAIL;
561 metadatahdr = (METADATAHDR *)ptr;
563 assembly->metadatahdr = HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR));
564 if (!assembly->metadatahdr)
565 return E_OUTOFMEMORY;
567 size = FIELD_OFFSET(METADATAHDR, Version);
568 memcpy(assembly->metadatahdr, metadatahdr, size);
570 /* we don't care about the version string */
572 ofs = FIELD_OFFSET(METADATAHDR, Flags);
573 ptr += FIELD_OFFSET(METADATAHDR, Version) + metadatahdr->VersionLength + 1;
574 dest = (BYTE *)assembly->metadatahdr + ofs;
575 memcpy(dest, ptr, sizeof(METADATAHDR) - ofs);
577 *hdrsz = sizeof(METADATAHDR) - sizeof(LPSTR) + metadatahdr->VersionLength + 1;
579 return S_OK;
582 static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
584 METADATASTREAMHDR *streamhdr;
585 ULONG rva, i, ofs;
586 LPSTR stream;
587 HRESULT hr;
588 DWORD hdrsz;
589 BYTE *ptr;
591 hr = parse_metadata_header(assembly, &hdrsz);
592 if (FAILED(hr))
593 return hr;
595 rva = assembly->corhdr->MetaData.VirtualAddress;
596 ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva + hdrsz, NULL);
597 if (!ptr)
598 return E_FAIL;
600 for (i = 0; i < assembly->metadatahdr->Streams; i++)
602 streamhdr = (METADATASTREAMHDR *)ptr;
603 ofs = rva_to_offset(assembly->nthdr, rva + streamhdr->Offset);
605 ptr += sizeof(METADATASTREAMHDR);
606 stream = (LPSTR)ptr;
608 if (!lstrcmpA(stream, "#~"))
610 hr = parse_clr_tables(assembly, ofs);
611 if (FAILED(hr))
612 return hr;
614 else if (!lstrcmpA(stream, "#Strings") || !lstrcmpA(stream, "Strings"))
615 assembly->strings = assembly_data_offset(assembly, ofs);
616 else if (!lstrcmpA(stream, "#Blob") || !lstrcmpA(stream, "Blob"))
617 assembly->blobs = assembly_data_offset(assembly, ofs);
619 ptr += lstrlenA(stream) + 1;
620 ptr = (BYTE *)(((UINT_PTR)ptr + 3) & ~3); /* align on DWORD boundary */
623 return S_OK;
626 static HRESULT parse_pe_header(ASSEMBLY *assembly)
628 IMAGE_DATA_DIRECTORY *datadirs;
630 assembly->nthdr = ImageNtHeader(assembly->data);
631 if (!assembly->nthdr)
632 return E_FAIL;
634 if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
636 IMAGE_OPTIONAL_HEADER64 *opthdr =
637 (IMAGE_OPTIONAL_HEADER64 *)&assembly->nthdr->OptionalHeader;
638 datadirs = opthdr->DataDirectory;
640 else
642 IMAGE_OPTIONAL_HEADER32 *opthdr =
643 (IMAGE_OPTIONAL_HEADER32 *)&assembly->nthdr->OptionalHeader;
644 datadirs = opthdr->DataDirectory;
647 if (!datadirs)
648 return E_FAIL;
650 if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||
651 !datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
653 return E_FAIL;
656 assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data,
657 datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL);
658 if (!assembly->corhdr)
659 return E_FAIL;
661 return S_OK;
664 HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
666 ASSEMBLY *assembly;
667 HRESULT hr;
669 *out = NULL;
671 assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY));
672 if (!assembly)
673 return E_OUTOFMEMORY;
675 assembly->path = strdupW(file);
676 if (!assembly->path)
678 hr = E_OUTOFMEMORY;
679 goto failed;
682 assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
683 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
684 if (assembly->hfile == INVALID_HANDLE_VALUE)
686 hr = HRESULT_FROM_WIN32(GetLastError());
687 goto failed;
690 assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
691 0, 0, NULL);
692 if (!assembly->hmap)
694 hr = HRESULT_FROM_WIN32(GetLastError());
695 goto failed;
698 assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
699 if (!assembly->data)
701 hr = HRESULT_FROM_WIN32(GetLastError());
702 goto failed;
705 hr = parse_pe_header(assembly);
706 if (FAILED(hr)) goto failed;
708 hr = parse_clr_metadata(assembly);
709 if (FAILED(hr)) goto failed;
711 *out = assembly;
712 return S_OK;
714 failed:
715 assembly_release(assembly);
716 return hr;
719 HRESULT assembly_release(ASSEMBLY *assembly)
721 if (!assembly)
722 return S_OK;
724 HeapFree(GetProcessHeap(), 0, assembly->metadatahdr);
725 HeapFree(GetProcessHeap(), 0, assembly->path);
726 UnmapViewOfFile(assembly->data);
727 CloseHandle(assembly->hmap);
728 CloseHandle(assembly->hfile);
729 HeapFree(GetProcessHeap(), 0, assembly);
731 return S_OK;
734 static LPWSTR assembly_dup_str(ASSEMBLY *assembly, DWORD index)
736 int len;
737 LPWSTR cpy;
738 LPSTR str = (LPSTR)&assembly->strings[index];
740 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
742 if ((cpy = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
743 MultiByteToWideChar(CP_ACP, 0, str, -1, cpy, len);
745 return cpy;
748 HRESULT assembly_get_name(ASSEMBLY *assembly, LPWSTR *name)
750 BYTE *ptr;
751 LONG offset;
752 DWORD stridx;
754 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
755 if (offset == -1)
756 return E_FAIL;
758 ptr = assembly_data_offset(assembly, offset);
759 if (!ptr)
760 return E_FAIL;
762 ptr += FIELD_OFFSET(ASSEMBLYTABLE, PublicKey) + assembly->blobsz;
763 if (assembly->stringsz == sizeof(DWORD))
764 stridx = *((DWORD *)ptr);
765 else
766 stridx = *((WORD *)ptr);
768 *name = assembly_dup_str(assembly, stridx);
769 if (!*name)
770 return E_OUTOFMEMORY;
772 return S_OK;
775 HRESULT assembly_get_path(ASSEMBLY *assembly, LPWSTR *path)
777 LPWSTR cpy = HeapAlloc(GetProcessHeap(), 0, (strlenW(assembly->path) + 1) * sizeof(WCHAR));
778 *path = cpy;
779 if (cpy)
780 strcpyW(cpy, assembly->path);
781 else
782 return E_OUTOFMEMORY;
784 return S_OK;
787 HRESULT assembly_get_version(ASSEMBLY *assembly, LPWSTR *version)
789 static const WCHAR format[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
791 ASSEMBLYTABLE *asmtbl;
792 LONG offset;
794 *version = NULL;
796 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
797 if (offset == -1)
798 return E_FAIL;
800 asmtbl = assembly_data_offset(assembly, offset);
801 if (!asmtbl)
802 return E_FAIL;
804 *version = HeapAlloc(GetProcessHeap(), 0, sizeof(format) + 4 * strlen("65535") * sizeof(WCHAR));
805 if (!*version)
806 return E_OUTOFMEMORY;
808 sprintfW(*version, format, asmtbl->MajorVersion, asmtbl->MinorVersion,
809 asmtbl->BuildNumber, asmtbl->RevisionNumber);
811 return S_OK;
814 static BYTE *assembly_get_blob(ASSEMBLY *assembly, WORD index, ULONG *size)
816 return GetData(&assembly->blobs[index], size);
819 HRESULT assembly_get_pubkey_token(ASSEMBLY *assembly, LPWSTR *token)
821 ASSEMBLYTABLE *asmtbl;
822 ULONG i, size;
823 LONG offset;
824 BYTE *hashdata;
825 HCRYPTPROV crypt;
826 HCRYPTHASH hash;
827 BYTE *pubkey;
828 BYTE tokbytes[BYTES_PER_TOKEN];
829 HRESULT hr = E_FAIL;
830 LPWSTR tok;
832 *token = NULL;
834 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
835 if (offset == -1)
836 return E_FAIL;
838 asmtbl = assembly_data_offset(assembly, offset);
839 if (!asmtbl)
840 return E_FAIL;
842 pubkey = assembly_get_blob(assembly, asmtbl->PublicKey, &size);
844 if (!CryptAcquireContextA(&crypt, NULL, NULL, PROV_RSA_FULL,
845 CRYPT_VERIFYCONTEXT))
846 return E_FAIL;
848 if (!CryptCreateHash(crypt, CALG_SHA1, 0, 0, &hash))
849 return E_FAIL;
851 if (!CryptHashData(hash, pubkey, size, 0))
852 return E_FAIL;
854 size = 0;
855 if (!CryptGetHashParam(hash, HP_HASHVAL, NULL, &size, 0))
856 return E_FAIL;
858 hashdata = HeapAlloc(GetProcessHeap(), 0, size);
859 if (!hashdata)
861 hr = E_OUTOFMEMORY;
862 goto done;
865 if (!CryptGetHashParam(hash, HP_HASHVAL, hashdata, &size, 0))
866 goto done;
868 for (i = size - 1; i >= size - 8; i--)
869 tokbytes[size - i - 1] = hashdata[i];
871 tok = HeapAlloc(GetProcessHeap(), 0, (TOKEN_LENGTH + 1) * sizeof(WCHAR));
872 if (!tok)
874 hr = E_OUTOFMEMORY;
875 goto done;
878 token_to_str(tokbytes, tok);
880 *token = tok;
881 hr = S_OK;
883 done:
884 HeapFree(GetProcessHeap(), 0, hashdata);
885 CryptDestroyHash(hash);
886 CryptReleaseContext(crypt, 0);
888 return hr;