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); }
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])); }
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; } } } } }
/// <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; } } }
public void Serialize(PackedBitWriter reader) { throw new NotImplementedException(); }
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"))); }