using System; using System.Diagnostics; using System.IO; namespace QuickLook.Plugin.PEViewer.PEImageParser; /// /// Represents a section of a PE image file, containing the header and a [] representing the contents of the section. /// [DebuggerDisplay($"{nameof(ImageSection)}: Header = {{Header.Name,nq}}, Size: {{Data.Length}}")] public sealed class ImageSection { /// /// Gets the section header. /// public ImageSectionHeader Header { get; private set; } /// /// Gets a [] representing the contents of the section. /// public byte[] Data { get; set; } = null!; internal ImageSection(ImageSectionHeader header) { Header = header; } public void SetDataFromRsrc(byte[] originalImage) { if (Header.PointerToRawData + Header.SizeOfRawData <= originalImage.Length) { Data = originalImage.GetBytes((int)Header.PointerToRawData, (int)Header.SizeOfRawData); } else { throw new PEImageParseException(int.MinValue, "Section '" + Header.Name + "' incomplete."); } } public void SetDataFromRsrc(Stream originalImage, uint? length = null) { if (Header.PointerToRawData + Header.SizeOfRawData <= (length ?? originalImage.Length)) { Data = originalImage.GetBytes((int)Header.PointerToRawData, (int)Header.SizeOfRawData); } else { throw new PEImageParseException(int.MinValue, "Section '" + Header.Name + "' incomplete."); } } } /// /// Provides support for creation and generation of generic objects. /// file static class Create { /// /// Copies a specified number of bytes from this [] and returns a new array representing a fraction of the original []. /// /// The [] to take the subset of bytes from. /// A value specifying the offset from which to start copying bytes. /// A value specifying the number of bytes to copy. /// /// A new [] representing a fraction of the original []. /// public static byte[] GetBytes(this byte[] array, int index, int count) { byte[] result = new byte[count]; Buffer.BlockCopy(array, index, result, 0, count); return result; } public static byte[] GetBytes(this Stream stream, long index, int count) { byte[] buffer = new byte[count]; // Ensure the stream is at the correct position long currentPosition = stream.Position; long bytesToSkip = index - currentPosition; if (bytesToSkip < 0) { throw new ArgumentException("Offset is before the current position in the stream."); } // Skip bytes until reaching the target offset while (bytesToSkip > 0) { int bytesSkipped = (int)Math.Min(bytesToSkip, int.MaxValue); stream.Read(new byte[bytesSkipped], 0, bytesSkipped); bytesToSkip -= bytesSkipped; } // Read the required number of bytes int bytesRead = stream.Read(buffer, 0, count); if (bytesRead < count) { throw new EndOfStreamException("The stream has fewer bytes available than requested."); } return buffer; } }