private static List <State> GetStates(ReverseWindowReader data, int address) { var states = new List <State> { new State { Command = new Command { Simple = true, Value = data[address], CopySize = 1 }, Address = address } }; for (int offset = 1; offset <= RingSize; offset++) { var cmd = TestCandidate(data, address, address - offset); if (cmd != null) { states.Add(new State { Command = cmd, Address = address }); } } return(states); }
private static Command TestCandidate(ReverseWindowReader data, int targetAddress, int sourceAddress) { if (data[targetAddress] != data[sourceAddress]) { return(null); } var target = data.Branch(targetAddress); var source = data.Branch(sourceAddress); var count = 0; while (count < MaxCopySize) { if (target.Byte() != source.Byte()) { break; } count++; } if (count < MinCopySize) { return(null); } return(new Command { Simple = false, CopySize = count, Address = (sourceAddress - count + 1 + StartWriteAddress) % RingSize }); }
public static byte[] CompressMax(byte[] target) { if (target == null) { throw new ArgumentNullException(nameof(target)); } var data = new ReverseWindowReader(target, 0); var states = new State[target.Length]; for (int i = 0; i < target.Length; i++) { var candidates = GetStates(data, i); State best = null; foreach (var current in candidates) { if (current.NextAddress < 0) { current.PathLength = current.Size; } else { // TODO: not checking states[] access for null because we want it to throw exception current.PathLength = states[current.NextAddress].PathLength + current.Size; } if ((best == null) || (current.PathLength < best.PathLength)) { best = current; } } states[i] = best; } var step = states[states.Length - 1]; var commands = new List <Command> { step.Command }; while (step.NextAddress >= 0) { step = states[step.NextAddress]; commands.Add(step.Command); } return(CommandsToBytes(commands)); }
public static byte[] Compress(byte[] target) { if (target == null) { throw new ArgumentNullException(nameof(target)); } var commands = new List <Command>(); var address = target.Length - 1; var data = new ReverseWindowReader(target, address); while (address >= 0) { Command cmd = null; var offset = 1; while ((offset <= RingSize) && (cmd == null || cmd.CopySize < MaxCopySize)) { var testCommand = TestCandidate(data, address, address - offset); if ((testCommand != null) && ((cmd == null) || (testCommand.CopySize > cmd.CopySize))) { cmd = testCommand; } offset++; } if (cmd == null) { cmd = new Command { Simple = true, Value = data[address] }; address--; } else { address -= cmd.CopySize; } commands.Add(cmd); } return(CommandsToBytes(commands)); }