/Mono.Cecil.PE/ImageReader.cs
C# | 793 lines | 560 code | 126 blank | 107 comment | 50 complexity | d686551c2e1bb0a02d4e5356741f1a6a MD5 | raw file
1// 2// Author: 3// Jb Evain (jbevain@gmail.com) 4// 5// Copyright (c) 2008 - 2015 Jb Evain 6// Copyright (c) 2008 - 2011 Novell, Inc. 7// 8// Licensed under the MIT/X11 license. 9// 10 11using System; 12using System.IO; 13 14using Mono.Cecil.Cil; 15using Mono.Cecil.Metadata; 16using Mono.Collections.Generic; 17 18using RVA = System.UInt32; 19 20namespace Mono.Cecil.PE { 21 22 sealed class ImageReader : BinaryStreamReader { 23 24 readonly Image image; 25 26 DataDirectory cli; 27 DataDirectory metadata; 28 29 uint table_heap_offset; 30 31 public ImageReader (Disposable<Stream> stream, string file_name) 32 : base (stream.value) 33 { 34 image = new Image (); 35 image.Stream = stream; 36 image.FileName = file_name; 37 } 38 39 void MoveTo (DataDirectory directory) 40 { 41 BaseStream.Position = image.ResolveVirtualAddress (directory.VirtualAddress); 42 } 43 44 void ReadImage () 45 { 46 if (BaseStream.Length < 128) 47 throw new BadImageFormatException (); 48 49 // - DOSHeader 50 51 // PE 2 52 // Start 58 53 // Lfanew 4 54 // End 64 55 56 if (ReadUInt16 () != 0x5a4d) 57 throw new BadImageFormatException (); 58 59 Advance (58); 60 61 MoveTo (ReadUInt32 ()); 62 63 if (ReadUInt32 () != 0x00004550) 64 throw new BadImageFormatException (); 65 66 // - PEFileHeader 67 68 // Machine 2 69 image.Architecture = ReadArchitecture (); 70 71 // NumberOfSections 2 72 ushort sections = ReadUInt16 (); 73 74 // TimeDateStamp 4 75 image.Timestamp = ReadUInt32 (); 76 // PointerToSymbolTable 4 77 // NumberOfSymbols 4 78 // OptionalHeaderSize 2 79 Advance (10); 80 81 // Characteristics 2 82 ushort characteristics = ReadUInt16 (); 83 84 ushort subsystem, dll_characteristics; 85 ReadOptionalHeaders (out subsystem, out dll_characteristics); 86 ReadSections (sections); 87 ReadCLIHeader (); 88 ReadMetadata (); 89 ReadDebugHeader (); 90 91 image.Kind = GetModuleKind (characteristics, subsystem); 92 image.Characteristics = (ModuleCharacteristics) dll_characteristics; 93 } 94 95 TargetArchitecture ReadArchitecture () 96 { 97 return (TargetArchitecture) ReadUInt16 (); 98 } 99 100 static ModuleKind GetModuleKind (ushort characteristics, ushort subsystem) 101 { 102 if ((characteristics & 0x2000) != 0) // ImageCharacteristics.Dll 103 return ModuleKind.Dll; 104 105 if (subsystem == 0x2 || subsystem == 0x9) // SubSystem.WindowsGui || SubSystem.WindowsCeGui 106 return ModuleKind.Windows; 107 108 return ModuleKind.Console; 109 } 110 111 void ReadOptionalHeaders (out ushort subsystem, out ushort dll_characteristics) 112 { 113 // - PEOptionalHeader 114 // - StandardFieldsHeader 115 116 // Magic 2 117 bool pe64 = ReadUInt16 () == 0x20b; 118 119 // pe32 || pe64 120 121 image.LinkerVersion = ReadUInt16 (); 122 // CodeSize 4 123 // InitializedDataSize 4 124 // UninitializedDataSize4 125 // EntryPointRVA 4 126 // BaseOfCode 4 127 // BaseOfData 4 || 0 128 129 // - NTSpecificFieldsHeader 130 131 // ImageBase 4 || 8 132 // SectionAlignment 4 133 // FileAlignement 4 134 // OSMajor 2 135 // OSMinor 2 136 // UserMajor 2 137 // UserMinor 2 138 // SubSysMajor 2 139 // SubSysMinor 2 140 Advance(44); 141 142 image.SubSystemMajor = ReadUInt16 (); 143 image.SubSystemMinor = ReadUInt16 (); 144 145 // Reserved 4 146 // ImageSize 4 147 // HeaderSize 4 148 // FileChecksum 4 149 Advance (16); 150 151 // SubSystem 2 152 subsystem = ReadUInt16 (); 153 154 // DLLFlags 2 155 dll_characteristics = ReadUInt16 (); 156 // StackReserveSize 4 || 8 157 // StackCommitSize 4 || 8 158 // HeapReserveSize 4 || 8 159 // HeapCommitSize 4 || 8 160 // LoaderFlags 4 161 // NumberOfDataDir 4 162 163 // - DataDirectoriesHeader 164 165 // ExportTable 8 166 // ImportTable 8 167 168 Advance (pe64 ? 56 : 40); 169 170 // ResourceTable 8 171 172 image.Win32Resources = ReadDataDirectory (); 173 174 // ExceptionTable 8 175 // CertificateTable 8 176 // BaseRelocationTable 8 177 178 Advance (24); 179 180 // Debug 8 181 image.Debug = ReadDataDirectory (); 182 183 // Copyright 8 184 // GlobalPtr 8 185 // TLSTable 8 186 // LoadConfigTable 8 187 // BoundImport 8 188 // IAT 8 189 // DelayImportDescriptor8 190 Advance (56); 191 192 // CLIHeader 8 193 cli = ReadDataDirectory (); 194 195 if (cli.IsZero) 196 throw new BadImageFormatException (); 197 198 // Reserved 8 199 Advance (8); 200 } 201 202 string ReadAlignedString (int length) 203 { 204 int read = 0; 205 var buffer = new char [length]; 206 while (read < length) { 207 var current = ReadByte (); 208 if (current == 0) 209 break; 210 211 buffer [read++] = (char) current; 212 } 213 214 Advance (-1 + ((read + 4) & ~3) - read); 215 216 return new string (buffer, 0, read); 217 } 218 219 string ReadZeroTerminatedString (int length) 220 { 221 int read = 0; 222 var buffer = new char [length]; 223 var bytes = ReadBytes (length); 224 while (read < length) { 225 var current = bytes [read]; 226 if (current == 0) 227 break; 228 229 buffer [read++] = (char) current; 230 } 231 232 return new string (buffer, 0, read); 233 } 234 235 void ReadSections (ushort count) 236 { 237 var sections = new Section [count]; 238 239 for (int i = 0; i < count; i++) { 240 var section = new Section (); 241 242 // Name 243 section.Name = ReadZeroTerminatedString (8); 244 245 // VirtualSize 4 246 Advance (4); 247 248 // VirtualAddress 4 249 section.VirtualAddress = ReadUInt32 (); 250 // SizeOfRawData 4 251 section.SizeOfRawData = ReadUInt32 (); 252 // PointerToRawData 4 253 section.PointerToRawData = ReadUInt32 (); 254 255 // PointerToRelocations 4 256 // PointerToLineNumbers 4 257 // NumberOfRelocations 2 258 // NumberOfLineNumbers 2 259 // Characteristics 4 260 Advance (16); 261 262 sections [i] = section; 263 } 264 265 image.Sections = sections; 266 } 267 268 void ReadCLIHeader () 269 { 270 MoveTo (cli); 271 272 // - CLIHeader 273 274 // Cb 4 275 // MajorRuntimeVersion 2 276 // MinorRuntimeVersion 2 277 Advance (8); 278 279 // Metadata 8 280 metadata = ReadDataDirectory (); 281 // Flags 4 282 image.Attributes = (ModuleAttributes) ReadUInt32 (); 283 // EntryPointToken 4 284 image.EntryPointToken = ReadUInt32 (); 285 // Resources 8 286 image.Resources = ReadDataDirectory (); 287 // StrongNameSignature 8 288 image.StrongName = ReadDataDirectory (); 289 // CodeManagerTable 8 290 // VTableFixups 8 291 // ExportAddressTableJumps 8 292 // ManagedNativeHeader 8 293 } 294 295 void ReadMetadata () 296 { 297 MoveTo (metadata); 298 299 if (ReadUInt32 () != 0x424a5342) 300 throw new BadImageFormatException (); 301 302 // MajorVersion 2 303 // MinorVersion 2 304 // Reserved 4 305 Advance (8); 306 307 image.RuntimeVersion = ReadZeroTerminatedString (ReadInt32 ()); 308 309 // Flags 2 310 Advance (2); 311 312 var streams = ReadUInt16 (); 313 314 var section = image.GetSectionAtVirtualAddress (metadata.VirtualAddress); 315 if (section == null) 316 throw new BadImageFormatException (); 317 318 image.MetadataSection = section; 319 320 for (int i = 0; i < streams; i++) 321 ReadMetadataStream (section); 322 323 if (image.PdbHeap != null) 324 ReadPdbHeap (); 325 326 if (image.TableHeap != null) 327 ReadTableHeap (); 328 } 329 330 void ReadDebugHeader () 331 { 332 if (image.Debug.IsZero) { 333 image.DebugHeader = new ImageDebugHeader (Empty<ImageDebugHeaderEntry>.Array); 334 return; 335 } 336 337 MoveTo (image.Debug); 338 339 var entries = new ImageDebugHeaderEntry [(int) image.Debug.Size / ImageDebugDirectory.Size]; 340 341 for (int i = 0; i < entries.Length; i++) { 342 var directory = new ImageDebugDirectory { 343 Characteristics = ReadInt32 (), 344 TimeDateStamp = ReadInt32 (), 345 MajorVersion = ReadInt16 (), 346 MinorVersion = ReadInt16 (), 347 Type = (ImageDebugType) ReadInt32 (), 348 SizeOfData = ReadInt32 (), 349 AddressOfRawData = ReadInt32 (), 350 PointerToRawData = ReadInt32 (), 351 }; 352 353 if (directory.PointerToRawData == 0 || directory.SizeOfData < 0) { 354 entries [i] = new ImageDebugHeaderEntry (directory, Empty<byte>.Array); 355 continue; 356 } 357 358 var position = Position; 359 try { 360 MoveTo ((uint) directory.PointerToRawData); 361 var data = ReadBytes (directory.SizeOfData); 362 entries [i] = new ImageDebugHeaderEntry (directory, data); 363 } finally { 364 Position = position; 365 } 366 } 367 368 image.DebugHeader = new ImageDebugHeader (entries); 369 } 370 371 void ReadMetadataStream (Section section) 372 { 373 // Offset 4 374 uint offset = metadata.VirtualAddress - section.VirtualAddress + ReadUInt32 (); // relative to the section start 375 376 // Size 4 377 uint size = ReadUInt32 (); 378 379 var data = ReadHeapData (offset, size); 380 381 var name = ReadAlignedString (16); 382 switch (name) { 383 case "#~": 384 case "#-": 385 image.TableHeap = new TableHeap (data); 386 table_heap_offset = offset; 387 break; 388 case "#Strings": 389 image.StringHeap = new StringHeap (data); 390 break; 391 case "#Blob": 392 image.BlobHeap = new BlobHeap (data); 393 break; 394 case "#GUID": 395 image.GuidHeap = new GuidHeap (data); 396 break; 397 case "#US": 398 image.UserStringHeap = new UserStringHeap (data); 399 break; 400 case "#Pdb": 401 image.PdbHeap = new PdbHeap (data); 402 break; 403 } 404 } 405 406 byte [] ReadHeapData (uint offset, uint size) 407 { 408 var position = BaseStream.Position; 409 MoveTo (offset + image.MetadataSection.PointerToRawData); 410 var data = ReadBytes ((int) size); 411 BaseStream.Position = position; 412 413 return data; 414 } 415 416 void ReadTableHeap () 417 { 418 var heap = image.TableHeap; 419 420 MoveTo (table_heap_offset + image.MetadataSection.PointerToRawData); 421 422 // Reserved 4 423 // MajorVersion 1 424 // MinorVersion 1 425 Advance (6); 426 427 // HeapSizes 1 428 var sizes = ReadByte (); 429 430 // Reserved2 1 431 Advance (1); 432 433 // Valid 8 434 heap.Valid = ReadInt64 (); 435 436 // Sorted 8 437 heap.Sorted = ReadInt64 (); 438 439 if (image.PdbHeap != null) { 440 for (int i = 0; i < Mixin.TableCount; i++) { 441 if (!image.PdbHeap.HasTable ((Table) i)) 442 continue; 443 444 heap.Tables [i].Length = image.PdbHeap.TypeSystemTableRows [i]; 445 } 446 } 447 448 for (int i = 0; i < Mixin.TableCount; i++) { 449 if (!heap.HasTable ((Table) i)) 450 continue; 451 452 heap.Tables [i].Length = ReadUInt32 (); 453 } 454 455 SetIndexSize (image.StringHeap, sizes, 0x1); 456 SetIndexSize (image.GuidHeap, sizes, 0x2); 457 SetIndexSize (image.BlobHeap, sizes, 0x4); 458 459 ComputeTableInformations (); 460 } 461 462 static void SetIndexSize (Heap heap, uint sizes, byte flag) 463 { 464 if (heap == null) 465 return; 466 467 heap.IndexSize = (sizes & flag) > 0 ? 4 : 2; 468 } 469 470 int GetTableIndexSize (Table table) 471 { 472 return image.GetTableIndexSize (table); 473 } 474 475 int GetCodedIndexSize (CodedIndex index) 476 { 477 return image.GetCodedIndexSize (index); 478 } 479 480 void ComputeTableInformations () 481 { 482 uint offset = (uint) BaseStream.Position - table_heap_offset - image.MetadataSection.PointerToRawData; // header 483 484 int stridx_size = image.StringHeap.IndexSize; 485 int guididx_size = image.GuidHeap != null ? image.GuidHeap.IndexSize : 2; 486 int blobidx_size = image.BlobHeap != null ? image.BlobHeap.IndexSize : 2; 487 488 var heap = image.TableHeap; 489 var tables = heap.Tables; 490 491 for (int i = 0; i < Mixin.TableCount; i++) { 492 var table = (Table) i; 493 if (!heap.HasTable (table)) 494 continue; 495 496 int size; 497 switch (table) { 498 case Table.Module: 499 size = 2 // Generation 500 + stridx_size // Name 501 + (guididx_size * 3); // Mvid, EncId, EncBaseId 502 break; 503 case Table.TypeRef: 504 size = GetCodedIndexSize (CodedIndex.ResolutionScope) // ResolutionScope 505 + (stridx_size * 2); // Name, Namespace 506 break; 507 case Table.TypeDef: 508 size = 4 // Flags 509 + (stridx_size * 2) // Name, Namespace 510 + GetCodedIndexSize (CodedIndex.TypeDefOrRef) // BaseType 511 + GetTableIndexSize (Table.Field) // FieldList 512 + GetTableIndexSize (Table.Method); // MethodList 513 break; 514 case Table.FieldPtr: 515 size = GetTableIndexSize (Table.Field); // Field 516 break; 517 case Table.Field: 518 size = 2 // Flags 519 + stridx_size // Name 520 + blobidx_size; // Signature 521 break; 522 case Table.MethodPtr: 523 size = GetTableIndexSize (Table.Method); // Method 524 break; 525 case Table.Method: 526 size = 8 // Rva 4, ImplFlags 2, Flags 2 527 + stridx_size // Name 528 + blobidx_size // Signature 529 + GetTableIndexSize (Table.Param); // ParamList 530 break; 531 case Table.ParamPtr: 532 size = GetTableIndexSize (Table.Param); // Param 533 break; 534 case Table.Param: 535 size = 4 // Flags 2, Sequence 2 536 + stridx_size; // Name 537 break; 538 case Table.InterfaceImpl: 539 size = GetTableIndexSize (Table.TypeDef) // Class 540 + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Interface 541 break; 542 case Table.MemberRef: 543 size = GetCodedIndexSize (CodedIndex.MemberRefParent) // Class 544 + stridx_size // Name 545 + blobidx_size; // Signature 546 break; 547 case Table.Constant: 548 size = 2 // Type 549 + GetCodedIndexSize (CodedIndex.HasConstant) // Parent 550 + blobidx_size; // Value 551 break; 552 case Table.CustomAttribute: 553 size = GetCodedIndexSize (CodedIndex.HasCustomAttribute) // Parent 554 + GetCodedIndexSize (CodedIndex.CustomAttributeType) // Type 555 + blobidx_size; // Value 556 break; 557 case Table.FieldMarshal: 558 size = GetCodedIndexSize (CodedIndex.HasFieldMarshal) // Parent 559 + blobidx_size; // NativeType 560 break; 561 case Table.DeclSecurity: 562 size = 2 // Action 563 + GetCodedIndexSize (CodedIndex.HasDeclSecurity) // Parent 564 + blobidx_size; // PermissionSet 565 break; 566 case Table.ClassLayout: 567 size = 6 // PackingSize 2, ClassSize 4 568 + GetTableIndexSize (Table.TypeDef); // Parent 569 break; 570 case Table.FieldLayout: 571 size = 4 // Offset 572 + GetTableIndexSize (Table.Field); // Field 573 break; 574 case Table.StandAloneSig: 575 size = blobidx_size; // Signature 576 break; 577 case Table.EventMap: 578 size = GetTableIndexSize (Table.TypeDef) // Parent 579 + GetTableIndexSize (Table.Event); // EventList 580 break; 581 case Table.EventPtr: 582 size = GetTableIndexSize (Table.Event); // Event 583 break; 584 case Table.Event: 585 size = 2 // Flags 586 + stridx_size // Name 587 + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // EventType 588 break; 589 case Table.PropertyMap: 590 size = GetTableIndexSize (Table.TypeDef) // Parent 591 + GetTableIndexSize (Table.Property); // PropertyList 592 break; 593 case Table.PropertyPtr: 594 size = GetTableIndexSize (Table.Property); // Property 595 break; 596 case Table.Property: 597 size = 2 // Flags 598 + stridx_size // Name 599 + blobidx_size; // Type 600 break; 601 case Table.MethodSemantics: 602 size = 2 // Semantics 603 + GetTableIndexSize (Table.Method) // Method 604 + GetCodedIndexSize (CodedIndex.HasSemantics); // Association 605 break; 606 case Table.MethodImpl: 607 size = GetTableIndexSize (Table.TypeDef) // Class 608 + GetCodedIndexSize (CodedIndex.MethodDefOrRef) // MethodBody 609 + GetCodedIndexSize (CodedIndex.MethodDefOrRef); // MethodDeclaration 610 break; 611 case Table.ModuleRef: 612 size = stridx_size; // Name 613 break; 614 case Table.TypeSpec: 615 size = blobidx_size; // Signature 616 break; 617 case Table.ImplMap: 618 size = 2 // MappingFlags 619 + GetCodedIndexSize (CodedIndex.MemberForwarded) // MemberForwarded 620 + stridx_size // ImportName 621 + GetTableIndexSize (Table.ModuleRef); // ImportScope 622 break; 623 case Table.FieldRVA: 624 size = 4 // RVA 625 + GetTableIndexSize (Table.Field); // Field 626 break; 627 case Table.EncLog: 628 size = 8; 629 break; 630 case Table.EncMap: 631 size = 4; 632 break; 633 case Table.Assembly: 634 size = 16 // HashAlgId 4, Version 4 * 2, Flags 4 635 + blobidx_size // PublicKey 636 + (stridx_size * 2); // Name, Culture 637 break; 638 case Table.AssemblyProcessor: 639 size = 4; // Processor 640 break; 641 case Table.AssemblyOS: 642 size = 12; // Platform 4, Version 2 * 4 643 break; 644 case Table.AssemblyRef: 645 size = 12 // Version 2 * 4 + Flags 4 646 + (blobidx_size * 2) // PublicKeyOrToken, HashValue 647 + (stridx_size * 2); // Name, Culture 648 break; 649 case Table.AssemblyRefProcessor: 650 size = 4 // Processor 651 + GetTableIndexSize (Table.AssemblyRef); // AssemblyRef 652 break; 653 case Table.AssemblyRefOS: 654 size = 12 // Platform 4, Version 2 * 4 655 + GetTableIndexSize (Table.AssemblyRef); // AssemblyRef 656 break; 657 case Table.File: 658 size = 4 // Flags 659 + stridx_size // Name 660 + blobidx_size; // HashValue 661 break; 662 case Table.ExportedType: 663 size = 8 // Flags 4, TypeDefId 4 664 + (stridx_size * 2) // Name, Namespace 665 + GetCodedIndexSize (CodedIndex.Implementation); // Implementation 666 break; 667 case Table.ManifestResource: 668 size = 8 // Offset, Flags 669 + stridx_size // Name 670 + GetCodedIndexSize (CodedIndex.Implementation); // Implementation 671 break; 672 case Table.NestedClass: 673 size = GetTableIndexSize (Table.TypeDef) // NestedClass 674 + GetTableIndexSize (Table.TypeDef); // EnclosingClass 675 break; 676 case Table.GenericParam: 677 size = 4 // Number, Flags 678 + GetCodedIndexSize (CodedIndex.TypeOrMethodDef) // Owner 679 + stridx_size; // Name 680 break; 681 case Table.MethodSpec: 682 size = GetCodedIndexSize (CodedIndex.MethodDefOrRef) // Method 683 + blobidx_size; // Instantiation 684 break; 685 case Table.GenericParamConstraint: 686 size = GetTableIndexSize (Table.GenericParam) // Owner 687 + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Constraint 688 break; 689 case Table.Document: 690 size = blobidx_size // Name 691 + guididx_size // HashAlgorithm 692 + blobidx_size // Hash 693 + guididx_size; // Language 694 break; 695 case Table.MethodDebugInformation: 696 size = GetTableIndexSize (Table.Document) // Document 697 + blobidx_size; // SequencePoints 698 break; 699 case Table.LocalScope: 700 size = GetTableIndexSize (Table.Method) // Method 701 + GetTableIndexSize (Table.ImportScope) // ImportScope 702 + GetTableIndexSize (Table.LocalVariable) // VariableList 703 + GetTableIndexSize (Table.LocalConstant) // ConstantList 704 + 4 * 2; // StartOffset, Length 705 break; 706 case Table.LocalVariable: 707 size = 2 // Attributes 708 + 2 // Index 709 + stridx_size; // Name 710 break; 711 case Table.LocalConstant: 712 size = stridx_size // Name 713 + blobidx_size; // Signature 714 break; 715 case Table.ImportScope: 716 size = GetTableIndexSize (Table.ImportScope) // Parent 717 + blobidx_size; 718 break; 719 case Table.StateMachineMethod: 720 size = GetTableIndexSize (Table.Method) // MoveNextMethod 721 + GetTableIndexSize (Table.Method); // KickOffMethod 722 break; 723 case Table.CustomDebugInformation: 724 size = GetCodedIndexSize (CodedIndex.HasCustomDebugInformation) // Parent 725 + guididx_size // Kind 726 + blobidx_size; // Value 727 break; 728 default: 729 throw new NotSupportedException (); 730 } 731 732 tables [i].RowSize = (uint) size; 733 tables [i].Offset = offset; 734 735 offset += (uint) size * tables [i].Length; 736 } 737 } 738 739 void ReadPdbHeap () 740 { 741 var heap = image.PdbHeap; 742 743 var buffer = new ByteBuffer (heap.data); 744 745 heap.Id = buffer.ReadBytes (20); 746 heap.EntryPoint = buffer.ReadUInt32 (); 747 heap.TypeSystemTables = buffer.ReadInt64 (); 748 heap.TypeSystemTableRows = new uint [Mixin.TableCount]; 749 750 for (int i = 0; i < Mixin.TableCount; i++) { 751 var table = (Table) i; 752 if (!heap.HasTable (table)) 753 continue; 754 755 heap.TypeSystemTableRows [i] = buffer.ReadUInt32 (); 756 } 757 } 758 759 public static Image ReadImage (Disposable<Stream> stream, string file_name) 760 { 761 try { 762 var reader = new ImageReader (stream, file_name); 763 reader.ReadImage (); 764 return reader.image; 765 } catch (EndOfStreamException e) { 766 throw new BadImageFormatException (stream.value.GetFileName (), e); 767 } 768 } 769 770 public static Image ReadPortablePdb (Disposable<Stream> stream, string file_name) 771 { 772 try { 773 var reader = new ImageReader (stream, file_name); 774 var length = (uint) stream.value.Length; 775 776 reader.image.Sections = new[] { 777 new Section { 778 PointerToRawData = 0, 779 SizeOfRawData = length, 780 VirtualAddress = 0, 781 VirtualSize = length, 782 } 783 }; 784 785 reader.metadata = new DataDirectory (0, length); 786 reader.ReadMetadata (); 787 return reader.image; 788 } catch (EndOfStreamException e) { 789 throw new BadImageFormatException (stream.value.GetFileName (), e); 790 } 791 } 792 } 793}