I'm writing a little C# appx package editor (appx is basically a zip file containing a bunch of XML metadata files).
In order to make a valid appx file, I need to create a block map file (XML) that contains for each file two attributes : hash and size as explained here (https://learn.microsoft.com/en-us/uwp/schemas/blockmapschema/element-block)
Hash represent a 64kb uncompressed chunk of a file. Size represent the size of that chunk after being compressed (deflate algorithm). Here is what I wrote so far as proof of concept :
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
namespace StreamTest
{
class Program
{
static void Main(string[] args)
{
using (var srcFile = File.OpenRead(@"C:\Test\sample.txt"))
{
ZipAndHash(srcFile);
}
Console.ReadLine();
}
static void ZipAndHash(Stream inStream)
{
const int blockSize = 65536; //64KB
var uncompressedBuffer = new byte[blockSize];
int bytesRead;
int totalBytesRead = 0;
//Create a ZIP file
using (FileStream zipStream = new FileStream(@"C:\Test\test.zip", FileMode.Create))
{
using (ZipArchive zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Create))
{
using (BinaryWriter zipWriter = new BinaryWriter(zipArchive.CreateEntry("test.txt").Open()))
{
//Read stream with a 64kb buffer
while ((bytesRead = inStream.Read(uncompressedBuffer, 0, uncompressedBuffer.Length)) > 0)
{
totalBytesRead = totalBytesRead + bytesRead;
//Compress current block to the Zip entry
if (uncompressedBuffer.Length == bytesRead)
{
//Hash each 64kb block before compression
hashBlock(uncompressedBuffer);
//Compress
zipWriter.Write(uncompressedBuffer);
}
else
{
//Hash remaining bytes and compress
hashBlock(uncompressedBuffer.Take(bytesRead).ToArray());
zipWriter.Write(uncompressedBuffer.Take(bytesRead).ToArray());
}
}
//How to obtain the size of the compressed block after invoking zipWriter.Write() ?
Console.WriteLine($"total bytes : {totalBytesRead}");
}
}
}
}
private static void hashBlock(byte[] uncompressedBuffer)
{
// hash the block
}
}
}
I can easily get the hash attribute by using a 64kb buffer while reading a stream, my question is :
How do I obtain the compressed size of each 64kb block after using zipWrite.Write(), is it even possible with System.IO.Compression or should I use something else ?