private void WriteTypeClass(BinaryWriterX bw, object writeValue, Type writeType, ValueStorage storage) { var typeAttributes = new MemberAttributeInfo(writeType); var bitFieldInfoAttribute = typeAttributes.BitFieldInfoAttribute; var alignmentAttribute = typeAttributes.AlignmentAttribute; if (bitFieldInfoAttribute != null) { bw.Flush(); } bw.BitOrder = (bitFieldInfoAttribute?.BitOrder != BitOrder.Default ? bitFieldInfoAttribute?.BitOrder : bw.BitOrder) ?? bw.BitOrder; bw.BlockSize = bitFieldInfoAttribute?.BlockSize ?? bw.BlockSize; if (bw.BlockSize != 8 && bw.BlockSize != 4 && bw.BlockSize != 2 && bw.BlockSize != 1) { throw new InvalidBitFieldInfoException(bw.BlockSize); } var fields = writeType.GetFields().OrderBy(fi => fi.MetadataToken); foreach (var field in fields) { // If field condition is false, write no value and ignore field var conditionAttribute = field.GetCustomAttribute <ConditionAttribute>(); if (!ResolveCondition(conditionAttribute, storage)) { continue; } var fieldValue = field.GetValue(writeValue); storage.Add(field.Name, fieldValue); var bitInfo = field.GetCustomAttribute <BitFieldAttribute>(); if (bitInfo != null) { bw.WriteBits(Convert.ToInt64(fieldValue), bitInfo.BitLength); } else { WriteTypeInternal(bw, fieldValue, storage, field); } } bw.Flush(); // Apply alignment if (alignmentAttribute != null) { bw.WriteAlignment(alignmentAttribute.Alignment); } }
public void NibbleWriting() { var expect = new byte[] { 0x84, 0x08 }; var ms = new MemoryStream(); using (var bw = new BinaryWriterX(ms)) { bw.WriteNibble(0x04); bw.WriteNibble(0x08); bw.WriteNibble(0x08); bw.Flush(); Assert.IsTrue(ms.ToArray().SequenceEqual(expect)); } }
public void BitWriting() { var expect = new byte[] { 0x00, 0x80, 0x0F, 0xF8 }; var ms = new MemoryStream(); using (var bw = new BinaryWriterX(ms, true, ByteOrder.LittleEndian, BitOrder.MSBFirst, 2)) { bw.WriteBit(true); bw.Flush(); bw.WriteBits(0x1F, 5); bw.WriteBits(0x00, 6); bw.WriteBits(0x0F, 5); Assert.IsTrue(ms.ToArray().SequenceEqual(expect)); } var expect2 = new byte[] { 0x00, 0x80, 0x00, 0x01 }; var ms2 = new MemoryStream(); using (var bw = new BinaryWriterX(ms2, ByteOrder.LittleEndian, BitOrder.LowestAddressFirst, 2)) { bw.WriteBit(false); bw.WriteBits(0, 14); bw.WriteBit(true); bw.ByteOrder = ByteOrder.BigEndian; bw.WriteBit(false); bw.WriteBits(0, 14); bw.WriteBit(true); Assert.IsTrue(ms2.ToArray().SequenceEqual(expect2)); } }
/// <summary> /// Compress a file using the CRILAYLA compression. /// </summary> /// <param name="input">Uncompressed file.</param> /// <returns></returns> public static byte[] Compress(Stream input) { if (input.Length <= RawDataSize) { throw new ArgumentException("Input needs to be longer than 256 bytes"); } using (var br = new BinaryReaderX(input)) { var uncompressedData = br.ReadBytes(RawDataSize); var inputSize = (int)input.Length - RawDataSize; var header = new CrilaylaHeader() { UncompressedSize = inputSize }; var maxCompLength = input.Length + inputSize / 8 + ((inputSize % 8 > 0) ? 1 : 0); var dest = new MemoryStream() { Position = 0x10 + maxCompLength }; using (var bw = new BinaryWriterX(new ReverseStream(dest), true)) { int done_so_far = 0; void WriteRaw() { bw.WriteBit(false); br.BaseStream.Position = br.BaseStream.Length - ++done_so_far; bw.WriteBits(br.ReadByte(), 8); }; void WriteBackref(byte[] backref, int backrefPos) { if (backref.Length < 3) { throw new ArgumentException("Backref too short"); } var end_backref = backrefPos + backref.Length; var offset = done_so_far - (inputSize - end_backref) - 3; long this_chunk = 0; long leftover = backref.Length; leftover -= 3; bw.WriteBit(true); bw.WriteBits(offset, 13); int bits_max, bits = 2; int[] next_bits = new int[] { 0, 0, 3, 5, 0, 8, 0, 0, 8 }; do { bits_max = (1 << bits) - 1; this_chunk = Math.Min(leftover, bits_max); leftover -= this_chunk; bw.WriteBits(this_chunk, bits); bits = next_bits[bits]; } while (this_chunk == bits_max); done_so_far += backref.Length; } // Must do first 3 bytes raw for (done_so_far = 0; done_so_far < 3 && done_so_far < inputSize;) { WriteRaw(); } int sliding_window_size = 0x2000 + 2; while (done_so_far < inputSize) { var needle_len = inputSize - done_so_far; var backref_max = Math.Min(sliding_window_size, done_so_far); br.BaseStream.Position = RawDataSize; var backrefInfo = LongestMatch(needle_len, br.ReadBytes(needle_len + backref_max)); if ((backrefInfo.backref?.Length ?? 0) < 3) { WriteRaw(); } else { WriteBackref(backrefInfo.backref, backrefInfo.backrefPos); } } bw.Flush(); } header.CompressedSize = (int)(dest.Length - dest.Position); var destStart = dest.Position -= 0x10; using (var bw = new BinaryWriterX(dest, true)) { bw.WriteType(header); bw.BaseStream.Position += header.CompressedSize; bw.Write(uncompressedData); } dest.Position = destStart; return(new BinaryReaderX(dest).ReadBytes((int)(dest.Length - destStart))); } }