diff --git a/projects/client/RabbitMQ.Client/src/client/impl/WireFormatting.cs b/projects/client/RabbitMQ.Client/src/client/impl/WireFormatting.cs index a81087a4b3..f9dd8a2fa4 100644 --- a/projects/client/RabbitMQ.Client/src/client/impl/WireFormatting.cs +++ b/projects/client/RabbitMQ.Client/src/client/impl/WireFormatting.cs @@ -57,11 +57,17 @@ public static decimal AmqpToDecimal(byte scale, uint unsignedMantissa) throw new SyntaxError("Unrepresentable AMQP decimal table field: " + "scale=" + scale); } - return new decimal((int)(unsignedMantissa & 0x7FFFFFFF), - 0, - 0, - ((unsignedMantissa & 0x80000000) == 0) ? false : true, - scale); + + return new decimal( + // The low 32 bits of a 96-bit integer + lo: (int)(unsignedMantissa & 0x7FFFFFFF), + // The middle 32 bits of a 96-bit integer. + mid: 0, + // The high 32 bits of a 96-bit integer. + hi: 0, + isNegative: (unsignedMantissa & 0x80000000) != 0, + // A power of 10 ranging from 0 to 28. + scale: scale); } public static void DecimalToAmqp(decimal value, out byte scale, out int mantissa) @@ -91,7 +97,7 @@ public static IList ReadArray(NetworkBinaryReader reader) { IList array = new List(); long arrayLength = reader.ReadUInt32(); - Stream backingStream = reader.BaseStream; + var backingStream = reader.BaseStream; long startPosition = backingStream.Position; while ((backingStream.Position - startPosition) < arrayLength) { @@ -129,10 +135,12 @@ public static object ReadFieldValue(NetworkBinaryReader reader) case 'F': value = ReadTable(reader); break; - case 'A': value = ReadArray(reader); break; + case 'B': + value = reader.ReadByte(); + break; case 'b': value = reader.ReadSByte(); break; @@ -215,7 +223,7 @@ public static IDictionary ReadTable(NetworkBinaryReader reader) IDictionary table = new Dictionary(); long tableLength = reader.ReadUInt32(); - Stream backingStream = reader.BaseStream; + var backingStream = reader.BaseStream; long startPosition = backingStream.Position; while ((backingStream.Position - startPosition) < tableLength) { @@ -247,7 +255,7 @@ public static void WriteArray(NetworkBinaryWriter writer, IList val) } else { - Stream backingStream = writer.BaseStream; + var backingStream = writer.BaseStream; long patchPosition = backingStream.Position; writer.Write((uint)0); // length of table - will be backpatched foreach (object entry in val) @@ -264,93 +272,82 @@ public static void WriteArray(NetworkBinaryWriter writer, IList val) public static void WriteDecimal(NetworkBinaryWriter writer, decimal value) { - byte scale; - int mantissa; - DecimalToAmqp(value, out scale, out mantissa); + DecimalToAmqp(value, out var scale, out var mantissa); WriteOctet(writer, scale); WriteLong(writer, (uint)mantissa); } public static void WriteFieldValue(NetworkBinaryWriter writer, object value) { - if (value == null) - { - WriteOctet(writer, (byte)'V'); - } - else if (value is string) - { - WriteOctet(writer, (byte)'S'); - WriteLongstr(writer, Encoding.UTF8.GetBytes((string)value)); - } - else if (value is byte[]) - { - WriteOctet(writer, (byte)'S'); - WriteLongstr(writer, (byte[])value); - } - else if (value is int) - { - WriteOctet(writer, (byte)'I'); - writer.Write((int)value); - } - else if (value is decimal) - { - WriteOctet(writer, (byte)'D'); - WriteDecimal(writer, (decimal)value); - } - else if (value is AmqpTimestamp) - { - WriteOctet(writer, (byte)'T'); - WriteTimestamp(writer, (AmqpTimestamp)value); - } - else if (value is IDictionary) - { - WriteOctet(writer, (byte)'F'); - WriteTable(writer, (IDictionary)value); - } - else if (value is IList) - { - WriteOctet(writer, (byte)'A'); - WriteArray(writer, (IList)value); - } - else if (value is sbyte) - { - WriteOctet(writer, (byte)'b'); - writer.Write((sbyte)value); - } - else if (value is double) - { - WriteOctet(writer, (byte)'d'); - writer.Write((double)value); - } - else if (value is float) - { - WriteOctet(writer, (byte)'f'); - writer.Write((float)value); - } - else if (value is long) - { - WriteOctet(writer, (byte)'l'); - writer.Write((long)value); - } - else if (value is short) - { - WriteOctet(writer, (byte)'s'); - writer.Write((short)value); - } - else if (value is bool) + switch (value) { - WriteOctet(writer, (byte)'t'); - WriteOctet(writer, (byte)(((bool)value) ? 1 : 0)); - } - else if (value is BinaryTableValue) - { - WriteOctet(writer, (byte)'x'); - WriteLongstr(writer, ((BinaryTableValue)value).Bytes); - } - else - { - throw new WireFormattingException("Value cannot appear as table value", - value); + case null: + WriteOctet(writer, (byte)'V'); + break; + case string val: + WriteOctet(writer, (byte)'S'); + WriteLongstr(writer, Encoding.UTF8.GetBytes(val)); + break; + case byte[] val: + WriteOctet(writer, (byte)'S'); + WriteLongstr(writer, val); + break; + case int val: + WriteOctet(writer, (byte)'I'); + writer.Write(val); + break; + case decimal val: + WriteOctet(writer, (byte)'D'); + WriteDecimal(writer, val); + break; + case AmqpTimestamp val: + WriteOctet(writer, (byte)'T'); + WriteTimestamp(writer, val); + break; + case IDictionary val: + WriteOctet(writer, (byte)'F'); + WriteTable(writer, val); + break; + case IList val: + WriteOctet(writer, (byte)'A'); + WriteArray(writer, val); + break; + case byte val: + WriteOctet(writer, (byte)'B'); + writer.Write(val); + break; + case sbyte val: + WriteOctet(writer, (byte)'b'); + writer.Write(val); + break; + case double val: + WriteOctet(writer, (byte)'d'); + writer.Write(val); + break; + case float val: + WriteOctet(writer, (byte)'f'); + writer.Write(val); + break; + case long val: + WriteOctet(writer, (byte)'l'); + writer.Write(val); + break; + case short val: + WriteOctet(writer, (byte)'s'); + writer.Write(val); + break; + case bool val: + WriteOctet(writer, (byte)'t'); + WriteOctet(writer, (byte)(val ? 1 : 0)); + break; + case BinaryTableValue val: + WriteOctet(writer, (byte)'x'); + WriteLongstr(writer, val.Bytes); + break; + default: + throw new WireFormattingException( + $"Value of type '{value.GetType().Name}' cannot appear as table value", + value); } } @@ -382,14 +379,16 @@ public static void WriteShort(NetworkBinaryWriter writer, ushort val) public static void WriteShortstr(NetworkBinaryWriter writer, string val) { - byte[] bytes = Encoding.UTF8.GetBytes(val); - int len = bytes.Length; - if (len > 255) + var bytes = Encoding.UTF8.GetBytes(val); + var length = bytes.Length; + + if (length > 255) { throw new WireFormattingException("Short string too long; " + - "UTF-8 encoded length=" + len + ", max=255"); + "UTF-8 encoded length=" + length + ", max=255"); } - writer.Write((byte)len); + + writer.Write((byte)length); writer.Write(bytes); } @@ -415,15 +414,14 @@ public static void WriteTable(NetworkBinaryWriter writer, IDictionary val) } else { - Stream backingStream = writer.BaseStream; + var backingStream = writer.BaseStream; long patchPosition = backingStream.Position; writer.Write((uint)0); // length of table - will be backpatched foreach (DictionaryEntry entry in val) { WriteShortstr(writer, entry.Key.ToString()); - object value = entry.Value; - WriteFieldValue(writer, value); + WriteFieldValue(writer, entry.Value); } // Now, backpatch the table length. @@ -457,15 +455,14 @@ public static void WriteTable(NetworkBinaryWriter writer, IDictionary entry in val) + foreach (var entry in val) { WriteShortstr(writer, entry.Key); - object value = entry.Value; - WriteFieldValue(writer, value); + WriteFieldValue(writer, entry.Value); } // Now, backpatch the table length. diff --git a/projects/client/Unit/src/unit/TestFieldTableFormatting.cs b/projects/client/Unit/src/unit/TestFieldTableFormatting.cs index 007b943da6..e6caaccf8c 100644 --- a/projects/client/Unit/src/unit/TestFieldTableFormatting.cs +++ b/projects/client/Unit/src/unit/TestFieldTableFormatting.cs @@ -117,17 +117,19 @@ public void TestQpidJmsTypes() { NetworkBinaryWriter w = Writer(); Hashtable t = new Hashtable(); + t["B"] = (byte)255; t["b"] = (sbyte)-128; t["d"] = (double)123; t["f"] = (float)123; t["l"] = (long)123; t["s"] = (short)123; t["t"] = true; - byte[] xbytes = new byte[] { 0xaa, 0x55 }; + byte[] xbytes = { 0xaa, 0x55 }; t["x"] = new BinaryTableValue(xbytes); t["V"] = null; WireFormatting.WriteTable(w, t); IDictionary nt = (IDictionary)WireFormatting.ReadTable(Reader(Contents(w))); + Assert.AreEqual(typeof(byte), nt["B"].GetType()); Assert.AreEqual((byte)255, nt["B"]); Assert.AreEqual(typeof(sbyte), nt["b"].GetType()); Assert.AreEqual((sbyte)-128, nt["b"]); Assert.AreEqual(typeof(double), nt["d"].GetType()); Assert.AreEqual((double)123, nt["d"]); Assert.AreEqual(typeof(float), nt["f"].GetType()); Assert.AreEqual((float)123, nt["f"]); diff --git a/projects/client/Unit/src/unit/TestFieldTableFormattingGeneric.cs b/projects/client/Unit/src/unit/TestFieldTableFormattingGeneric.cs index fd7377a51d..2f18c391d0 100644 --- a/projects/client/Unit/src/unit/TestFieldTableFormattingGeneric.cs +++ b/projects/client/Unit/src/unit/TestFieldTableFormattingGeneric.cs @@ -119,6 +119,7 @@ public void TestQpidJmsTypes() { NetworkBinaryWriter w = Writer(); IDictionary t = new Dictionary(); + t["B"] = (byte)255; t["b"] = (sbyte)-128; t["d"] = (double)123; t["f"] = (float)123; @@ -130,6 +131,7 @@ public void TestQpidJmsTypes() t["V"] = null; WireFormatting.WriteTable(w, t); IDictionary nt = (IDictionary)WireFormatting.ReadTable(Reader(Contents(w))); + Assert.AreEqual(typeof(byte), nt["B"].GetType()); Assert.AreEqual((byte)255, nt["B"]); Assert.AreEqual(typeof(sbyte), nt["b"].GetType()); Assert.AreEqual((sbyte)-128, nt["b"]); Assert.AreEqual(typeof(double), nt["d"].GetType()); Assert.AreEqual((double)123, nt["d"]); Assert.AreEqual(typeof(float), nt["f"].GetType()); Assert.AreEqual((float)123, nt["f"]);