2023-08-27 21:27:15 +02:00
|
|
|
using System;
|
2023-08-26 22:11:08 +02:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Runtime.InteropServices;
|
2023-08-27 21:27:15 +02:00
|
|
|
using System.Text;
|
2023-08-26 22:11:08 +02:00
|
|
|
|
|
|
|
|
namespace Microsoft.WindowsPhone.Imaging
|
|
|
|
|
{
|
2023-08-27 20:48:25 +02:00
|
|
|
public class FullFlashUpdateImage
|
|
|
|
|
{
|
2023-08-27 21:27:15 +02:00
|
|
|
private readonly Stream imageStream;
|
|
|
|
|
|
|
|
|
|
public FullFlashUpdateImage(Stream imageStream)
|
2023-08-27 20:48:25 +02:00
|
|
|
{
|
2023-08-27 21:27:15 +02:00
|
|
|
this.imageStream = imageStream;
|
|
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
_ffuStoragePools = new List<FullFlashUpdateStoragePool>();
|
|
|
|
|
_ffuStores = new List<FullFlashUpdateStore>();
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 21:27:15 +02:00
|
|
|
using BinaryReader binaryReader = new(imageStream, Encoding.UTF8, true);
|
2023-08-27 20:48:25 +02:00
|
|
|
uint num = binaryReader.ReadUInt32();
|
|
|
|
|
byte[] signature = binaryReader.ReadBytes(12);
|
|
|
|
|
if (num != FullFlashUpdateHeaders.SecurityHeaderSize || !SecurityHeader.ValidateSignature(signature))
|
|
|
|
|
{
|
|
|
|
|
throw new ImageCommonException(CodeSite.StorageService, ErrorCategory.BadContent, "Unable to load image because the security header is invalid.");
|
|
|
|
|
}
|
|
|
|
|
_securityHeader.ByteCount = num;
|
|
|
|
|
_securityHeader.ChunkSize = binaryReader.ReadUInt32();
|
|
|
|
|
_securityHeader.HashAlgorithmID = binaryReader.ReadUInt32();
|
|
|
|
|
_securityHeader.CatalogSize = binaryReader.ReadUInt32();
|
|
|
|
|
_securityHeader.HashTableSize = binaryReader.ReadUInt32();
|
|
|
|
|
CatalogData = binaryReader.ReadBytes((int)_securityHeader.CatalogSize);
|
|
|
|
|
HashTableData = binaryReader.ReadBytes((int)_securityHeader.HashTableSize);
|
|
|
|
|
_ = binaryReader.ReadBytes((int)SecurityPadding);
|
|
|
|
|
num = binaryReader.ReadUInt32();
|
|
|
|
|
signature = binaryReader.ReadBytes(12);
|
|
|
|
|
if ((num != FullFlashUpdateHeaders.ImageHeaderSize && num != FullFlashUpdateHeaders.ImageHeaderExSize) || !ImageHeader.ValidateSignature(signature))
|
|
|
|
|
{
|
|
|
|
|
throw new ImageCommonException(CodeSite.StorageService, ErrorCategory.BadContent, "Unable to load image because the image header is invalid.");
|
|
|
|
|
}
|
|
|
|
|
_imageHeader.ByteCount = num;
|
|
|
|
|
_imageHeader.ManifestLength = binaryReader.ReadUInt32();
|
|
|
|
|
_imageHeader.ChunkSize = binaryReader.ReadUInt32();
|
|
|
|
|
_imageHeader.NumberOfDeviceTargetingIds = num == FullFlashUpdateHeaders.ImageHeaderSize ? 0U : binaryReader.ReadUInt32();
|
|
|
|
|
Manifest = new FullFlashUpdateManifest(this, binaryReader.ReadBytes((int)_imageHeader.ManifestLength));
|
|
|
|
|
Manifest.Validate("2.0");
|
|
|
|
|
if (_imageHeader.ChunkSize > 0U)
|
|
|
|
|
{
|
|
|
|
|
_ = binaryReader.ReadBytes((int)CalculateAlignment((uint)imageStream.Position, _imageHeader.ChunkSize * 1024U));
|
|
|
|
|
}
|
|
|
|
|
_payloadOffset = imageStream.Position;
|
|
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 21:27:15 +02:00
|
|
|
public Stream GetImageStream()
|
2023-08-27 20:48:25 +02:00
|
|
|
{
|
2023-08-27 21:27:15 +02:00
|
|
|
imageStream.Position = _payloadOffset;
|
|
|
|
|
return imageStream;
|
2023-08-27 20:48:25 +02:00
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
internal void AddStoragePool(ManifestCategory A_1)
|
|
|
|
|
{
|
|
|
|
|
if (A_1 == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException("category");
|
|
|
|
|
}
|
|
|
|
|
_ffuStoragePools.Add(new FullFlashUpdateStoragePool(this, A_1));
|
|
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
internal void AddStore(ManifestCategory A_1)
|
|
|
|
|
{
|
|
|
|
|
if (A_1 == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException("category");
|
|
|
|
|
}
|
|
|
|
|
_ffuStores.Add(new FullFlashUpdateStore(this, null, A_1));
|
|
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public static int ImageHeaderSize => Marshal.SizeOf(new ImageHeader());
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public static int ImageHeaderExSize => Marshal.SizeOf(new ImageHeaderEx());
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public byte[] CatalogData
|
|
|
|
|
{
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public byte[] HashTableData
|
|
|
|
|
{
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public List<FullFlashUpdateStoragePool> StoragePools => new(_ffuStoragePools);
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public List<FullFlashUpdateStore> Stores => new(_ffuStores);
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public int StoreCount => Stores.Count;
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public FullFlashUpdateManifest Manifest
|
|
|
|
|
{
|
|
|
|
|
get; private set;
|
|
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
internal uint SecurityPadding
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
uint num = 1024U;
|
|
|
|
|
if (_imageHeader.ChunkSize != 0U)
|
|
|
|
|
{
|
|
|
|
|
num *= _imageHeader.ChunkSize;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (_securityHeader.ChunkSize == 0U)
|
|
|
|
|
{
|
|
|
|
|
throw new ImageCommonException(CodeSite.StorageService, ErrorCategory.BadContent, "Neither the of the headers have been initialized with a chunk size.");
|
|
|
|
|
}
|
|
|
|
|
num *= _securityHeader.ChunkSize;
|
|
|
|
|
}
|
|
|
|
|
return CalculateAlignment(FullFlashUpdateHeaders.SecurityHeaderSize + (uint)(CatalogData != null ? CatalogData.Length : 0) + (uint)(HashTableData != null ? HashTableData.Length : 0), num);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
private uint CalculateAlignment(uint A_1, uint A_2)
|
|
|
|
|
{
|
|
|
|
|
uint result = 0U;
|
|
|
|
|
uint num = A_1 % A_2;
|
|
|
|
|
if (num > 0U)
|
|
|
|
|
{
|
|
|
|
|
result = A_2 - num;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public static readonly uint PartitionTypeMbr = 0U;
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
public static readonly uint PartitionTypeGpt = 1U;
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
private readonly List<FullFlashUpdateStoragePool> _ffuStoragePools;
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
private readonly List<FullFlashUpdateStore> _ffuStores;
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
private readonly long _payloadOffset;
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
private readonly ImageHeaderEx _imageHeader = new();
|
2023-08-26 22:11:08 +02:00
|
|
|
|
2023-08-27 20:48:25 +02:00
|
|
|
private SecurityHeader _securityHeader;
|
|
|
|
|
}
|
2023-08-26 22:11:08 +02:00
|
|
|
}
|