[FUSION] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / fusion / 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 "wincrypt.h"
29 #include "dbghelp.h"
30 #include "ole2.h"
31 #include "fusion.h"
32 #include "corhdr.h"
33
34 #include "fusionpriv.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37
38 #define TableFromToken(tk) (TypeFromToken(tk) >> 24)
39 #define TokenFromTable(idx) (idx << 24)
40
41 #define MAX_CLR_TABLES 64
42
43 #define MD_STRINGS_BIT 0x1
44 #define MD_GUIDS_BIT 0x2
45 #define MD_BLOBS_BIT 0x4
46
47 typedef struct tagCLRTABLE
48 {
49 INT rows;
50 DWORD offset;
51 } CLRTABLE;
52
53 struct tagASSEMBLY
54 {
55 LPWSTR path;
56
57 HANDLE hfile;
58 HANDLE hmap;
59 BYTE *data;
60
61 IMAGE_NT_HEADERS *nthdr;
62 IMAGE_COR20_HEADER *corhdr;
63
64 METADATAHDR *metadatahdr;
65
66 METADATATABLESHDR *tableshdr;
67 DWORD numtables;
68 DWORD *numrows;
69 CLRTABLE tables[MAX_CLR_TABLES];
70
71 DWORD stringsz;
72 DWORD guidsz;
73 DWORD blobsz;
74
75 BYTE *strings;
76 BYTE *blobs;
77 };
78
79 static DWORD rva_to_offset(IMAGE_NT_HEADERS *nthdrs, DWORD rva)
80 {
81 DWORD offset = rva, limit;
82 IMAGE_SECTION_HEADER *img;
83 WORD i;
84
85 img = IMAGE_FIRST_SECTION(nthdrs);
86
87 if (rva < img->PointerToRawData)
88 return rva;
89
90 for (i = 0; i < nthdrs->FileHeader.NumberOfSections; i++)
91 {
92 if (img[i].SizeOfRawData)
93 limit = img[i].SizeOfRawData;
94 else
95 limit = img[i].Misc.VirtualSize;
96
97 if (rva >= img[i].VirtualAddress &&
98 rva < (img[i].VirtualAddress + limit))
99 {
100 if (img[i].PointerToRawData != 0)
101 {
102 offset -= img[i].VirtualAddress;
103 offset += img[i].PointerToRawData;
104 }
105
106 return offset;
107 }
108 }
109
110 return 0;
111 }
112
113 static BYTE *GetData(BYTE *pData, ULONG *pLength)
114 {
115 if ((*pData & 0x80) == 0x00)
116 {
117 *pLength = (*pData & 0x7f);
118 return pData + 1;
119 }
120
121 if ((*pData & 0xC0) == 0x80)
122 {
123 *pLength = ((*pData & 0x3f) << 8 | *(pData + 1));
124 return pData + 2;
125 }
126
127 if ((*pData & 0xE0) == 0xC0)
128 {
129 *pLength = ((*pData & 0x1f) << 24 | *(pData + 1) << 16 |
130 *(pData + 2) << 8 | *(pData + 3));
131 return pData + 4;
132 }
133
134 *pLength = (ULONG)-1;
135 return 0;
136 }
137
138 static VOID *assembly_data_offset(ASSEMBLY *assembly, ULONG offset)
139 {
140 return &assembly->data[offset];
141 }
142
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
148
149 static inline ULONG get_table_size(const ASSEMBLY *assembly, DWORD index)
150 {
151 DWORD size;
152 INT tables;
153
154 switch (TokenFromTable(index))
155 {
156 case mdtModule:
157 {
158 size = sizeof(MODULETABLE) + (assembly->stringsz - sizeof(WORD)) +
159 2 * (assembly->guidsz - sizeof(WORD));
160 break;
161 }
162 case mdtTypeRef:
163 {
164 size = sizeof(TYPEREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD));
165
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;
173 }
174 case mdtTypeDef:
175 {
176 size = sizeof(TYPEDEFTABLE) + 2 * (assembly->stringsz - sizeof(WORD));
177
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;
183
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;
189 }
190 case mdtFieldDef:
191 {
192 size = sizeof(FIELDTABLE) + (assembly->stringsz - sizeof(WORD)) +
193 (assembly->blobsz - sizeof(WORD));
194 break;
195 }
196 case mdtMethodDef:
197 {
198 size = sizeof(METHODDEFTABLE) + (assembly->stringsz - sizeof(WORD)) +
199 (assembly->blobsz - sizeof(WORD));
200
201 size += (assembly->tables[TableFromToken(mdtParamDef)].rows >
202 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
203 break;
204 }
205 case mdtParamDef:
206 {
207 size = sizeof(PARAMTABLE) + (assembly->stringsz - sizeof(WORD));
208 break;
209 }
210 case mdtInterfaceImpl:
211 {
212 size = sizeof(INTERFACEIMPLTABLE);
213
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;
220 }
221 case mdtMemberRef:
222 {
223 size = sizeof(MEMBERREFTABLE) + (assembly->stringsz - sizeof(WORD)) +
224 (assembly->blobsz - sizeof(WORD));
225
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;
234 }
235 case 0x0B000000: /* FIXME */
236 {
237 size = sizeof(CONSTANTTABLE) + (assembly->blobsz - sizeof(WORD));
238
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;
245 }
246 case mdtCustomAttribute:
247 {
248 size = sizeof(CUSTOMATTRIBUTETABLE) + (assembly->blobsz - sizeof(WORD));
249
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;
269
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;
275 }
276 case 0x0D000000: /* FIXME */
277 {
278 size = sizeof(FIELDMARSHALTABLE) + (assembly->blobsz - sizeof(WORD));
279
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;
285 }
286 case mdtPermission:
287 {
288 size = sizeof(DECLSECURITYTABLE) + (assembly->blobsz - sizeof(WORD));
289
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;
296 }
297 case 0x0F000000: /* FIXME */
298 {
299 size = sizeof(CLASSLAYOUTTABLE);
300 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
301 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
302 break;
303 }
304 case 0x10000000: /* FIXME */
305 {
306 size = sizeof(FIELDLAYOUTTABLE);
307 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
308 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
309 break;
310 }
311 case mdtSignature:
312 {
313 size = sizeof(STANDALONESIGTABLE) + (assembly->blobsz - sizeof(WORD));
314 break;
315 }
316 case 0x12000000: /* FIXME */
317 {
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;
324 }
325 case mdtEvent:
326 {
327 size = sizeof(EVENTTABLE) + (assembly->stringsz - sizeof(WORD));
328
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;
335 }
336 case 0x15000000:/* FIXME */
337 {
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;
344 }
345 case mdtProperty:
346 {
347 size = sizeof(PROPERTYTABLE) + (assembly->stringsz - sizeof(WORD)) +
348 (assembly->blobsz - sizeof(WORD));
349 break;
350 }
351 case 0x18000000: /* FIXME */
352 {
353 size = sizeof(METHODSEMANTICSTABLE);
354
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;
359
360 size += (assembly->tables[TableFromToken(mdtMethodDef)].rows >
361 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
362 break;
363 }
364 case 0x19000000: /* FIXME */
365 {
366 size = sizeof(METHODIMPLTABLE);
367
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;
372
373 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
374 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
375 break;
376 }
377 case mdtModuleRef:
378 {
379 size = sizeof(MODULEREFTABLE) + (assembly->stringsz - sizeof(WORD));
380 break;
381 }
382 case mdtTypeSpec:
383 {
384 size = sizeof(TYPESPECTABLE) + (assembly->blobsz - sizeof(WORD));
385 break;
386 }
387 case 0x1C000000: /* FIXME */
388 {
389 size = sizeof(IMPLMAPTABLE) + (assembly->stringsz - sizeof(WORD));
390
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;
395
396 size += (assembly->tables[TableFromToken(mdtModuleRef)].rows >
397 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
398 break;
399 }
400 case 0x1D000000: /* FIXME */
401 {
402 size = sizeof(FIELDRVATABLE);
403 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
404 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
405 break;
406 }
407 case mdtAssembly:
408 {
409 size = sizeof(ASSEMBLYTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) +
410 (assembly->blobsz - sizeof(WORD));
411 break;
412 }
413 case 0x20000001: /* FIXME */
414 {
415 size = sizeof(ASSEMBLYPROCESSORTABLE);
416 break;
417 }
418 case 0x22000000: /* FIXME */
419 {
420 size = sizeof(ASSEMBLYOSTABLE);
421 break;
422 }
423 case mdtAssemblyRef:
424 {
425 size = sizeof(ASSEMBLYREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) +
426 2 * (assembly->blobsz - sizeof(WORD));
427 break;
428 }
429 case 0x24000000: /* FIXME */
430 {
431 size = sizeof(ASSEMBLYREFPROCESSORTABLE);
432 size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows >
433 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
434 break;
435 }
436 case 0x25000000: /* FIXME */
437 {
438 size = sizeof(ASSEMBLYREFOSTABLE);
439 size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows >
440 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
441 break;
442 }
443 case mdtFile:
444 {
445 size = sizeof(FILETABLE) + (assembly->stringsz - sizeof(WORD)) +
446 (assembly->blobsz - sizeof(WORD));
447 break;
448 }
449 case mdtExportedType:
450 {
451 size = sizeof(EXPORTEDTYPETABLE) + 2 * (assembly->stringsz - sizeof(WORD));
452
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;
458 }
459 case mdtManifestResource:
460 {
461 size = sizeof(MANIFESTRESTABLE) + (assembly->stringsz - sizeof(WORD));
462
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;
468 }
469 case 0x29000000: /* FIXME */
470 {
471 size = sizeof(NESTEDCLASSTABLE);
472 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
473 MAX_TABLES_WORD) ? 2 * sizeof(WORD) : 0;
474 break;
475 }
476 default:
477 return 0;
478 }
479
480 return size;
481 }
482
483 static HRESULT parse_clr_tables(ASSEMBLY *assembly, ULONG offset)
484 {
485 DWORD i, count;
486 ULONG currofs;
487 ULONGLONG mask;
488
489 currofs = offset;
490 assembly->tableshdr = assembly_data_offset(assembly, currofs);
491 if (!assembly->tableshdr)
492 return E_FAIL;
493
494 assembly->stringsz = (assembly->tableshdr->HeapOffsetSizes & MD_STRINGS_BIT) ?
495 sizeof(DWORD) : sizeof(WORD);
496 assembly->guidsz = (assembly->tableshdr->HeapOffsetSizes & MD_GUIDS_BIT) ?
497 sizeof(DWORD) : sizeof(WORD);
498 assembly->blobsz = (assembly->tableshdr->HeapOffsetSizes & MD_BLOBS_BIT) ?
499 sizeof(DWORD) : sizeof(WORD);
500
501 currofs += sizeof(METADATATABLESHDR);
502 assembly->numrows = assembly_data_offset(assembly, currofs);
503 if (!assembly->numrows)
504 return E_FAIL;
505
506 memset(assembly->tables, -1, MAX_CLR_TABLES * sizeof(CLRTABLE));
507
508 for (i = count = 0, mask = 1; i < MAX_CLR_TABLES; i++, mask <<= 1)
509 {
510 if (assembly->tableshdr->MaskValid.QuadPart & mask)
511 assembly->tables[i].rows = assembly->numrows[count++];
512 }
513 assembly->numtables = count;
514 currofs += assembly->numtables * sizeof(DWORD);
515
516 for (i = 0, mask = 1; i < MAX_CLR_TABLES; i++, mask <<= 1)
517 {
518 if (assembly->tableshdr->MaskValid.QuadPart & mask)
519 {
520 assembly->tables[i].offset = currofs;
521 currofs += get_table_size(assembly, i) * assembly->tables[i].rows;
522 }
523 }
524
525 return S_OK;
526 }
527
528 static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz)
529 {
530 METADATAHDR *metadatahdr;
531 BYTE *ptr, *dest;
532 DWORD size, ofs;
533 ULONG rva;
534
535 rva = assembly->corhdr->MetaData.VirtualAddress;
536 ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL);
537 if (!ptr)
538 return E_FAIL;
539
540 metadatahdr = (METADATAHDR *)ptr;
541
542 if (!(assembly->metadatahdr = heap_alloc(sizeof(*assembly->metadatahdr)))) return E_OUTOFMEMORY;
543
544 size = FIELD_OFFSET(METADATAHDR, Version);
545 memcpy(assembly->metadatahdr, metadatahdr, size);
546
547 assembly->metadatahdr->Version = (LPSTR)&metadatahdr->Version;
548
549 ofs = FIELD_OFFSET(METADATAHDR, Flags);
550 ptr += FIELD_OFFSET(METADATAHDR, Version) + metadatahdr->VersionLength + 1;
551 dest = (BYTE *)assembly->metadatahdr + ofs;
552 memcpy(dest, ptr, sizeof(METADATAHDR) - ofs);
553
554 *hdrsz = sizeof(METADATAHDR) - sizeof(LPSTR) + metadatahdr->VersionLength + 1;
555
556 return S_OK;
557 }
558
559 static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
560 {
561 METADATASTREAMHDR *streamhdr;
562 ULONG rva, i, ofs;
563 LPSTR stream;
564 HRESULT hr;
565 DWORD hdrsz;
566 BYTE *ptr;
567
568 hr = parse_metadata_header(assembly, &hdrsz);
569 if (FAILED(hr))
570 return hr;
571
572 rva = assembly->corhdr->MetaData.VirtualAddress;
573 ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva + hdrsz, NULL);
574 if (!ptr)
575 return E_FAIL;
576
577 for (i = 0; i < assembly->metadatahdr->Streams; i++)
578 {
579 streamhdr = (METADATASTREAMHDR *)ptr;
580 ofs = rva_to_offset(assembly->nthdr, rva + streamhdr->Offset);
581
582 ptr += sizeof(METADATASTREAMHDR);
583 stream = (LPSTR)ptr;
584
585 if (!lstrcmpA(stream, "#~"))
586 {
587 hr = parse_clr_tables(assembly, ofs);
588 if (FAILED(hr))
589 return hr;
590 }
591 else if (!lstrcmpA(stream, "#Strings") || !lstrcmpA(stream, "Strings"))
592 assembly->strings = assembly_data_offset(assembly, ofs);
593 else if (!lstrcmpA(stream, "#Blob") || !lstrcmpA(stream, "Blob"))
594 assembly->blobs = assembly_data_offset(assembly, ofs);
595
596 ptr += ((lstrlenA(stream) + 1) + 3) & ~3; /* align on DWORD boundary */
597 }
598
599 return S_OK;
600 }
601
602 static HRESULT parse_pe_header(ASSEMBLY *assembly)
603 {
604 IMAGE_DATA_DIRECTORY *datadirs;
605
606 assembly->nthdr = ImageNtHeader(assembly->data);
607 if (!assembly->nthdr)
608 return E_FAIL;
609
610 if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
611 {
612 IMAGE_OPTIONAL_HEADER64 *opthdr =
613 (IMAGE_OPTIONAL_HEADER64 *)&assembly->nthdr->OptionalHeader;
614 datadirs = opthdr->DataDirectory;
615 }
616 else
617 {
618 IMAGE_OPTIONAL_HEADER32 *opthdr =
619 (IMAGE_OPTIONAL_HEADER32 *)&assembly->nthdr->OptionalHeader;
620 datadirs = opthdr->DataDirectory;
621 }
622
623 if (!datadirs)
624 return E_FAIL;
625
626 if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||
627 !datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
628 {
629 return E_FAIL;
630 }
631
632 assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data,
633 datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL);
634 if (!assembly->corhdr)
635 return E_FAIL;
636
637 return S_OK;
638 }
639
640 HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
641 {
642 ASSEMBLY *assembly;
643 HRESULT hr;
644
645 *out = NULL;
646
647 if (!(assembly = heap_alloc_zero(sizeof(*assembly)))) return E_OUTOFMEMORY;
648
649 assembly->path = strdupW(file);
650 if (!assembly->path)
651 {
652 hr = E_OUTOFMEMORY;
653 goto failed;
654 }
655
656 assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
657 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
658 if (assembly->hfile == INVALID_HANDLE_VALUE)
659 {
660 hr = HRESULT_FROM_WIN32(GetLastError());
661 goto failed;
662 }
663
664 assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
665 0, 0, NULL);
666 if (!assembly->hmap)
667 {
668 hr = HRESULT_FROM_WIN32(GetLastError());
669 goto failed;
670 }
671
672 assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
673 if (!assembly->data)
674 {
675 hr = HRESULT_FROM_WIN32(GetLastError());
676 goto failed;
677 }
678
679 hr = parse_pe_header(assembly);
680 if (FAILED(hr)) goto failed;
681
682 hr = parse_clr_metadata(assembly);
683 if (FAILED(hr)) goto failed;
684
685 *out = assembly;
686 return S_OK;
687
688 failed:
689 assembly_release(assembly);
690 return hr;
691 }
692
693 HRESULT assembly_release(ASSEMBLY *assembly)
694 {
695 if (!assembly)
696 return S_OK;
697
698 heap_free(assembly->metadatahdr);
699 heap_free(assembly->path);
700 UnmapViewOfFile(assembly->data);
701 CloseHandle(assembly->hmap);
702 CloseHandle(assembly->hfile);
703 heap_free(assembly);
704
705 return S_OK;
706 }
707
708 static LPWSTR assembly_dup_str(const ASSEMBLY *assembly, DWORD index)
709 {
710 int len;
711 LPWSTR cpy;
712 LPCSTR str = (LPCSTR)&assembly->strings[index];
713
714 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
715
716 if ((cpy = heap_alloc(len * sizeof(WCHAR))))
717 MultiByteToWideChar(CP_ACP, 0, str, -1, cpy, len);
718
719 return cpy;
720 }
721
722 HRESULT assembly_get_name(ASSEMBLY *assembly, LPWSTR *name)
723 {
724 BYTE *ptr;
725 LONG offset;
726 DWORD stridx;
727
728 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
729 if (offset == -1)
730 return E_FAIL;
731
732 ptr = assembly_data_offset(assembly, offset);
733 if (!ptr)
734 return E_FAIL;
735
736 ptr += FIELD_OFFSET(ASSEMBLYTABLE, PublicKey) + assembly->blobsz;
737 if (assembly->stringsz == sizeof(DWORD))
738 stridx = *(DWORD *)ptr;
739 else
740 stridx = *(WORD *)ptr;
741
742 *name = assembly_dup_str(assembly, stridx);
743 if (!*name)
744 return E_OUTOFMEMORY;
745
746 return S_OK;
747 }
748
749 HRESULT assembly_get_path(const ASSEMBLY *assembly, LPWSTR *path)
750 {
751 WCHAR *cpy = heap_alloc((strlenW(assembly->path) + 1) * sizeof(WCHAR));
752 *path = cpy;
753 if (cpy)
754 strcpyW(cpy, assembly->path);
755 else
756 return E_OUTOFMEMORY;
757
758 return S_OK;
759 }
760
761 HRESULT assembly_get_version(ASSEMBLY *assembly, LPWSTR *version)
762 {
763 static const WCHAR format[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
764
765 ASSEMBLYTABLE *asmtbl;
766 LONG offset;
767
768 *version = NULL;
769
770 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
771 if (offset == -1)
772 return E_FAIL;
773
774 asmtbl = assembly_data_offset(assembly, offset);
775 if (!asmtbl)
776 return E_FAIL;
777
778 if (!(*version = heap_alloc(sizeof(format) + 4 * strlen("65535") * sizeof(WCHAR))))
779 return E_OUTOFMEMORY;
780
781 sprintfW(*version, format, asmtbl->MajorVersion, asmtbl->MinorVersion,
782 asmtbl->BuildNumber, asmtbl->RevisionNumber);
783
784 return S_OK;
785 }
786
787 PEKIND assembly_get_architecture(ASSEMBLY *assembly)
788 {
789 if ((assembly->corhdr->MajorRuntimeVersion == 2) && (assembly->corhdr->MinorRuntimeVersion == 0))
790 return peNone; /* .NET 1.x assembly */
791
792 if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
793 return peAMD64; /* AMD64/IA64 assembly */
794
795 if ((assembly->corhdr->Flags & COMIMAGE_FLAGS_ILONLY) && !(assembly->corhdr->Flags & COMIMAGE_FLAGS_32BITREQUIRED))
796 return peMSIL; /* MSIL assembly */
797
798 return peI386; /* x86 assembly */
799 }
800
801 static BYTE *assembly_get_blob(ASSEMBLY *assembly, DWORD index, ULONG *size)
802 {
803 return GetData(&assembly->blobs[index], size);
804 }
805
806 HRESULT assembly_get_pubkey_token(ASSEMBLY *assembly, LPWSTR *token)
807 {
808 ULONG i, size;
809 LONG offset;
810 BYTE *hashdata, *pubkey, *ptr;
811 HCRYPTPROV crypt;
812 HCRYPTHASH hash;
813 BYTE tokbytes[BYTES_PER_TOKEN];
814 HRESULT hr = E_FAIL;
815 LPWSTR tok;
816 DWORD idx;
817
818 *token = NULL;
819
820 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
821 if (offset == -1)
822 return E_FAIL;
823
824 ptr = assembly_data_offset(assembly, offset);
825 if (!ptr)
826 return E_FAIL;
827
828 ptr += FIELD_OFFSET(ASSEMBLYTABLE, PublicKey);
829 if (assembly->blobsz == sizeof(DWORD))
830 idx = *(DWORD *)ptr;
831 else
832 idx = *(WORD *)ptr;
833
834 pubkey = assembly_get_blob(assembly, idx, &size);
835
836 if (!CryptAcquireContextA(&crypt, NULL, NULL, PROV_RSA_FULL,
837 CRYPT_VERIFYCONTEXT))
838 return E_FAIL;
839
840 if (!CryptCreateHash(crypt, CALG_SHA1, 0, 0, &hash))
841 return E_FAIL;
842
843 if (!CryptHashData(hash, pubkey, size, 0))
844 return E_FAIL;
845
846 size = 0;
847 if (!CryptGetHashParam(hash, HP_HASHVAL, NULL, &size, 0))
848 return E_FAIL;
849
850 if (!(hashdata = heap_alloc(size)))
851 {
852 hr = E_OUTOFMEMORY;
853 goto done;
854 }
855
856 if (!CryptGetHashParam(hash, HP_HASHVAL, hashdata, &size, 0))
857 goto done;
858
859 for (i = size - 1; i >= size - 8; i--)
860 tokbytes[size - i - 1] = hashdata[i];
861
862 if (!(tok = heap_alloc((TOKEN_LENGTH + 1) * sizeof(WCHAR))))
863 {
864 hr = E_OUTOFMEMORY;
865 goto done;
866 }
867
868 token_to_str(tokbytes, tok);
869
870 *token = tok;
871 hr = S_OK;
872
873 done:
874 heap_free(hashdata);
875 CryptDestroyHash(hash);
876 CryptReleaseContext(crypt, 0);
877
878 return hr;
879 }
880
881 HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version)
882 {
883 *version = assembly->metadatahdr->Version;
884 return S_OK;
885 }
886
887 HRESULT assembly_get_external_files(ASSEMBLY *assembly, LPWSTR **files, DWORD *count)
888 {
889 LONG offset;
890 INT i, num_rows;
891 WCHAR **ret;
892 BYTE *ptr;
893 DWORD idx;
894
895 *count = 0;
896
897 offset = assembly->tables[TableFromToken(mdtFile)].offset;
898 if (offset == -1)
899 return S_OK;
900
901 ptr = assembly_data_offset(assembly, offset);
902 if (!ptr)
903 return S_OK;
904
905 num_rows = assembly->tables[TableFromToken(mdtFile)].rows;
906 if (num_rows <= 0)
907 return S_OK;
908
909 if (!(ret = heap_alloc(num_rows * sizeof(WCHAR *)))) return E_OUTOFMEMORY;
910
911 for (i = 0; i < num_rows; i++)
912 {
913 ptr += sizeof(DWORD); /* skip Flags field */
914 if (assembly->stringsz == sizeof(DWORD))
915 idx = *(DWORD *)ptr;
916 else
917 idx = *(WORD *)ptr;
918
919 ret[i] = assembly_dup_str(assembly, idx);
920 if (!ret[i])
921 {
922 for (; i >= 0; i--) heap_free(ret[i]);
923 heap_free(ret);
924 return E_OUTOFMEMORY;
925 }
926 ptr += assembly->stringsz; /* skip Name field */
927 ptr += assembly->blobsz; /* skip Hash field */
928 }
929 *count = num_rows;
930 *files = ret;
931 return S_OK;
932 }