コード例 #1
0
        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);
            }
        }
コード例 #2
0
        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));
            }
        }
コード例 #3
0
        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));
            }
        }
コード例 #4
0
        /// <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)));
            }
        }