diff --git a/Img2Ffu.Library/Img2Ffu.Library.csproj b/Img2Ffu.Library/Img2Ffu.Library.csproj deleted file mode 100644 index 1e598df..0000000 --- a/Img2Ffu.Library/Img2Ffu.Library.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net8.0-windows - enable - enable - AnyCPU;ARM32;ARM64;x86;x64 - true - - - - - - - - - - - diff --git a/Img2Ffu.Library/Reader/Compression/WindowsNativeCompression.cs b/Img2Ffu.Library/Reader/Compression/WindowsNativeCompression.cs deleted file mode 100644 index d2da77c..0000000 --- a/Img2Ffu.Library/Reader/Compression/WindowsNativeCompression.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Reader.Compression -{ - internal class WindowsNativeCompression - { - [DllImport("ntdll.dll")] - private static extern uint RtlGetCompressionWorkSpaceSize(ushort CompressionFormatAndEngine, out uint CompressBufferWorkSpaceSize, out uint CompressFragmentWorkSpaceSize); - - [DllImport("ntdll.dll")] - private static extern uint RtlDecompressBufferEx(ushort CompressionFormat, byte[] UncompressedBuffer, int UncompressedBufferSize, byte[] CompressedBuffer, int CompressedBufferSize, out int FinalUncompressedSize, byte[] WorkSpace); - - [DllImport("ntdll.dll")] - private static extern uint RtlCompressBuffer(ushort CompressionFormatAndEngine, byte[] UncompressedBuffer, int UncompressedBufferSize, byte[] CompressedBuffer, int CompressedBufferSize, int UncompressedChunkSize, out int FinalCompressedSize, byte[] WorkSpace); - - public static byte[] Decompress(WindowsNativeCompressionAlgorithm CompressionFormat, byte[] CompressedBuffer, int UncompressedBufferSize) - { - uint ntStatus = RtlGetCompressionWorkSpaceSize((ushort)CompressionFormat, out uint compressBufferWorkSpaceSize, out _); - if (ntStatus != 0) - { - throw new Exception($"Cannot get decompress workspace size! NTSTATUS=0x{ntStatus:X8}"); - } - - byte[] UncompressedBuffer = new byte[UncompressedBufferSize]; - byte[] workSpace = new byte[compressBufferWorkSpaceSize]; - - - ntStatus = RtlDecompressBufferEx((ushort)CompressionFormat, UncompressedBuffer, UncompressedBuffer.Length, CompressedBuffer, CompressedBuffer.Length, out _, workSpace); - return ntStatus != 0 ? throw new Exception($"Cannot decompress buffer! NTSTATUS=0x{ntStatus:X8}") : UncompressedBuffer; - } - - public static byte[] Compress(WindowsNativeCompressionAlgorithm CompressionFormat, byte[] UncompressedBuffer, int CompressedBufferSize) - { - uint ntStatus = RtlGetCompressionWorkSpaceSize((ushort)CompressionFormat, out uint compressBufferWorkSpaceSize, out _); - if (ntStatus != 0) - { - throw new Exception($"Cannot get compression workspace size! NTSTATUS=0x{ntStatus:X8}"); - } - - byte[] CompressedBuffer = new byte[CompressedBufferSize]; - byte[] workSpace = new byte[compressBufferWorkSpaceSize]; - - - ntStatus = RtlCompressBuffer((ushort)CompressionFormat, UncompressedBuffer, UncompressedBuffer.Length, CompressedBuffer, CompressedBuffer.Length, 4096, out _, workSpace); - return ntStatus != 0 ? throw new Exception($"Cannot compress buffer! NTSTATUS=0x{ntStatus:X8}") : CompressedBuffer; - } - } -} diff --git a/Img2Ffu.Library/Reader/Compression/WindowsNativeCompressionAlgorithm.cs b/Img2Ffu.Library/Reader/Compression/WindowsNativeCompressionAlgorithm.cs deleted file mode 100644 index f15e365..0000000 --- a/Img2Ffu.Library/Reader/Compression/WindowsNativeCompressionAlgorithm.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Img2Ffu.Reader.Compression -{ - [Flags] - public enum WindowsNativeCompressionAlgorithm - { - COMPRESSION_FORMAT_NONE = 0x0000, - COMPRESSION_ENGINE_STANDARD = 0x0000, - COMPRESSION_FORMAT_DEFAULT = 0x0001, - COMPRESSION_FORMAT_LZNT1 = 0x0002, - COMPRESSION_FORMAT_XPRESS = 0x0003, - COMPRESSION_FORMAT_XPRESS_HUFF = 0x0004, - COMPRESSION_ENGINE_MAXIMUM = 0x0100, - COMPRESSION_ENGINE_HIBER = 0x0200 - } -} diff --git a/Img2Ffu.Library/Reader/Data/ImageFlash.cs b/Img2Ffu.Library/Reader/Data/ImageFlash.cs deleted file mode 100644 index 5d618ac..0000000 --- a/Img2Ffu.Library/Reader/Data/ImageFlash.cs +++ /dev/null @@ -1,194 +0,0 @@ -using Img2Ffu.Reader.Compression; -using Img2Ffu.Reader.Enums; -using Img2Ffu.Reader.Structs; -using System.Text; - -namespace Img2Ffu.Reader.Data -{ - internal class ImageFlash - { - public ImageHeader ImageHeader; - public string ManifestData = ""; - public byte[] Padding = []; - public readonly List Stores = []; - - private readonly long DataBlocksPosition; - private readonly long InitialStreamPosition; - - - public ImageFlash(Stream stream) - { - InitialStreamPosition = stream.Position; - ImageHeader = stream.ReadStructure(); - - if (ImageHeader.Signature != "ImageFlash ") - { - throw new InvalidDataException("Invalid Image Header Signature!"); - } - - byte[] manifestDataBuffer = new byte[ImageHeader.ManifestLength]; - _ = stream.Read(manifestDataBuffer, 0, (int)ImageHeader.ManifestLength); - ASCIIEncoding asciiEncoding = new(); - ManifestData = asciiEncoding.GetString(manifestDataBuffer); - - long Position = stream.Position; - if (Position % (ImageHeader.ChunkSize * 1024) > 0) - { - long paddingSize = (ImageHeader.ChunkSize * 1024) - (Position % (ImageHeader.ChunkSize * 1024)); - Padding = new byte[paddingSize]; - _ = stream.Read(Padding, 0, (int)paddingSize); - } - - Store store = new(stream); - Stores.Add(store); - - if (store.StoreHeader.MajorVersion == 2 && store.StoreHeader.FullFlashMajorVersion == 2) - { - for (uint i = 2; i <= store.StoreHeaderV2.NumberOfStores; i++) - { - Stores.Add(new Store(stream)); - } - } - - DataBlocksPosition = stream.Position; - } - - - public ulong GetImageBlockCount() - { - ulong imageBlockCount = (ulong)(DataBlocksPosition - InitialStreamPosition) / (ImageHeader.ChunkSize * 1024); - ulong storeBlockCount = GetDataBlockCount(); - return imageBlockCount + storeBlockCount; - } - - public byte[] GetImageBlock(Stream Stream, ulong dataBlockIndex) - { - ulong imageBlockCount = (ulong)(DataBlocksPosition - InitialStreamPosition) / (ImageHeader.ChunkSize * 1024); - - // The data block is within the image headers - if (dataBlockIndex < imageBlockCount) - { - byte[] dataBlock = new byte[(ImageHeader.ChunkSize * 1024)]; - ulong dataBlockPosition = (ulong)InitialStreamPosition + (dataBlockIndex * (ImageHeader.ChunkSize * 1024)); - - _ = Stream.Seek((long)dataBlockPosition, SeekOrigin.Begin); - _ = Stream.Read(dataBlock, 0, dataBlock.Length); - - return dataBlock; - } - // The data block is within the store data blocks, those may be compressed - else - { - return GetDataBlock(Stream, dataBlockIndex - imageBlockCount); - } - } - - - public ulong GetDataBlockCount() - { - ulong dataBlockCount = 0; - foreach (Store store in Stores) - { - dataBlockCount += (ulong)store.WriteDescriptors.LongCount(); - } - return dataBlockCount; - } - - public byte[] GetDataBlock(Stream Stream, ulong dataBlockIndex) - { - ulong dataBlockIndexOffset = 0; - for (ulong storeIndex = 0; storeIndex < (ulong)Stores.Count; storeIndex++) - { - ulong storeDataBlockCount = GetStoreDataBlockCount(storeIndex); - if (dataBlockIndexOffset + storeDataBlockCount > dataBlockIndex) - { - return GetStoreDataBlock(Stream, storeIndex, dataBlockIndex - dataBlockIndexOffset); - } - - dataBlockIndexOffset += storeDataBlockCount; - } - - throw new Exception("Invalid data block index value"); - } - - - public ulong GetStoreDataBlockCount(ulong storeIndex) - { - return (ulong)Stores[(int)storeIndex].WriteDescriptors.LongCount(); - } - - public byte[] GetStoreDataBlock(Stream Stream, ulong storeIndex, ulong dataBlockIndex) - { - ulong dataBlockPosition = (ulong)DataBlocksPosition; - for (ulong s = 0; s < storeIndex; s++) - { - Store store = Stores[(int)s]; - if (store.CompressionAlgorithm != 0) - { - foreach (WriteDescriptor writeDescriptor in store.WriteDescriptors) - { - dataBlockPosition += writeDescriptor.DataSize; - } - } - else - { - dataBlockPosition += store.StoreHeader.WriteDescriptorCount * store.StoreHeader.BlockSize; - } - } - - Store currentStore = Stores[(int)storeIndex]; - byte[] dataBlock = new byte[currentStore.StoreHeader.BlockSize]; - - CompressionAlgorithm compressionAlgorithm = (CompressionAlgorithm)currentStore.CompressionAlgorithm; - - if (compressionAlgorithm != CompressionAlgorithm.None) - { - for (ulong i = 0; i < dataBlockIndex; i++) - { - WriteDescriptor writeDescriptor = currentStore.WriteDescriptors[(int)i]; - dataBlockPosition += writeDescriptor.DataSize; - } - - WriteDescriptor currentWriteDescriptor = currentStore.WriteDescriptors[(int)dataBlockIndex]; - uint compressedDataBlockSize = currentWriteDescriptor.DataSize; - byte[] compressedDataBlock = new byte[compressedDataBlockSize]; - - _ = Stream.Seek((long)dataBlockPosition, SeekOrigin.Begin); - _ = Stream.Read(compressedDataBlock, 0, compressedDataBlock.Length); - - switch ((CompressionAlgorithm)currentStore.CompressionAlgorithm) - { - case CompressionAlgorithm.LZNT1: - { - dataBlock = WindowsNativeCompression.Decompress(WindowsNativeCompressionAlgorithm.COMPRESSION_FORMAT_LZNT1, compressedDataBlock, (int)currentStore.StoreHeader.BlockSize); - break; - } - case CompressionAlgorithm.Default: - case CompressionAlgorithm.XPRESS: - { - dataBlock = WindowsNativeCompression.Decompress(WindowsNativeCompressionAlgorithm.COMPRESSION_FORMAT_XPRESS, compressedDataBlock, (int)currentStore.StoreHeader.BlockSize); - break; - } - case CompressionAlgorithm.XPRESS_HUFF: - { - dataBlock = WindowsNativeCompression.Decompress(WindowsNativeCompressionAlgorithm.COMPRESSION_FORMAT_XPRESS_HUFF, compressedDataBlock, (int)currentStore.StoreHeader.BlockSize); - break; - } - default: - { - throw new NotImplementedException("The compression algorithm this data block uses is not currently implemented."); - } - } - } - else - { - dataBlockPosition += dataBlockIndex * currentStore.StoreHeader.BlockSize; - - _ = Stream.Seek((long)dataBlockPosition, SeekOrigin.Begin); - _ = Stream.Read(dataBlock, 0, dataBlock.Length); - } - - return dataBlock; - } - } -} diff --git a/Img2Ffu.Library/Reader/Data/SignedImage.cs b/Img2Ffu.Library/Reader/Data/SignedImage.cs deleted file mode 100644 index 8990809..0000000 --- a/Img2Ffu.Library/Reader/Data/SignedImage.cs +++ /dev/null @@ -1,131 +0,0 @@ -using Img2Ffu.Reader.Structs; -using System.Collections; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Text; - -namespace Img2Ffu.Reader.Data -{ - internal class SignedImage - { - public SecurityHeader SecurityHeader; - public byte[] Catalog; - public byte[] TableOfHashes; - public byte[] Padding = []; - public ImageFlash Image; - - public ulong HeaderSize - { - get; - } - public int ChunkSize => (int)(SecurityHeader.ChunkSizeInKB * 1024); - public ulong TotalChunkCount => Image.GetImageBlockCount(); - - public readonly List BlockHashes = []; - public X509Certificate? Certificate; - - private readonly Stream Stream; - - public SignedImage(Stream stream) - { - Stream = stream; - - SecurityHeader = stream.ReadStructure(); - - if (SecurityHeader.Signature != "SignedImage ") - { - throw new InvalidDataException("Invalid Security Header Signature!"); - } - - Catalog = new byte[SecurityHeader.CatalogSize]; - _ = stream.Read(Catalog, 0, (int)SecurityHeader.CatalogSize); - - TableOfHashes = new byte[SecurityHeader.HashTableSize]; - _ = stream.Read(TableOfHashes, 0, (int)SecurityHeader.HashTableSize); - - long Position = stream.Position; - uint sizeOfBlock = SecurityHeader.ChunkSizeInKB * 1024; - if (Position % sizeOfBlock > 0) - { - long paddingSize = sizeOfBlock - (Position % sizeOfBlock); - Padding = new byte[paddingSize]; - _ = stream.Read(Padding, 0, (int)paddingSize); - } - - try - { - Certificate = new X509Certificate(Catalog); - } - catch { } - - Image = new ImageFlash(stream); - - HeaderSize = (ulong)stream.Position; - - ParseBlockHashes(); - } - - private void ParseBlockHashes() - { - BlockHashes.Clear(); - - ulong numberOfBlocksToVerify = Image.GetImageBlockCount(); - ulong sizeOfHash = (ulong)TableOfHashes.LongLength / numberOfBlocksToVerify; - - for (int i = 0; i < TableOfHashes.Length; i += (int)sizeOfHash) - { - BlockHashes.Add(TableOfHashes[i..(i + (int)sizeOfHash)]); - } - } - - private uint GetImageHeaderPosition() - { - uint sizeOfBlock = SecurityHeader.ChunkSizeInKB * 1024; - uint ImageHeaderPosition = SecurityHeader.Size + SecurityHeader.CatalogSize + SecurityHeader.HashTableSize; - if (ImageHeaderPosition % sizeOfBlock > 0) - { - uint paddingSize = sizeOfBlock - (ImageHeaderPosition % sizeOfBlock); - ImageHeaderPosition += paddingSize; - } - return ImageHeaderPosition; - } - - public void VerifyFFU() - { - ulong numberOfBlocksToVerify = Image.GetImageBlockCount(); - - long oldPosition = Stream.Position; - - using BinaryReader binaryReader = new(Stream, Encoding.ASCII, true); - using BinaryReader hashTableBinaryReader = new(new MemoryStream(TableOfHashes)); - - for (ulong i = 0; i < numberOfBlocksToVerify; i++) - { - Console.Title = $"{i + 1}/{numberOfBlocksToVerify}"; - - if (SecurityHeader.AlgorithmId == 0x0000800c) // SHA256 Algorithm ID - { - byte[] block = Image.GetImageBlock(Stream, i); - byte[] hash = SHA256.HashData(block); - byte[] hashTableHash = BlockHashes.ElementAt((int)i); - - if (!StructuralComparisons.StructuralEqualityComparer.Equals(hash, hashTableHash)) - { - _ = Stream.Seek(oldPosition, SeekOrigin.Begin); - throw new InvalidDataException($"The FFU image contains a mismatched hash value at chunk {i}. " + - $"Expected: {BitConverter.ToString(hashTableHash).Replace("-", "")} " + - $"Computed: {BitConverter.ToString(hash).Replace("-", "")}"); - } - } - else - { - throw new InvalidDataException($"Unknown Hash algorithm id: {SecurityHeader.AlgorithmId}"); - } - } - - Console.Title = $"{numberOfBlocksToVerify}/{numberOfBlocksToVerify}"; - - _ = Stream.Seek(oldPosition, SeekOrigin.Begin); - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Reader/Data/Store.cs b/Img2Ffu.Library/Reader/Data/Store.cs deleted file mode 100644 index daa7344..0000000 --- a/Img2Ffu.Library/Reader/Data/Store.cs +++ /dev/null @@ -1,96 +0,0 @@ -using Img2Ffu.Reader.Enums; -using Img2Ffu.Reader.Structs; -using System.Text; - -namespace Img2Ffu.Reader.Data -{ - internal class Store - { - public StoreHeader StoreHeader; - public uint CompressionAlgorithm; - public StoreHeaderV2 StoreHeaderV2; - public string DevicePath = ""; // Device path has no NUL at then end (V2 only) - public readonly List ValidationDescriptor = []; - public readonly List WriteDescriptors = []; - public readonly List PlatformIDs = []; - public byte[] Padding = []; - public readonly FFUVersion FFUVersion; - - public Store(Stream stream) - { - StoreHeader = stream.ReadStructure(); - - int lastFinding = 0; - for (int i = 0; i < StoreHeader.PlatformId.Length; i++) - { - if (StoreHeader.PlatformId[i] == '\0') - { - if (i == lastFinding) - { - break; - } - - ASCIIEncoding asciiEnconding = new(); - string PlatformID = asciiEnconding.GetString(StoreHeader.PlatformId[lastFinding..i]); - PlatformIDs.Add(PlatformID); - lastFinding = i + 1; - } - } - - FFUVersion = GetFFUVersion(); - - switch (FFUVersion) - { - case FFUVersion.V2: - { - StoreHeaderV2 = stream.ReadStructure(); - byte[] stringBytes = new byte[StoreHeaderV2.DevicePathLength * 2]; - _ = stream.Read(stringBytes, 0, stringBytes.Length); - UnicodeEncoding unicodeEncoding = new(); - DevicePath = unicodeEncoding.GetString(stringBytes); - break; - } - case FFUVersion.V1_COMPRESSED: - { - using BinaryReader binaryReader = new(stream, Encoding.ASCII, true); - CompressionAlgorithm = binaryReader.ReadUInt32(); - break; - } - } - - for (uint i = 0; i < StoreHeader.ValidateDescriptorCount; i++) - { - ValidationDescriptor.Add(new ValidationDescriptor(stream)); - } - - for (uint i = 0; i < StoreHeader.WriteDescriptorCount; i++) - { - WriteDescriptors.Add(new WriteDescriptor(stream, FFUVersion)); - } - - long Position = stream.Position; - if (Position % StoreHeader.BlockSize > 0) - { - long paddingSize = StoreHeader.BlockSize - (Position % StoreHeader.BlockSize); - Padding = new byte[paddingSize]; - _ = stream.Read(Padding, 0, (int)paddingSize); - } - } - - public override string ToString() - { - return $"{{StoreHeader: {StoreHeader}, StoreHeaderV2: {StoreHeaderV2}, DevicePath: {DevicePath}}}"; - } - - private FFUVersion GetFFUVersion() - { - return (StoreHeader.MajorVersion, StoreHeader.FullFlashMajorVersion) switch - { - (1, 2) => FFUVersion.V1, - (1, 3) => FFUVersion.V1_COMPRESSED, - (2, 2) => FFUVersion.V2, - _ => throw new InvalidDataException($"Unsupported FFU Store Format! MajorVersion: {StoreHeader.MajorVersion} FullFlashMajorVersion: {StoreHeader.FullFlashMajorVersion}"), - }; - } - } -} diff --git a/Img2Ffu.Library/Reader/Data/ValidationDescriptor.cs b/Img2Ffu.Library/Reader/Data/ValidationDescriptor.cs deleted file mode 100644 index 0173ace..0000000 --- a/Img2Ffu.Library/Reader/Data/ValidationDescriptor.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Img2Ffu.Reader.Structs; - -namespace Img2Ffu.Reader.Data -{ - internal class ValidationDescriptor - { - public ValidationEntry ValidationEntry; - public byte[] ValidationBytes; - - public ValidationDescriptor(Stream stream) - { - ValidationEntry = stream.ReadStructure(); - - ValidationBytes = new byte[ValidationEntry.dwByteCount]; - _ = stream.Read(ValidationBytes, 0, (int)ValidationEntry.dwByteCount); - } - - public ValidationDescriptor(ValidationEntry validationEntry, byte[] validationBytes) - { - ValidationEntry = validationEntry; - ValidationBytes = validationBytes; - ValidationEntry.dwByteCount = (uint)validationBytes.LongLength; - } - - public override string ToString() - { - return $"{{ValidationEntry: {ValidationEntry}}}"; - } - - public byte[] GetBytes() - { - List bytes = []; - - ValidationEntry.dwByteCount = (uint)ValidationBytes.Length; - - bytes.AddRange(ValidationEntry.GetBytes()); - bytes.AddRange(ValidationBytes); - - return [.. bytes]; - } - } -} diff --git a/Img2Ffu.Library/Reader/Data/WriteDescriptor.cs b/Img2Ffu.Library/Reader/Data/WriteDescriptor.cs deleted file mode 100644 index 1bfd448..0000000 --- a/Img2Ffu.Library/Reader/Data/WriteDescriptor.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Img2Ffu.Reader.Enums; -using Img2Ffu.Reader.Structs; -using System.Text; - -namespace Img2Ffu.Reader.Data -{ - internal class WriteDescriptor - { - public BlockDataEntry BlockDataEntry; - public uint DataSize; - - public readonly List DiskLocations = []; - private readonly bool HasDataSizeField; - - public WriteDescriptor(Stream stream, FFUVersion ffuVersion) - { - HasDataSizeField = ffuVersion == FFUVersion.V1_COMPRESSED; - - BlockDataEntry = stream.ReadStructure(); - - if (HasDataSizeField) - { - using BinaryReader binaryReader = new(stream, Encoding.ASCII, true); - DataSize = binaryReader.ReadUInt32(); - } - - for (uint i = 0; i < BlockDataEntry.LocationCount; i++) - { - DiskLocations.Add(stream.ReadStructure()); - } - } - - public WriteDescriptor(BlockDataEntry blockDataEntry, List diskLocations, uint compressedDataBlockSize) - { - HasDataSizeField = true; - - BlockDataEntry = blockDataEntry; - DiskLocations = diskLocations; - DataSize = compressedDataBlockSize; - } - - public WriteDescriptor(BlockDataEntry blockDataEntry, List diskLocations, FFUVersion ffuVersion) - { - HasDataSizeField = false; - - BlockDataEntry = blockDataEntry; - DiskLocations = diskLocations; - } - - public override string ToString() - { - return $"{{BlockDataEntry: {BlockDataEntry}}}"; - } - - public byte[] GetBytes() - { - List bytes = []; - - BlockDataEntry.LocationCount = (uint)DiskLocations.Count; - - bytes.AddRange(BlockDataEntry.GetBytes()); - - if (HasDataSizeField) - { - bytes.AddRange(BitConverter.GetBytes(DataSize)); - } - - foreach (DiskLocation diskLocation in DiskLocations) - { - bytes.AddRange(diskLocation.GetBytes()); - } - - return [.. bytes]; - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Reader/Enums/CompressionAlgorithm.cs b/Img2Ffu.Library/Reader/Enums/CompressionAlgorithm.cs deleted file mode 100644 index 93423ac..0000000 --- a/Img2Ffu.Library/Reader/Enums/CompressionAlgorithm.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Img2Ffu.Reader.Enums -{ - public enum CompressionAlgorithm - { - None = 0, - Default = 1, - LZNT1 = 2, - XPRESS = 3, - XPRESS_HUFF = 4 - } -} diff --git a/Img2Ffu.Library/Reader/Enums/DiskAccessMethod.cs b/Img2Ffu.Library/Reader/Enums/DiskAccessMethod.cs deleted file mode 100644 index 5fbf7c6..0000000 --- a/Img2Ffu.Library/Reader/Enums/DiskAccessMethod.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Img2Ffu.Reader.Enums -{ - public enum DiskAccessMethod - { - DISK_BEGIN = 0, - DISK_END = 2 - } -} diff --git a/Img2Ffu.Library/Reader/Enums/FFUVersion.cs b/Img2Ffu.Library/Reader/Enums/FFUVersion.cs deleted file mode 100644 index 80bd67c..0000000 --- a/Img2Ffu.Library/Reader/Enums/FFUVersion.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Img2Ffu.Reader.Enums -{ - internal enum FFUVersion - { - V1, - V1_COMPRESSED, - V2 - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Reader/FullFlashUpdateReaderStream.cs b/Img2Ffu.Library/Reader/FullFlashUpdateReaderStream.cs deleted file mode 100644 index 670c487..0000000 --- a/Img2Ffu.Library/Reader/FullFlashUpdateReaderStream.cs +++ /dev/null @@ -1,325 +0,0 @@ -using Img2Ffu.Reader.Data; - -namespace Img2Ffu.Reader -{ - public class FullFlashUpdateReaderStream : Stream - { - private readonly Stream ffuFileStream; - private readonly SignedImage signedImage; - private readonly ImageFlash image; - private readonly Store store; - private readonly ulong storeIndex; - private readonly long length; - private readonly long blockSize; - private readonly Dictionary blockTable; - - private long currentPosition = 0; - - public int SectorSize - { - get; - } - public int MinSectorCount - { - get; - } - - public string DevicePath => store.DevicePath; - - public FullFlashUpdateReaderStream(string FFUFilePath, ulong storeIndex) - { - ffuFileStream = File.OpenRead(FFUFilePath); - signedImage = new SignedImage(ffuFileStream); - image = signedImage.Image; - this.storeIndex = storeIndex; - store = image.Stores[(int)storeIndex]; - blockSize = store.StoreHeader.BlockSize; - (length, blockTable) = BuildBlockTable(); - - try - { - (int minSectorCount, int sectorSize)[] manifestStoreInformation = ExtractImageManifestStoreInformation(signedImage); - - (MinSectorCount, SectorSize) = manifestStoreInformation[storeIndex]; - - if (SectorSize == 0) - { - SectorSize = signedImage.ChunkSize; - } - - length = (long)((ulong)MinSectorCount * (ulong)SectorSize); - } - catch { } - } - - public static int GetStoreCount(string FFUFilePath) - { - using FileStream ffuStream = File.Open(FFUFilePath, FileMode.Open, FileAccess.Read, FileShare.Read); - SignedImage ffuFile = new(ffuStream); - return ffuFile.Image.Stores.Count; - } - - private static (int minSectorCount, int minSectorSize)[] ExtractImageManifestStoreInformation(SignedImage ffuFile) - { - List<(int minSectorCount, int minSectorSize)> manifestStoreInformation = []; - - int currentMinSectorCount = 0; - int currentSectorSize = 0; - bool isInStoreSection = false; - - foreach (string line in ffuFile.Image.ManifestData.Split("\n")) - { - if (line.StartsWith('[') && line.Contains(']')) - { - string sectionName = line.Split('[')[1].Split(']')[0]; - - if (isInStoreSection) - { - manifestStoreInformation.Add((currentMinSectorCount, currentSectorSize)); - } - - isInStoreSection = sectionName.Equals("Store", StringComparison.InvariantCultureIgnoreCase); - } - else if (isInStoreSection) - { - if (line.StartsWith("MinSectorCount", StringComparison.InvariantCultureIgnoreCase)) - { - bool success = int.TryParse(line.Split("=")[1].Trim(), out int tempCurrentMinSectorCount); - currentMinSectorCount = success ? tempCurrentMinSectorCount : throw new InvalidDataException(line); - } - else if (line.StartsWith("SectorSize", StringComparison.InvariantCultureIgnoreCase)) - { - bool success = int.TryParse(line.Split("=")[1].Trim(), out int tempCurrentMinSectorSize); - currentSectorSize = success ? tempCurrentMinSectorSize : throw new InvalidDataException(line); - } - } - } - - if (isInStoreSection) - { - manifestStoreInformation.Add((currentMinSectorCount, currentSectorSize)); - } - - return [.. manifestStoreInformation]; - } - - public override bool CanRead => true; - - public override bool CanSeek => true; - - public override bool CanWrite => false; - - public override long Length => length; - - private (long, Dictionary) BuildBlockTable() - { - // We do not want to immediately return because FFU files may first blank out sectors and then write post mortem - Dictionary blockTable = []; - - long blockMaxStart = 0; - long blockMaxEnd = 0; - - for (int i = 0; i < store.WriteDescriptors.Count; i++) - { - WriteDescriptor writeDescriptor = store.WriteDescriptors[i]; - foreach (Structs.DiskLocation diskLocation in writeDescriptor.DiskLocations) - { - switch (diskLocation.DiskAccessMethod) - { - case 0: - { - if (diskLocation.BlockIndex > blockMaxStart) - { - blockMaxStart = diskLocation.BlockIndex; - } - - long blockOffset = diskLocation.BlockIndex; - if (blockTable.ContainsKey(blockOffset)) - { - blockTable[blockOffset] = i; - } - else - { - blockTable.Add(blockOffset, i); - } - break; - } - case 2: - { - if (diskLocation.BlockIndex > blockMaxEnd) - { - blockMaxEnd = diskLocation.BlockIndex; - } - - long blockOffset = (Length / blockSize) - 1 - diskLocation.BlockIndex; - if (blockTable.ContainsKey(blockOffset)) - { - blockTable[blockOffset] = i; - } - else - { - blockTable.Add(blockOffset, i); - } - break; - } - } - } - } - - long totalBlocks = blockMaxStart + blockMaxEnd + 2; - - return (totalBlocks * blockSize, blockTable); - } - - private long GetBlockDataIndex(long realBlockOffset) - { - if (blockTable.ContainsKey(realBlockOffset)) - { - return blockTable[realBlockOffset]; - } - - return -1; // Invalid - } - - public override long Position - { - get => currentPosition; - set - { - if (currentPosition < 0) - { - throw new ArgumentOutOfRangeException("value"); - } - - // Workaround for malformed MBRs - /*if (currentPosition > Length) - { - throw new EndOfStreamException(); - }*/ - - currentPosition = value; - } - } - - public override void Flush() - { - // Nothing to do here - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - if (offset + count > buffer.Length) - { - throw new ArgumentException("The sum of offset and count is greater than the buffer length."); - } - - if (offset < 0) - { - throw new ArgumentOutOfRangeException("offset"); - } - - if (count < 0) - { - throw new ArgumentOutOfRangeException("count"); - } - - // Workaround for malformed MBRs - if (Position >= Length) - { - return count; - } - - long readBytes = count; - - if (Position + readBytes > Length) - { - readBytes = (int)(Length - Position); - } - - byte[] readBuffer = new byte[readBytes]; - Array.Fill(readBuffer, 0); - - // Read the buffer from the FFU file. - // First we have to figure out where do we land here. - - long overflowBlockStartByteCount = Position % blockSize; - long overflowBlockEndByteCount = (Position + readBytes) % blockSize; - - long startBlockIndex = (Position - overflowBlockStartByteCount) / blockSize; - long endBlockIndex = (Position + readBytes + (blockSize - overflowBlockEndByteCount)) / blockSize; - - byte[] allReadBlocks = new byte[(endBlockIndex - startBlockIndex + 1) * blockSize]; - - for (long currentBlock = startBlockIndex; currentBlock < endBlockIndex; currentBlock++) - { - long virtualBlockIndex = GetBlockDataIndex(currentBlock); - if (virtualBlockIndex != -1) - { - byte[] block = image.GetStoreDataBlock(ffuFileStream, storeIndex, (ulong)virtualBlockIndex); - Array.Copy(block, 0, allReadBlocks, (int)((currentBlock - startBlockIndex) * blockSize), blockSize); - } - } - - Array.Copy(allReadBlocks, overflowBlockStartByteCount, buffer, offset, readBytes); - - Position += readBytes; - - if (Position == Length) - { - // Workaround for malformed MBRs - //return 0; - } - - return (int)readBytes; - } - - public override long Seek(long offset, SeekOrigin origin) - { - switch (origin) - { - case SeekOrigin.Begin: - { - Position = offset; - break; - } - case SeekOrigin.Current: - { - Position += offset; - break; - } - case SeekOrigin.End: - { - Position = Length + offset; - break; - } - default: - { - throw new ArgumentException(nameof(origin)); - } - } - - return Position; - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - ffuFileStream.Dispose(); - } - } -} diff --git a/Img2Ffu.Library/Reader/StructExtensions.cs b/Img2Ffu.Library/Reader/StructExtensions.cs deleted file mode 100644 index e2f1e9c..0000000 --- a/Img2Ffu.Library/Reader/StructExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Reader -{ - public static class StructExtensions - { - public static T GetStruct(this byte[] bytes) where T : struct - { - int requiredSize = Marshal.SizeOf(typeof(T)); - if (bytes.Length < requiredSize) - { - throw new Exception($"Invalid buffer size for passed in structure. Expected: {requiredSize} Provided: {bytes.Length}"); - } - - GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); - T structure = Marshal.PtrToStructure(handle.AddrOfPinnedObject()); - handle.Free(); - return structure; - } - - public static byte[] GetBytes(this T structure) where T : struct - { - byte[] bytes = new byte[Marshal.SizeOf(typeof(T))]; - GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); - Marshal.StructureToPtr(structure, handle.AddrOfPinnedObject(), false); - handle.Free(); - return bytes; - } - - public static T Read(this BinaryReader reader) where T : struct - { - byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T))); - return bytes.GetStruct(); - } - - public static void Write(this BinaryWriter writer, T structure) where T : struct - { - byte[] bytes = structure.GetBytes(); - writer.Write(bytes); - } - - public static T ReadStructure(this Stream stream) where T : struct - { - using BinaryReader binaryReader = new(stream, System.Text.Encoding.ASCII, true); - return binaryReader.Read(); - } - - public static void WriteStructure(this Stream stream, T structure) where T : struct - { - using BinaryWriter binaryWriter = new(stream, System.Text.Encoding.ASCII, true); - binaryWriter.Write(structure); - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Reader/Structs/BlockDataEntry.cs b/Img2Ffu.Library/Reader/Structs/BlockDataEntry.cs deleted file mode 100644 index ae79ca5..0000000 --- a/Img2Ffu.Library/Reader/Structs/BlockDataEntry.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Reader.Structs -{ - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct BlockDataEntry - { - public uint LocationCount; - public uint BlockCount; - - public override readonly string ToString() - { - return $"{{LocationCount: {LocationCount}, BlockCount: {BlockCount}}}"; - } - } -} diff --git a/Img2Ffu.Library/Reader/Structs/DiskLocation.cs b/Img2Ffu.Library/Reader/Structs/DiskLocation.cs deleted file mode 100644 index 958ae11..0000000 --- a/Img2Ffu.Library/Reader/Structs/DiskLocation.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Reader.Structs -{ - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct DiskLocation - { - public uint DiskAccessMethod; - public uint BlockIndex; - - public override readonly string ToString() - { - return $"{{DiskAccessMethod: {DiskAccessMethod}, BlockIndex: {BlockIndex}}}"; - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Reader/Structs/ImageHeader.cs b/Img2Ffu.Library/Reader/Structs/ImageHeader.cs deleted file mode 100644 index 7f9dc26..0000000 --- a/Img2Ffu.Library/Reader/Structs/ImageHeader.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Reader.Structs -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct ImageHeader - { - public uint Size; // sizeof(ImageHeader) - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)] - public string Signature; // "ImageFlash " - public uint ManifestLength; // in bytes - public uint ChunkSize; // Used only during image generation. - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Reader/Structs/SecurityHeader.cs b/Img2Ffu.Library/Reader/Structs/SecurityHeader.cs deleted file mode 100644 index c15572c..0000000 --- a/Img2Ffu.Library/Reader/Structs/SecurityHeader.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Reader.Structs -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct SecurityHeader - { - public uint Size; // size of struct, overall - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)] - public string Signature; // "SignedImage " - public uint ChunkSizeInKB; // size of a hashed chunk within the image - public uint AlgorithmId; // algorithm used to hash - public uint CatalogSize; // size of catalog to validate - public uint HashTableSize; // size of hash table - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Reader/Structs/StoreHeader.cs b/Img2Ffu.Library/Reader/Structs/StoreHeader.cs deleted file mode 100644 index 66b8c3e..0000000 --- a/Img2Ffu.Library/Reader/Structs/StoreHeader.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Reader.Structs -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct StoreHeader - { - public uint UpdateType; // indicates partial or full flash - public ushort MajorVersion, MinorVersion; // used to validate struct - public ushort FullFlashMajorVersion, FullFlashMinorVersion; // FFU version, i.e. the image format - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 192)] - public byte[] PlatformId; // string which indicates what device this FFU is intended to be written to - public uint BlockSize; // size of an image block in bytes – the device’s actual sector size may differ - public uint WriteDescriptorCount; // number of write descriptors to iterate through - public uint WriteDescriptorLength; // total size of all the write descriptors, in bytes (included so they can be read out up front and interpreted later) - public uint ValidateDescriptorCount; // number of validation descriptors to check - public uint ValidateDescriptorLength; // total size of all the validation descriptors, in bytes - public uint InitialTableIndex; // block index in the payload of the initial (invalid) GPT - public uint InitialTableCount; // count of blocks for the initial GPT, i.e. the GPT spans blockArray[idx..(idx + count -1)] - public uint FlashOnlyTableIndex; // first block index in the payload of the flash-only GPT (included so safe flashing can be accomplished) - public uint FlashOnlyTableCount; // count of blocks in the flash-only GPT - public uint FinalTableIndex; // index in the table of the real GPT - public uint FinalTableCount; // number of blocks in the real GPT - - public override readonly string ToString() - { - return $"{{UpdateType: {UpdateType}, MajorVersion: {MajorVersion}, MinorVersion: {MinorVersion}}}"; - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Reader/Structs/StoreHeaderV2.cs b/Img2Ffu.Library/Reader/Structs/StoreHeaderV2.cs deleted file mode 100644 index 15fe042..0000000 --- a/Img2Ffu.Library/Reader/Structs/StoreHeaderV2.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Reader.Structs -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct StoreHeaderV2 - { - public ushort NumberOfStores; // Total number of stores (V2 only) - public ushort StoreIndex; // Current store index, 1-based (V2 only) - public ulong StorePayloadSize; // Payload data only, excludes padding (V2 only) - public ushort DevicePathLength; // Length of the device path (V2 only) - - public override readonly string ToString() - { - return $"{{NumberOfStores: {NumberOfStores}, StoreIndex: {StoreIndex}, StorePayloadSize: {StorePayloadSize}, DevicePathLength: {DevicePathLength}}}"; - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Reader/Structs/ValidationEntry.cs b/Img2Ffu.Library/Reader/Structs/ValidationEntry.cs deleted file mode 100644 index ab67289..0000000 --- a/Img2Ffu.Library/Reader/Structs/ValidationEntry.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Reader.Structs -{ - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct ValidationEntry - { - public uint dwSectorIndex; - public uint dwSectorOffset; - public uint dwByteCount; - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Data/BlockDataEntry.cs b/Img2Ffu.Library/Writer/Data/BlockDataEntry.cs deleted file mode 100644 index e81b746..0000000 --- a/Img2Ffu.Library/Writer/Data/BlockDataEntry.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Img2Ffu.Writer.Data -{ - public class BlockDataEntry - { - public uint LocationCount; - public uint BlockCount; - } -} diff --git a/Img2Ffu.Library/Writer/Data/CompressionAlgorithm.cs b/Img2Ffu.Library/Writer/Data/CompressionAlgorithm.cs deleted file mode 100644 index a55df57..0000000 --- a/Img2Ffu.Library/Writer/Data/CompressionAlgorithm.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Img2Ffu.Writer.Data -{ - public enum CompressionAlgorithm - { - None = 0, - Default = 1, - LZNT1 = 2, - XPRESS = 3, - XPRESS_HUFF = 4 - } -} diff --git a/Img2Ffu.Library/Writer/Data/DeviceTargetInfo.cs b/Img2Ffu.Library/Writer/Data/DeviceTargetInfo.cs deleted file mode 100644 index 904a734..0000000 --- a/Img2Ffu.Library/Writer/Data/DeviceTargetInfo.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.Text; - -namespace Img2Ffu.Writer.Data -{ - public class DeviceTargetInfo(string manufacturer, string family, string productName, string productVersion, string sKUNumber, string baseboardManufacturer, string baseboardProduct) - { - private uint ManufacturerLength; - - private uint FamilyLength; - - private uint ProductNameLength; - - private uint ProductVersionLength; - - private uint SKUNumberLength; - - private uint BaseboardManufacturerLength; - - private uint BaseboardProductLength; - - public string Manufacturer { get; } = manufacturer; - - public string Family { get; } = family; - - public string ProductName { get; } = productName; - - public string ProductVersion { get; } = productVersion; - - public string SKUNumber { get; } = sKUNumber; - - public string BaseboardManufacturer { get; } = baseboardManufacturer; - - public string BaseboardProduct { get; } = baseboardProduct; - - internal byte[] GetResultingBuffer() - { - using MemoryStream DeviceTargetInfoStream = new(); - using BinaryWriter binaryWriter = new(DeviceTargetInfoStream); - - ManufacturerLength = (uint)Manufacturer.Length; - FamilyLength = (uint)Family.Length; - ProductNameLength = (uint)ProductName.Length; - ProductVersionLength = (uint)ProductVersion.Length; - SKUNumberLength = (uint)SKUNumber.Length; - BaseboardManufacturerLength = (uint)BaseboardManufacturer.Length; - BaseboardProductLength = (uint)BaseboardProduct.Length; - - binaryWriter.Write(ManufacturerLength); - binaryWriter.Write(FamilyLength); - binaryWriter.Write(ProductNameLength); - binaryWriter.Write(ProductVersionLength); - binaryWriter.Write(SKUNumberLength); - binaryWriter.Write(BaseboardManufacturerLength); - binaryWriter.Write(BaseboardProductLength); - - binaryWriter.Write(Encoding.ASCII.GetBytes(Manufacturer)); - binaryWriter.Write(Encoding.ASCII.GetBytes(Family)); - binaryWriter.Write(Encoding.ASCII.GetBytes(ProductName)); - binaryWriter.Write(Encoding.ASCII.GetBytes(ProductVersion)); - binaryWriter.Write(Encoding.ASCII.GetBytes(SKUNumber)); - binaryWriter.Write(Encoding.ASCII.GetBytes(BaseboardManufacturer)); - binaryWriter.Write(Encoding.ASCII.GetBytes(BaseboardProduct)); - - byte[] DeviceTargetInfoBuffer = new byte[DeviceTargetInfoStream.Length]; - _ = DeviceTargetInfoStream.Seek(0, SeekOrigin.Begin); - DeviceTargetInfoStream.ReadExactly(DeviceTargetInfoBuffer, 0, DeviceTargetInfoBuffer.Length); - - return DeviceTargetInfoBuffer; - } - } -} diff --git a/Img2Ffu.Library/Writer/Data/DiskLocation.cs b/Img2Ffu.Library/Writer/Data/DiskLocation.cs deleted file mode 100644 index 8071cde..0000000 --- a/Img2Ffu.Library/Writer/Data/DiskLocation.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Img2Ffu.Writer.Data -{ - public class DiskLocation - { - public uint DiskAccessMethod; - public uint BlockIndex; - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Data/FlashUpdateType.cs b/Img2Ffu.Library/Writer/Data/FlashUpdateType.cs deleted file mode 100644 index 349797c..0000000 --- a/Img2Ffu.Library/Writer/Data/FlashUpdateType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Img2Ffu.Writer.Data -{ - public enum FlashUpdateType - { - Full, - Partial - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Data/FlashUpdateVersion.cs b/Img2Ffu.Library/Writer/Data/FlashUpdateVersion.cs deleted file mode 100644 index a3778b5..0000000 --- a/Img2Ffu.Library/Writer/Data/FlashUpdateVersion.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Img2Ffu.Writer.Data -{ - public enum FlashUpdateVersion - { - V1, - V1_COMPRESSED, - V2 - } -} diff --git a/Img2Ffu.Library/Writer/Data/ImageHeader.cs b/Img2Ffu.Library/Writer/Data/ImageHeader.cs deleted file mode 100644 index e62bb05..0000000 --- a/Img2Ffu.Library/Writer/Data/ImageHeader.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using System.Text; - -namespace Img2Ffu.Writer.Data -{ - internal class ImageHeader - { - public uint ManifestLength - { - get; set; - } - - public byte[] GetResultingBuffer(uint BlockSize, bool HasDeviceTargetInfo, uint DeviceTargetInfosCount) - { - using MemoryStream ImageHeaderStream = new(); - using BinaryWriter binaryWriter = new(ImageHeaderStream); - - binaryWriter.Write(HasDeviceTargetInfo ? 28u : 24u); // Size - binaryWriter.Write(Encoding.ASCII.GetBytes("ImageFlash ")); // Signature - binaryWriter.Write(ManifestLength); // Manifest Length - binaryWriter.Write(BlockSize / 1024); // Chunk Size in KB - - if (HasDeviceTargetInfo) - { - binaryWriter.Write(DeviceTargetInfosCount); // Device Target Infos Count - } - - byte[] ImageHeaderBuffer = new byte[ImageHeaderStream.Length]; - _ = ImageHeaderStream.Seek(0, SeekOrigin.Begin); - ImageHeaderStream.ReadExactly(ImageHeaderBuffer, 0, ImageHeaderBuffer.Length); - - return ImageHeaderBuffer; - } - } -} diff --git a/Img2Ffu.Library/Writer/Data/SecurityHeader.cs b/Img2Ffu.Library/Writer/Data/SecurityHeader.cs deleted file mode 100644 index d1d7c8e..0000000 --- a/Img2Ffu.Library/Writer/Data/SecurityHeader.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using System.Text; - -namespace Img2Ffu.Writer.Data -{ - public class SecurityHeader - { - private readonly uint Size = 32; - private readonly string Signature = "SignedImage "; - private readonly uint HashAlgorithm = 0x800C; // SHA256 algorithm id - - public uint CatalogSize; - public uint HashTableSize; - - public byte[] GetResultingBuffer(uint BlockSize) - { - using MemoryStream SecurityHeaderStream = new(); - using BinaryWriter binaryWriter = new(SecurityHeaderStream); - - uint ChunkSizeInKb = BlockSize / 1024; - - binaryWriter.Write(Size); - binaryWriter.Write(Encoding.ASCII.GetBytes(Signature)); - binaryWriter.Write(ChunkSizeInKb); - binaryWriter.Write(HashAlgorithm); - binaryWriter.Write(CatalogSize); - binaryWriter.Write(HashTableSize); - - byte[] SecurityHeaderBuffer = new byte[SecurityHeaderStream.Length]; - _ = SecurityHeaderStream.Seek(0, SeekOrigin.Begin); - SecurityHeaderStream.ReadExactly(SecurityHeaderBuffer, 0, SecurityHeaderBuffer.Length); - - return SecurityHeaderBuffer; - } - } -} diff --git a/Img2Ffu.Library/Writer/Data/StoreHeader.cs b/Img2Ffu.Library/Writer/Data/StoreHeader.cs deleted file mode 100644 index afbcc1d..0000000 --- a/Img2Ffu.Library/Writer/Data/StoreHeader.cs +++ /dev/null @@ -1,190 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using System.Text; - -namespace Img2Ffu.Writer.Data -{ - public class StoreHeader - { - private uint UpdateType = 0; // Full update - - private ushort MajorVersion = 1; - private ushort MinorVersion = 0; - private ushort FullFlashMajorVersion = 2; - private ushort FullFlashMinorVersion = 0; - - // Size is 0xC0 - public required string[] PlatformIds - { - get; set; - } - - public uint BlockSize - { - get; set; - } - public uint WriteDescriptorCount - { - get; set; - } - public uint WriteDescriptorLength - { - get; set; - } - public uint ValidateDescriptorCount { get; set; } = 0; - public uint ValidateDescriptorLength { get; set; } = 0; - public uint InitialTableIndex { get; set; } = 0; - public uint InitialTableCount { get; set; } = 0; - public uint FlashOnlyTableIndex { get; set; } = 0; // Should be the index of the critical partitions, but for now we don't implement that - public uint FlashOnlyTableCount { get; set; } = 1; - - private uint FinalTableIndex; //= WriteDescriptorCount - FinalTableCount; - - public uint FinalTableCount { get; set; } = 0; - - // V1 Compressed - private uint CompressionAlgorithm = 0; // 0: None, 1: GZip - - // V2 - public ushort NumberOfStores - { - get; set; - } // 0x4 (Total number of stores) - public ushort StoreIndex - { - get; set; - } // 0x1 (Starts counting from 1) - public ulong StorePayloadSize - { - get; set; - } // 0x420000 - - private ushort DevicePathLength; // 0x2b - // Must be followed by the unicode string of the device path - // So the total size would be doubled from DevicePathLength in bytes in the binary - - private byte[] DevicePathBuffer; - - public required string DevicePath - { - get; set; - } - - public byte[] GetResultingBuffer(FlashUpdateVersion storeHeaderVersion, FlashUpdateType storeHeaderUpdateType, CompressionAlgorithm storeHeaderCompressionAlgorithm) - { - switch (storeHeaderVersion) - { - case FlashUpdateVersion.V1: - MajorVersion = 1; - MinorVersion = 0; - FullFlashMajorVersion = 2; - FullFlashMinorVersion = 0; - break; - case FlashUpdateVersion.V1_COMPRESSED: - MajorVersion = 1; - MinorVersion = 0; - FullFlashMajorVersion = 3; - FullFlashMinorVersion = 0; - CompressionAlgorithm = (uint)storeHeaderCompressionAlgorithm; - break; - case FlashUpdateVersion.V2: - MajorVersion = 2; - MinorVersion = 0; - FullFlashMajorVersion = 2; - FullFlashMinorVersion = 0; - UnicodeEncoding UnicodeEncoding = new(); - DevicePathBuffer = UnicodeEncoding.GetBytes(DevicePath.ToCharArray()); - DevicePathLength = (ushort)DevicePath.Length; - break; - } - - switch (storeHeaderUpdateType) - { - case FlashUpdateType.Full: - UpdateType = 0; - break; - case FlashUpdateType.Partial: - UpdateType = 1; - break; - } - - byte[] PlatformIdsBuffer = new byte[192]; - int CurrentBufferSize = 0; - foreach (string PlatformId in PlatformIds) - { - byte[] PlatformIdBuffer = Encoding.ASCII.GetBytes(PlatformId); - int AddedBufferSize = PlatformIdBuffer.Length + 1; - if (CurrentBufferSize + AddedBufferSize > PlatformIdsBuffer.Length - 1) - { - break; - } - PlatformIdBuffer.CopyTo(PlatformIdsBuffer, CurrentBufferSize); - CurrentBufferSize += AddedBufferSize; - } - - FinalTableIndex = WriteDescriptorCount - FinalTableCount; - - using MemoryStream StoreHeaderStream = new(); - using BinaryWriter binaryWriter = new(StoreHeaderStream); - - binaryWriter.Write(UpdateType); - binaryWriter.Write(MajorVersion); - binaryWriter.Write(MinorVersion); - binaryWriter.Write(FullFlashMajorVersion); - binaryWriter.Write(FullFlashMinorVersion); - binaryWriter.Write(PlatformIdsBuffer); - binaryWriter.Write(BlockSize); - binaryWriter.Write(WriteDescriptorCount); - binaryWriter.Write(WriteDescriptorLength); - binaryWriter.Write(ValidateDescriptorCount); - binaryWriter.Write(ValidateDescriptorLength); - binaryWriter.Write(InitialTableIndex); - binaryWriter.Write(InitialTableCount); - binaryWriter.Write(FlashOnlyTableIndex); - binaryWriter.Write(FlashOnlyTableCount); - binaryWriter.Write(FinalTableIndex); - binaryWriter.Write(FinalTableCount); - - switch (storeHeaderVersion) - { - case FlashUpdateVersion.V1_COMPRESSED: - binaryWriter.Write(CompressionAlgorithm); - break; - case FlashUpdateVersion.V2: - binaryWriter.Write(NumberOfStores); - binaryWriter.Write(StoreIndex); - binaryWriter.Write(StorePayloadSize); - binaryWriter.Write(DevicePathLength); - binaryWriter.Write(DevicePathBuffer); - break; - } - - byte[] StoreHeaderBuffer = new byte[StoreHeaderStream.Length]; - _ = StoreHeaderStream.Seek(0, SeekOrigin.Begin); - StoreHeaderStream.ReadExactly(StoreHeaderBuffer, 0, StoreHeaderBuffer.Length); - - return StoreHeaderBuffer; - } - } -} diff --git a/Img2Ffu.Library/Writer/Data/WriteDescriptor.cs b/Img2Ffu.Library/Writer/Data/WriteDescriptor.cs deleted file mode 100644 index b85669d..0000000 --- a/Img2Ffu.Library/Writer/Data/WriteDescriptor.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace Img2Ffu.Writer.Data -{ - public class WriteDescriptor - { - public required BlockDataEntry BlockDataEntry - { - get; set; - } - public required DiskLocation[] DiskLocations - { - get; set; - } - - public byte[] GetResultingBuffer(FlashUpdateVersion storeHeaderVersion, uint CompressedDataBlockSize = 0) - { - using MemoryStream WriteDescriptorStream = new(); - using BinaryWriter binaryWriter = new(WriteDescriptorStream); - - BlockDataEntry.LocationCount = (uint)DiskLocations.Length; - - binaryWriter.Write(BlockDataEntry.LocationCount); - binaryWriter.Write(BlockDataEntry.BlockCount); - - switch (storeHeaderVersion) - { - case FlashUpdateVersion.V1_COMPRESSED: - binaryWriter.Write(CompressedDataBlockSize); - break; - } - - foreach (DiskLocation DiskLocation in DiskLocations) - { - binaryWriter.Write(DiskLocation.DiskAccessMethod); - binaryWriter.Write(DiskLocation.BlockIndex); - } - - byte[] WriteDescriptorBuffer = new byte[WriteDescriptorStream.Length]; - _ = WriteDescriptorStream.Seek(0, SeekOrigin.Begin); - WriteDescriptorStream.ReadExactly(WriteDescriptorBuffer, 0, WriteDescriptorBuffer.Length); - - return WriteDescriptorBuffer; - } - } -} diff --git a/Img2Ffu.Library/Writer/FFUFactory.cs b/Img2Ffu.Library/Writer/FFUFactory.cs deleted file mode 100644 index d6a3770..0000000 --- a/Img2Ffu.Library/Writer/FFUFactory.cs +++ /dev/null @@ -1,542 +0,0 @@ -using DiscUtils; -using Img2Ffu.Writer.Data; -using Img2Ffu.Writer.Flashing; -using Img2Ffu.Writer.Manifest; -using System.Diagnostics; -using System.Security.Cryptography; -using System.Text; - -namespace Img2Ffu.Writer -{ - public class FFUFactory - { - - private static byte[] GenerateCatalogFile(byte[] hashData) - { - byte[] catalog_first_part = [0x30, 0x82, 0x01, 0x44, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02, 0xA0, 0x82, 0x01, 0x35, 0x30, 0x82, 0x01, 0x31, 0x02, 0x01, 0x01, 0x31, 0x00, 0x30, 0x82, 0x01, 0x26, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0A, 0x01, 0xA0, 0x82, 0x01, 0x17, 0x30, 0x82, 0x01, 0x13, 0x30, 0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0C, 0x01, 0x01, 0x04, 0x10, 0xA8, 0xCA, 0xD9, 0x7D, 0xBF, 0x6D, 0x67, 0x4D, 0xB1, 0x4D, 0x62, 0xFB, 0xE6, 0x26, 0x22, 0xD4, 0x17, 0x0D, 0x32, 0x30, 0x30, 0x31, 0x31, 0x30, 0x31, 0x32, 0x31, 0x32, 0x32, 0x37, 0x5A, 0x30, 0x0E, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0C, 0x01, 0x02, 0x05, 0x00, 0x30, 0x81, 0xD1, 0x30, 0x81, 0xCE, 0x04, 0x1E, 0x48, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x54, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x2E, 0x00, 0x62, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x62, 0x00, 0x00, 0x00, 0x31, 0x81, 0xAB, 0x30, 0x45, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04, 0x31, 0x37, 0x30, 0x35, 0x30, 0x10, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x19, 0xA2, 0x02, 0x80, 0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14]; - byte[] catalog_second_part = [0x30, 0x62, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0C, 0x02, 0x02, 0x31, 0x54, 0x30, 0x52, 0x1E, 0x4C, 0x00, 0x7B, 0x00, 0x44, 0x00, 0x45, 0x00, 0x33, 0x00, 0x35, 0x00, 0x31, 0x00, 0x41, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2D, 0x00, 0x38, 0x00, 0x45, 0x00, 0x35, 0x00, 0x39, 0x00, 0x2D, 0x00, 0x31, 0x00, 0x31, 0x00, 0x44, 0x00, 0x30, 0x00, 0x2D, 0x00, 0x38, 0x00, 0x43, 0x00, 0x34, 0x00, 0x37, 0x00, 0x2D, 0x00, 0x30, 0x00, 0x30, 0x00, 0x43, 0x00, 0x30, 0x00, 0x34, 0x00, 0x46, 0x00, 0x43, 0x00, 0x32, 0x00, 0x39, 0x00, 0x35, 0x00, 0x45, 0x00, 0x45, 0x00, 0x7D, 0x02, 0x02, 0x02, 0x00, 0x31, 0x00]; - - byte[] hash = SHA1.HashData(hashData); - - byte[] catalog = new byte[catalog_first_part.Length + hash.Length + catalog_second_part.Length]; - Buffer.BlockCopy(catalog_first_part, 0, catalog, 0, catalog_first_part.Length); - Buffer.BlockCopy(hash, 0, catalog, catalog_first_part.Length, hash.Length); - Buffer.BlockCopy(catalog_second_part, 0, catalog, catalog_first_part.Length + hash.Length, catalog_second_part.Length); - - return catalog; - } - - private static byte[] GenerateCatalogFile2(byte[] hashData) - { - string catalog = Path.GetTempFileName(); - string cdf = Path.GetTempFileName(); - string hashTableBlob = Path.GetTempFileName(); - - File.WriteAllBytes(hashTableBlob, hashData); - - using (StreamWriter streamWriter = new(cdf)) - { - streamWriter.WriteLine("[CatalogHeader]"); - streamWriter.WriteLine("Name={0}", catalog); - streamWriter.WriteLine("[CatalogFiles]"); - streamWriter.WriteLine("{0}={1}", "HashTable.blob", hashTableBlob); - } - - using (Process process = new()) - { - process.StartInfo.FileName = "MakeCat.exe"; - process.StartInfo.Arguments = string.Format("\"{0}\"", cdf); - process.StartInfo.UseShellExecute = false; - process.StartInfo.CreateNoWindow = true; - process.StartInfo.RedirectStandardOutput = true; - - _ = process.Start(); - process.WaitForExit(); - - if (process.ExitCode != 0) - { - throw new Exception(); - } - } - - byte[] catalogBuffer = File.ReadAllBytes(catalog); - - File.Delete(catalog); - File.Delete(hashTableBlob); - File.Delete(cdf); - - return catalogBuffer; - } - - private static byte[] GetWriteDescriptorsBuffer(KeyValuePair[] payloads, FlashUpdateVersion storeHeaderVersion) - { - using MemoryStream WriteDescriptorsStream = new(); - using BinaryWriter binaryWriter = new(WriteDescriptorsStream); - - foreach (KeyValuePair payload in payloads) - { - byte[] WriteDescriptorBuffer = payload.Value.WriteDescriptor.GetResultingBuffer(storeHeaderVersion); - binaryWriter.Write(WriteDescriptorBuffer); - } - - byte[] WriteDescriptorsBuffer = new byte[WriteDescriptorsStream.Length]; - _ = WriteDescriptorsStream.Seek(0, SeekOrigin.Begin); - WriteDescriptorsStream.ReadExactly(WriteDescriptorsBuffer, 0, WriteDescriptorsBuffer.Length); - - return WriteDescriptorsBuffer; - } - - private static byte[] GenerateHashTable(MemoryStream FFUMetadataHeaderTempFileStream, KeyValuePair[] BlockPayloads, uint BlockSize) - { - _ = FFUMetadataHeaderTempFileStream.Seek(0, SeekOrigin.Begin); - - using MemoryStream HashTableStream = new(); - using BinaryWriter binaryWriter = new(HashTableStream); - - for (int i = 0; i < FFUMetadataHeaderTempFileStream.Length / BlockSize; i++) - { - byte[] buffer = new byte[BlockSize]; - _ = FFUMetadataHeaderTempFileStream.Read(buffer, 0, (int)BlockSize); - byte[] hash = SHA256.HashData(buffer); - binaryWriter.Write(hash, 0, hash.Length); - } - - foreach (KeyValuePair payload in BlockPayloads) - { - binaryWriter.Write(payload.Key.Bytes, 0, payload.Key.Bytes.Length); - } - - byte[] HashTableBuffer = new byte[HashTableStream.Length]; - _ = HashTableStream.Seek(0, SeekOrigin.Begin); - HashTableStream.ReadExactly(HashTableBuffer, 0, HashTableBuffer.Length); - - return HashTableBuffer; - } - - /* - *: Device Targeting Infos is optional - **: Only available on V1_COMPRESSION FFU file formats - ***: Only available on V2 FFU file formats - - - Validation Descriptor is always of size 0 - - While it is possible in the struct to specify more than one Block - for a BlockDataEntry it shall only be equal to 0 - - The hash table contains every hash of every block in the FFU file - starting from the Image Header to the end - - When using V1_COMPRESSION FFU file format, BlockDataEntry contains - an extra entry of size 4 bytes - - Multiple locations for a block data entry only copies the block - to multiple places - - +------------------------------+ - | | - | Security Header | - | | - +------------------------------+ - | | - | Security Catalog | - | | - +------------------------------+ - | | - | Hash Table | - | | - +------------------------------+ - | | - | (Block Size) Padding | - | | - +------------------------------+ - | | - | Image Header | - | | - +------------------------------+ - | * | - | Image Header Extended | - | DeviceTargetingInfoCount | - | | - +------------------------------+ - | | - | Image Manifest | - | | - +------------------------------+ - | * | - | DeviceTargetInfoLengths[0] | - | | - +------------------------------+ - | * | - | DeviceTargetInfoStrings[0] | - | | - +------------------------------+ - | * | - | . . . | - | | - +------------------------------+ - | * | - | DeviceTargetInfoLengths[n] | - | | - +------------------------------+ - | * | - | DeviceTargetInfoStrings[n] | - | | - +------------------------------+ - | | - | (Block Size) Padding | - | | - +------------------------------+ - | | - | Store Header[0] | - | | - +------------------------------+ - | * * | - | CompressionAlgo[0] | - | | - +------------------------------+ - | * * * | - | Store Header Ex[0] | - | | - +------------------------------+ - | | - | Validation Descriptor[0] | - | | - +------------------------------+ - | | - | Write Descriptors[0] | - |(BlockDataEntry+DiskLocations)| - +------------------------------+ - | | - | (Block Size) Padding[0] | - | | - +------------------------------+ - | * * * | - | . . . | - | | - +------------------------------+ - | * * * | - | Store Header[n] | - | | - +------------------------------+ - | * * * | - | Store Header Ex[n] | - | | - +------------------------------+ - | * * * | - | Validation Descriptor[n] | - | | - +------------------------------+ - | * * * | - | Write Descriptors[n] | - |(BlockDataEntry+DiskLocations)| - +------------------------------+ - | * * * | - | (Block Size) Padding[n] | - | | - +------------------------------+ - | | - | Data Blocks | - | | - +------------------------------+ - */ - - private static (uint MinSectorCount, List partitions, byte[] StoreHeaderBuffer, byte[] WriteDescriptorBuffer, KeyValuePair[] BlockPayloads, FlashPart[] flashParts, VirtualDisk InputDisk) GenerateStore(string InputFile, string[] PlatformIDs, uint SectorSize, uint BlockSize, string[] ExcludedPartitionNames, uint MaximumNumberOfBlankBlocksAllowed, FlashUpdateVersion FlashUpdateVersion, ILogging Logging) - { - Logging.Log("Opening input file..."); - - Stream InputStream; - VirtualDisk? InputDisk = null; - - if (InputFile.Contains(@"\\.\physicaldrive", StringComparison.CurrentCultureIgnoreCase)) - { - InputStream = new Img2Ffu.Streams.DeviceStream(InputFile, FileAccess.Read); - } - else if (File.Exists(InputFile) && Path.GetExtension(InputFile).Equals(".vhd", StringComparison.InvariantCultureIgnoreCase)) - { - DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(DiscUtils.Vhd.Disk).Assembly); - DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(DiscUtils.Vhdx.Disk).Assembly); - InputDisk = VirtualDisk.OpenDisk(InputFile, FileAccess.Read); - InputStream = InputDisk.Content; - } - else if (File.Exists(InputFile) && Path.GetExtension(InputFile).Equals(".vhdx", StringComparison.InvariantCultureIgnoreCase)) - { - DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(DiscUtils.Vhd.Disk).Assembly); - DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(DiscUtils.Vhdx.Disk).Assembly); - InputDisk = VirtualDisk.OpenDisk(InputFile, FileAccess.Read); - InputStream = InputDisk.Content; - } - else if (File.Exists(InputFile)) - { - InputStream = new FileStream(InputFile, FileMode.Open); - } - else - { - Logging.Log("Unknown input specified"); - return (0, null, null, null, null, null, null); - } - - Logging.Log("Generating Image Slices..."); - (FlashPart[] flashParts, List partitions) = ImageSplitter.GetImageSlices(InputStream, BlockSize, ExcludedPartitionNames, SectorSize, Logging); - - Logging.Log("Generating Block Payloads..."); - KeyValuePair[] BlockPayloads = BlockPayloadsGenerator.GetOptimizedPayloads(flashParts, BlockSize, MaximumNumberOfBlankBlocksAllowed, Logging); - - bool IsFixedDiskLength = false; // POC! - BlockPayloads = BlockPayloadsGenerator.GetGPTPayloads(BlockPayloads, InputStream, BlockSize, IsFixedDiskLength); - - Logging.Log("Generating write descriptors..."); - byte[] WriteDescriptorBuffer = GetWriteDescriptorsBuffer(BlockPayloads, FlashUpdateVersion); - - Logging.Log("Generating store header..."); - StoreHeader store = new() - { - WriteDescriptorCount = (uint)BlockPayloads.LongLength, - WriteDescriptorLength = (uint)WriteDescriptorBuffer.Length, - PlatformIds = PlatformIDs, - BlockSize = BlockSize, - - // POC Begins - NumberOfStores = 1, - StoreIndex = 1, - DevicePath = "VenHw(860845C1-BE09-4355-8BC1-30D64FF8E63A)", - StorePayloadSize = (ulong)BlockPayloads.LongLength * BlockSize - // POC Ends - }; - - byte[] StoreHeaderBuffer = store.GetResultingBuffer(FlashUpdateVersion, FlashUpdateType.Full, CompressionAlgorithm.None); - - uint MinSectorCount = (uint)(InputStream.Length / SectorSize); - - return (MinSectorCount, partitions, StoreHeaderBuffer, WriteDescriptorBuffer, BlockPayloads, flashParts, InputDisk); - } - - public static void GenerateFFU(string InputFile, string FFUFile, string[] PlatformIDs, uint SectorSize, uint BlockSize, string AntiTheftVersion, string OperatingSystemVersion, string[] ExcludedPartitionNames, uint MaximumNumberOfBlankBlocksAllowed, FlashUpdateVersion FlashUpdateVersion, List deviceTargetInfos, ILogging Logging) - { - if (File.Exists(FFUFile)) - { - Logging.Log("File already exists!", ILoggingLevel.Error); - return; - } - - Logging.Log($"Input image: {InputFile}"); - Logging.Log($"Destination image: {FFUFile}"); - Logging.Log($"Platform IDs: {string.Join("\nPlatform IDs: ", PlatformIDs)}"); - Logging.Log($"Sector Size: {SectorSize}"); - Logging.Log($"Block Size: {BlockSize}"); - Logging.Log($"Anti Theft Version: {AntiTheftVersion}"); - Logging.Log($"OS Version: {OperatingSystemVersion}"); - Logging.Log(""); - - (uint MinSectorCount, List partitions, byte[] StoreHeaderBuffer, byte[] WriteDescriptorBuffer, KeyValuePair[] BlockPayloads, FlashPart[] flashParts, VirtualDisk InputDisk) = GenerateStore(InputFile, PlatformIDs, SectorSize, BlockSize, ExcludedPartitionNames, MaximumNumberOfBlankBlocksAllowed, FlashUpdateVersion, Logging); - - // Todo make this read the image itself - Logging.Log("Generating full flash manifest..."); - FullFlashManifest FullFlash = new() - { - OSVersion = OperatingSystemVersion, - DevicePlatformId3 = PlatformIDs.Count() > 3 ? PlatformIDs[3] : "", - DevicePlatformId2 = PlatformIDs.Count() > 2 ? PlatformIDs[2] : "", - DevicePlatformId1 = PlatformIDs.Count() > 1 ? PlatformIDs[1] : "", - DevicePlatformId0 = PlatformIDs[0], - AntiTheftVersion = AntiTheftVersion - }; - - Logging.Log("Generating store manifest..."); - StoreManifest Store = new() - { - SectorSize = SectorSize, - MinSectorCount = MinSectorCount - }; - - Logging.Log("Generating image manifest..."); - string ImageManifest = ManifestIni.BuildUpManifest(FullFlash, Store, partitions); - byte[] ManifestBuffer = Encoding.ASCII.GetBytes(ImageManifest); - - - Logging.Log("Generating image header..."); - ImageHeader ImageHeader = new() - { - ManifestLength = (uint)ManifestBuffer.Length - }; - - byte[] ImageHeaderBuffer = ImageHeader.GetResultingBuffer(BlockSize, deviceTargetInfos.Count != 0, (uint)deviceTargetInfos.Count); - - using MemoryStream FFUMetadataHeaderStream = new(); - - // - // Image Header - // - Logging.Log("Writing Image Header..."); - FFUMetadataHeaderStream.Write(ImageHeaderBuffer, 0, ImageHeaderBuffer.Length); - - // - // Image Manifest - // - Logging.Log("Writing Image Manifest..."); - FFUMetadataHeaderStream.Write(ManifestBuffer, 0, ManifestBuffer.Length); - - if (deviceTargetInfos.Count != 0) - { - // - // Device Target Infos... - // - Logging.Log("Writing Device Target Infos..."); - foreach (DeviceTargetInfo deviceTargetInfo in deviceTargetInfos) - { - byte[] deviceTargetInfoBuffer = deviceTargetInfo.GetResultingBuffer(); - FFUMetadataHeaderStream.Write(deviceTargetInfoBuffer, 0, deviceTargetInfoBuffer.Length); - } - } - - // - // (Block Size) Padding - // - Logging.Log("Writing Padding..."); - RoundUpToChunks(FFUMetadataHeaderStream, BlockSize); - - // - // Store Header[0] - // - Logging.Log("Writing Store Header..."); - FFUMetadataHeaderStream.Write(StoreHeaderBuffer, 0, StoreHeaderBuffer.Length); - - // - // Write Descriptors[0] - // - Logging.Log("Writing Write Descriptors..."); - FFUMetadataHeaderStream.Write(WriteDescriptorBuffer, 0, WriteDescriptorBuffer.Length); - - // - // (Block Size) Padding[0] - // - Logging.Log("Writing Padding..."); - RoundUpToChunks(FFUMetadataHeaderStream, BlockSize); - - Logging.Log("Generating image hash table..."); - byte[] HashTable = GenerateHashTable(FFUMetadataHeaderStream, BlockPayloads, BlockSize); - - Logging.Log("Generating image catalog..."); - byte[] CatalogBuffer = GenerateCatalogFile(HashTable); - - Logging.Log("Generating Security Header..."); - SecurityHeader security = new() - { - HashTableSize = (uint)HashTable.Length, - CatalogSize = (uint)CatalogBuffer.Length - }; - - byte[] SecurityHeaderBuffer = security.GetResultingBuffer(BlockSize); - - byte[] FFUMetadataHeaderBuffer = new byte[FFUMetadataHeaderStream.Length]; - _ = FFUMetadataHeaderStream.Seek(0, SeekOrigin.Begin); - _ = FFUMetadataHeaderStream.Read(FFUMetadataHeaderBuffer, 0, (int)FFUMetadataHeaderStream.Length); - - Logging.Log("Opening FFU file for writing..."); - WriteFFUFile(FFUFile, SecurityHeaderBuffer, CatalogBuffer, HashTable, FFUMetadataHeaderBuffer, BlockPayloads, flashParts, BlockSize, Logging); - - InputDisk?.Dispose(); - } - - private static void WriteFFUFile(string FFUFile, byte[] SecurityHeaderBuffer, byte[] CatalogBuffer, byte[] HashTable, byte[] FFUMetadataHeaderBuffer, KeyValuePair[] BlockPayloads, FlashPart[] flashParts, uint BlockSize, ILogging Logging) - { - FileStream FFUFileStream = new(FFUFile, FileMode.CreateNew); - - // - // Security Header - // - Logging.Log("Writing Security Header..."); - FFUFileStream.Write(SecurityHeaderBuffer, 0, SecurityHeaderBuffer.Length); - - // - // Security Catalog - // - Logging.Log("Writing Security Catalog..."); - FFUFileStream.Write(CatalogBuffer, 0, CatalogBuffer.Length); - - // - // Hash Table - // - Logging.Log("Writing Hash Table..."); - FFUFileStream.Write(HashTable, 0, HashTable.Length); - - // - // (Block Size) Padding - // - Logging.Log("Writing Padding..."); - RoundUpToChunks(FFUFileStream, BlockSize); - - // - // Image Header - // Image Manifest - // (Block Size) Padding - // Store Header[0] - // Write Descriptors[0] - // (Block Size) Padding[0] - // - Logging.Log("Writing Image Header..."); - Logging.Log("Writing Image Manifest..."); - Logging.Log("Writing Padding..."); - Logging.Log("Writing Store Header..."); - Logging.Log("Writing Write Descriptors..."); - Logging.Log("Writing Padding..."); - FFUFileStream.Write(FFUMetadataHeaderBuffer, 0, FFUMetadataHeaderBuffer.Length); - - DateTime startTime = DateTime.Now; - - // - // Data Blocks - // - Logging.Log("Writing Data Blocks..."); - for (ulong CurrentBlockIndex = 0; CurrentBlockIndex < (ulong)BlockPayloads.LongLength; CurrentBlockIndex++) - { - BlockPayload BlockPayload = BlockPayloads.ElementAt((int)CurrentBlockIndex).Value; - byte[] BlockBuffer = BlockPayload.ReadBlock(BlockSize); - - FFUFileStream.Write(BlockBuffer, 0, (int)BlockSize); - - ulong totalBytes = (ulong)BlockPayloads.LongLength * BlockSize; - ulong bytesRead = CurrentBlockIndex * BlockSize; - ulong sourcePosition = CurrentBlockIndex * BlockSize; - - ShowProgress(totalBytes, startTime, bytesRead, sourcePosition, Logging); - } - Logging.Log(""); - - FFUFileStream.Close(); - } - - private static void RoundUpToChunks(FileStream stream, uint chunkSize) - { - long Size = stream.Length; - if ((Size % chunkSize) > 0) - { - long padding = (uint)(((Size / chunkSize) + 1) * chunkSize) - Size; - stream.Write(new byte[padding], 0, (int)padding); - } - } - - private static void RoundUpToChunks(MemoryStream stream, uint chunkSize) - { - long Size = stream.Length; - if ((Size % chunkSize) > 0) - { - long padding = (uint)(((Size / chunkSize) + 1) * chunkSize) - Size; - stream.Write(new byte[padding], 0, (int)padding); - } - } - - private static void ShowProgress(ulong TotalBytes, DateTime startTime, ulong BytesRead, ulong SourcePosition, ILogging Logging) - { - DateTime now = DateTime.Now; - TimeSpan timeSoFar = now - startTime; - - double milliseconds = timeSoFar.TotalMilliseconds / BytesRead * (TotalBytes - BytesRead); - double ticks = milliseconds * TimeSpan.TicksPerMillisecond; - if ((ticks > long.MaxValue) || (ticks < long.MinValue) || double.IsNaN(ticks)) - { - milliseconds = 0; - } - TimeSpan remaining = TimeSpan.FromMilliseconds(milliseconds); - - double speed = Math.Round(SourcePosition / 1024L / 1024L / timeSoFar.TotalSeconds); - - Logging.Log(string.Format($"{LoggingHelpers.GetDismLikeProgBar(int.Parse((BytesRead * 100 / TotalBytes).ToString()))} {speed}MB/s {Math.Truncate(remaining.TotalHours):00}:{remaining.Minutes:00}:{remaining.Seconds:00}.{remaining.Milliseconds:000}"), returnLine: false, severity: ILoggingLevel.Information); - } - } -} diff --git a/Img2Ffu.Library/Writer/FlashPart.cs b/Img2Ffu.Library/Writer/FlashPart.cs deleted file mode 100644 index 4a5cbbc..0000000 --- a/Img2Ffu.Library/Writer/FlashPart.cs +++ /dev/null @@ -1,31 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -namespace Img2Ffu.Writer -{ - internal class FlashPart(Stream Stream, ulong StartLocation) - { - public ulong StartLocation = StartLocation; - public Stream Stream = Stream; - } -} diff --git a/Img2Ffu.Library/Writer/Flashing/BlockPayload.cs b/Img2Ffu.Library/Writer/Flashing/BlockPayload.cs deleted file mode 100644 index 4dc8eb4..0000000 --- a/Img2Ffu.Library/Writer/Flashing/BlockPayload.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using Img2Ffu.Writer.Data; - -namespace Img2Ffu.Writer.Flashing -{ - public class BlockPayload(WriteDescriptor WriteDescriptor, Stream Stream, ulong StreamLocation) - { - public WriteDescriptor WriteDescriptor = WriteDescriptor; - public Stream Stream = Stream; - public ulong FlashPartStreamLocation = StreamLocation; - - internal byte[] ReadBlock(ulong BlockSize) - { - _ = Stream.Seek((long)FlashPartStreamLocation, SeekOrigin.Begin); - - byte[] BlockBuffer = new byte[BlockSize]; - _ = Stream.Read(BlockBuffer, 0, (int)BlockSize); - - return BlockBuffer; - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Flashing/BlockPayloadsGenerator.cs b/Img2Ffu.Library/Writer/Flashing/BlockPayloadsGenerator.cs deleted file mode 100644 index b719cce..0000000 --- a/Img2Ffu.Library/Writer/Flashing/BlockPayloadsGenerator.cs +++ /dev/null @@ -1,305 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using Img2Ffu.Writer.Data; -using System.Collections; -using System.Security.Cryptography; - -namespace Img2Ffu.Writer.Flashing -{ - internal class BlockPayloadsGenerator - { - private static void ShowProgress(ulong CurrentProgress, ulong TotalProgress, DateTime startTime, bool DisplayRed, ILogging Logging) - { - DateTime now = DateTime.Now; - TimeSpan timeSoFar = now - startTime; - - double milliseconds = timeSoFar.TotalMilliseconds / CurrentProgress * (TotalProgress - CurrentProgress); - double ticks = milliseconds * TimeSpan.TicksPerMillisecond; - if (ticks > long.MaxValue || ticks < long.MinValue || double.IsNaN(ticks)) - { - milliseconds = 0; - } - TimeSpan remaining = TimeSpan.FromMilliseconds(milliseconds); - - Logging.Log(string.Format($"{LoggingHelpers.GetDismLikeProgBar(int.Parse((CurrentProgress * 100 / TotalProgress).ToString()))} {Math.Truncate(remaining.TotalHours):00}:{remaining.Minutes:00}:{remaining.Seconds:00}.{remaining.Milliseconds:000}"), returnLine: false, severity: DisplayRed ? ILoggingLevel.Warning : ILoggingLevel.Information); - } - - internal static KeyValuePair[] GetGPTPayloads(KeyValuePair[] blockPayloads, Stream stream, uint BlockSize, bool IsFixedDiskLength) - { - List> blockPayloadsList = [.. blockPayloads]; - - byte[] EMPTY_BLOCK_HASH = SHA256.HashData(new byte[BlockSize]); - - // Erase both GPTs as per spec first - blockPayloadsList.Insert(0, new KeyValuePair(new ByteArrayKey(EMPTY_BLOCK_HASH), new BlockPayload( - new WriteDescriptor() - { - BlockDataEntry = new BlockDataEntry() - { - BlockCount = 1, - LocationCount = 2 - }, - DiskLocations = - [ - new DiskLocation() - { - BlockIndex = 0, - DiskAccessMethod = 0 - }, - new DiskLocation() - { - BlockIndex = 0, - DiskAccessMethod = 2 // From End - } - ] - }, - new MemoryStream(new byte[(int)BlockSize]), - 0 - ))); - - byte[] PrimaryGPTBuffer = new byte[(int)BlockSize]; - _ = stream.Seek(0, SeekOrigin.Begin); - _ = stream.Read(PrimaryGPTBuffer, 0, (int)BlockSize); - - MemoryStream primaryGPTStream = new(PrimaryGPTBuffer); - - KeyValuePair primaryGPTKeyValuePair = new(new ByteArrayKey(SHA256.HashData(primaryGPTStream)), new BlockPayload( - new WriteDescriptor() - { - BlockDataEntry = new BlockDataEntry() - { - BlockCount = 1, - LocationCount = 1 - }, - DiskLocations = - [ - new DiskLocation() - { - BlockIndex = 0, - DiskAccessMethod = 0 - } - ] - }, - primaryGPTStream, - 0 - )); - - if (IsFixedDiskLength) - { - ulong endGPTChunkStartLocation = (ulong)stream.Length - BlockSize; - byte[] SecondaryGPTBuffer = new byte[(int)BlockSize]; - _ = stream.Seek((long)endGPTChunkStartLocation, SeekOrigin.Begin); - _ = stream.Read(SecondaryGPTBuffer, 0, (int)BlockSize); - - MemoryStream secondaryGPTStream = new(SecondaryGPTBuffer); - - // Now add back both GPTs - // Apparently the first one needs to be added twice? - blockPayloadsList.Add(primaryGPTKeyValuePair); - blockPayloadsList.Add(primaryGPTKeyValuePair); - - blockPayloadsList.Add(new KeyValuePair(new ByteArrayKey(SHA256.HashData(secondaryGPTStream)), new BlockPayload( - new WriteDescriptor() - { - BlockDataEntry = new BlockDataEntry() - { - BlockCount = 1, - LocationCount = 1 - }, - DiskLocations = - [ - new DiskLocation() - { - BlockIndex = 0, - DiskAccessMethod = 2 - } - ] - }, - secondaryGPTStream, - 0 - ))); - } - else - { - // Now add back both GPTs - // Apparently the first one needs to be added twice? - blockPayloadsList.Insert(1, primaryGPTKeyValuePair); - blockPayloadsList.Add(primaryGPTKeyValuePair); - - ulong endGPTChunkStartLocation = (ulong)stream.Length - BlockSize; - byte[] SecondaryGPTBuffer = new byte[(int)BlockSize]; - _ = stream.Seek((long)endGPTChunkStartLocation, SeekOrigin.Begin); - _ = stream.Read(SecondaryGPTBuffer, 0, (int)BlockSize); - - MemoryStream secondaryGPTStream = new(SecondaryGPTBuffer); - - // HACK - blockPayloadsList.Add(new KeyValuePair(new ByteArrayKey(SHA256.HashData(secondaryGPTStream)), new BlockPayload( - new WriteDescriptor() - { - BlockDataEntry = new BlockDataEntry() - { - BlockCount = 1, - LocationCount = 1 - }, - DiskLocations = - [ - new DiskLocation() - { - BlockIndex = 0, - DiskAccessMethod = 2 - } - ] - }, - secondaryGPTStream, - 0 - ))); - } - - return [.. blockPayloadsList]; - } - - internal static KeyValuePair[] GetOptimizedPayloads(FlashPart[] flashParts, uint BlockSize, uint BlankSectorBufferSize, ILogging Logging) - { - List> hashedBlocks = []; - - if (flashParts == null) - { - return [.. hashedBlocks]; - } - - ulong CurrentBlockCount = 0; - ulong TotalBlockCount = 0; - foreach (FlashPart flashPart in flashParts) - { - TotalBlockCount += (ulong)flashPart.Stream.Length / BlockSize; - } - - DateTime startTime = DateTime.Now; - - Logging.Log($"Total Block Count: {TotalBlockCount} - {TotalBlockCount * BlockSize / (1024 * 1024 * 1024)}GB"); - Logging.Log("Hashing resources..."); - - bool blankPayloadPhase = false; - ulong blankPayloadCount = 0; - - byte[] EMPTY_BLOCK_HASH = SHA256.HashData(new byte[BlockSize]); - - List> blankBlocks = []; - - foreach (FlashPart flashPart in flashParts) - { - _ = flashPart.Stream.Seek(0, SeekOrigin.Begin); - long totalBlockCount = flashPart.Stream.Length / BlockSize; - - for (uint blockIndex = 0; blockIndex < totalBlockCount; blockIndex++) - { - byte[] blockBuffer = new byte[BlockSize]; - long streamPosition = flashPart.Stream.Position; - _ = flashPart.Stream.Read(blockBuffer, 0, (int)BlockSize); - byte[] blockHash = SHA256.HashData(blockBuffer); - - if (!StructuralComparisons.StructuralEqualityComparer.Equals(EMPTY_BLOCK_HASH, blockHash)) - { - hashedBlocks.Add(new KeyValuePair(new ByteArrayKey(blockHash), new BlockPayload( - new WriteDescriptor() - { - BlockDataEntry = new BlockDataEntry() - { - BlockCount = 1, - LocationCount = 1 - }, - DiskLocations = - [ - new DiskLocation() - { - BlockIndex = (uint)((flashPart.StartLocation / BlockSize) + blockIndex), - DiskAccessMethod = 0 - } - ] - }, - flashPart.Stream, - (ulong)streamPosition - ))); - - if (blankPayloadPhase && blankPayloadCount < BlankSectorBufferSize) - { - foreach (KeyValuePair blankPayload in blankBlocks) - { - hashedBlocks.Add(blankPayload); - } - } - - blankPayloadPhase = false; - blankPayloadCount = 0; - blankBlocks.Clear(); - } - else if (blankPayloadCount < BlankSectorBufferSize) - { - blankPayloadPhase = true; - blankPayloadCount++; - - blankBlocks.Add(new KeyValuePair(new ByteArrayKey(blockHash), new BlockPayload( - new WriteDescriptor() - { - BlockDataEntry = new BlockDataEntry() - { - BlockCount = 1, - LocationCount = 1 - }, - DiskLocations = - [ - new DiskLocation() - { - BlockIndex = (uint)((flashPart.StartLocation / BlockSize) + blockIndex), - DiskAccessMethod = 0 - } - ] - }, - flashPart.Stream, - (ulong)streamPosition - ))); - } - else if (blankPayloadCount >= BlankSectorBufferSize && blankBlocks.Count > 0) - { - foreach (KeyValuePair blankPayload in blankBlocks) - { - hashedBlocks.Add(blankPayload); - } - - blankBlocks.Clear(); - } - - CurrentBlockCount++; - ShowProgress(CurrentBlockCount, TotalBlockCount, startTime, blankPayloadPhase, Logging); - } - } - - Logging.Log(""); - Logging.Log($"FFU Block Count: {hashedBlocks.Count} - {hashedBlocks.Count * BlockSize / (1024 * 1024 * 1024)}GB"); - - return [.. hashedBlocks]; - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Flashing/ByteArrayKey.cs b/Img2Ffu.Library/Writer/Flashing/ByteArrayKey.cs deleted file mode 100644 index 029ab69..0000000 --- a/Img2Ffu.Library/Writer/Flashing/ByteArrayKey.cs +++ /dev/null @@ -1,129 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using System.Diagnostics.CodeAnalysis; - -namespace Img2Ffu.Writer.Flashing -{ - public readonly struct ByteArrayKey - { - public readonly byte[] Bytes; - private readonly int _hashCode; - - public override bool Equals(object obj) - { - ByteArrayKey other = (ByteArrayKey)obj; - return Compare(Bytes, other.Bytes); - } - - public override int GetHashCode() - { - return _hashCode; - } - - private static int GetHashCode([NotNull] byte[] bytes) - { - unchecked - { - int hash = 17; - for (int i = 0; i < bytes.Length; i++) - { - hash = (hash * 23) + bytes[i]; - } - return hash; - } - } - - public ByteArrayKey(byte[] bytes) - { - Bytes = bytes; - _hashCode = GetHashCode(bytes); - } - - public static ByteArrayKey Create(byte[] bytes) - { - return new ByteArrayKey(bytes); - } - - public static unsafe bool Compare(byte[] a1, byte[] a2) - { - if (a1 == null || a2 == null || a1.Length != a2.Length) - { - return false; - } - - fixed (byte* p1 = a1, p2 = a2) - { - byte* x1 = p1, x2 = p2; - int l = a1.Length; - for (int i = 0; i < l / 8; i++, x1 += 8, x2 += 8) - { - if (*(long*)x1 != *(long*)x2) - { - return false; - } - } - - if ((l & 4) != 0) - { - if (*(int*)x1 != *(int*)x2) - { - return false; - } - - x1 += 4; - x2 += 4; - } - if ((l & 2) != 0) - { - if (*(short*)x1 != *(short*)x2) - { - return false; - } - - x1 += 2; - x2 += 2; - } - if ((l & 1) != 0) - { - if (*x1 != *x2) - { - return false; - } - } - - return true; - } - } - - public static bool operator ==(ByteArrayKey left, ByteArrayKey right) - { - return left.Equals(right); - } - - public static bool operator !=(ByteArrayKey left, ByteArrayKey right) - { - return !(left == right); - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Flashing/FileSystemAllocationUtils.cs b/Img2Ffu.Library/Writer/Flashing/FileSystemAllocationUtils.cs deleted file mode 100644 index 484dd56..0000000 --- a/Img2Ffu.Library/Writer/Flashing/FileSystemAllocationUtils.cs +++ /dev/null @@ -1,74 +0,0 @@ -using DiscUtils; -using DiscUtils.Ntfs; - -namespace Img2Ffu.Writer.Flashing -{ - internal class FileSystemAllocationUtils - { - public static (ulong StartOffset, ulong Length)[] GetNTFSAllocatedClustersMap(Stream fileSystemStream) - { - try - { - using NtfsFileSystem fileSystem = new(fileSystemStream); - ulong totalClusters = (ulong)fileSystem.TotalClusters; - ulong usedClusters = (ulong)fileSystem.UsedSpace / (ulong)fileSystem.ClusterSize; - - List ClustersInUse = []; - for (ulong i = 0; i < totalClusters; i++) - { - if (fileSystem.IsClusterInUse((long)i)) - { - ClustersInUse.Add((ulong)fileSystem.ClusterToOffset((long)i)); - } - } - return GetAllocatedClustersMap(ClustersInUse, fileSystem); - } - catch (InvalidFileSystemException) - { - // Not NTFS - throw; - } - } - - private static (ulong StartOffset, ulong Length)[] GetAllocatedClustersMap(List ClustersInUse, IClusterBasedFileSystem fileSystem) - { - ulong sizeOfOneCluster = (ulong)fileSystem.ClusterSize; - ClustersInUse.Sort(); - - if (ClustersInUse[0] != 0) - { - ClustersInUse.Insert(0, ClustersInUse[0]); - } - - List<(ulong StartOffset, ulong Length)> FileSystemParts = []; - - foreach (ulong clusterStartOffset in ClustersInUse) - { - if (FileSystemParts.Count == 0) - { - FileSystemParts.Add((clusterStartOffset, sizeOfOneCluster)); - } - else - { - (ulong StartOffset, ulong Length) = FileSystemParts[^1]; - if (StartOffset + Length == clusterStartOffset) - { - FileSystemParts[^1] = (StartOffset, Length + sizeOfOneCluster); - } - else - { - FileSystemParts.Add((clusterStartOffset, sizeOfOneCluster)); - } - } - } - - return [.. FileSystemParts]; - } - - public static bool IsNTFS(Stream fileSystemStream) - { - _ = fileSystemStream.Seek(0, SeekOrigin.Begin); - return NtfsFileSystem.Detect(fileSystemStream); - } - } -} diff --git a/Img2Ffu.Library/Writer/GPT/GPT.cs b/Img2Ffu.Library/Writer/GPT/GPT.cs deleted file mode 100644 index 3d41b9d..0000000 --- a/Img2Ffu.Library/Writer/GPT/GPT.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using Img2Ffu.Writer.Helpers; - -namespace Img2Ffu -{ - public partial class GPT - { - public byte[] GPTBuffer; - private readonly uint HeaderOffset; - private readonly uint HeaderSize; - private uint TableOffset; - private uint TableSize; - private readonly uint PartitionEntrySize; - private readonly uint MaxPartitions; - internal ulong FirstUsableSector; - internal ulong LastUsableSector; - internal bool HasChanged = false; - - public List Partitions = []; - - internal static uint GetGPTSize(byte[] GPTBuffer, uint SectorSize) - { - uint? TempHeaderOffset = ByteOperations.FindAscii(GPTBuffer, "EFI PART") ?? throw new Exception("Bad GPT"); - - uint HeaderOffset = (uint)TempHeaderOffset; - uint TableOffset = HeaderOffset + SectorSize; - uint MaxPartitions = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x50); - uint PartitionEntrySize = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x54); - uint TableSize = MaxPartitions * PartitionEntrySize; - - return TableOffset + TableSize; - } - - internal GPT(byte[] GPTBuffer, uint SectorSize) - { - this.GPTBuffer = GPTBuffer; - uint? TempHeaderOffset = ByteOperations.FindAscii(GPTBuffer, "EFI PART") ?? throw new Exception("Bad GPT"); - - HeaderOffset = (uint)TempHeaderOffset; - HeaderSize = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x0C); - TableOffset = HeaderOffset + SectorSize; - FirstUsableSector = ByteOperations.ReadUInt64(GPTBuffer, HeaderOffset + 0x28); - LastUsableSector = ByteOperations.ReadUInt64(GPTBuffer, HeaderOffset + 0x30); - MaxPartitions = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x50); - PartitionEntrySize = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x54); - TableSize = MaxPartitions * PartitionEntrySize; - if ((TableOffset + TableSize) > GPTBuffer.Length) - { - throw new Exception("Bad GPT"); - } - - uint PartitionOffset = TableOffset; - - while (PartitionOffset < (TableOffset + TableSize)) - { - string Name = ByteOperations.ReadUnicodeString(GPTBuffer, PartitionOffset + 0x38, 0x48).TrimEnd([(char)0, ' ']); - if (Name.Length == 0) - { - break; - } - - Partition CurrentPartition = new() - { - Name = Name, - FirstSector = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x20), - LastSector = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x28), - PartitionTypeGuid = ByteOperations.ReadGuid(GPTBuffer, PartitionOffset + 0x00), - PartitionGuid = ByteOperations.ReadGuid(GPTBuffer, PartitionOffset + 0x10), - Attributes = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x30) - }; - Partitions.Add(CurrentPartition); - PartitionOffset += PartitionEntrySize; - } - - HasChanged = false; - } - - internal Partition GetPartition(string Name) - { - return Partitions.Where(p => string.Compare(p.Name, Name, true) == 0).FirstOrDefault(); - } - - internal byte[] Rebuild(uint SectorSize) - { - if (GPTBuffer == null) - { - TableSize = 0x21 * SectorSize; - TableOffset = 0; - GPTBuffer = new byte[TableSize]; - } - else - { - Array.Clear(GPTBuffer, (int)TableOffset, (int)TableSize); - } - - uint PartitionOffset = TableOffset; - foreach (Partition CurrentPartition in Partitions) - { - ByteOperations.WriteGuid(GPTBuffer, PartitionOffset + 0x00, CurrentPartition.PartitionTypeGuid); - ByteOperations.WriteGuid(GPTBuffer, PartitionOffset + 0x10, CurrentPartition.PartitionGuid); - ByteOperations.WriteUInt64(GPTBuffer, PartitionOffset + 0x20, CurrentPartition.FirstSector); - ByteOperations.WriteUInt64(GPTBuffer, PartitionOffset + 0x28, CurrentPartition.LastSector); - ByteOperations.WriteUInt64(GPTBuffer, PartitionOffset + 0x30, CurrentPartition.Attributes); - ByteOperations.WriteUnicodeString(GPTBuffer, PartitionOffset + 0x38, CurrentPartition.Name, 0x48); - - PartitionOffset += PartitionEntrySize; - } - - ByteOperations.WriteUInt32(GPTBuffer, HeaderOffset + 0x58, ByteOperations.CRC32(GPTBuffer, TableOffset, TableSize)); - ByteOperations.WriteUInt32(GPTBuffer, HeaderOffset + 0x10, 0); - ByteOperations.WriteUInt32(GPTBuffer, HeaderOffset + 0x10, ByteOperations.CRC32(GPTBuffer, HeaderOffset, HeaderSize)); - - return GPTBuffer; - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/GPT/Partition.cs b/Img2Ffu.Library/Writer/GPT/Partition.cs deleted file mode 100644 index d2be15e..0000000 --- a/Img2Ffu.Library/Writer/GPT/Partition.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -namespace Img2Ffu -{ - public partial class GPT - { - public class Partition - { - private ulong _SizeInSectors; - private ulong _FirstSector; - private ulong _LastSector; - - public required string Name; // 0x48 - public Guid PartitionTypeGuid; // 0x10 - public Guid PartitionGuid; // 0x10 - internal ulong Attributes; // 0x08 - - internal ulong SizeInSectors - { - get => _SizeInSectors != 0 ? _SizeInSectors : LastSector - FirstSector + 1; - set - { - _SizeInSectors = value; - if (FirstSector != 0) - { - LastSector = FirstSector + _SizeInSectors - 1; - } - } - } - - internal ulong FirstSector // 0x08 - { - get => _FirstSector; - set - { - _FirstSector = value; - if (_SizeInSectors != 0) - { - _LastSector = FirstSector + _SizeInSectors - 1; - } - } - } - - internal ulong LastSector // 0x08 - { - get => _LastSector; - set - { - _LastSector = value; - _SizeInSectors = 0; - } - } - - public string Volume => @"\\?\Volume" + PartitionGuid.ToString("b") + @"\"; - - public string FirstSectorAsString - { - get => "0x" + FirstSector.ToString("X16"); - set => FirstSector = Convert.ToUInt64(value, 16); - } - - public string LastSectorAsString - { - get => "0x" + LastSector.ToString("X16"); - set => LastSector = Convert.ToUInt64(value, 16); - } - - public string AttributesAsString - { - get => "0x" + Attributes.ToString("X16"); - set => Attributes = Convert.ToUInt64(value, 16); - } - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Helpers/ByteOperations.cs b/Img2Ffu.Library/Writer/Helpers/ByteOperations.cs deleted file mode 100644 index 4b2414f..0000000 --- a/Img2Ffu.Library/Writer/Helpers/ByteOperations.cs +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -// These functions assume same endianness for the CPU architecture and the raw data it reads from or writes to. - -namespace Img2Ffu.Writer.Helpers -{ - internal static class ByteOperations - { - internal static string ReadUnicodeString(byte[] ByteArray, uint Offset, uint Length) - { - byte[] Bytes = new byte[Length]; - Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length); - return System.Text.Encoding.Unicode.GetString(Bytes); - } - - internal static void WriteAsciiString(byte[] ByteArray, uint Offset, string Text, uint? MaxBufferLength = null) - { - if (MaxBufferLength != null) - { - Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength); - } - - byte[] TextBytes = System.Text.Encoding.ASCII.GetBytes(Text); - int WriteLength = TextBytes.Length; - if (WriteLength > MaxBufferLength) - { - WriteLength = (int)MaxBufferLength; - } - - Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength); - } - - internal static void WriteUnicodeString(byte[] ByteArray, uint Offset, string Text, uint? MaxBufferLength = null) - { - if (MaxBufferLength != null) - { - Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength); - } - - byte[] TextBytes = System.Text.Encoding.Unicode.GetBytes(Text); - int WriteLength = TextBytes.Length; - if (WriteLength > MaxBufferLength) - { - WriteLength = (int)MaxBufferLength; - } - - Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength); - } - - internal static uint ReadUInt32(byte[] ByteArray, uint Offset) - { - return BitConverter.ToUInt32(ByteArray, (int)Offset); - } - - internal static void WriteUInt32(byte[] ByteArray, uint Offset, uint Value) - { - Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4); - } - - internal static ulong ReadUInt64(byte[] ByteArray, uint Offset) - { - return BitConverter.ToUInt64(ByteArray, (int)Offset); - } - - internal static void WriteUInt64(byte[] ByteArray, uint Offset, ulong Value) - { - Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 8); - } - - internal static Guid ReadGuid(byte[] ByteArray, uint Offset) - { - byte[] GuidBuffer = new byte[0x10]; - Buffer.BlockCopy(ByteArray, (int)Offset, GuidBuffer, 0, 0x10); - return new Guid(GuidBuffer); - } - - internal static void WriteGuid(byte[] ByteArray, uint Offset, Guid Value) - { - Buffer.BlockCopy(Value.ToByteArray(), 0, ByteArray, (int)Offset, 0x10); - } - - internal static uint? FindAscii(byte[] SourceBuffer, string Pattern) - { - return FindPattern(SourceBuffer, System.Text.Encoding.ASCII.GetBytes(Pattern), null, null); - } - - internal static uint? FindPattern(byte[] SourceBuffer, byte[] Pattern, byte[]? Mask, byte[]? OutPattern) - { - return FindPattern(SourceBuffer, 0, null, Pattern, Mask, OutPattern); - } - - internal static bool Compare(byte[] Array1, byte[] Array2) - { - return System.Collections.StructuralComparisons.StructuralEqualityComparer.Equals(Array1, Array2); - } - - internal static uint? FindPattern(byte[] SourceBuffer, uint SourceOffset, uint? SourceSize, byte[] Pattern, byte[] Mask, byte[] OutPattern) - { - // The mask is optional. - // In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard. - - uint? Result = null; - - uint SearchPosition = SourceOffset; - int i; - - while (SearchPosition <= SourceBuffer.Length - Pattern.Length && (SourceSize == null || SearchPosition <= SourceOffset + SourceSize - Pattern.Length)) - { - bool Match = true; - for (i = 0; i < Pattern.Length; i++) - { - if (SourceBuffer[SearchPosition + i] != Pattern[i]) - { - if (Mask == null || Mask[i] == 0) - { - Match = false; - break; - } - } - } - - if (Match) - { - Result = SearchPosition; - - if (OutPattern != null) - { - Buffer.BlockCopy(SourceBuffer, (int)SearchPosition, OutPattern, 0, Pattern.Length); - } - - break; - } - - SearchPosition++; - } - - return Result; - } - - private static readonly uint[] CRC32Table = [ - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, - 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, - 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, - 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, - 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, - 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, - 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, - 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, - 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, - 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, - 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, - 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, - 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, - 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, - 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, - 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, - 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, - 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, - 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, - 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - ]; - - internal static uint CRC32(byte[] Input, uint Offset, uint Length) - { - if (Input == null || Offset + Length > Input.Length) - { - throw new ArgumentException(); - } - - unchecked - { - uint crc = (uint)((uint)0 ^ -1); - for (uint i = Offset; i < Offset + Length; i++) - { - crc = (crc >> 8) ^ CRC32Table[(crc ^ Input[i]) & 0xFF]; - } - crc = (uint)(crc ^ -1); - - if (crc < 0) - { - crc += (uint)4294967296; - } - - return crc; - } - } - } -} diff --git a/Img2Ffu.Library/Writer/ILogging.cs b/Img2Ffu.Library/Writer/ILogging.cs deleted file mode 100644 index 2d02004..0000000 --- a/Img2Ffu.Library/Writer/ILogging.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Img2Ffu.Writer -{ - public interface ILogging - { - public void Log(string message, ILoggingLevel severity = ILoggingLevel.Information, bool returnLine = true); - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/ILoggingLevel.cs b/Img2Ffu.Library/Writer/ILoggingLevel.cs deleted file mode 100644 index dfc30dc..0000000 --- a/Img2Ffu.Library/Writer/ILoggingLevel.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Img2Ffu.Writer -{ - public enum ILoggingLevel - { - Information, - Warning, - Error - } -} diff --git a/Img2Ffu.Library/Writer/ImageSplitter.cs b/Img2Ffu.Library/Writer/ImageSplitter.cs deleted file mode 100644 index f22cb9b..0000000 --- a/Img2Ffu.Library/Writer/ImageSplitter.cs +++ /dev/null @@ -1,308 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using Img2Ffu.Writer.Streams; -using static Img2Ffu.GPT; - -namespace Img2Ffu.Writer -{ - internal class ImageSplitter - { - internal static readonly string IS_UNLOCKED_PARTITION_NAME = "IS_UNLOCKED"; - internal static readonly string HACK_PARTITION_NAME = "HACK"; - internal static readonly string BACKUP_BS_NV_PARTITION_NAME = "BACKUP_BS_NV"; - internal static readonly string UEFI_BS_NV_PARTITION_NAME = "UEFI_BS_NV"; - - internal static GPT GetGPT(Stream stream, uint BlockSize, uint sectorSize, ILogging Logging) - { - byte[] GPTBuffer = new byte[BlockSize]; - _ = stream.Read(GPTBuffer, 0, (int)BlockSize); - - uint requiredGPTBufferSize = GetGPTSize(GPTBuffer, sectorSize); - if (BlockSize < requiredGPTBufferSize) - { - string errorMessage = $"The Block size is too small to contain the GPT, the GPT is {requiredGPTBufferSize} bytes long, the Block size is {BlockSize} bytes long"; - Logging.Log(errorMessage, ILoggingLevel.Error); - throw new Exception(errorMessage); - } - - uint sectorsInABlock = BlockSize / sectorSize; - - GPT GPT = new(GPTBuffer, sectorSize); - - if (BlockSize > requiredGPTBufferSize && GPT.Partitions.OrderBy(x => x.FirstSector).Any(x => x.FirstSector < sectorsInABlock)) - { - Partition conflictingPartition = GPT.Partitions.OrderBy(x => x.FirstSector).First(x => x.FirstSector < sectorsInABlock); - - string errorMessage = $"The Block size is too big to contain only the GPT, the GPT is {requiredGPTBufferSize} bytes long, the Block size is {BlockSize} bytes long. The overlapping partition is {conflictingPartition.Name} at {conflictingPartition.FirstSector * sectorSize}"; - Logging.Log(errorMessage, ILoggingLevel.Error); - throw new Exception(errorMessage); - } - - return GPT; - } - - internal static (FlashPart[], List partitions) GetImageSlices(Stream stream, uint BlockSize, string[] ExcludedPartitionNames, uint sectorSize, ILogging Logging) - { - GPT GPT = GetGPT(stream, BlockSize, sectorSize, Logging); - uint sectorsInABlock = BlockSize / sectorSize; - - Logging.Log($"Sector Size: {sectorSize}"); - Logging.Log($"Block Size: {BlockSize}"); - Logging.Log($"Sectors in a Block: {sectorsInABlock}"); - - List Partitions = GPT.Partitions; - - bool isUnlocked = GPT.GetPartition(IS_UNLOCKED_PARTITION_NAME) != null; - bool isUnlockedSpecA = GPT.GetPartition(HACK_PARTITION_NAME) != null && GPT.GetPartition(BACKUP_BS_NV_PARTITION_NAME) != null; - - if (isUnlocked) - { - Logging.Log($"The phone is an unlocked Spec B phone, {UEFI_BS_NV_PARTITION_NAME} will be kept in the FFU image for the unlock to work"); - } - - if (isUnlockedSpecA) - { - Logging.Log($"The phone is an UEFI unlocked Spec A phone, {UEFI_BS_NV_PARTITION_NAME} will be kept in the FFU image for the unlock to work"); - } - - List flashParts = []; - - Logging.Log("Partitions with a * appended are ignored partitions"); - Logging.Log(""); - - int maxPartitionNameSize = Partitions.Select(x => x.Name.Length).Max() + 1; - int maxPartitionLastSector = Partitions.Select(x => x.LastSector.ToString().Length).Max() + 1; - - Logging.Log($"{"Name".PadRight(maxPartitionNameSize)} - " + - $"{"First".PadRight(maxPartitionLastSector)} - " + - $"{"Last".PadRight(maxPartitionLastSector)} - " + - $"{"Sectors".PadRight(maxPartitionLastSector)} - " + - $"{"Blocks".PadRight(maxPartitionLastSector)}", - ILoggingLevel.Information); - Logging.Log(""); - - ulong CurrentStartingOffset = 0; - ulong CurrentEndingOffset = 0; - List<(ulong StartOffset, ulong Length)> AllocatedPartitionsMap = []; - - foreach (Partition Partition in Partitions.OrderBy(x => x.FirstSector)) - { - bool IsPartitionExcluded = false; - - if (ExcludedPartitionNames.Any(x => x == Partition.Name)) - { - IsPartitionExcluded = true; - if (isUnlocked && Partition.Name == UEFI_BS_NV_PARTITION_NAME) - { - IsPartitionExcluded = false; - } - - if (isUnlockedSpecA && Partition.Name == UEFI_BS_NV_PARTITION_NAME) - { - IsPartitionExcluded = false; - } - } - - string name = $"{(IsPartitionExcluded ? "*" : "")}{Partition.Name}"; - - Logging.Log($"{name.PadRight(maxPartitionNameSize)} - " + - $"{(Partition.FirstSector + "s").PadRight(maxPartitionLastSector)} - " + - $"{(Partition.LastSector + "s").PadRight(maxPartitionLastSector)} - " + - $"{(Partition.SizeInSectors + "s").PadRight(maxPartitionLastSector)} - " + - $"{((Partition.SizeInSectors / (double)sectorsInABlock) + "c").PadRight(maxPartitionLastSector)}", - IsPartitionExcluded ? ILoggingLevel.Warning : ILoggingLevel.Information); - - ulong CurrentPartitionStartingOffset = Partition.FirstSector * sectorSize; - ulong CurrentPartitionEndingOffset = (Partition.LastSector + 1) * sectorSize; - - if (IsPartitionExcluded) - { - if (AllocatedPartitionsMap.Count != 0) - { - ulong AllocationTotalSizeInBytes = CurrentEndingOffset - CurrentStartingOffset; - (ulong StartOffset, ulong Length)[] AllocatedBlocks = GetBlockAlignedAllocationMap([.. AllocatedPartitionsMap], AllocationTotalSizeInBytes, BlockSize); - - foreach ((ulong StartOffset, ulong Length) in AllocatedBlocks) - { - ulong blockStartOffset = CurrentStartingOffset + StartOffset; - PartialStream blockStream = new(stream, (long)blockStartOffset, (long)(blockStartOffset + Length)); - FlashPart flashPart = new(blockStream, blockStartOffset); - flashParts.Add(flashPart); - } - - AllocatedPartitionsMap.Clear(); - CurrentStartingOffset = 0; - CurrentEndingOffset = 0; - } - } - else - { - // 0 would be the GPT, we can't land in this case here because we deal with partitions - if (CurrentStartingOffset == 0) - { - CurrentStartingOffset = CurrentPartitionStartingOffset; - CurrentEndingOffset = CurrentPartitionEndingOffset; - } - else - { - CurrentEndingOffset = CurrentPartitionEndingOffset; - } - - ulong allocationOffset = CurrentPartitionStartingOffset - CurrentStartingOffset; - - PartialStream partialStream = new(stream, (long)CurrentPartitionStartingOffset, (long)CurrentPartitionEndingOffset); - - /*if (FileSystemAllocationUtils.IsNTFS(partialStream)) - { - (ulong StartOffset, ulong Length)[] AllocatedClusterMap = FileSystemAllocationUtils.GetNTFSAllocatedClustersMap(partialStream); - //AllocatedPartitionsMap.AddRange(AllocatedClusterMap.Select(x => (allocationOffset + x.StartOffset, x.Length))); - - (ulong StartOffset, ulong Length) lastElement = AllocatedClusterMap.MaxBy(x => x.StartOffset); - AllocatedPartitionsMap.Add((allocationOffset, lastElement.StartOffset + lastElement.Length)); - } - else*/ - { - AllocatedPartitionsMap.Add((allocationOffset, Partition.SizeInSectors * sectorSize)); - } - } - } - - if (AllocatedPartitionsMap.Count != 0) - { - (ulong StartOffset, ulong Length)[] AllocatedBlocks = GetBlockAlignedAllocationMap([.. AllocatedPartitionsMap], CurrentStartingOffset - CurrentEndingOffset, BlockSize); - - foreach ((ulong StartOffset, ulong Length) in AllocatedBlocks) - { - ulong blockStartOffset = CurrentStartingOffset + StartOffset; - PartialStream blockStream = new(stream, (long)blockStartOffset, (long)(blockStartOffset + Length)); - FlashPart flashPart = new(blockStream, blockStartOffset); - flashParts.Add(flashPart); - } - - AllocatedPartitionsMap.Clear(); - CurrentStartingOffset = 0; - CurrentEndingOffset = 0; - } - - FlashPart[] finalFlashParts = [.. flashParts]; - - Logging.Log(""); - Logging.Log("Final Flash Parts"); - Logging.Log(""); - PrintFlashParts(finalFlashParts, sectorSize, BlockSize, Logging); - Logging.Log(""); - - foreach (FlashPart flashPart in finalFlashParts) - { - ulong totalSectors = (ulong)flashPart.Stream.Length / sectorSize; - ulong firstSector = flashPart.StartLocation / sectorSize; - ulong lastSector = firstSector + totalSectors - 1; - - if (firstSector % sectorsInABlock != 0) - { - string errorMessage = $"- The stream doesn't start on a Block boundary (Total Sectors: {totalSectors} - First Sector: {firstSector} - Last Sector: {lastSector}) - Overflow: {firstSector % sectorsInABlock}, a Block is {sectorsInABlock} sectors"; - Logging.Log(errorMessage, ILoggingLevel.Error); - throw new Exception(errorMessage); - } - - if ((lastSector + 1) % sectorsInABlock != 0) - { - string errorMessage = $"- The stream doesn't end on a Block boundary (Total Sectors: {totalSectors} - First Sector: {firstSector} - Last Sector: {lastSector}) - Overflow: {(lastSector + 1) % sectorsInABlock}, a Block is {sectorsInABlock} sectors"; - Logging.Log(errorMessage, ILoggingLevel.Error); - throw new Exception(errorMessage); - } - } - - return (finalFlashParts, Partitions); - } - - internal static (ulong StartOffset, ulong Length)[] GetBlockAlignedAllocationMap((ulong StartOffset, ulong Length)[] AllocationMap, ulong TotalSizeInBytes, ulong BlockSize) - { - List<(ulong StartOffset, ulong Length)> AllocatedBlocks = []; - - (ulong MaxStartOffset, ulong MaxLength) = AllocationMap.MaxBy(x => x.StartOffset + x.Length); - ulong MaxEndOffset = MaxStartOffset + MaxLength; - - ulong MaxNumberOfBlocks = (MaxEndOffset / BlockSize) + 1; - - (ulong MinStartOffset, ulong MinLength) = AllocationMap.MinBy(x => x.StartOffset); - ulong MinNumberOfBlocks = MinStartOffset / BlockSize; - - for (ulong CurrentBlockIndex = MinNumberOfBlocks; CurrentBlockIndex < MaxNumberOfBlocks; CurrentBlockIndex++) - { - ulong CurrentBlockStartOffset = CurrentBlockIndex * BlockSize; - ulong CurrentBlockEndOffset = CurrentBlockStartOffset + BlockSize; - - if (AllocationMap.Any(Allocation => (CurrentBlockEndOffset > Allocation.StartOffset) && ((Allocation.StartOffset + Allocation.Length) > CurrentBlockStartOffset))) - { - if (AllocatedBlocks.Count == 0) - { - AllocatedBlocks.Add((CurrentBlockStartOffset, BlockSize)); - } - else - { - (ulong LastStartOffset, ulong LastLength) = AllocatedBlocks[^1]; - if (LastStartOffset + LastLength == CurrentBlockStartOffset) - { - AllocatedBlocks[^1] = (LastStartOffset, LastLength + BlockSize); - } - else - { - AllocatedBlocks.Add((CurrentBlockStartOffset, BlockSize)); - } - } - } - } - - ulong NewAllocationTotalSizeInBytes = AllocatedBlocks[^1].StartOffset + AllocatedBlocks[^1].Length; - - if (NewAllocationTotalSizeInBytes > TotalSizeInBytes) - { - AllocatedBlocks[^1] = (AllocatedBlocks[^1].StartOffset, AllocatedBlocks[^1].Length - (NewAllocationTotalSizeInBytes - TotalSizeInBytes)); - } - - return [.. AllocatedBlocks]; - } - - internal static void PrintFlashParts(FlashPart[] finalFlashParts, uint sectorSize, uint BlockSize, ILogging Logging) - { - for (int i = 0; i < finalFlashParts.Length; i++) - { - FlashPart flashPart = finalFlashParts[i]; - PrintFlashPart(flashPart, sectorSize, BlockSize, $"FlashPart[{i}]", Logging); - } - } - - internal static void PrintFlashPart(FlashPart flashPart, uint sectorSize, uint BlockSize, string name, ILogging Logging) - { - uint sectorsInABlock = BlockSize / sectorSize; - - ulong totalSectors = (ulong)flashPart.Stream.Length / sectorSize; - ulong firstSector = flashPart.StartLocation / sectorSize; - ulong lastSector = firstSector + totalSectors - 1; - - Logging.Log($"{name} - {firstSector}s - {lastSector}s - {totalSectors}s - {totalSectors / (double)sectorsInABlock}c", ILoggingLevel.Information); - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/LoggingHelpers.cs b/Img2Ffu.Library/Writer/LoggingHelpers.cs deleted file mode 100644 index 22e897f..0000000 --- a/Img2Ffu.Library/Writer/LoggingHelpers.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Img2Ffu.Writer -{ - internal static class LoggingHelpers - { - internal static string GetDismLikeProgBar(int perc) - { - int eqsLength = (int)((double)perc / 100 * 55); - string bases = new string('=', eqsLength) + new string(' ', 55 - eqsLength); - bases = bases.Insert(28, perc + "%"); - if (perc == 100) - { - bases = bases[1..]; - } - else if (perc < 10) - { - bases = bases.Insert(28, " "); - } - - return $"[{bases}]"; - } - } -} diff --git a/Img2Ffu.Library/Writer/Manifest/FullFlashManifest.cs b/Img2Ffu.Library/Writer/Manifest/FullFlashManifest.cs deleted file mode 100644 index d84a82e..0000000 --- a/Img2Ffu.Library/Writer/Manifest/FullFlashManifest.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -namespace Img2Ffu.Writer.Manifest -{ - internal class FullFlashManifest - { - public required string OSVersion; - public string AntiTheftVersion = "1.1"; // Allow flashing on all devices - public string Description = "Update on: " + DateTime.Now.ToString("u") + "::\r\n"; - - public string StateSeparationLevel = "0"; - public string UEFI = "True"; - public string Version = "2.0"; - public required string DevicePlatformId3; - public required string DevicePlatformId2; - public required string DevicePlatformId1; - public required string DevicePlatformId0; - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Manifest/ManifestIni.cs b/Img2Ffu.Library/Writer/Manifest/ManifestIni.cs deleted file mode 100644 index a841bec..0000000 --- a/Img2Ffu.Library/Writer/Manifest/ManifestIni.cs +++ /dev/null @@ -1,198 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -namespace Img2Ffu.Writer.Manifest -{ - internal class ManifestIni - { - internal static string BuildUpFullFlashSection(FullFlashManifest fullFlash) - { - string FullFlashSection = "[FullFlash]\r\n"; - - if (!string.IsNullOrEmpty(fullFlash.OSVersion)) - { - FullFlashSection += $"OSVersion = {fullFlash.OSVersion}\r\n"; - } - - if (!string.IsNullOrEmpty(fullFlash.AntiTheftVersion)) - { - FullFlashSection += $"AntiTheftVersion = {fullFlash.AntiTheftVersion}\r\n"; - } - - if (!string.IsNullOrEmpty(fullFlash.Description)) - { - FullFlashSection += $"Description = {fullFlash.Description}\r\n"; - } - - FullFlashSection += "\r\n"; - - if (!string.IsNullOrEmpty(fullFlash.StateSeparationLevel)) - { - FullFlashSection += $"StateSeparationLevel = {fullFlash.StateSeparationLevel}\r\n"; - } - - if (!string.IsNullOrEmpty(fullFlash.UEFI)) - { - FullFlashSection += $"UEFI = {fullFlash.UEFI}\r\n"; - } - - if (!string.IsNullOrEmpty(fullFlash.Version)) - { - FullFlashSection += $"Version = {fullFlash.Version}\r\n"; - } - - if (!string.IsNullOrEmpty(fullFlash.DevicePlatformId3)) - { - FullFlashSection += $"DevicePlatformId3 = {fullFlash.DevicePlatformId3}\r\n"; - } - - if (!string.IsNullOrEmpty(fullFlash.DevicePlatformId2)) - { - FullFlashSection += $"DevicePlatformId2 = {fullFlash.DevicePlatformId2}\r\n"; - } - - if (!string.IsNullOrEmpty(fullFlash.DevicePlatformId1)) - { - FullFlashSection += $"DevicePlatformId1 = {fullFlash.DevicePlatformId1}\r\n"; - } - - if (!string.IsNullOrEmpty(fullFlash.DevicePlatformId0)) - { - FullFlashSection += $"DevicePlatformId0 = {fullFlash.DevicePlatformId0}\r\n"; - } - - FullFlashSection += "\r\n"; - - return FullFlashSection; - } - - internal static string BuildUpStoreSection(StoreManifest store) - { - string StoreSection = "[Store]\r\n"; - StoreSection += $"OnlyAllocateDefinedGptEntries = False\r\n"; - StoreSection += $"StoreId = {{5a585bae-900b-41b5-b736-a4cecffc34b4}}\r\n"; - StoreSection += $"IsMainOSStore = False\r\n"; - StoreSection += $"DevicePath = VenHw(860845C1-BE09-4355-8BC1-30D64FF8E63A)\r\n"; - StoreSection += $"StoreType = Default\r\n"; - StoreSection += $"MinSectorCount = {store.MinSectorCount}\r\n"; - StoreSection += $"SectorSize = {store.SectorSize}\r\n"; - StoreSection += "\r\n"; - return StoreSection; - } - - internal static string BuildUpPartitionSection(PartitionManifest partition) - { - string PartitionSection = "[Partition]\r\n"; - - if (partition.ByteAlignment.HasValue) - { - PartitionSection += $"ByteAlignment = {partition.ByteAlignment.Value}\r\n"; - } - - if (!string.IsNullOrEmpty(partition.FileSystem)) - { - PartitionSection += $"FileSystem = {partition.FileSystem}\r\n"; - } - - PartitionSection += $"UsedSectors = {partition.UsedSectors}\r\n"; - - if (partition.UseAllSpace.HasValue) - { - PartitionSection += $"UseAllSpace = {(partition.UseAllSpace.Value ? "True" : "False")}\r\n"; - } - - if (partition.Type != null) - { - PartitionSection += $"Type = {{{partition.Type.Value.ToString().ToUpper()}}}\r\n"; - } - - PartitionSection += $"TotalSectors = {partition.TotalSectors}\r\n"; - - if (partition.RequiredToFlash.HasValue) - { - PartitionSection += $"RequiredToFlash = {(partition.RequiredToFlash.Value ? "True" : "False")}\r\n"; - } - - if (!string.IsNullOrEmpty(partition.Primary)) - { - PartitionSection += $"Primary = {partition.Primary}\r\n"; - } - - if (!string.IsNullOrEmpty(partition.Name)) - { - PartitionSection += $"Name = {partition.Name}\r\n"; - } - - if (partition.ClusterSize.HasValue) - { - PartitionSection += $"ClusterSize = {partition.ClusterSize.Value}\r\n"; - } - - PartitionSection += "\r\n"; - - return PartitionSection; - } - - internal static string BuildUpStoragePoolSection() - { - string StoragePoolSection = "[StoragePool]\r\n"; - StoragePoolSection += "Name = OSPool\r\n"; - StoragePoolSection += "\r\n"; - return StoragePoolSection; - } - - internal static string BuildUpManifest(FullFlashManifest fullFlash, StoreManifest store, List partitions) - { - string Manifest = ""; - - Manifest += BuildUpFullFlashSection(fullFlash); - Manifest += BuildUpStoragePoolSection(); - Manifest += BuildUpStoreSection(store); - - foreach (PartitionManifest partition in partitions) - { - Manifest += BuildUpPartitionSection(partition); - } - - return Manifest; - } - - internal static List GPTPartitionsToPartitions(List partitions) - { - List Parts = []; - - // TODO: implement more - foreach (GPT.Partition part in partitions) - { - Parts.Add(new PartitionManifest() { Name = part.Name, TotalSectors = (uint)part.SizeInSectors, UsedSectors = (uint)part.SizeInSectors, RequiredToFlash = true, Type = part.PartitionTypeGuid }); - } - - return Parts; - } - - internal static string BuildUpManifest(FullFlashManifest fullFlash, StoreManifest store, List partitions) - { - return BuildUpManifest(fullFlash, store, GPTPartitionsToPartitions(partitions)); - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Manifest/PartitionManifest.cs b/Img2Ffu.Library/Writer/Manifest/PartitionManifest.cs deleted file mode 100644 index 343831d..0000000 --- a/Img2Ffu.Library/Writer/Manifest/PartitionManifest.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -namespace Img2Ffu.Writer.Manifest -{ - internal class PartitionManifest - { - public bool? RequiredToFlash; - public uint UsedSectors; - public Guid? Type; - public uint TotalSectors; - public string Primary; - public required string Name; - public string FileSystem; - public uint? ByteAlignment; - public uint? ClusterSize; - public bool? UseAllSpace; - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Manifest/StoreManifest.cs b/Img2Ffu.Library/Writer/Manifest/StoreManifest.cs deleted file mode 100644 index cca9ff1..0000000 --- a/Img2Ffu.Library/Writer/Manifest/StoreManifest.cs +++ /dev/null @@ -1,31 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -namespace Img2Ffu.Writer.Manifest -{ - internal class StoreManifest - { - public uint SectorSize; - public uint MinSectorCount; - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Streams/DISK_GEOMETRY.cs b/Img2Ffu.Library/Writer/Streams/DISK_GEOMETRY.cs deleted file mode 100644 index 9faa171..0000000 --- a/Img2Ffu.Library/Writer/Streams/DISK_GEOMETRY.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 -Copyright (c) 2018, Proto Beta Test - protobetatest.com - @ProtoBetaTest - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Streams -{ - public partial class DeviceStream - { - [StructLayout(LayoutKind.Sequential)] - private struct DISK_GEOMETRY - { - internal long Cylinders; - internal MEDIA_TYPE MediaType; - internal uint TracksPerCylinder; - internal uint SectorsPerTrack; - internal uint BytesPerSector; - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Streams/DISK_GEOMETRY_EX.cs b/Img2Ffu.Library/Writer/Streams/DISK_GEOMETRY_EX.cs deleted file mode 100644 index 53f93ce..0000000 --- a/Img2Ffu.Library/Writer/Streams/DISK_GEOMETRY_EX.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 -Copyright (c) 2018, Proto Beta Test - protobetatest.com - @ProtoBetaTest - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using System.Runtime.InteropServices; - -namespace Img2Ffu.Streams -{ - public partial class DeviceStream - { - [StructLayout(LayoutKind.Sequential)] - private struct DISK_GEOMETRY_EX - { - internal DISK_GEOMETRY Geometry; - internal long DiskSize; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - internal byte[] Data; - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Streams/DeviceStream.cs b/Img2Ffu.Library/Writer/Streams/DeviceStream.cs deleted file mode 100644 index 7a5439d..0000000 --- a/Img2Ffu.Library/Writer/Streams/DeviceStream.cs +++ /dev/null @@ -1,373 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 -Copyright (c) 2018, Proto Beta Test - protobetatest.com - @ProtoBetaTest - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -using Microsoft.Win32.SafeHandles; -using System.ComponentModel; -using System.Runtime.InteropServices; - -namespace Img2Ffu.Streams -{ - public partial class DeviceStream : Stream - { - private const uint GENERIC_READ = 0x80000000; - private const uint GENERIC_WRITE = 0x40000000; - - private const uint OPEN_EXISTING = 3; - private const uint FILE_ATTRIBUTE_DEVICE = 0x40; - private const uint FILE_FLAG_NO_BUFFERING = 0x20000000; - private const uint FILE_FLAG_WRITE_THROUGH = 0x80000000; - private const uint DISK_BASE = 7; - - private const uint FILE_ANY_ACCESS = 0; - private const uint FILE_SHARE_READ = 1; - private const uint FILE_SHARE_WRITE = 2; - - private const uint FILE_DEVICE_FILE_SYSTEM = 9; - private const uint METHOD_BUFFERED = 0; - - private static readonly uint DISK_GET_DRIVE_GEOMETRY_EX = CTL_CODE(DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS); - private static readonly uint FSCTL_LOCK_VOLUME = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS); - private static readonly uint FSCTL_UNLOCK_VOLUME = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS); - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern nint CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, nint lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, nint hTemplateFile); - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool ReadFile(nint hFile, byte[] lpBuffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, nint lpOverlapped); - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool WriteFile(nint hFile, byte[] lpBuffer, int nNumberOfBytesToWrite, ref int lpNumberOfBytesWritten, nint lpOverlapped); - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern uint DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, nint lpInBuffer, uint nInBufferSize, nint lpOutBuffer, int nOutBufferSize, ref uint lpBytesReturned, nint lpOverlapped); - - [DllImport("kernel32.dll")] - private static extern bool SetFilePointerEx(SafeFileHandle hFile, long liDistanceToMove, out long lpNewFilePointer, uint dwMoveMethod); - - private SafeFileHandle? handleValue = null; - private long _Position = 0; - private readonly long _length = 0; - private readonly uint _sectorsize = 0; - private readonly bool _canWrite = false; - private readonly bool _canRead = false; - private bool disposed = false; - - private static uint CTL_CODE(uint DeviceType, uint Function, uint Method, uint Access) - { - return (DeviceType << 16) | (Access << 14) | (Function << 2) | Method; - } - - public DeviceStream(string device, FileAccess access) - { - if (string.IsNullOrEmpty(device)) - { - throw new ArgumentNullException(nameof(device)); - } - - uint fileAccess = 0; - switch (access) - { - case FileAccess.Read: - fileAccess = GENERIC_READ; - _canRead = true; - break; - case FileAccess.ReadWrite: - fileAccess = GENERIC_READ | GENERIC_WRITE; - _canRead = true; - _canWrite = true; - break; - case FileAccess.Write: - fileAccess = GENERIC_WRITE; - _canWrite = true; - break; - } - - string devicePath = @"\\.\PhysicalDrive" + device.ToLower().Replace(@"\\.\physicaldrive", ""); - - (_length, _sectorsize) = GetDiskProperties(devicePath); - - nint ptr = CreateFile(devicePath, fileAccess, 0, nint.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_DEVICE | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, nint.Zero); - handleValue = new SafeFileHandle(ptr, true); - - if (handleValue.IsInvalid) - { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - } - - uint lpBytesReturned = 0; - uint result = DeviceIoControl(handleValue, FSCTL_LOCK_VOLUME, nint.Zero, 0, nint.Zero, 0, ref lpBytesReturned, nint.Zero); - - if (result == 0) - { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - } - } - - public override bool CanRead => _canRead; - - public override bool CanSeek => true; - - public override bool CanWrite => _canWrite; - - public override void Flush() - { - return; - } - - public override long Length => _length; - - public override long Position - { - get => _Position; - set => Seek(value, SeekOrigin.Begin); - } - - /// - /// - /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and - /// (offset + count - 1) replaced by the bytes read from the current source. - /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. - /// The maximum number of bytes to be read from the current stream. - /// - private int InternalRead(byte[] buffer, int offset, int count) - { - int BytesRead = 0; - byte[] BufBytes = new byte[count]; - if (!ReadFile(handleValue.DangerousGetHandle(), BufBytes, count, ref BytesRead, nint.Zero)) - { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - } - for (int i = 0; i < BytesRead; i++) - { - buffer[offset + i] = BufBytes[i]; - } - - _Position += count; - - return BytesRead; - } - - /// - /// Some devices cannot read portions that are not modulo a sector, this aims to fix that issue. - /// - /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and - /// (offset + count - 1) replaced by the bytes read from the current source. - /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. - /// The maximum number of bytes to be read from the current stream. - /// - public override int Read(byte[] buffer, int offset, int count) - { - if (count % _sectorsize != 0) - { - long extrastart = Position % _sectorsize; - if (extrastart != 0) - { - _ = Seek(-extrastart, SeekOrigin.Current); - } - - long addedcount = _sectorsize - (count % _sectorsize); - long ncount = count + addedcount; - byte[] tmpbuffer = new byte[extrastart + buffer.Length + addedcount]; - buffer.CopyTo(tmpbuffer, extrastart); - _ = InternalRead(tmpbuffer, offset + (int)extrastart, (int)ncount); - tmpbuffer.ToList().Skip((int)extrastart).Take(count + offset).ToArray().CopyTo(buffer, 0); - return count; - } - - return InternalRead(buffer, offset, count); - } - - public override int ReadByte() - { - int BytesRead = 0; - byte[] lpBuffer = new byte[1]; - if (!ReadFile( - handleValue.DangerousGetHandle(), // handle to file - lpBuffer, // data buffer - 1, // number of bytes to read - ref BytesRead, // number of bytes read - nint.Zero - )) - { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - ; - } - - _Position += 1; - - return lpBuffer[0]; - } - - public override void WriteByte(byte Byte) - { - int BytesWritten = 0; - byte[] lpBuffer = [Byte]; - if (!WriteFile( - handleValue.DangerousGetHandle(), // handle to file - lpBuffer, // data buffer - 1, // number of bytes to write - ref BytesWritten, // number of bytes written - nint.Zero - )) - { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - ; - } - - _Position += 1; - } - - public override long Seek(long offset, SeekOrigin origin) - { - long off = offset; - - switch (origin) - { - case SeekOrigin.Current: - off += _Position; - break; - case SeekOrigin.End: - off += _length; - break; - } - - if (!SetFilePointerEx(handleValue, off, out long ret, 0)) - { - return _Position; - } - - _Position = ret; - - return ret; - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - int BytesWritten = 0; - byte[] BufBytes = new byte[count]; - for (int i = 0; i < count; i++) - { - BufBytes[offset + i] = buffer[i]; - } - - if (!WriteFile(handleValue.DangerousGetHandle(), BufBytes, count, ref BytesWritten, nint.Zero)) - { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - } - - _Position += count; - } - - public override void Close() - { - uint lpBytesReturned = 0; - uint result = DeviceIoControl(handleValue, FSCTL_UNLOCK_VOLUME, nint.Zero, 0, nint.Zero, 0, ref lpBytesReturned, nint.Zero); - - if (0 == result) - { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - } - - handleValue.Close(); - handleValue.Dispose(); - handleValue = null; - base.Close(); - } - - private new void Dispose() - { - Dispose(true); - base.Dispose(); - GC.SuppressFinalize(this); - } - - private new void Dispose(bool disposing) - { - // Check to see if Dispose has already been called. - if (!disposed) - { - if (disposing) - { - if (handleValue != null) - { - uint lpBytesReturned = 0; - uint result = DeviceIoControl(handleValue, FSCTL_UNLOCK_VOLUME, nint.Zero, 0, nint.Zero, 0, ref lpBytesReturned, nint.Zero); - - if (0 == result) - { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - } - - handleValue.Close(); - handleValue.Dispose(); - handleValue = null; - } - } - // Note disposing has been done. - disposed = true; - } - } - - private static (long, uint) GetDiskProperties(string deviceName) - { - DISK_GEOMETRY_EX x = new(); - Execute(ref x, DISK_GET_DRIVE_GEOMETRY_EX, deviceName); - return (x.DiskSize, x.Geometry.BytesPerSector); - } - - private static void Execute(ref T x, uint dwIoControlCode, string lpFileName, uint dwDesiredAccess = GENERIC_READ, uint dwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ, nint lpSecurityAttributes = default, uint dwCreationDisposition = OPEN_EXISTING, uint dwFlagsAndAttributes = 0, nint hTemplateFile = default) - { - nint hDevice = CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - - SafeFileHandle handleValue = new(hDevice, true); - - if (handleValue.IsInvalid) - { - throw new Win32Exception(Marshal.GetLastWin32Error()); - } - - int nOutBufferSize = Marshal.SizeOf(typeof(T)); - nint lpOutBuffer = Marshal.AllocHGlobal(nOutBufferSize); - uint lpBytesReturned = default; - - uint result = DeviceIoControl(handleValue, dwIoControlCode, nint.Zero, 0, lpOutBuffer, nOutBufferSize, ref lpBytesReturned, nint.Zero); - - if (result == 0) - { - throw new Win32Exception(Marshal.GetLastWin32Error()); - } - - x = (T)Marshal.PtrToStructure(lpOutBuffer, typeof(T)); - Marshal.FreeHGlobal(lpOutBuffer); - - handleValue.Close(); - handleValue.Dispose(); - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Streams/MEDIA_TYPE.cs b/Img2Ffu.Library/Writer/Streams/MEDIA_TYPE.cs deleted file mode 100644 index 4cd5852..0000000 --- a/Img2Ffu.Library/Writer/Streams/MEDIA_TYPE.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 -Copyright (c) 2018, Proto Beta Test - protobetatest.com - @ProtoBetaTest - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -namespace Img2Ffu.Streams -{ - public partial class DeviceStream - { - private enum MEDIA_TYPE : int - { - Unknown = 0, - F5_1Pt2_512 = 1, - F3_1Pt44_512 = 2, - F3_2Pt88_512 = 3, - F3_20Pt8_512 = 4, - F3_720_512 = 5, - F5_360_512 = 6, - F5_320_512 = 7, - F5_320_1024 = 8, - F5_180_512 = 9, - F5_160_512 = 10, - RemovableMedia = 11, - FixedMedia = 12, - F3_120M_512 = 13, - F3_640_512 = 14, - F5_640_512 = 15, - F5_720_512 = 16, - F3_1Pt2_512 = 17, - F3_1Pt23_1024 = 18, - F5_1Pt23_1024 = 19, - F3_128Mb_512 = 20, - F3_230Mb_512 = 21, - F8_256_128 = 22, - F3_200Mb_512 = 23, - F3_240M_512 = 24, - F3_32M_512 = 25 - } - } -} \ No newline at end of file diff --git a/Img2Ffu.Library/Writer/Streams/PartialStream.cs b/Img2Ffu.Library/Writer/Streams/PartialStream.cs deleted file mode 100644 index 9b4140c..0000000 --- a/Img2Ffu.Library/Writer/Streams/PartialStream.cs +++ /dev/null @@ -1,111 +0,0 @@ -/* - -Copyright (c) 2019, Gustave Monce - gus33000.me - @gus33000 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ -namespace Img2Ffu.Writer.Streams -{ - internal class PartialStream : Stream - { - private Stream? innerStream; - - private bool disposed; - private readonly long startOffset; - private readonly long endOffset; - - public PartialStream(Stream stream, long StartOffset, long EndOffset) - { - _ = stream.Seek(StartOffset, SeekOrigin.Begin); - startOffset = StartOffset; - endOffset = EndOffset; - innerStream = stream; - } - - public override bool CanRead => innerStream.CanRead; - public override bool CanSeek => innerStream.CanSeek; - public override bool CanWrite => innerStream.CanWrite; - public override long Length => endOffset - startOffset; - public override long Position - { - get => innerStream.Position - startOffset; set => innerStream.Position = value + startOffset; - } - - public override void Flush() - { - innerStream.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return innerStream.Read(buffer, offset, count); - } - - public override long Seek(long offset, SeekOrigin origin) - { - return origin == SeekOrigin.Begin - ? innerStream.Seek(offset + startOffset, origin) - : origin == SeekOrigin.End ? innerStream.Seek(endOffset + offset, origin) : innerStream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - innerStream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - innerStream.Write(buffer, offset, count); - } - - public override void Close() - { - innerStream.Dispose(); - innerStream = null; - base.Close(); - } - - private new void Dispose() - { - Dispose(true); - base.Dispose(); - GC.SuppressFinalize(this); - } - - private new void Dispose(bool disposing) - { - // Check to see if Dispose has already been called. - if (!disposed) - { - if (disposing) - { - if (innerStream != null) - { - innerStream.Dispose(); - innerStream = null; - } - } - - // Note disposing has been done. - disposed = true; - } - } - } -} \ No newline at end of file