Пример #1
0
        public void Encode()
        {
            var writer     = new PackedBitWriter();
            var serializer = new PackedBitSerializer(typeof(PasswordProperties));

            serializer.Serialize(writer, Properties);

            byte[] bytes = writer.ToArray();

            // The bitpacking we use assumes that information is packed from the left which means that it makes a big difference for a byte full of bools
            // Information is actually packed from the right of the byte
            // Ergo we just have to flip each byte
            // However first we handle the only 32-bit value (which can't be fixed by a naive flip)
            if (!BitConverter.IsLittleEndian)
            {
                // The game age value comes in little-endian format
                Swap(bytes, GameAgeStartByteIndex, GameAgeEndByteIndex);
                Swap(bytes, GameAgeStartByteIndex + 1, GameAgeEndByteIndex - 1);
            }
            for (int i = 0; i < ChecksumByteCount; i++)
            {
                if (i >= GameAgeStartByteIndex && i <= GameAgeEndByteIndex)
                {
                    continue;
                }
                bytes[i] = bytes[i].ReverseBits();
            }

            byte checksum = CalculateChecksum(bytes, Properties.Shift);

            Properties.Checksum = checksum;

            if (Properties.Shift > 0)
            {
                bytes = bytes.RotateRight(Properties.Shift);
            }

            byte[] encoded = new byte[ChecksumByte];
            Buffer.BlockCopy(bytes, 0, encoded, 0, ChecksumByteCount);
            encoded[ShiftByte - 1]    = Properties.Shift;
            encoded[ChecksumByte - 1] = Properties.Checksum;

            Encoded = AlphabetMapper.TranslateComputerBytesToMetroidString(encoded);
        }
