1
0
mirror of https://github.com/chylex/Brotli-Builder.git synced 2024-10-21 23:42:48 +02:00
Brotli-Builder/BrotliLib/Brotli/Components/MetaBlock.Type.PaddedEmpty.cs

115 lines
4.5 KiB
C#

using System;
using BrotliLib.Brotli.Components.Header;
using BrotliLib.Collections;
using BrotliLib.Markers;
using BrotliLib.Markers.Serialization;
using BrotliLib.Markers.Types;
using BrotliLib.Serialization;
namespace BrotliLib.Brotli.Components{
partial class MetaBlock{
/// <inheritdoc />
/// <summary>
/// <code>ISLAST = 0, MLEN = 0</code>
/// </summary>
public class PaddedEmpty : MetaBlock{
private const int MaxLengthDescriptionBytes = 3;
private const int MaxSkippableBytes = 1 << (8 * MaxLengthDescriptionBytes);
private static int CalculateBytesRequired(int hiddenBytes){
if (hiddenBytes < 0){
throw new ArgumentOutOfRangeException(nameof(hiddenBytes), "The amount of bytes must be at least 0.");
}
else if (hiddenBytes == 0){
return 0;
}
for(int bytes = 1; bytes <= MaxLengthDescriptionBytes; bytes++){
int maxValue = 1 << (8 * bytes);
if (hiddenBytes <= maxValue){
return bytes;
}
}
throw new ArgumentOutOfRangeException(nameof(hiddenBytes), "The amount of bytes (" + hiddenBytes + ") cannot be expressed with at most " + MaxLengthDescriptionBytes + " bytes.");
}
// Instance
public byte[] HiddenData => CollectionHelper.Clone(hiddenData);
public int HiddenDataLength => hiddenData.Length;
private readonly byte[] hiddenData;
public PaddedEmpty(byte[] hiddenData) : base(DataLength.Empty){
if (hiddenData.Length > MaxSkippableBytes){
throw new ArgumentOutOfRangeException(nameof(hiddenData), "The hidden data length must be at most " + MaxSkippableBytes + " bytes.");
}
this.hiddenData = CollectionHelper.Clone(hiddenData);
}
public override void Decompress(BrotliGlobalState state){}
public override bool Equals(object obj){
return obj is PaddedEmpty other &&
base.Equals(other) &&
CollectionHelper.Equal(hiddenData, other.hiddenData);
}
public override int GetHashCode(){
return HashCode.Combine(ParentHashCode(), CollectionHelper.HashCode(hiddenData));
}
// Serialization
internal new static readonly BitDeserializer<PaddedEmpty, NoContext> Deserialize = MarkedBitDeserializer.Title<PaddedEmpty, NoContext>(
"Contents",
(reader, context) => {
if (reader.NextBit("reserved")){
throw new InvalidOperationException("Reserved bit in empty meta-block must be 0.");
}
int skipDescriptionBytes = reader.NextChunk(2, "MSKIPBYTES");
int skipLength = (skipDescriptionBytes == 0) ? 0 : reader.NextChunk(8 * skipDescriptionBytes, "MSKIPLEN", value => 1 + value);
byte[] bytes = new byte[skipLength];
reader.AlignToByteBoundary();
reader.MarkStart();
if (reader.MarkerLevel == MarkerLevel.Verbose){
for(int index = 0; index < skipLength; index++){
bytes[index] = reader.NextAlignedByte("byte");
}
reader.MarkEndTitle("Skipped Bytes");
}
else{
for(int index = 0; index < skipLength; index++){
bytes[index] = reader.NextAlignedByte();
}
reader.MarkEnd(new TextMarker("(" + skipLength + " skipped byte" + (skipLength == 1 ? ")" : "s)")));
}
return new PaddedEmpty(bytes);
}
);
internal new static readonly BitSerializer<PaddedEmpty, NoContext> Serialize = (writer, obj, context) => {
writer.WriteBit(false);
byte[] bytes = obj.hiddenData;
int lengthDescriptionBytes = CalculateBytesRequired(bytes.Length);
writer.WriteChunk(2, lengthDescriptionBytes);
writer.WriteChunk(8 * lengthDescriptionBytes, bytes.Length - 1);
writer.WriteAlignedBytes(bytes);
};
}
}
}