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
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
61 IMAGE_NT_HEADERS
*nthdr
;
62 IMAGE_COR20_HEADER
*corhdr
;
64 METADATAHDR
*metadatahdr
;
66 METADATATABLESHDR
*tableshdr
;
69 CLRTABLE tables
[MAX_CLR_TABLES
];
79 static DWORD
rva_to_offset(IMAGE_NT_HEADERS
*nthdrs
, DWORD rva
)
81 DWORD offset
= rva
, limit
;
82 IMAGE_SECTION_HEADER
*img
;
85 img
= IMAGE_FIRST_SECTION(nthdrs
);
87 if (rva
< img
->PointerToRawData
)
90 for (i
= 0; i
< nthdrs
->FileHeader
.NumberOfSections
; i
++)
92 if (img
[i
].SizeOfRawData
)
93 limit
= img
[i
].SizeOfRawData
;
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
;
113 static BYTE
*GetData(BYTE
*pData
, ULONG
*pLength
)
115 if ((*pData
& 0x80) == 0x00)
117 *pLength
= (*pData
& 0x7f);
121 if ((*pData
& 0xC0) == 0x80)
123 *pLength
= ((*pData
& 0x3f) << 8 | *(pData
+ 1));
127 if ((*pData
& 0xE0) == 0xC0)
129 *pLength
= ((*pData
& 0x1f) << 24 | *(pData
+ 1) << 16 |
130 *(pData
+ 2) << 8 | *(pData
+ 3));
134 *pLength
= (ULONG
)-1;
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(const ASSEMBLY
*assembly
, DWORD index
)
154 switch (TokenFromTable(index
))
158 size
= sizeof(MODULETABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
159 2 * (assembly
->guidsz
- sizeof(WORD
));
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;
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;
192 size
= sizeof(FIELDTABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
193 (assembly
->blobsz
- sizeof(WORD
));
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;
207 size
= sizeof(PARAMTABLE
) + (assembly
->stringsz
- sizeof(WORD
));
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;
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;
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;
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;
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;
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;
297 case 0x0F000000: /* FIXME */
299 size
= sizeof(CLASSLAYOUTTABLE
);
300 size
+= (assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
>
301 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
304 case 0x10000000: /* FIXME */
306 size
= sizeof(FIELDLAYOUTTABLE
);
307 size
+= (assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
>
308 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
313 size
= sizeof(STANDALONESIGTABLE
) + (assembly
->blobsz
- sizeof(WORD
));
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;
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;
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;
347 size
= sizeof(PROPERTYTABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
348 (assembly
->blobsz
- sizeof(WORD
));
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;
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;
379 size
= sizeof(MODULEREFTABLE
) + (assembly
->stringsz
- sizeof(WORD
));
384 size
= sizeof(TYPESPECTABLE
) + (assembly
->blobsz
- sizeof(WORD
));
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;
400 case 0x1D000000: /* FIXME */
402 size
= sizeof(FIELDRVATABLE
);
403 size
+= (assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
>
404 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
409 size
= sizeof(ASSEMBLYTABLE
) + 2 * (assembly
->stringsz
- sizeof(WORD
)) +
410 (assembly
->blobsz
- sizeof(WORD
));
413 case 0x20000001: /* FIXME */
415 size
= sizeof(ASSEMBLYPROCESSORTABLE
);
418 case 0x22000000: /* FIXME */
420 size
= sizeof(ASSEMBLYOSTABLE
);
425 size
= sizeof(ASSEMBLYREFTABLE
) + 2 * (assembly
->stringsz
- sizeof(WORD
)) +
426 2 * (assembly
->blobsz
- sizeof(WORD
));
429 case 0x24000000: /* FIXME */
431 size
= sizeof(ASSEMBLYREFPROCESSORTABLE
);
432 size
+= (assembly
->tables
[TableFromToken(mdtAssemblyRef
)].rows
>
433 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
436 case 0x25000000: /* FIXME */
438 size
= sizeof(ASSEMBLYREFOSTABLE
);
439 size
+= (assembly
->tables
[TableFromToken(mdtAssemblyRef
)].rows
>
440 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
445 size
= sizeof(FILETABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
446 (assembly
->blobsz
- sizeof(WORD
));
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;
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;
469 case 0x29000000: /* FIXME */
471 size
= sizeof(NESTEDCLASSTABLE
);
472 size
+= (assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
>
473 MAX_TABLES_WORD
) ? 2 * sizeof(WORD
) : 0;
483 static HRESULT
parse_clr_tables(ASSEMBLY
*assembly
, ULONG offset
)
490 assembly
->tableshdr
= assembly_data_offset(assembly
, currofs
);
491 if (!assembly
->tableshdr
)
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
);
501 currofs
+= sizeof(METADATATABLESHDR
);
502 assembly
->numrows
= assembly_data_offset(assembly
, currofs
);
503 if (!assembly
->numrows
)
506 memset(assembly
->tables
, -1, MAX_CLR_TABLES
* sizeof(CLRTABLE
));
508 for (i
= count
= 0, mask
= 1; i
< MAX_CLR_TABLES
; i
++, mask
<<= 1)
510 if (assembly
->tableshdr
->MaskValid
.QuadPart
& mask
)
511 assembly
->tables
[i
].rows
= assembly
->numrows
[count
++];
513 assembly
->numtables
= count
;
514 currofs
+= assembly
->numtables
* sizeof(DWORD
);
516 for (i
= 0, mask
= 1; i
< MAX_CLR_TABLES
; i
++, mask
<<= 1)
518 if (assembly
->tableshdr
->MaskValid
.QuadPart
& mask
)
520 assembly
->tables
[i
].offset
= currofs
;
521 currofs
+= get_table_size(assembly
, i
) * assembly
->tables
[i
].rows
;
528 static HRESULT
parse_metadata_header(ASSEMBLY
*assembly
, DWORD
*hdrsz
)
530 METADATAHDR
*metadatahdr
;
535 rva
= assembly
->corhdr
->MetaData
.VirtualAddress
;
536 ptr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
, rva
, NULL
);
540 metadatahdr
= (METADATAHDR
*)ptr
;
542 assembly
->metadatahdr
= HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR
));
543 if (!assembly
->metadatahdr
)
544 return E_OUTOFMEMORY
;
546 size
= FIELD_OFFSET(METADATAHDR
, Version
);
547 memcpy(assembly
->metadatahdr
, metadatahdr
, size
);
549 assembly
->metadatahdr
->Version
= (LPSTR
)&metadatahdr
->Version
;
551 ofs
= FIELD_OFFSET(METADATAHDR
, Flags
);
552 ptr
+= FIELD_OFFSET(METADATAHDR
, Version
) + metadatahdr
->VersionLength
+ 1;
553 dest
= (BYTE
*)assembly
->metadatahdr
+ ofs
;
554 memcpy(dest
, ptr
, sizeof(METADATAHDR
) - ofs
);
556 *hdrsz
= sizeof(METADATAHDR
) - sizeof(LPSTR
) + metadatahdr
->VersionLength
+ 1;
561 static HRESULT
parse_clr_metadata(ASSEMBLY
*assembly
)
563 METADATASTREAMHDR
*streamhdr
;
570 hr
= parse_metadata_header(assembly
, &hdrsz
);
574 rva
= assembly
->corhdr
->MetaData
.VirtualAddress
;
575 ptr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
, rva
+ hdrsz
, NULL
);
579 for (i
= 0; i
< assembly
->metadatahdr
->Streams
; i
++)
581 streamhdr
= (METADATASTREAMHDR
*)ptr
;
582 ofs
= rva_to_offset(assembly
->nthdr
, rva
+ streamhdr
->Offset
);
584 ptr
+= sizeof(METADATASTREAMHDR
);
587 if (!lstrcmpA(stream
, "#~"))
589 hr
= parse_clr_tables(assembly
, ofs
);
593 else if (!lstrcmpA(stream
, "#Strings") || !lstrcmpA(stream
, "Strings"))
594 assembly
->strings
= assembly_data_offset(assembly
, ofs
);
595 else if (!lstrcmpA(stream
, "#Blob") || !lstrcmpA(stream
, "Blob"))
596 assembly
->blobs
= assembly_data_offset(assembly
, ofs
);
598 ptr
+= lstrlenA(stream
) + 1;
599 ptr
= (BYTE
*)(((UINT_PTR
)ptr
+ 3) & ~3); /* align on DWORD boundary */
605 static HRESULT
parse_pe_header(ASSEMBLY
*assembly
)
607 IMAGE_DATA_DIRECTORY
*datadirs
;
609 assembly
->nthdr
= ImageNtHeader(assembly
->data
);
610 if (!assembly
->nthdr
)
613 if (assembly
->nthdr
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)
615 IMAGE_OPTIONAL_HEADER64
*opthdr
=
616 (IMAGE_OPTIONAL_HEADER64
*)&assembly
->nthdr
->OptionalHeader
;
617 datadirs
= opthdr
->DataDirectory
;
621 IMAGE_OPTIONAL_HEADER32
*opthdr
=
622 (IMAGE_OPTIONAL_HEADER32
*)&assembly
->nthdr
->OptionalHeader
;
623 datadirs
= opthdr
->DataDirectory
;
629 if (!datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
||
630 !datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].Size
)
635 assembly
->corhdr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
,
636 datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
, NULL
);
637 if (!assembly
->corhdr
)
643 HRESULT
assembly_create(ASSEMBLY
**out
, LPCWSTR file
)
650 assembly
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ASSEMBLY
));
652 return E_OUTOFMEMORY
;
654 assembly
->path
= strdupW(file
);
661 assembly
->hfile
= CreateFileW(file
, GENERIC_READ
, FILE_SHARE_READ
,
662 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
663 if (assembly
->hfile
== INVALID_HANDLE_VALUE
)
665 hr
= HRESULT_FROM_WIN32(GetLastError());
669 assembly
->hmap
= CreateFileMappingW(assembly
->hfile
, NULL
, PAGE_READONLY
,
673 hr
= HRESULT_FROM_WIN32(GetLastError());
677 assembly
->data
= MapViewOfFile(assembly
->hmap
, FILE_MAP_READ
, 0, 0, 0);
680 hr
= HRESULT_FROM_WIN32(GetLastError());
684 hr
= parse_pe_header(assembly
);
685 if (FAILED(hr
)) goto failed
;
687 hr
= parse_clr_metadata(assembly
);
688 if (FAILED(hr
)) goto failed
;
694 assembly_release(assembly
);
698 HRESULT
assembly_release(ASSEMBLY
*assembly
)
703 HeapFree(GetProcessHeap(), 0, assembly
->metadatahdr
);
704 HeapFree(GetProcessHeap(), 0, assembly
->path
);
705 UnmapViewOfFile(assembly
->data
);
706 CloseHandle(assembly
->hmap
);
707 CloseHandle(assembly
->hfile
);
708 HeapFree(GetProcessHeap(), 0, assembly
);
713 static LPWSTR
assembly_dup_str(const ASSEMBLY
*assembly
, DWORD index
)
717 LPCSTR str
= (LPCSTR
)&assembly
->strings
[index
];
719 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
721 if ((cpy
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
722 MultiByteToWideChar(CP_ACP
, 0, str
, -1, cpy
, len
);
727 HRESULT
assembly_get_name(ASSEMBLY
*assembly
, LPWSTR
*name
)
733 offset
= assembly
->tables
[TableFromToken(mdtAssembly
)].offset
;
737 ptr
= assembly_data_offset(assembly
, offset
);
741 ptr
+= FIELD_OFFSET(ASSEMBLYTABLE
, PublicKey
) + assembly
->blobsz
;
742 if (assembly
->stringsz
== sizeof(DWORD
))
743 stridx
= *(DWORD
*)ptr
;
745 stridx
= *(WORD
*)ptr
;
747 *name
= assembly_dup_str(assembly
, stridx
);
749 return E_OUTOFMEMORY
;
754 HRESULT
assembly_get_path(const ASSEMBLY
*assembly
, LPWSTR
*path
)
756 LPWSTR cpy
= HeapAlloc(GetProcessHeap(), 0, (strlenW(assembly
->path
) + 1) * sizeof(WCHAR
));
759 strcpyW(cpy
, assembly
->path
);
761 return E_OUTOFMEMORY
;
766 HRESULT
assembly_get_version(ASSEMBLY
*assembly
, LPWSTR
*version
)
768 static const WCHAR format
[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
770 ASSEMBLYTABLE
*asmtbl
;
775 offset
= assembly
->tables
[TableFromToken(mdtAssembly
)].offset
;
779 asmtbl
= assembly_data_offset(assembly
, offset
);
783 *version
= HeapAlloc(GetProcessHeap(), 0, sizeof(format
) + 4 * strlen("65535") * sizeof(WCHAR
));
785 return E_OUTOFMEMORY
;
787 sprintfW(*version
, format
, asmtbl
->MajorVersion
, asmtbl
->MinorVersion
,
788 asmtbl
->BuildNumber
, asmtbl
->RevisionNumber
);
793 PEKIND
assembly_get_architecture(ASSEMBLY
*assembly
)
795 if ((assembly
->corhdr
->MajorRuntimeVersion
== 2) && (assembly
->corhdr
->MinorRuntimeVersion
== 0))
796 return peNone
; /* .NET 1.x assembly */
798 if (assembly
->nthdr
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)
799 return peAMD64
; /* AMD64/IA64 assembly */
801 if ((assembly
->corhdr
->Flags
& COMIMAGE_FLAGS_ILONLY
) && !(assembly
->corhdr
->Flags
& COMIMAGE_FLAGS_32BITREQUIRED
))
802 return peMSIL
; /* MSIL assembly */
804 return peI386
; /* x86 assembly */
807 static BYTE
*assembly_get_blob(ASSEMBLY
*assembly
, DWORD index
, ULONG
*size
)
809 return GetData(&assembly
->blobs
[index
], size
);
812 HRESULT
assembly_get_pubkey_token(ASSEMBLY
*assembly
, LPWSTR
*token
)
816 BYTE
*hashdata
, *pubkey
, *ptr
;
819 BYTE tokbytes
[BYTES_PER_TOKEN
];
826 offset
= assembly
->tables
[TableFromToken(mdtAssembly
)].offset
;
830 ptr
= assembly_data_offset(assembly
, offset
);
834 ptr
+= FIELD_OFFSET(ASSEMBLYTABLE
, PublicKey
);
835 if (assembly
->blobsz
== sizeof(DWORD
))
840 pubkey
= assembly_get_blob(assembly
, idx
, &size
);
842 if (!CryptAcquireContextA(&crypt
, NULL
, NULL
, PROV_RSA_FULL
,
843 CRYPT_VERIFYCONTEXT
))
846 if (!CryptCreateHash(crypt
, CALG_SHA1
, 0, 0, &hash
))
849 if (!CryptHashData(hash
, pubkey
, size
, 0))
853 if (!CryptGetHashParam(hash
, HP_HASHVAL
, NULL
, &size
, 0))
856 hashdata
= HeapAlloc(GetProcessHeap(), 0, size
);
863 if (!CryptGetHashParam(hash
, HP_HASHVAL
, hashdata
, &size
, 0))
866 for (i
= size
- 1; i
>= size
- 8; i
--)
867 tokbytes
[size
- i
- 1] = hashdata
[i
];
869 tok
= HeapAlloc(GetProcessHeap(), 0, (TOKEN_LENGTH
+ 1) * sizeof(WCHAR
));
876 token_to_str(tokbytes
, tok
);
882 HeapFree(GetProcessHeap(), 0, hashdata
);
883 CryptDestroyHash(hash
);
884 CryptReleaseContext(crypt
, 0);
889 HRESULT
assembly_get_runtime_version(ASSEMBLY
*assembly
, LPSTR
*version
)
891 *version
= assembly
->metadatahdr
->Version
;
895 HRESULT
assembly_get_external_files(ASSEMBLY
*assembly
, LPWSTR
**files
, DWORD
*count
)
905 offset
= assembly
->tables
[TableFromToken(mdtFile
)].offset
;
909 ptr
= assembly_data_offset(assembly
, offset
);
913 num_rows
= assembly
->tables
[TableFromToken(mdtFile
)].rows
;
917 ret
= HeapAlloc(GetProcessHeap(), 0, num_rows
* sizeof(WCHAR
*));
919 return E_OUTOFMEMORY
;
921 for (i
= 0; i
< num_rows
; i
++)
923 ptr
+= sizeof(DWORD
); /* skip Flags field */
924 if (assembly
->stringsz
== sizeof(DWORD
))
929 ret
[i
] = assembly_dup_str(assembly
, idx
);
932 for (; i
>= 0; i
--) HeapFree(GetProcessHeap(), 0, ret
[i
]);
933 HeapFree(GetProcessHeap(), 0, ret
);
934 return E_OUTOFMEMORY
;
936 ptr
+= assembly
->stringsz
; /* skip Name field */
937 ptr
+= assembly
->blobsz
; /* skip Hash field */