Пример #2
0
        public void ArgumentValidation()
        {
            PackedBitWriter writer = new PackedBitWriter();

            Assert.ThrowsExact <BitCountException>(() => writer.Write(-1, byte.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(-1, ushort.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(-1, uint.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(-1, ulong.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(0, byte.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(0, ushort.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(0, uint.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(0, ulong.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(65, byte.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(65, ushort.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(65, uint.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(65, ulong.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(-1, sbyte.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(-1, short.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(-1, int.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(-1, long.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(0, sbyte.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(0, short.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(0, int.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(0, long.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(65, sbyte.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(65, short.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(65, int.MaxValue));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(65, long.MaxValue));

            Assert.ThrowsExact <ArgumentNullException>(() => writer.Write(null as string));
            Assert.ThrowsExact <ArgumentNullException>(() => writer.Write(null as string, Encoding.UTF8));
            Assert.ThrowsExact <ArgumentNullException>(() => writer.Write("string", null));

            Assert.ThrowsExact <BitCountException>(() => writer.Write(-1, new byte[] { 0 }));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(0, new byte[] { 0 }));
            Assert.ThrowsExact <BitCountException>(() => writer.Write(65, new byte[] { 0 }));

            Assert.ThrowsExact <ArgumentNullException>(() => writer.Write(1, null as byte[]));
            Assert.ThrowsExact <ArgumentException>(() => writer.Write(1, new byte[0]));
            Assert.ThrowsExact <ArgumentException>(() => writer.Write(1, new byte[0]));
        }
Пример #3
0
 private void WriteImperativeBits(PackedBitWriter writer, object value, IEnumerable <PropertyInfo> properties, Func <PropertyInfo, BitPair> getBitPair)
 {
     foreach (PropertyInfo prop in properties)
     {
         if (prop.PropertyType == typeof(bool))
         {
             writer.Write((bool)prop.GetValue(value, null));
         }
         else
         {
             BitPair write    = getBitPair(prop);
             int     bitRange = write.Count;
             if (write.Signed)
             {
                 if (prop.PropertyType == typeof(sbyte))
                 {
                     writer.WriteSigned(bitRange, (sbyte)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(short))
                 {
                     writer.WriteSigned(bitRange, (short)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(int))
                 {
                     writer.WriteSigned(bitRange, (int)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(long))
                 {
                     writer.WriteSigned(bitRange, (long)prop.GetValue(value, null));
                 }
                 else
                 {
                     throw CodePath.Unreachable;
                 }
             }
             else
             {
                 if (prop.PropertyType == typeof(sbyte))
                 {
                     writer.Write(bitRange, (sbyte)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(short))
                 {
                     writer.Write(bitRange, (short)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(int))
                 {
                     writer.Write(bitRange, (int)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(long))
                 {
                     writer.Write(bitRange, (long)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(byte))
                 {
                     writer.Write(bitRange, (byte)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(ushort))
                 {
                     writer.Write(bitRange, (ushort)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(uint))
                 {
                     writer.Write(bitRange, (uint)prop.GetValue(value, null));
                 }
                 else if (prop.PropertyType == typeof(ulong))
                 {
                     writer.Write(bitRange, (ulong)prop.GetValue(value, null));
                 }
                 else
                 {
                     throw CodePath.Unreachable;
                 }
             }
         }
     }
 }
Пример #4
0
        /// <summary>
        /// Serializes an object into a PackedBitWriter stream.
        /// </summary>
        /// <param name="writer">The stream to serialize to.</param>
        /// <param name="value">The object to serialize.</param>
        /// <exception cref="ArgumentNullException"><paramref name="writer" /> is null.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="value" /> is null.</exception>
        public void Serialize(PackedBitWriter writer, object value)
        {
            if (object.ReferenceEquals(writer, null))
            {
                throw new ArgumentNullException(nameof(writer));
            }
            if (object.ReferenceEquals(value, null))
            {
                throw new ArgumentNullException(nameof(value));
            }

            if (ImplementsInterface)
            {
                ((IPackedBitSerializable)value).Serialize(writer);
            }
            else
            {
                var properties = GetProperties(SerializeType);

                if (HasOrder)
                {
                    properties = properties.OrderBy(p => (p.GetCustomAttribute <PackedBitOrderAttribute>() ?? new PackedBitOrderAttribute(0)).LowBit);
                    WriteImperativeBits(writer, value, properties, (prop) => {
                        PackedBitOrderAttribute bitOrderAttr = prop.GetCustomAttribute <PackedBitOrderAttribute>();
                        return(new BitPair()
                        {
                            Count = bitOrderAttr.BitCount,
                            Signed = bitOrderAttr.Signed,
                        });
                    });
                }
                else if (HasRange)
                {
                    properties = properties.OrderBy(p => (p.GetCustomAttribute <PackedBitRangeAttribute>() ?? new PackedBitRangeAttribute(0)).LowBit);
                    WriteImperativeBits(writer, value, properties, (prop) => {
                        PackedBitRangeAttribute bitRangeAttr = prop.GetCustomAttribute <PackedBitRangeAttribute>();
                        return(new BitPair()
                        {
                            Count = bitRangeAttr.HasHighBit ?
                                    bitRangeAttr.HighBit - (bitRangeAttr.LowBit - 1) :
                                    1,
                            Signed = bitRangeAttr.Signed,
                        });
                    });
                }
                else if (HasSize)
                {
                    WriteImperativeBits(writer, value, properties, (prop) => {
                        PackedBitSizeAttribute bitSizeAttr = prop.GetCustomAttribute <PackedBitSizeAttribute>();
                        return(new BitPair()
                        {
                            Count = bitSizeAttr.BitCount,
                            Signed = bitSizeAttr.Signed,
                        });
                    });
                }
                else
                {
                    throw CodePath.Unreachable;
                }
            }
        }
Пример #5
0
 public void Serialize(PackedBitWriter reader)
 {
     throw new NotImplementedException();
 }
Пример #6
0
        public void Basics()
        {
            PackedBitWriter writer = null;

            Assert.DoesNotThrow(() => writer = new PackedBitWriter());
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(false));
            Assert.DoesNotThrow(() => writer.Write(false));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(false));
            Assert.DoesNotThrow(() => writer.Write(false));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(4, (sbyte)3));
            Assert.DoesNotThrow(() => writer.Write(4, (byte)4));
            Assert.DoesNotThrow(() => writer.Write(6, (short)13));
            Assert.DoesNotThrow(() => writer.Write(6, (ushort)14));
            Assert.DoesNotThrow(() => writer.Write(6, (int)23));
            Assert.DoesNotThrow(() => writer.Write(6, (uint)24));
            Assert.DoesNotThrow(() => writer.Write(8, (long)33));
            Assert.DoesNotThrow(() => writer.Write(8, (ulong)34));
            Assert.DoesNotThrow(() => writer.Write(false));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.Write(false));
            Assert.DoesNotThrow(() => writer.Write(false));
            Assert.DoesNotThrow(() => writer.Write(true));
            Assert.DoesNotThrow(() => writer.WriteSigned(4, (sbyte)-3));
            Assert.DoesNotThrow(() => writer.Write(2.4d));
            Assert.DoesNotThrow(() => writer.Write(88.4f));
            Assert.DoesNotThrow(() => writer.WriteSigned(6, (short)-13));
            Assert.DoesNotThrow(() => writer.WriteSigned(6, (int)-23));
            Assert.DoesNotThrow(() => writer.WriteSigned(8, (long)-33));
            Assert.DoesNotThrow(() => writer.Write("datà"));
            Assert.DoesNotThrow(() => writer.Write("data", Encoding.ASCII));
            Assert.DoesNotThrow(() => writer.Write(2, (sbyte)3));

            byte[] result = null;
            // byteQuantity must have an exact bit count in order to be correct
            // Please ensure that the test above produces an exact bit count
            // Please also ensure that PackedBitReader is updated upon changes here
            int byteQuantity = (
                1 + 1 + 1 + 1 + 1 +
                1 + 1 + 1 + 1 + 1 +
                4 + 4 + 6 + 6 + 6 +
                6 + 8 + 8 + 1 + 1 +
                1 + 1 + 1 + 1 + 1 +
                1 + 64 + 32 + 5 + 7 + 7 + 9 +
                // datà should be 5 bytes in UTF8
                // length should always be 32 bits
                32 + 8 + 8 + 8 + 8 + 8 +
                // Since ASCII is 7-bit, should be chars = bytes
                32 + 8 + 8 + 8 + 8 +
                2
                ) / Constants.BitsInByte;

            Assert.DoesNotThrow(() => result = writer.ToArray());
            Assert.NotNull(result);
            Assert.Equal(result.Length, byteQuantity);

            var hex = string.Join(
                ", ",
                result.Select(v => "0x" + v.ToString("X2")));
        }