1
0
mirror of https://github.com/chylex/Brotli-Builder.git synced 2025-08-16 12:31:46 +02:00
Files
.github
BrotliBuilder
BrotliCalc
BrotliImpl
BrotliLib
Brotli
Components
Compressed
Data
BlockLengthCode.cs
BlockSwitchCommand.cs
BlockSwitchTracker.cs
BlockTypeCode.cs
DistanceCode.Type.Complex.cs
DistanceCode.Type.Direct.cs
DistanceCode.Type.Last.cs
DistanceCode.cs
DistanceInfo.cs
InsertCopyCommand.cs
InsertCopyLengthCode.cs
InsertCopyLengths.cs
Literal.cs
Header
MetaBlock.Type.Compressed.cs
MetaBlock.Type.LastEmpty.cs
MetaBlock.Type.PaddedEmpty.cs
MetaBlock.Type.Uncompressed.cs
MetaBlock.cs
WindowSize.cs
Dictionary
Encode
Output
Parameters
Streaming
Utils
BrotliFileStructure.cs
BrotliGlobalState.cs
Collections
Markers
Numbers
Serialization
BrotliLib.csproj
LICENSE-BROTLI.txt
Paper
UnitTests
.gitignore
BrotliBuilder.sln
LICENSE
README.md

123 lines
5.1 KiB
C#

using System;
using System.Linq;
using BrotliLib.Brotli.Components.Header;
using BrotliLib.Brotli.Utils;
using BrotliLib.Numbers;
using InsertCopyTree = BrotliLib.Brotli.Components.Header.HuffmanTree<BrotliLib.Brotli.Components.Data.InsertCopyLengthCode>;
namespace BrotliLib.Brotli.Components.Data{
/// <summary>
/// Describes a <see cref="HuffmanTree{T}"/> symbol used to calculate lengths of an insert&amp;copy code.
/// https://tools.ietf.org/html/rfc7932#section-5
/// </summary>
public sealed class InsertCopyLengthCode : IComparable<InsertCopyLengthCode>{
public static readonly AlphabetSize AlphabetSize = new AlphabetSize(704);
public static readonly InsertCopyTree.Context TreeContext = new InsertCopyTree.Context(AlphabetSize, value => new InsertCopyLengthCode(value), symbol => symbol.CompactedCode);
// Cell offsets
private static readonly int[] InsertCellOffsets = {
0, 0, 0, 0, 8, 8, 0, 16, 8, 16, 16
};
private static readonly int[] CopyCellOffsets = {
0, 8, 0, 8, 0, 8, 16, 0, 16, 8, 16
};
private static readonly (IntRange i, IntRange c)[] PairedCellOffsets = InsertCellOffsets.Zip(CopyCellOffsets, (i, c) => (new IntRange(i, i + 7), new IntRange(c, c + 7))).ToArray();
private static int DetermineCellIndex(int insertCode, int copyCode, bool useDistanceCodeZero){
int startCellIndex = useDistanceCodeZero ? 0 : 2;
for(int index = startCellIndex; index < PairedCellOffsets.Length; index++){
var (i, c) = PairedCellOffsets[index];
if (i.Contains(insertCode) && c.Contains(copyCode)){
return index;
}
}
throw new ArgumentException("Could not determine cell index of insert&copy length code.");
}
// Data
/// <summary>
/// Combined <see cref="InsertCode"/> and <see cref="CopyCode"/> values into a single value from the insert&amp;copy alphabet.
/// </summary>
public int CompactedCode { get; }
/// <summary>
/// Code used to determine the <see cref="InsertCopyLengths.InsertLength"/> value.
/// </summary>
public int InsertCode { get; }
/// <summary>
/// Code used to determine the <see cref="InsertCopyLengths.CopyLength"/> value.
/// </summary>
public int CopyCode { get; }
/// <summary>
/// Whether to skip reading the <see cref="DistanceCode"/>, and use distance code 0 instead.
/// </summary>
public bool UseDistanceCodeZero { get; }
/// <summary>
/// Initializes the code with a value from the insert&amp;copy alphabet.
/// </summary>
public InsertCopyLengthCode(int compactedCode){
if (compactedCode < 0 || compactedCode >= AlphabetSize.SymbolCount){
throw new ArgumentOutOfRangeException(nameof(compactedCode), "Compacted insert&copy length code must be in the range [0; " + AlphabetSize.SymbolCount + ").");
}
int cell = compactedCode / 64;
this.CompactedCode = compactedCode;
this.InsertCode = InsertCellOffsets[cell] + ((compactedCode >> 3) & 0b111);
this.CopyCode = CopyCellOffsets[cell] + (compactedCode & 0b111);
this.UseDistanceCodeZero = cell < 2;
}
/// <summary>
/// Initializes the code with the concrete insert and copy codes, and the flag which determines whether to use an implied distance code zero.
/// </summary>
public InsertCopyLengthCode(int insertCode, int copyCode, ImplicitDistanceCodeZero implicitDCZ){
if (insertCode < 0 || insertCode > 23){
throw new ArgumentOutOfRangeException(nameof(insertCode), "Insert code must be in the range [0; 23].");
}
if (copyCode < 0 || copyCode > 23){
throw new ArgumentOutOfRangeException(nameof(copyCode), "Copy code must be in the range [0; 23].");
}
bool useDistanceCodeZero = implicitDCZ.Decide(insertCode, copyCode);
int cell = DetermineCellIndex(insertCode, copyCode, useDistanceCodeZero);
this.CompactedCode = (64 * cell) + ((insertCode & 0b111) << 3) | (copyCode & 0b111);
this.InsertCode = insertCode;
this.CopyCode = copyCode;
this.UseDistanceCodeZero = useDistanceCodeZero;
}
public int CompareTo(InsertCopyLengthCode other){
return CompactedCode.CompareTo(other.CompactedCode);
}
// Object
public override bool Equals(object obj){
return obj is InsertCopyLengthCode code &&
CompactedCode == code.CompactedCode;
}
public override int GetHashCode(){
return HashCode.Combine(CompactedCode);
}
public override string ToString(){
return "Code = " + CompactedCode + " (InsertCode = " + InsertCode + ", CopyCode = " + CopyCode + (UseDistanceCodeZero ? ", DistanceCodeZero" : "") + ")";
}
}
}