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 LPSTR
strdupWtoA(LPCWSTR str
)
87 len
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
88 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
90 WideCharToMultiByte(CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
95 static DWORD
rva_to_offset(IMAGE_NT_HEADERS
*nthdrs
, DWORD rva
)
97 DWORD offset
= rva
, limit
;
98 IMAGE_SECTION_HEADER
*img
;
101 img
= IMAGE_FIRST_SECTION(nthdrs
);
103 if (rva
< img
->PointerToRawData
)
106 for (i
= 0; i
< nthdrs
->FileHeader
.NumberOfSections
; i
++)
108 if (img
[i
].SizeOfRawData
)
109 limit
= img
[i
].SizeOfRawData
;
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
;
129 static BYTE
*GetData(BYTE
*pData
, ULONG
*pLength
)
131 if ((*pData
& 0x80) == 0x00)
133 *pLength
= (*pData
& 0x7f);
137 if ((*pData
& 0xC0) == 0x80)
139 *pLength
= ((*pData
& 0x3f) << 8 | *(pData
+ 1));
143 if ((*pData
& 0xE0) == 0xC0)
145 *pLength
= ((*pData
& 0x1f) << 24 | *(pData
+ 1) << 16 |
146 *(pData
+ 2) << 8 | *(pData
+ 3));
150 *pLength
= (ULONG
)-1;
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
)
170 switch (TokenFromTable(index
))
174 size
= sizeof(MODULETABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
175 2 * (assembly
->guidsz
- sizeof(WORD
));
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;
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;
208 size
= sizeof(FIELDTABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
209 (assembly
->blobsz
- sizeof(WORD
));
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;
223 size
= sizeof(PARAMTABLE
) + (assembly
->stringsz
- sizeof(WORD
));
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;
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;
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;
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;
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;
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;
313 case 0x0F000000: /* FIXME */
315 size
= sizeof(CLASSLAYOUTTABLE
);
316 size
+= (assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
>
317 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
320 case 0x10000000: /* FIXME */
322 size
= sizeof(FIELDLAYOUTTABLE
);
323 size
+= (assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
>
324 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
329 size
= sizeof(STANDALONESIGTABLE
) + (assembly
->blobsz
- sizeof(WORD
));
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;
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;
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;
363 size
= sizeof(PROPERTYTABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
364 (assembly
->blobsz
- sizeof(WORD
));
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;
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;
395 size
= sizeof(MODULEREFTABLE
) + (assembly
->stringsz
- sizeof(WORD
));
400 size
= sizeof(TYPESPECTABLE
) + (assembly
->blobsz
- sizeof(WORD
));
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;
416 case 0x1D000000: /* FIXME */
418 size
= sizeof(FIELDRVATABLE
);
419 size
+= (assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
>
420 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
425 size
= sizeof(ASSEMBLYTABLE
) + 2 * (assembly
->stringsz
- sizeof(WORD
)) +
426 (assembly
->blobsz
- sizeof(WORD
));
429 case 0x20000001: /* FIXME */
431 size
= sizeof(ASSEMBLYPROCESSORTABLE
);
434 case 0x22000000: /* FIXME */
436 size
= sizeof(ASSEMBLYOSTABLE
);
441 size
= sizeof(ASSEMBLYREFTABLE
) + 2 * (assembly
->stringsz
- sizeof(WORD
)) +
442 2 * (assembly
->blobsz
- sizeof(WORD
));
445 case 0x24000000: /* FIXME */
447 size
= sizeof(ASSEMBLYREFPROCESSORTABLE
);
448 size
+= (assembly
->tables
[TableFromToken(mdtAssemblyRef
)].rows
>
449 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
452 case 0x25000000: /* FIXME */
454 size
= sizeof(ASSEMBLYREFOSTABLE
);
455 size
+= (assembly
->tables
[TableFromToken(mdtAssemblyRef
)].rows
>
456 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
461 size
= sizeof(FILETABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
462 (assembly
->blobsz
- sizeof(WORD
));
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;
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;
485 case 0x29000000: /* FIXME */
487 size
= sizeof(NESTEDCLASSTABLE
);
488 size
+= (assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
>
489 MAX_TABLES_WORD
) ? 2 * sizeof(WORD
) : 0;
499 static HRESULT
parse_clr_tables(ASSEMBLY
*assembly
, ULONG offset
)
501 DWORD i
, previ
, offidx
;
505 assembly
->tableshdr
= (METADATATABLESHDR
*)assembly_data_offset(assembly
, currofs
);
506 if (!assembly
->tableshdr
)
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
)
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
;
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
];
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
;
565 static HRESULT
parse_metadata_header(ASSEMBLY
*assembly
, DWORD
*hdrsz
)
567 METADATAHDR
*metadatahdr
;
572 rva
= assembly
->corhdr
->MetaData
.VirtualAddress
;
573 ptr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
, rva
, NULL
);
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;
598 static HRESULT
parse_clr_metadata(ASSEMBLY
*assembly
)
600 METADATASTREAMHDR
*streamhdr
;
607 hr
= parse_metadata_header(assembly
, &hdrsz
);
611 rva
= assembly
->corhdr
->MetaData
.VirtualAddress
;
612 ptr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
, rva
+ hdrsz
, NULL
);
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
);
624 if (!lstrcmpA(stream
, "#~"))
626 hr
= parse_clr_tables(assembly
, ofs
);
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 */
642 static HRESULT
parse_pe_header(ASSEMBLY
*assembly
)
644 IMAGE_DATA_DIRECTORY
*datadirs
;
646 assembly
->nthdr
= ImageNtHeader(assembly
->data
);
647 if (!assembly
->nthdr
)
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
;
657 datadirs
= assembly
->nthdr
->OptionalHeader
.DataDirectory
;
662 if (!datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
||
663 !datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].Size
)
668 assembly
->corhdr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
,
669 datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
, NULL
);
670 if (!assembly
->corhdr
)
676 HRESULT
assembly_create(ASSEMBLY
**out
, LPCWSTR file
)
683 assembly
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ASSEMBLY
));
685 return E_OUTOFMEMORY
;
687 assembly
->path
= strdupWtoA(file
);
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());
702 assembly
->hmap
= CreateFileMappingW(assembly
->hfile
, NULL
, PAGE_READONLY
,
706 hr
= HRESULT_FROM_WIN32(GetLastError());
710 assembly
->data
= MapViewOfFile(assembly
->hmap
, FILE_MAP_READ
, 0, 0, 0);
713 hr
= HRESULT_FROM_WIN32(GetLastError());
717 hr
= parse_pe_header(assembly
);
718 if (FAILED(hr
)) goto failed
;
720 hr
= parse_clr_metadata(assembly
);
721 if (FAILED(hr
)) goto failed
;
727 assembly_release(assembly
);
731 HRESULT
assembly_release(ASSEMBLY
*assembly
)
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
);
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);
755 HRESULT
assembly_get_name(ASSEMBLY
*assembly
, LPSTR
*name
)
761 offset
= assembly
->tables
[TableFromToken(mdtAssembly
)].offset
;
765 ptr
= assembly_data_offset(assembly
, offset
);
769 ptr
+= FIELD_OFFSET(ASSEMBLYTABLE
, PublicKey
) + assembly
->blobsz
;
770 if (assembly
->stringsz
== sizeof(DWORD
))
771 stridx
= *((DWORD
*)ptr
);
773 stridx
= *((WORD
*)ptr
);
775 *name
= assembly_dup_str(assembly
, stridx
);
777 return E_OUTOFMEMORY
;
782 HRESULT
assembly_get_path(ASSEMBLY
*assembly
, LPSTR
*path
)
784 LPSTR cpy
= HeapAlloc(GetProcessHeap(), 0, strlen(assembly
->path
)+1);
787 strcpy(cpy
, assembly
->path
);
789 return E_OUTOFMEMORY
;
794 HRESULT
assembly_get_version(ASSEMBLY
*assembly
, LPSTR
*version
)
797 VS_FIXEDFILEINFO
*ffi
;
801 size
= GetFileVersionInfoSizeA(assembly
->path
, NULL
);
803 return HRESULT_FROM_WIN32(GetLastError());
805 verdata
= HeapAlloc(GetProcessHeap(), 0, size
);
807 return E_OUTOFMEMORY
;
809 if (!GetFileVersionInfoA(assembly
->path
, 0, size
, verdata
))
811 hr
= HRESULT_FROM_WIN32(GetLastError());
815 if (!VerQueryValueA(verdata
, "\\", (LPVOID
*)&ffi
, &size
))
817 hr
= HRESULT_FROM_WIN32(GetLastError());
821 *version
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
);
828 sprintf(*version
, "%d.%d.%d.%d", HIWORD(ffi
->dwFileVersionMS
),
829 LOWORD(ffi
->dwFileVersionMS
), HIWORD(ffi
->dwFileVersionLS
),
830 LOWORD(ffi
->dwFileVersionLS
));
833 HeapFree(GetProcessHeap(), 0, verdata
);
837 HRESULT
assembly_get_architecture(ASSEMBLY
*assembly
, DWORD fixme
)
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
)
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
;
876 BYTE tokbytes
[BYTES_PER_TOKEN
];
882 offset
= assembly
->tables
[TableFromToken(mdtAssembly
)].offset
;
886 asmtbl
= (ASSEMBLYTABLE
*)assembly_data_offset(assembly
, offset
);
890 pubkey
= assembly_get_blob(assembly
, asmtbl
->PublicKey
, &size
);
892 if (!CryptAcquireContextA(&crypt
, NULL
, NULL
, PROV_RSA_FULL
,
893 CRYPT_VERIFYCONTEXT
))
896 if (!CryptCreateHash(crypt
, CALG_SHA1
, 0, 0, &hash
))
899 if (!CryptHashData(hash
, pubkey
, size
, 0))
903 if (!CryptGetHashParam(hash
, HP_HASHVAL
, NULL
, &size
, 0))
906 hashdata
= HeapAlloc(GetProcessHeap(), 0, size
);
913 if (!CryptGetHashParam(hash
, HP_HASHVAL
, hashdata
, &size
, 0))
916 for (i
= size
- 1; i
>= size
- 8; i
--)
917 tokbytes
[size
- i
- 1] = hashdata
[i
];
919 tok
= HeapAlloc(GetProcessHeap(), 0, TOKEN_LENGTH
);
926 bytes_to_str(tokbytes
, BYTES_PER_TOKEN
, tok
);
927 tok
[TOKEN_LENGTH
- 1] = '\0';
933 HeapFree(GetProcessHeap(), 0, hashdata
);
934 CryptDestroyHash(hash
);
935 CryptReleaseContext(crypt
, 0);