/// <summary> /// Function to decode an image from a <see cref="Stream"/>. /// </summary> /// <param name="stream">The stream containing the image data to read.</param> /// <param name="size">The size of the image within the stream, in bytes.</param> /// <returns>A <see cref="IGorgonImage"/> containing the image data from the stream.</returns> /// <exception cref="GorgonException">Thrown when the image data in the stream has a pixel format that is unsupported.</exception> /// <remarks> /// <para> /// A codec must implement this method in order to decode the image data. /// </para> /// </remarks> protected override IGorgonImage OnDecodeFromStream(Stream stream, long size) { // Read the image meta data so we'll know how large the data should be. IGorgonImageInfo settings = ReadMetaData(stream); // Calculate the expected size of the image. int dataSize = settings.Width * settings.Height * sizeof(ushort); if ((size - TvHeader.SizeInBytes) != dataSize) { throw new GorgonException(GorgonResult.CannotRead, "The data in the stream is not the same size as the proposed image size."); } // Create our resulting image buffer. var result = new GorgonImage(settings); using (var reader = new GorgonBinaryReader(stream, true)) { // Write each scanline. for (int y = 0; y < settings.Height; ++y) { // Ensure that we move to the next line by the row pitch and not the amount of pixels. // Some images put padding in for alignment reasons which can throw off the data offsets. int ptrPosition = (y * result.Buffers[0].PitchInformation.RowPitch); // Decode the pixels in the scan line for our resulting image. for (int x = 0; x < settings.Width; ++x) { // Get our current pixel. ushort pixel = reader.ReadUInt16(); // Since we encode 1 byte per color component for each pixel, we need to bump up the bit shift // by 8 bits. Once we get above 24 bits we'll start over since we're only working with 4 bytes // per pixel in the destination. // We determine how many bits to shift the pixel based on horizontal positioning. // We assume that the image is based on 4 bytes/pixel. In most cases this value should be // determined by dividing the row pitch by the image width. // Write the color by shifting the byte in the source data to the appropriate byte position. uint color = (uint)(((pixel >> 8) & 0xff) << (8 * (x % 3))); uint alpha = (uint)((pixel & 0xff) << 24); ref uint imagePixel = ref result.ImageData.ReadAs <uint>(ptrPosition); imagePixel = color | alpha; ptrPosition += sizeof(uint); } } }
/// <summary> /// Function to decode an uncompressed run of pixel data. /// </summary> /// <param name="reader">The reader used to read the data in the stream.</param> /// <param name="dest">The destination buffer pointer.</param> /// <param name="x">The current horizontal position in the scanline.</param> /// <param name="runLength">The size of the run, in pixels.</param> /// <param name="width">The total width of the run.</param> /// <param name="expand"><b>true</b> to expand a 24bpp scanline to 32bpp, or <b>false</b> if no expansion is needed.</param> /// <param name="flipHorizontal"><b>true</b> to decode the pixels from right to left, or <b>false</b> to decode from left to right.</param> /// <param name="format">The pixel format.</param> /// <returns><b>true</b> if the run contains entirely transparent pixels, or <b>false</b> if not.</returns> private unsafe bool DecodeRleEncodedRun(GorgonBinaryReader reader, ref byte *dest, ref int x, int runLength, int width, bool expand, bool flipHorizontal, BufferFormat format) { bool result = true; switch (format) { case BufferFormat.R8_UNorm: for (; runLength > 0; --runLength, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec)); } if (!flipHorizontal) { *(dest++) = reader.ReadByte(); } else { *(dest--) = reader.ReadByte(); } } break; case BufferFormat.B5G5R5A1_UNorm: { ushort *destPtr = (ushort *)dest; ushort pixel = reader.ReadUInt16(); if ((pixel & 0x8000) != 0) { result = false; } for (; runLength > 0; runLength--, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec)); } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } dest = (byte *)destPtr; } return(result); case BufferFormat.R8G8B8A8_UNorm: { uint pixel; // Do expansion. if (expand) { pixel = (uint)((reader.ReadByte() << 16) | (reader.ReadByte() << 8) | reader.ReadByte() | 0xFF000000); result = false; } else { pixel = reader.ReadUInt32(); if ((pixel & 0xFF000000) != 0) { result = false; } } uint *destPtr = (uint *)dest; for (; runLength > 0; --runLength, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec)); } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } dest = (byte *)destPtr; } return(result); } return(false); }
/// <summary> /// Function to decode an uncompressed run of pixel data. /// </summary> /// <param name="reader">The reader used to read the data from the stream.</param> /// <param name="dest">The destination buffer pointer.</param> /// <param name="x">The current horizontal position in the scanline.</param> /// <param name="runLength">The size of the run, in pixels.</param> /// <param name="width">The total width of the run.</param> /// <param name="expand"><b>true</b> to expand a 24bpp scanline to 32bpp, or <b>false</b> if no expansion is needed.</param> /// <param name="flipHorizontal"><b>true</b> to decode the pixels from right to left, or <b>false</b> to decode from left to right.</param> /// <param name="format">The pixel format.</param> /// <returns><b>true</b> if the run contains entirely transparent pixels, or <b>false</b> if not.</returns> private unsafe bool DecodeUncompressedRun(GorgonBinaryReader reader, ref byte *dest, ref int x, int runLength, int width, bool expand, bool flipHorizontal, BufferFormat format) { bool result = true; switch (format) { case BufferFormat.R8_UNorm: for (; runLength > 0; --runLength, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec)); } if (!flipHorizontal) { *(dest++) = reader.ReadByte(); } else { *(dest--) = reader.ReadByte(); } } break; case BufferFormat.B5G5R5A1_UNorm: { ushort *destPtr = (ushort *)dest; for (; runLength > 0; runLength--, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec)); } ushort pixel = reader.ReadUInt16(); if ((pixel & 0x8000) != 0) { result = false; } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } // Send the updated destination address back to the calling function. // This is kind of ugly, but too lazy to make it nice. dest = (byte *)destPtr; } return(result); case BufferFormat.R8G8B8A8_UNorm: { uint *destPtr = (uint *)dest; for (; runLength > 0; --runLength, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec)); } uint pixel; if (expand) { pixel = (uint)((reader.ReadByte() << 16) | (reader.ReadByte() << 8) | reader.ReadByte() | 0xFF000000); result = false; } else { pixel = reader.ReadUInt32(); if ((pixel & 0xFF000000) != 0) { result = false; } } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } // Send the updated destination address back to the calling function. // This is kind of ugly, but too lazy to make it nice. dest = (byte *)destPtr; } return(result); } return(false); }
/// <summary> /// Function to determine if the assembly defined in the assembly path is a .NET managed assembly or not. /// </summary> /// <param name="assemblyPath">The path to the assembly.</param> /// <returns>A tuple containing <b>true</b> if the file is a .NET managed assembly, <b>false</b> if not, and the type of expected platform that the assembly code is supposed to work under.</returns> public static (bool isManaged, AssemblyPlatformType platform) IsManagedAssembly(string assemblyPath) { if (!File.Exists(assemblyPath)) { return(false, AssemblyPlatformType.Unknown); } uint cor2HeaderPtr = 0; AssemblyPlatformType platformType; // For this, we'll go into the guts of the file and read the data required instead of loading the assembly data and using exceptions to determine // the assembly type. // // This code is adapted from this stack overflow answer: // https://stackoverflow.com/questions/367761/how-to-determine-whether-a-dll-is-a-managed-assembly-or-native-prevent-loading using (FileStream stream = File.Open(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var reader = new GorgonBinaryReader(stream, false)) { // File is less than 64 bytes, not a portable executable. if (stream.Length < 64) { return(false, AssemblyPlatformType.Unknown); } stream.Position = 0x3C; uint headerPointer = reader.ReadUInt32(); if (headerPointer == 0) { headerPointer = 0x80; } if (headerPointer > stream.Length - 256) { return(false, AssemblyPlatformType.Unknown); } stream.Position = headerPointer; uint signature = reader.ReadUInt32(); if (signature != PeHeaderSignature) { return(false, AssemblyPlatformType.Unknown); } stream.Position += 20; ushort exePlatform = reader.ReadUInt16(); if ((exePlatform != Pe32Bit) && (exePlatform != Pe64bit)) { return(false, AssemblyPlatformType.Unknown); } uint rvaPointer = 0; switch (exePlatform) { case Pe32Bit: platformType = AssemblyPlatformType.x86; rvaPointer = headerPointer + 232; break; case Pe64bit: platformType = AssemblyPlatformType.x64; rvaPointer = headerPointer + 248; break; default: return(false, AssemblyPlatformType.Unknown); } stream.Position = rvaPointer; cor2HeaderPtr = reader.ReadUInt32(); } // AnyCPU assemblies are marked as x86. We need to read the cor20 header, but I'm lazy and it's a lot of work. // So, we'll use the old tried and true method of reading the assembly metadata. We shouldn't exception here because // we've already determined that we're not using a native DLL. GetAssemblyName doesn't care if our executing platform // environment is x64 or x86 and our DLL doesn't match, it just reads the metadata (tested and confirmed). if ((cor2HeaderPtr != 0) && (platformType == AssemblyPlatformType.x86)) { var name = AssemblyName.GetAssemblyName(assemblyPath); if (name.ProcessorArchitecture == ProcessorArchitecture.MSIL) { platformType = AssemblyPlatformType.AnyCpu; } } return(cor2HeaderPtr != 0, platformType); }