diff options
author | Robert Greig <rgreig@apache.org> | 2007-02-13 16:56:03 +0000 |
---|---|---|
committer | Robert Greig <rgreig@apache.org> | 2007-02-13 16:56:03 +0000 |
commit | f1e37d08908f9dc1aa2728c8379091846bccbf13 (patch) | |
tree | c0a6fdd4b35416c552a8b5bc7847c1a85b3b6303 | |
parent | cd7311844c3058bcc7a0a73e26d31570da63bed7 (diff) | |
download | qpid-python-f1e37d08908f9dc1aa2728c8379091846bccbf13.tar.gz |
(Path submitted by Tomas Restrepo) Qpid-336 Field table updated to match Java client.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@507096 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | dotnet/Qpid.Buffer/FixedByteBuffer.cs | 22 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/HeapByteBuffer.cs | 75 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/Qpid.Buffer.csproj | 2 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/Qpid.Buffer.mdp | 6 | ||||
-rw-r--r-- | dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj | 6 | ||||
-rw-r--r-- | dotnet/Qpid.Common.Tests/Qpid.Common.Tests.mdp | 4 | ||||
-rw-r--r-- | dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs | 270 | ||||
-rw-r--r-- | dotnet/Qpid.Common/Framing/AMQType.cs | 700 | ||||
-rw-r--r-- | dotnet/Qpid.Common/Framing/AMQTypeMap.cs | 75 | ||||
-rw-r--r-- | dotnet/Qpid.Common/Framing/AMQTypedValue.cs | 76 | ||||
-rw-r--r-- | dotnet/Qpid.Common/Framing/EncodingUtils.cs | 607 | ||||
-rw-r--r-- | dotnet/Qpid.Common/Framing/FieldTable.cs | 729 | ||||
-rw-r--r-- | dotnet/Qpid.Common/Qpid.Common.csproj | 3 | ||||
-rw-r--r-- | dotnet/Qpid.Common/Qpid.Common.mdp | 5 |
14 files changed, 2158 insertions, 422 deletions
diff --git a/dotnet/Qpid.Buffer/FixedByteBuffer.cs b/dotnet/Qpid.Buffer/FixedByteBuffer.cs index 39a17a6fa7..d2f3ca8a3c 100644 --- a/dotnet/Qpid.Buffer/FixedByteBuffer.cs +++ b/dotnet/Qpid.Buffer/FixedByteBuffer.cs @@ -211,7 +211,7 @@ namespace Qpid.Buffer public short getShort() { - throw new NotImplementedException(); + return _buf.GetShort(); } public short getShort(int index) @@ -221,7 +221,7 @@ namespace Qpid.Buffer public void putShort(short value) { - throw new NotImplementedException(); + _buf.Put(value); } public void putShort(int index, short value) @@ -231,7 +231,7 @@ namespace Qpid.Buffer public int getInt() { - throw new NotImplementedException(); + return _buf.GetInt(); } public int getInt(int index) @@ -241,7 +241,7 @@ namespace Qpid.Buffer public void putInt(int value) { - throw new NotImplementedException(); + _buf.Put(value); } public void putInt(int index, int value) @@ -261,7 +261,7 @@ namespace Qpid.Buffer public long getLong() { - throw new NotImplementedException(); + return _buf.GetLong(); } public long getLong(int index) @@ -271,7 +271,7 @@ namespace Qpid.Buffer public void putLong(long value) { - throw new NotImplementedException(); + _buf.Put(value); } public void putLong(int index, long value) @@ -286,17 +286,17 @@ namespace Qpid.Buffer public float getFloat() { - throw new NotImplementedException(); + return _buf.GetFloat(); } public float getFloat(int index) { - throw new NotImplementedException(); + throw new NotImplementedException(); } public void putFloat(float value) { - throw new NotImplementedException(); + _buf.Put(value); } public void putFloat(int index, float value) @@ -306,7 +306,7 @@ namespace Qpid.Buffer public double getDouble() { - throw new NotImplementedException(); + return _buf.GetDouble(); } public double getDouble(int index) @@ -316,7 +316,7 @@ namespace Qpid.Buffer public void putDouble(double value) { - throw new NotImplementedException(); + _buf.Put(value); } public void putDouble(int index, double value) diff --git a/dotnet/Qpid.Buffer/HeapByteBuffer.cs b/dotnet/Qpid.Buffer/HeapByteBuffer.cs index 3ac99021d7..f95fe1c241 100644 --- a/dotnet/Qpid.Buffer/HeapByteBuffer.cs +++ b/dotnet/Qpid.Buffer/HeapByteBuffer.cs @@ -221,6 +221,40 @@ namespace Qpid.Buffer _underlyingData[_position++] = (byte) (data >> 8); _underlyingData[_position++] = (byte) data; } + + public void Put(short data) + { + Put((ushort)data); + } + + public void Put(int data) + { + Put((uint)data); + } + + public void Put(long data) + { + Put((ulong)data); + } + + public void Put(float data) + { + unsafe + { + uint val = *((uint*)&data); + Put(val); + } + } + + public void Put(double data) + { + unsafe + { + ulong val = *((ulong*)&data); + Put(val); + } + } + /// <summary> /// Read the byte at the current position and increment the position @@ -289,8 +323,44 @@ namespace Qpid.Buffer byte b6 = _underlyingData[_position++]; byte b7 = _underlyingData[_position++]; byte b8 = _underlyingData[_position++]; - return (ulong)((b1 << 56) + (b2 << 48) + (b3 << 40) + (b4 << 32) + (b5 << 24) + - (b6 << 16) + (b7 << 8) + b8); + // all the casts necessary because otherwise each subexpression + // only gets promoted to uint and cause incorrect results + return (((ulong)b1 << 56) + ((ulong)b2 << 48) + ((ulong)b3 << 40) + + ((ulong)b4 << 32) + ((ulong)b5 << 24) + + ((ulong)b6 << 16) + ((ulong)b7 << 8) + b8); + } + + public short GetShort() + { + return (short) GetUnsignedShort(); + } + + public int GetInt() + { + return (int) GetUnsignedInt(); + } + + public long GetLong() + { + return (long) GetUnsignedLong(); + } + + public float GetFloat() + { + unsafe + { + uint val = GetUnsignedInt(); + return *((float*)&val); + } + } + + public double GetDouble() + { + unsafe + { + ulong val = GetUnsignedLong(); + return *((double*)&val); + } } public /*override*/ string GetString(uint length, Encoding encoder) @@ -401,3 +471,4 @@ namespace Qpid.Buffer } } + diff --git a/dotnet/Qpid.Buffer/Qpid.Buffer.csproj b/dotnet/Qpid.Buffer/Qpid.Buffer.csproj index 3e4b302a3a..e6bade037b 100644 --- a/dotnet/Qpid.Buffer/Qpid.Buffer.csproj +++ b/dotnet/Qpid.Buffer/Qpid.Buffer.csproj @@ -21,6 +21,7 @@ <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -29,6 +30,7 @@ <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
diff --git a/dotnet/Qpid.Buffer/Qpid.Buffer.mdp b/dotnet/Qpid.Buffer/Qpid.Buffer.mdp index 1e2a655357..8f2497e8b9 100644 --- a/dotnet/Qpid.Buffer/Qpid.Buffer.mdp +++ b/dotnet/Qpid.Buffer/Qpid.Buffer.mdp @@ -4,13 +4,13 @@ <Output directory="./bin/Debug" assembly="Qpid.Buffer" /> <Build debugmode="True" target="Library" /> <Execution runwithwarnings="True" consolepause="False" runtime="MsNet" clr-version="Net_1_1" /> - <CodeGeneration compiler="Csc" warninglevel="4" optimize="True" unsafecodeallowed="False" generateoverflowchecks="True" generatexmldocumentation="False" ctype="CSharpCompilerParameters" /> + <CodeGeneration compiler="Csc" warninglevel="4" optimize="True" unsafecodeallowed="True" generateoverflowchecks="True" generatexmldocumentation="False" ctype="CSharpCompilerParameters" /> </Configuration> <Configuration name="Release" ctype="DotNetProjectConfiguration"> <Output directory="./bin/Release" assembly="Qpid.Buffer" /> <Build debugmode="False" target="Library" /> <Execution runwithwarnings="True" consolepause="False" runtime="MsNet" clr-version="Net_1_1" /> - <CodeGeneration compiler="Csc" warninglevel="4" optimize="True" unsafecodeallowed="False" generateoverflowchecks="True" generatexmldocumentation="False" ctype="CSharpCompilerParameters" /> + <CodeGeneration compiler="Csc" warninglevel="4" optimize="True" unsafecodeallowed="True" generateoverflowchecks="True" generatexmldocumentation="False" ctype="CSharpCompilerParameters" /> </Configuration> </Configurations> <DeployTargets /> @@ -32,4 +32,4 @@ <References> <ProjectReference type="Gac" localcopy="True" refto="System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </References> -</Project>
\ No newline at end of file +</Project> diff --git a/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj b/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj index fb9aec55cf..8c5142e690 100644 --- a/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj +++ b/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj @@ -18,6 +18,7 @@ <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <UseVSHostingProcess>true</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -39,8 +40,13 @@ <ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Qpid\Collections\TestLinkedHashtable.cs" />
+ <Compile Include="Qpid\Framing\TestAMQType.cs" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
+ <Project>{44384DF2-B0A4-4580-BDBC-EE4BAA87D995}</Project>
+ <Name>Qpid.Buffer</Name>
+ </ProjectReference>
<ProjectReference Include="..\Qpid.Common\Qpid.Common.csproj">
<Project>{77064C42-24D2-4CEB-9EA2-0EF481A43205}</Project>
<Name>Qpid.Common</Name>
diff --git a/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.mdp b/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.mdp index 2ef60cbca2..e7b74c9756 100644 --- a/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.mdp +++ b/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.mdp @@ -17,10 +17,12 @@ <Contents> <File name="./Properties/AssemblyInfo.cs" subtype="Code" buildaction="Compile" /> <File name="./Qpid/Collections/TestLinkedHashtable.cs" subtype="Code" buildaction="Compile" /> + <File name="./Qpid/Framing/TestAMQType.cs" subtype="Code" buildaction="Compile" /> </Contents> <References> <ProjectReference type="Gac" localcopy="True" refto="System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <ProjectReference type="Assembly" localcopy="True" refto="../Qpid.Client.Tests/lib/nunit/nunit.framework.dll" /> + <ProjectReference type="Project" localcopy="True" refto="Qpid.Buffer" /> <ProjectReference type="Project" localcopy="True" refto="Qpid.Common" /> </References> -</Project>
\ No newline at end of file +</Project> diff --git a/dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs b/dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs new file mode 100644 index 0000000000..805d728db6 --- /dev/null +++ b/dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs @@ -0,0 +1,270 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using NUnit.Framework;
+using Qpid.Buffer;
+using Qpid.Framing;
+
+namespace Qpid.Framing.Tests
+{
+ [TestFixture]
+ public class TestAMQType
+ {
+
+ #region LONG_STRING tests
+ [Test]
+ public void LONG_STRING_ReadWrite()
+ {
+ AMQType type = AMQType.LONG_STRING;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+ const string VALUE = "simple string 1";
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // LONG_STRING tests
+
+ #region UINT32 tests
+ [Test]
+ public void UINT32_CanGetEncodingSize()
+ {
+ AMQType type = AMQType.UINT32;
+ Assert.AreEqual(4, type.GetEncodingSize(1234443));
+ }
+
+ [Test]
+ public void UINT32_ToNativeValue()
+ {
+ AMQType type = AMQType.UINT32;
+ Assert.AreEqual(1, type.ToNativeValue(1));
+ Assert.AreEqual(1, type.ToNativeValue((short)1));
+ Assert.AreEqual(1, type.ToNativeValue((byte)1));
+ Assert.AreEqual(1, type.ToNativeValue("1"));
+
+ try
+ {
+ Assert.AreEqual(1, type.ToNativeValue("adasdads"));
+ Assert.Fail("Invalid format allowed");
+ } catch ( FormatException )
+ {
+ }
+ }
+
+ [Test]
+ public void UINT32_ReadWrite()
+ {
+ AMQType type = AMQType.UINT32;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+ const uint VALUE = 0xFFEEDDCC;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // UINT32 Tests
+
+ #region VOID Tests
+ [Test]
+ public void VOID_CanGetEncodingSize()
+ {
+ AMQType type = AMQType.VOID;
+ Assert.AreEqual(0, type.GetEncodingSize(null));
+ }
+
+ [Test]
+ public void VOID_ToNativeValue()
+ {
+ AMQType type = AMQType.VOID;
+ Assert.IsNull(type.ToNativeValue(null));
+
+ try
+ {
+ type.ToNativeValue("asdasd");
+ Assert.Fail("converted invalid value");
+ } catch (FormatException)
+ {
+ }
+ }
+
+ [Test]
+ public void VOID_ReadWrite()
+ {
+ AMQType type = AMQType.VOID;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+
+ type.WriteToBuffer(null, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(null, value.Value);
+ }
+
+ #endregion // VOID Tests
+
+ #region BOOLEAN Tests
+ [Test]
+ public void BOOLEAN_CanGetEncodingSize()
+ {
+ AMQType type = AMQType.BOOLEAN;
+ Assert.AreEqual(1, type.GetEncodingSize(true));
+ }
+
+ [Test]
+ public void BOOLEAN_ToNativeValue()
+ {
+ AMQType type = AMQType.BOOLEAN;
+ Assert.AreEqual(true, type.ToNativeValue(true));
+ Assert.AreEqual(false, type.ToNativeValue("false"));
+
+ try
+ {
+ type.ToNativeValue("asdasd");
+ Assert.Fail("converted invalid value");
+ } catch ( FormatException )
+ {
+ }
+ }
+
+ [Test]
+ public void BOOLEAN_ReadWrite()
+ {
+ AMQType type = AMQType.BOOLEAN;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+
+ type.WriteToBuffer(true, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(true, value.Value);
+ }
+ #endregion // BOOLEAN Tests
+
+ #region INT16 tests
+ [Test]
+ public void INT16_ReadWrite()
+ {
+ AMQType type = AMQType.INT16;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+ const short VALUE = -32765;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ //public void UINT16_ReadWrite()
+ //{
+ // AMQType type = AMQType.UINT16;
+ // ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+ // const ushort VALUE = 64321;
+
+ // type.WriteToBuffer(VALUE, buffer);
+ // buffer.flip();
+ // buffer.position(0);
+ // AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ // Assert.AreEqual(VALUE, value.Value);
+ //}
+ #endregion // INT16 Tests
+
+ #region INT32 tests
+ [Test]
+ public void INT32_ReadWrite()
+ {
+ AMQType type = AMQType.INT32;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+ const int VALUE = -39273563;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // INT32 Tests
+
+ #region INT64 tests
+ [Test]
+ public void INT64_ReadWrite()
+ {
+ AMQType type = AMQType.INT64;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+ const long VALUE = -(2^43+1233123);
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ [Test]
+ public void UINT64_ReadWrite()
+ {
+ AMQType type = AMQType.UINT64;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+ const ulong VALUE = (2 ^ 61 + 1233123);
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // INT64 Tests
+
+ #region FLOAT tests
+ [Test]
+ public void FLOAT_ReadWrite()
+ {
+ AMQType type = AMQType.FLOAT;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+ const float VALUE = 1.2345000E-035f;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // FLOAT Tests
+
+ #region DOUBLE tests
+ [Test]
+ public void DOUBLE_ReadWrite()
+ {
+ AMQType type = AMQType.DOUBLE;
+ ByteBuffer buffer = (new SimpleByteBufferAllocator()).Allocate(0x1000, false);
+ const double VALUE = 1.2345000E-045;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.flip();
+ buffer.position(0);
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // FLOAT Tests
+ }
+}
diff --git a/dotnet/Qpid.Common/Framing/AMQType.cs b/dotnet/Qpid.Common/Framing/AMQType.cs new file mode 100644 index 0000000000..3bcc6c6222 --- /dev/null +++ b/dotnet/Qpid.Common/Framing/AMQType.cs @@ -0,0 +1,700 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Text;
+using Qpid.Buffer;
+
+namespace Qpid.Framing
+{
+ /// <summary>
+ /// Base class for the Field Table Type system.
+ /// Ported over from the Java AMQType enumeration
+ /// </summary>
+ public abstract class AMQType
+ {
+ private byte _identifier;
+
+ /// <summary>
+ /// Type code identifier for this type
+ /// </summary>
+ public byte Identifier
+ {
+ get { return _identifier; }
+ }
+
+ protected AMQType(char identifier)
+ {
+ _identifier = (byte)identifier;
+ }
+
+ /// <summary>
+ /// Create a new <see cref="AMQTypedValue"/> instance
+ /// </summary>
+ /// <param name="value">Value to initialize with</param>
+ /// <returns>A new typed value instance</returns>
+ public AMQTypedValue AsTypedValue(object value)
+ {
+ return new AMQTypedValue(this, ToNativeValue(value));
+ }
+
+ /// <summary>
+ /// Write the specified value to the buffer using the encoding
+ /// specified for this type
+ /// </summary>
+ /// <param name="value">Value to write</param>
+ /// <param name="buffer">Buffer to write to</param>
+ public void WriteToBuffer(object value, ByteBuffer buffer)
+ {
+ buffer.put(Identifier);
+ WriteValueImpl(value, buffer);
+ }
+
+ public override string ToString()
+ {
+ return ((Char) Identifier).ToString();
+ }
+
+ /// <summary>
+ /// Get the encoding size for the specified value in this type format
+ /// </summary>
+ /// <param name="value">Value to find encoded size for</param>
+ /// <returns>The encoded size</returns>
+ public abstract uint GetEncodingSize(object value);
+ /// <summary>
+ /// Convert the specified value to this type
+ /// </summary>
+ /// <param name="value">Value to convert</param>
+ /// <returns>The converted value</returns>
+ public abstract object ToNativeValue(object value);
+
+ /// <summary>
+ /// Read a value from the specified buffer using the encoding for
+ /// this type
+ /// </summary>
+ /// <param name="buffer">Buffer to read from</param>
+ /// <returns>The value read</returns>
+ public abstract object ReadValueFromBuffer(ByteBuffer buffer);
+
+ protected abstract void WriteValueImpl(Object value, ByteBuffer buffer);
+
+
+ #region Known Types
+ //
+ // Known Types
+ //
+
+ // long string is not defined in the proposed specification,
+ // and the 'S' discriminator is left for unsigned short (16-bit) values
+ public static readonly AMQType LONG_STRING = new AMQLongStringType();
+ public static readonly AMQType UINT32 = new AMQUInt32Type();
+ public static readonly AMQType DECIMAL = new AMQDecimalType();
+ public static readonly AMQType TIMESTAMP = new AMQTimeStampType();
+ public static readonly AMQType FIELD_TABLE = new AMQFieldTableType();
+ public static readonly AMQType VOID = new AMQVoidType();
+ public static readonly AMQType BINARY = new AMQBinaryType();
+ public static readonly AMQType ASCII_STRING = new AMQAsciiStringType();
+ public static readonly AMQType WIDE_STRING = new AMQWideStringType();
+ public static readonly AMQType BOOLEAN = new AMQBooleanType();
+ public static readonly AMQType ASCII_CHARACTER = new AMQAsciiCharType();
+ public static readonly AMQType BYTE = new AMQByteType();
+ public static readonly AMQType SBYTE = new AMQSByteType();
+ public static readonly AMQType INT16 = new AMQInt16Type();
+ public static readonly AMQType UINT16 = new AMQUInt16Type();
+ public static readonly AMQType INT32 = new AMQInt32Type();
+ public static readonly AMQType INT64 = new AMQInt64Type();
+ public static readonly AMQType UINT64 = new AMQUInt64Type();
+ public static readonly AMQType FLOAT = new AMQFloatType();
+ public static readonly AMQType DOUBLE = new AMQDoubleType();
+
+ #endregion // Known Types
+
+ #region Type Implementation
+ //
+ // Type Implementation
+ //
+
+ sealed class AMQLongStringType : AMQType
+ {
+ public AMQLongStringType() : base('S')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedLongStringLength((string) value);
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value == null )
+ throw new ArgumentNullException("value");
+ return value.ToString();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadLongString(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteLongStringBytes(buffer, (string) value);
+ }
+
+ }
+
+ sealed class AMQUInt32Type : AMQType
+ {
+ public AMQUInt32Type() : base('I')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.UnsignedIntegerLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToUInt32(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadUnsignedInteger(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteUnsignedInteger(buffer, (uint) value);
+ }
+
+ }
+
+ sealed class AMQDecimalType : AMQType
+ {
+ public AMQDecimalType() : base('D')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ sealed class AMQTimeStampType : AMQType
+ {
+ public AMQTimeStampType() : base('T')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ sealed class AMQFieldTableType : AMQType
+ {
+ public AMQFieldTableType() : base('F')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ sealed class AMQVoidType : AMQType
+ {
+ public AMQVoidType() : base('V')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return 0;
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value != null )
+ throw new FormatException(string.Format("Cannot convert {0} to VOID type", value));
+ return null;
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return null;
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ }
+ }
+
+ // Extended Types
+
+ sealed class AMQBinaryType : AMQType
+ {
+ public AMQBinaryType() : base('x')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedLongstrLength((byte[]) value);
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value is byte[] || value == null )
+ {
+ return value;
+ }
+ throw new ArgumentException("Value cannot be converted to byte[]");
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadLongstr(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteLongstr(buffer, (byte[])value);
+ }
+ }
+
+ sealed class AMQAsciiStringType : AMQType
+ {
+ public AMQAsciiStringType() : base('c')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedAsciiStringLength((string)value);
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value == null )
+ throw new ArgumentNullException("value");
+ return value.ToString();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadAsciiString(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteAsciiString(buffer, (string)value);
+ }
+ }
+
+ sealed class AMQWideStringType : AMQType
+ {
+ // todo: Change encoding to UTF16 (java code still uses default
+ // ascii encoding for wide strings
+ private static readonly Encoding ENCODING = Encoding.ASCII;
+
+ public AMQWideStringType()
+ : base('C')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedLongStringLength((string)value, ENCODING);
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value == null )
+ throw new ArgumentNullException("value");
+ return value.ToString();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadLongString(buffer, ENCODING);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteLongStringBytes(buffer, (string)value, ENCODING);
+ }
+ }
+
+ sealed class AMQBooleanType : AMQType
+ {
+ public AMQBooleanType() : base('t')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedBooleanLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToBoolean(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadBoolean(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteBoolean(buffer, (bool)value);
+ }
+ }
+
+ sealed class AMQAsciiCharType : AMQType
+ {
+ public AMQAsciiCharType() : base('k')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedCharLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToChar(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadChar(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteChar(buffer, (char)value);
+ }
+ }
+
+ sealed class AMQByteType : AMQType
+ {
+ public AMQByteType() : base('B')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedByteLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToByte(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadByte(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteByte(buffer, (byte)value);
+ }
+ }
+
+ sealed class AMQSByteType : AMQType
+ {
+ public AMQSByteType()
+ : base('b')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedSByteLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToSByte(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadSByte(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteSByte(buffer, (sbyte)value);
+ }
+ }
+
+ sealed class AMQInt16Type : AMQType
+ {
+ public AMQInt16Type() : base('s')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedShortLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToInt16(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadShort(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteShort(buffer, (short)value);
+ }
+ }
+
+ sealed class AMQUInt16Type : AMQType
+ {
+ public AMQUInt16Type()
+ : base('S')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedUnsignedShortLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToUInt16(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadUnsignedShort(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteUnsignedShort(buffer, (ushort)value);
+ }
+ }
+
+ sealed class AMQInt32Type : AMQType
+ {
+ public AMQInt32Type() : base('i')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedIntegerLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToInt32(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadInteger(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteInteger(buffer, (int)value);
+ }
+ }
+
+ sealed class AMQInt64Type : AMQType
+ {
+ public AMQInt64Type() : base('l')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedLongLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToInt64(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadLong(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteLong(buffer, (long)value);
+ }
+ }
+
+ sealed class AMQUInt64Type : AMQType
+ {
+ public AMQUInt64Type()
+ : base('L')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedUnsignedLongLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToUInt64(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadUnsignedLong(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteUnsignedLong(buffer, (ulong)value);
+ }
+ }
+
+ sealed class AMQFloatType : AMQType
+ {
+ public AMQFloatType() : base('f')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedFloatLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToSingle(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadFloat(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteFloat(buffer, (float)value);
+ }
+ }
+
+ sealed class AMQDoubleType : AMQType
+ {
+ public AMQDoubleType() : base('d')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedDoubleLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToDouble(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadDouble(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteDouble(buffer, (double)value);
+ }
+ }
+
+ #endregion // Type Implementation
+
+ } // class AMQType
+}
diff --git a/dotnet/Qpid.Common/Framing/AMQTypeMap.cs b/dotnet/Qpid.Common/Framing/AMQTypeMap.cs new file mode 100644 index 0000000000..56d0119a16 --- /dev/null +++ b/dotnet/Qpid.Common/Framing/AMQTypeMap.cs @@ -0,0 +1,75 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Collections;
+
+namespace Qpid.Framing
+{
+ public sealed class AMQTypeMap
+ {
+ private static Hashtable _reverseTypeMap;
+
+ private AMQTypeMap()
+ {
+ }
+
+ static AMQTypeMap()
+ {
+ _reverseTypeMap = Hashtable.Synchronized(new Hashtable());
+
+ Add(AMQType.LONG_STRING);
+ Add(AMQType.BOOLEAN);
+ Add(AMQType.BYTE);
+ Add(AMQType.SBYTE);
+ Add(AMQType.INT16);
+ // not supported for now as type code conflicts
+ // with LONG_STRING
+ //Add(AMQType.UINT16);
+ Add(AMQType.INT32);
+ Add(AMQType.UINT32);
+ Add(AMQType.INT64);
+ Add(AMQType.UINT64);
+ Add(AMQType.FLOAT);
+ Add(AMQType.DOUBLE);
+ Add(AMQType.DECIMAL);
+ Add(AMQType.BINARY);
+ Add(AMQType.ASCII_STRING);
+ Add(AMQType.WIDE_STRING);
+ Add(AMQType.ASCII_CHARACTER);
+ Add(AMQType.TIMESTAMP);
+ Add(AMQType.FIELD_TABLE);
+ Add(AMQType.VOID);
+ }
+
+ public static AMQType GetType(byte identifier)
+ {
+ AMQType type = (AMQType)_reverseTypeMap[identifier];
+ if ( type == null )
+ throw new ArgumentOutOfRangeException(string.Format("No such type code: {0:x}", identifier));
+ return type;
+ }
+
+ private static void Add(AMQType type)
+ {
+ _reverseTypeMap.Add(type.Identifier, type);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Common/Framing/AMQTypedValue.cs b/dotnet/Qpid.Common/Framing/AMQTypedValue.cs new file mode 100644 index 0000000000..08b5c1e6e9 --- /dev/null +++ b/dotnet/Qpid.Common/Framing/AMQTypedValue.cs @@ -0,0 +1,76 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using Qpid.Buffer;
+
+namespace Qpid.Framing
+{
+ public class AMQTypedValue
+ {
+ private readonly AMQType _type;
+ private readonly object _value;
+
+ public AMQType Type
+ {
+ get { return _type; }
+ }
+
+ public object Value
+ {
+ get { return _value; }
+ }
+
+ public uint EncodingLength
+ {
+ get { return _type.GetEncodingSize(_value); }
+ }
+
+ public AMQTypedValue(AMQType type, object value)
+ {
+ if ( type == null )
+ throw new ArgumentNullException("type");
+ _type = type;
+ _value = type.ToNativeValue(value);
+ }
+
+ public AMQTypedValue(AMQType type, ByteBuffer buffer)
+ {
+ _type = type;
+ _value = type.ReadValueFromBuffer(buffer);
+ }
+
+ public void WriteToBuffer(ByteBuffer buffer)
+ {
+ _type.WriteToBuffer(_value, buffer);
+ }
+
+ public static AMQTypedValue ReadFromBuffer(ByteBuffer buffer)
+ {
+ AMQType type = AMQTypeMap.GetType(buffer.get());
+ return new AMQTypedValue(type, buffer);
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{0}: {1}", Type, Value);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Common/Framing/EncodingUtils.cs b/dotnet/Qpid.Common/Framing/EncodingUtils.cs index bb51f14b18..564c9d87ef 100644 --- a/dotnet/Qpid.Common/Framing/EncodingUtils.cs +++ b/dotnet/Qpid.Common/Framing/EncodingUtils.cs @@ -24,235 +24,428 @@ using Qpid.Buffer; namespace Qpid.Framing { - public class EncodingUtils - { - private static readonly Encoding DEFAULT_ENCODER = Encoding.ASCII; - - public static ushort EncodedShortStringLength(string s) - { - if (s == null) - { - return 1; - } - else - { - return (ushort)(1 + s.Length); - } - } + public class EncodingUtils + { + private static readonly Encoding DEFAULT_ENCODER = Encoding.ASCII; - public static uint EncodedLongStringLength(string s) - { - if (s == null) + // SHORT STRING + public static ushort EncodedShortStringLength(string s) + { + if ( s == null ) + { + return 1; + } else + { + return (ushort)(1 + s.Length); + } + } + public static void WriteShortStringBytes(ByteBuffer buffer, string s) + { + if ( s != null ) + { + //try + //{ + //final byte[] encodedString = s.getBytes(STRING_ENCODING); + byte[] encodedString; + lock ( DEFAULT_ENCODER ) { - return 4; + encodedString = DEFAULT_ENCODER.GetBytes(s); } - else - { - return (uint)(4 + s.Length); - } - } + // TODO: check length fits in an unsigned byte + buffer.put((byte)encodedString.Length); + buffer.put(encodedString); - public static int EncodedLongstrLength(byte[] bytes) - { - if (bytes == null) - { - return 4; - } - else - { - return 4 + bytes.Length; - } - } + } else + { + // really writing out unsigned byte + buffer.put((byte)0); + } + } - public static uint EncodedFieldTableLength(FieldTable table) - { - if (table == null) - { - // size is encoded as 4 octets - return 4; - } - else - { - // size of the table plus 4 octets for the size - return table.EncodedSize + 4; - } - } + // ASCII STRINGS + public static uint EncodedAsciiStringLength(string s) + { + // TODO: move this to 2-byte length once the proposed encodings + // have been approved. Also, validate length! + if ( s == null ) + return 4; + else + return (uint) (4 + s.Length); + } + public static string ReadAsciiString(ByteBuffer buffer) + { + return ReadLongString(buffer, DEFAULT_ENCODER); + } + public static void WriteAsciiString(ByteBuffer buffer, string s) + { + WriteLongStringBytes(buffer, s, DEFAULT_ENCODER); + } - public static void WriteShortStringBytes(ByteBuffer buffer, string s) - { - if (s != null) - { - //try - //{ - //final byte[] encodedString = s.getBytes(STRING_ENCODING); - byte[] encodedString; - lock (DEFAULT_ENCODER) - { - encodedString = DEFAULT_ENCODER.GetBytes(s); - } - // TODO: check length fits in an unsigned byte - buffer.put((byte) encodedString.Length); - buffer.put(encodedString); - - } - else - { - // really writing out unsigned byte - buffer.put((byte) 0); - } - } + // LONG STRING + public static uint EncodedLongStringLength(string s) + { + return EncodedLongStringLength(s, DEFAULT_ENCODER); + } - public static void WriteLongStringBytes(ByteBuffer buffer, string s) - { - if (!(s == null || s.Length <= 0xFFFE)) - { - throw new ArgumentException("String too long"); - } - if (s != null) + public static uint EncodedLongStringLength(string s, Encoding encoding) + { + if ( s == null ) + { + return 4; + } else + { + return (uint)(4 + encoding.GetByteCount(s)); + } + } + public static string ReadLongString(ByteBuffer buffer) + { + return ReadLongString(buffer, DEFAULT_ENCODER); + } + public static string ReadLongString(ByteBuffer buffer, Encoding encoding) + { + uint length = buffer.getUnsignedInt(); + if ( length == 0 ) + { + return null; + } else + { + byte[] data = new byte[length]; + buffer.get(data); + lock ( encoding ) { - buffer.put((uint)s.Length); - byte[] encodedString = null; - lock (DEFAULT_ENCODER) - { - encodedString = DEFAULT_ENCODER.GetBytes(s); - } - buffer.put(encodedString); - } - else - { - buffer.put((uint) 0); + return encoding.GetString(data); } - } + } + } + public static void WriteLongStringBytes(ByteBuffer buffer, string s) + { + WriteLongStringBytes(buffer, s, DEFAULT_ENCODER); + } - public static void WriteFieldTableBytes(ByteBuffer buffer, FieldTable table) - { - if (table != null) - { - table.WriteToBuffer(buffer); - } - else + public static void WriteLongStringBytes(ByteBuffer buffer, string s, Encoding encoding) + { + if ( !(s == null || s.Length <= 0xFFFE) ) + { + throw new ArgumentException("String too long"); + } + if ( s != null ) + { + lock ( encoding ) { - buffer.put((uint) 0); + byte[] encodedString = null; + encodedString = encoding.GetBytes(s); + buffer.put((uint)encodedString.Length); + buffer.put(encodedString); } - } + } else + { + buffer.put((uint)0); + } + } - public static void WriteBooleans(ByteBuffer buffer, bool[] values) - { - byte packedValue = 0; - for (int i = 0; i < values.Length; i++) - { - if (values[i]) - { - packedValue = (byte) (packedValue | (1 << i)); - } - } + // BINARY + public static uint EncodedLongstrLength(byte[] bytes) + { + if ( bytes == null ) + { + return 4; + } else + { + return (uint)(4 + bytes.Length); + } + } + public static byte[] ReadLongstr(ByteBuffer buffer) + { + uint length = buffer.getUnsignedInt(); + if ( length == 0 ) + { + return null; + } else + { + byte[] result = new byte[length]; + buffer.get(result); + return result; + } + } + public static void WriteLongstr(ByteBuffer buffer, byte[] data) + { + if ( data != null ) + { + buffer.put((uint)data.Length); + buffer.put(data); + } else + { + buffer.put((uint)0); + } + } - buffer.put(packedValue); - } + // BOOLEANS + public static bool[] ReadBooleans(ByteBuffer buffer) + { + byte packedValue = buffer.get(); + bool[] result = new bool[8]; - public static void WriteLongstr(ByteBuffer buffer, byte[] data) - { - if (data != null) - { - buffer.put((uint) data.Length); - buffer.put(data); - } - else + for ( int i = 0; i < 8; i++ ) + { + result[i] = ((packedValue & (1 << i)) != 0); + } + return result; + } + public static void WriteBooleans(ByteBuffer buffer, bool[] values) + { + byte packedValue = 0; + for ( int i = 0; i < values.Length; i++ ) + { + if ( values[i] ) { - buffer.put((uint) 0); + packedValue = (byte)(packedValue | (1 << i)); } - } + } - public static bool[] ReadBooleans(ByteBuffer buffer) - { - byte packedValue = buffer.get(); - bool[] result = new bool[8]; + buffer.put(packedValue); + } - for (int i = 0; i < 8; i++) - { - result[i] = ((packedValue & (1 << i)) != 0); - } - return result; - } - - /// <summary> - /// Reads the field table uaing the data in the specified buffer - /// </summary> - /// <param name="buffer">The buffer to read from.</param> - /// <returns>a populated field table</returns> - /// <exception cref="AMQFrameDecodingException">if the buffer does not contain a decodable field table</exception> - public static FieldTable ReadFieldTable(ByteBuffer buffer) - { - uint length = buffer.GetUnsignedInt(); - if (length == 0) - { - return null; - } - else - { - return new FieldTable(buffer, length); - } - } - - /// <summary> - /// Read a short string from the buffer - /// </summary> - /// <param name="buffer">The buffer to read from.</param> - /// <returns>a string</returns> - /// <exception cref="AMQFrameDecodingException">if the buffer does not contain a decodable short string</exception> - public static string ReadShortString(ByteBuffer buffer) - { - byte length = buffer.get(); - if (length == 0) - { - return null; - } - else - { - byte[] data = new byte[length]; - buffer.get(data); - - lock (DEFAULT_ENCODER) - { - return DEFAULT_ENCODER.GetString(data); -// return buffer.GetString(length, DEFAULT_ENCODER); - } - } - } + // FIELD TABLES + public static uint EncodedFieldTableLength(FieldTable table) + { + if ( table == null ) + { + // size is encoded as 4 octets + return 4; + } else + { + // size of the table plus 4 octets for the size + return table.EncodedSize + 4; + } + } + /// <summary> + /// Reads the field table using the data in the specified buffer + /// </summary> + /// <param name="buffer">The buffer to read from.</param> + /// <returns>a populated field table</returns> + /// <exception cref="AMQFrameDecodingException">if the buffer does not contain a decodable field table</exception> + public static FieldTable ReadFieldTable(ByteBuffer buffer) + { + uint length = buffer.GetUnsignedInt(); + if ( length == 0 ) + { + return null; + } else + { + return new FieldTable(buffer, length); + } + } + public static void WriteFieldTableBytes(ByteBuffer buffer, FieldTable table) + { + if ( table != null ) + { + table.WriteToBuffer(buffer); + } else + { + buffer.put((uint)0); + } + } - public static string ReadLongString(ByteBuffer buffer) - { - uint length = buffer.getUnsignedInt(); - if (length == 0) - { - return null; - } - else - { - byte[] data = new byte[length]; - buffer.get(data); - lock (DEFAULT_ENCODER) - { - return DEFAULT_ENCODER.GetString(data); - //return buffer.GetString(length, DEFAULT_ENCODER); - } - } - } - public static byte[] ReadLongstr(ByteBuffer buffer) - { - uint length = buffer.getUnsignedInt(); - if (length == 0) - { - return null; - } - else + /// <summary> + /// Read a short string from the buffer + /// </summary> + /// <param name="buffer">The buffer to read from.</param> + /// <returns>a string</returns> + /// <exception cref="AMQFrameDecodingException">if the buffer does not contain a decodable short string</exception> + public static string ReadShortString(ByteBuffer buffer) + { + byte length = buffer.get(); + if ( length == 0 ) + { + return null; + } else + { + byte[] data = new byte[length]; + buffer.get(data); + + lock ( DEFAULT_ENCODER ) { - byte[] result = new byte[length]; - buffer.get(result); - return result; + return DEFAULT_ENCODER.GetString(data); } - } - } + } + } + + + + // BOOLEAN + public static uint EncodedBooleanLength() + { + return 1; + } + public static bool ReadBoolean(ByteBuffer buffer) + { + byte packedValue = buffer.get(); + return (packedValue == 1); + } + public static void WriteBoolean(ByteBuffer buffer, bool value) + { + buffer.put((byte)(value ? 1 : 0)); + } + + + // CHAR + public static uint EncodedCharLength() + { + return EncodedByteLength(); + } + public static char ReadChar(ByteBuffer buffer) + { + return (char)buffer.get(); + } + public static void WriteChar(ByteBuffer buffer, char value) + { + buffer.put((byte)value); + } + + // BYTE + public static uint EncodedByteLength() + { + return 1; + } + public static byte ReadByte(ByteBuffer buffer) + { + return buffer.get(); + } + public static void WriteByte(ByteBuffer buffer, byte value) + { + buffer.put(value); + } + + // SBYTE + public static uint EncodedSByteLength() + { + return 1; + } + public static sbyte ReadSByte(ByteBuffer buffer) + { + return (sbyte)buffer.get(); + } + public static void WriteSByte(ByteBuffer buffer, sbyte value) + { + buffer.put((byte)value); + } + + // INT16 + public static uint EncodedShortLength() + { + return 2; + } + + public static short ReadShort(ByteBuffer buffer) + { + return buffer.getShort(); + } + public static void WriteShort(ByteBuffer buffer, short value) + { + buffer.putShort(value); + } + + // UINT16 + public static uint EncodedUnsignedShortLength() + { + return 2; + } + + public static ushort ReadUnsignedShort(ByteBuffer buffer) + { + return buffer.GetUnsignedShort(); + } + public static void WriteUnsignedShort(ByteBuffer buffer, ushort value) + { + buffer.put(value); + } + + + // INT32 + public static uint EncodedIntegerLength() + { + return 4; + } + public static int ReadInteger(ByteBuffer buffer) + { + return buffer.getInt(); + } + public static void WriteInteger(ByteBuffer buffer, int value) + { + buffer.putInt(value); + } + + // UINT32 + public static uint UnsignedIntegerLength() + { + return 4; + } + public static void WriteUnsignedInteger(ByteBuffer buffer, uint value) + { + buffer.put(value); + } + public static uint ReadUnsignedInteger(ByteBuffer buffer) + { + return buffer.getUnsignedInt(); + } + + // INT64 + public static uint EncodedUnsignedLongLength() + { + return 8; + } + public static ulong ReadUnsignedLong(ByteBuffer buffer) + { + return buffer.GetUnsignedLong(); + } + public static void WriteUnsignedLong(ByteBuffer buffer, ulong value) + { + buffer.put(value); + } + + // UINT64 + public static uint EncodedLongLength() + { + return 8; + } + public static long ReadLong(ByteBuffer buffer) + { + return buffer.getLong(); + } + public static void WriteLong(ByteBuffer buffer, long value) + { + buffer.putLong(value); + } + + // FLOAT + public static uint EncodedFloatLength() + { + return 4; + } + public static void WriteFloat(ByteBuffer buffer, float value) + { + buffer.putFloat(value); + } + public static float ReadFloat(ByteBuffer buffer) + { + return buffer.getFloat(); + } + + // DOUBLE + public static uint EncodedDoubleLength() + { + return 8; + } + public static void WriteDouble(ByteBuffer buffer, double value) + { + buffer.putDouble(value); + } + public static double ReadDouble(ByteBuffer buffer) + { + return buffer.getDouble(); + } + + } } diff --git a/dotnet/Qpid.Common/Framing/FieldTable.cs b/dotnet/Qpid.Common/Framing/FieldTable.cs index 193d96f6cd..b977bef0ba 100644 --- a/dotnet/Qpid.Common/Framing/FieldTable.cs +++ b/dotnet/Qpid.Common/Framing/FieldTable.cs @@ -21,153 +21,274 @@ using System; using System.Collections; using System.Text; +using log4net; using Qpid.Buffer; using Qpid.Collections; using Qpid.Messaging; namespace Qpid.Framing { - /// - /// From the protocol document: - /// field-table = short-integer *field-value-pair - /// field-value-pair = field-name field-value - /// field-name = short-string - /// field-value = 'S' long-string - /// 'I' long-integer - /// 'D' decimal-value - /// 'T' long-integer - /// decimal-value = decimals long-integer - /// decimals = OCTET - public class FieldTable : IFieldTable + public class FieldTable : IFieldTable, IEnumerable { - IDictionary _hash = new LinkedHashtable(); - - private uint _encodedSize = 0; + private static readonly ILog _log = LogManager.GetLogger(typeof(FieldTable)); + + IDictionary _properties; + private ByteBuffer _encodedForm; + private object _syncLock; + private uint _encodedSize; public FieldTable() { + _syncLock = new object(); } - /** - * Construct a new field table. - * @param buffer the buffer from which to read data. The length byte must be read already - * @param length the length of the field table. Must be > 0. - * @throws AMQFrameDecodingException if there is an error decoding the table - */ - public FieldTable(ByteBuffer buffer, uint length) - { - _encodedSize = length; - int sizeRead = 0; - while (sizeRead < _encodedSize) - { - int sizeRemaining = buffer.remaining(); - string key = EncodingUtils.ReadShortString(buffer); - // TODO: use proper charset decoder - char type = (char)buffer.get(); - object value; - switch (type) - { - case 'S': - value = EncodingUtils.ReadLongString(buffer); - break; - case 'I': - value = buffer.GetUnsignedInt(); - break; - default: - throw new AMQFrameDecodingException("Unsupported field table type: '" + type + "' charcode" + (int)type); - } - sizeRead += (sizeRemaining - buffer.remaining()); - - _hash.Add(key, value); - } + /// <summary> + /// Construct a new field table. + /// </summary> + /// <param name="buffer">the buffer from which to read data. The length byte must be read already</param> + /// <param name="length">the length of the field table. Must be > 0.</param> + /// <exception cref="AMQFrameDecodingException">if there is an error decoding the table</exception> + public FieldTable(ByteBuffer buffer, uint length) : this() + { + _encodedForm = buffer.slice(); + _encodedForm.limit((int)length); + _encodedSize = length; + buffer.skip((int)length); } + /// <summary> + /// The set of all property names + /// </summary> + public ICollection Keys + { + get + { + InitMapIfNecessary(); + return _properties.Keys; + } + } + + /// <summary> + /// Calculated size of this field table once encoded + /// </summary> public uint EncodedSize { - get - { - return _encodedSize; - } + get { return _encodedSize; } } + /// <summary> + /// Number of properties in the field table + /// </summary> public int Count { - get { return _hash.Count; } + get + { + InitMapIfNecessary(); + return _properties.Count; + } } + /// <summary> + /// Gets or sets the specified property. + /// </summary> + /// <param name="key">Property name</param> + /// <returns>The specified property value</returns> public object this[string key] - { - get - { - CheckKey(key); - return _hash[key]; - } + { + get { return GetObject(key); } + set { SetObject(key, value); } + } - set - { - CheckKey(key); - CheckValue(value); + #region Typed Setters and Getters + // + // Typed Setters and Getters + // + public bool GetBoolean(string key) + { + return (bool)this[key]; + } + public void SetBoolean(string key, bool value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.BOOLEAN.AsTypedValue(value)); + } + public byte GetByte(string key) + { + return (byte)this[key]; + } + public void SetByte(string key, byte value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.BYTE.AsTypedValue(value)); + } + public sbyte GetSByte(string key) + { + return (sbyte)this[key]; + } + public void SetSByte(string key, sbyte value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.SBYTE.AsTypedValue(value)); + } + public short GetInt16(string key) + { + return (short)this[key]; + } + public void SetInt16(string key, short value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.INT16.AsTypedValue(value)); + } + public int GetInt32(string key) + { + return (int)this[key]; + } + public void SetInt32(string key, int value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.INT32.AsTypedValue(value)); + } + public long GetInt64(string key) + { + return (long)this[key]; + } + public void SetInt64(string key, long value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.INT64.AsTypedValue(value)); + } + public char GetChar(string key) + { + return (char)this[key]; + } + public void SetChar(string key, char value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.ASCII_CHARACTER.AsTypedValue(value)); + } + public float GetFloat(string key) + { + return (float)this[key]; + } + public void SetFloat(string key, float value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.FLOAT.AsTypedValue(value)); + } + public double GetDouble(string key) + { + return (double)this[key]; + } + public void SetDouble(string key, double value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.DOUBLE.AsTypedValue(value)); + } + public decimal GetDecimal(string key) + { + return (decimal)this[key]; + } + public void SetDecimal(string key, decimal value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.DECIMAL.AsTypedValue(value)); + } + public string GetString(string key) + { + return (string)this[key]; + } + public void SetString(string key, string value) + { + CheckPropertyName(key); + if ( value == null ) + SetProperty(key, AMQType.VOID.AsTypedValue(null)); + else + SetProperty(key, AMQType.LONG_STRING.AsTypedValue(value)); + } + public byte[] GetBytes(string key) + { + return (byte[])this[key]; + } + public void SetBytes(string key, byte[] value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.BINARY.AsTypedValue(value)); + } + public ushort GetUInt16(string key) + { + return (ushort)this[key]; + } + public void SetUInt16(string key, ushort value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.UINT16.AsTypedValue(value)); + } + public uint GetUInt32(string key) + { + return (uint)this[key]; + } + public void SetUInt32(string key, uint value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.UINT32.AsTypedValue(value)); + } + public ulong GetUInt64(string key) + { + return (ulong)this[key]; + } + public void SetUInt64(string key, ulong value) + { + CheckPropertyName(key); + SetProperty(key, AMQType.UINT64.AsTypedValue(value)); + } + #endregion // Typed Setters and Getters - object oldValue = _hash[key]; - if (oldValue != null) - { - AdjustEncodingSizeWhenRemoving(key, oldValue); - } + #region Public Methods + // + // Public Methods + // - _hash[key] = value; - AdjustEncodingSizeWhenAdding(key, value); - } - } - - public void WriteToBuffer(ByteBuffer buffer) + /// <summary> + /// Removes the property with the specified name + /// </summary> + /// <param name="key">The name of the property to remove</param> + /// <returns>The previous value of the property or null</returns> + public AMQTypedValue RemoveKey(string key) { - // Write out the total length, which we have kept up to date as data is added. - buffer.put(_encodedSize); - WritePayload(buffer); + InitMapIfNecessary(); + _encodedForm = null; + AMQTypedValue value = (AMQTypedValue)_properties[key]; + if ( value != null ) + { + _properties.Remove(key); + _encodedSize -= EncodingUtils.EncodedShortStringLength(key); + _encodedSize--; + _encodedSize -= value.EncodingLength; + + } + return value; } + - private void WritePayload(ByteBuffer buffer) + /// <summary> + /// Remove the property with the specified name + /// </summary> + /// <param name="key">The name of the property to remove</param> + public void Remove(string key) { - foreach (DictionaryEntry lde in _hash) - { - string key = (string) lde.Key; - EncodingUtils.WriteShortStringBytes(buffer, key); - object value = lde.Value; - if (value is byte[]) - { - buffer.put((byte) 'S'); - EncodingUtils.WriteLongstr(buffer, (byte[]) value); - } - else if (value is string) - { - // TODO: look at using proper charset encoder - buffer.put((byte) 'S'); - EncodingUtils.WriteLongStringBytes(buffer, (string) value); - } - else if (value is uint) - { - // TODO: look at using proper charset encoder - buffer.put((byte) 'I'); - buffer.put((uint) value); - } - else - { - // Should never get here. - throw new InvalidOperationException("Unsupported type in FieldTable: " + value.GetType()); - } - } + RemoveKey(key); } - public byte[] GetDataAsBytes() + /// <summary> + /// Remove all properties from the table + /// </summary> + public void Clear() { - ByteBuffer buffer = ByteBuffer.allocate((int)_encodedSize); - WritePayload(buffer); - byte[] result = new byte[_encodedSize]; - buffer.flip(); - buffer.get(result); - //buffer.Release(); - return result; + InitMapIfNecessary(); + _encodedForm = null; + _properties.Clear(); + _encodedSize = 0; } /// <summary> @@ -177,124 +298,338 @@ namespace Qpid.Framing /// <param name="ft">the source field table</param> public void AddAll(IFieldTable ft) { - foreach (DictionaryEntry dictionaryEntry in ft) - { - this[(string)dictionaryEntry.Key] = dictionaryEntry.Value; - } + foreach ( DictionaryEntry dictionaryEntry in ft ) + { + this[(string)dictionaryEntry.Key] = dictionaryEntry.Value; + } } - private void CheckKey(object key) + /// <summary> + /// Get a enumerator over the internal property set. + /// Notice the enumerator will DictionaryEntry objects with + /// a string as the Key and an <see cref="AMQTypedValue"/> instance as the value + /// </summary> + /// <returns>The enumerator object</returns> + public IEnumerator GetEnumerator() { - if (key == null) - { - throw new ArgumentException("All keys must be Strings - was passed: null"); - } - else if (!(key is string)) - { - throw new ArgumentException("All keys must be Strings - was passed: " + key.GetType()); - } + return _properties.GetEnumerator(); } - private void CheckValue(object value) + /// <summary> + /// Indicates if a property with the given name exists + /// </summary> + /// <param name="s">Property name to check</param> + /// <returns>True if the property exists</returns> + public bool Contains(string s) { - if (!(value is string || value is uint || value is int || value is long)) - { - throw new ArgumentException("All values must be type string or int or long or uint, was passed: " + - value.GetType()); - } + return _properties.Contains(s); + } + + /// <summary> + /// Returns a dictionary mapping Property Names to the corresponding + /// <see cref="AMQTypedValue"/> value + /// </summary> + /// <returns>The internal dictionary</returns> + public IDictionary AsDictionary() + { + return _properties; } - void AdjustEncodingSizeWhenAdding(object key, object value) + /// <summary> + /// Returns a string representation of this field table + /// </summary> + /// <returns>A string</returns> + public override string ToString() { - _encodedSize += EncodingUtils.EncodedShortStringLength((string) key); - // the extra byte if for the type indicator what is written out - if (value is string) - { - _encodedSize += 1 + EncodingUtils.EncodedLongStringLength((string) value); - } - else if (value is int || value is uint || value is long) - { - _encodedSize += 1 + 4; - } - else + StringBuilder sb = new StringBuilder("FieldTable {"); + + bool first = true; + InitMapIfNecessary(); + foreach ( DictionaryEntry entry in _properties ) + { + if ( !first ) + { + sb.Append(", "); + } + first = false; + sb.Append(entry.Key).Append(" => ").Append(entry.Value); + } + + sb.Append("}"); + return sb.ToString(); + } + + /// <summary> + /// Serializes this instance to the specified <see cref="ByteBuffer"/>. + /// </summary> + /// <param name="buffer">The buffer to write to</param> + public void WriteToBuffer(ByteBuffer buffer) + { + if ( _log.IsDebugEnabled ) { - // Should never get here since was already checked - throw new Exception("Unsupported value type: " + value.GetType()); + _log.Debug("FieldTable::writeToBuffer: Writing encoded length of " + EncodedSize + "..."); } + + EncodingUtils.WriteUnsignedInteger(buffer, EncodedSize); + WritePayload(buffer); } - private void AdjustEncodingSizeWhenRemoving(object key, object value) + /// <summary> + /// Returns a byte array with the serialized representation + /// of this field table + /// </summary> + /// <returns>An array of bytes</returns> + public byte[] GetDataAsBytes() { - _encodedSize -= EncodingUtils.EncodedShortStringLength((string) key); - if (value != null) - { - if (value is string) - { - _encodedSize -= 1 + EncodingUtils.EncodedLongStringLength((string) value); - } - else if (value is int || value is uint || value is long) - { - _encodedSize -= 5; - } - else - { - // Should never get here - throw new Exception("Illegal value type: " + value.GetType()); - } - } + ByteBuffer buffer = ByteBuffer.allocate((int)_encodedSize); + WritePayload(buffer); + byte[] result = new byte[_encodedSize]; + buffer.flip(); + buffer.get(result); + //buffer.Release(); + return result; } - public IEnumerator GetEnumerator() + #endregion // Public Methods + + #region Private Methods + // + // Private Methods + // + + private static void CheckPropertyName(string propertyName) { - return _hash.GetEnumerator(); + if ( propertyName == null || propertyName.Length == 0 ) + throw new ArgumentNullException("propertyName"); + CheckIdentifierFormat(propertyName); } - public bool Contains(string s) + private static void CheckIdentifierFormat(string propertyName) { - return _hash.Contains(s); + // AMQP Spec: 4.2.5.5 Field Tables + // Guidelines for implementers: + // * Field names MUST start with a letter, '$' or '#' and may continue with + // letters, '$' or '#', digits, or underlines, to a maximum length of 128 + // characters. + // * The server SHOULD validate field names and upon receiving an invalid + // field name, it SHOULD signal a connection exception with reply code + // 503 (syntax error). Conformance test: amq_wlp_table_01. + // * A peer MUST handle duplicate fields by using only the first instance. + + + // AMQP length limit + if ( propertyName.Length > 128 ) + { + throw new ArgumentException("AMQP limits property names to 128 characters"); + } + + // AMQ start character + if ( !(Char.IsLetter(propertyName[0]) + || propertyName[0] == '$' + || propertyName[0] == '#' + || propertyName[0] == '_' ) )// Not official AMQP added for JMS. + { + throw new ArgumentException("Identifier '" + propertyName + "' does not start with a valid AMQP start character"); + } } - public void Clear() + private object GetObject(string key) + { + AMQTypedValue value = GetProperty(key); + return value != null ? value.Value : null; + } + + private void SetObject(string key, object value) + { + if ( value is bool ) + { + SetBoolean(key, (bool)value); + } else if ( value is byte ) + { + SetByte(key, (byte)value); + } else if ( value is sbyte ) + { + SetSByte(key, (sbyte)value); + } else if ( value is short ) + { + SetInt16(key, (short)value); + } else if ( value is ushort ) + { + SetUInt16(key, (ushort)value); + } else if ( value is int ) + { + SetInt32(key, (int) value); + } else if ( value is uint ) + { + SetUInt32(key, (uint)value); + } else if ( value is long ) + { + SetInt64(key, (long) value); + } else if ( value is ulong ) + { + SetUInt64(key, (ulong)value); + } else if ( value is char ) + { + SetChar(key, (char) value); + } else if ( value is float ) + { + SetFloat(key, (float) value); + } else if ( value is double ) + { + SetDouble(key, (double) value); + } else if ( value is decimal ) + { + SetDecimal(key, (decimal) value); + } else if ( value is string ) + { + SetString(key, (string) value); + } else if ( value is byte[] ) + { + SetBytes(key, (byte[])value); + } else + { + throw new ArgumentException("Data type not supported yet"); + } + } + + private AMQTypedValue GetProperty(string name) { - _hash.Clear(); - _encodedSize = 0; + lock ( _syncLock ) + { + if ( _properties == null ) + { + if ( _encodedForm == null ) + { + return null; + } else + { + PopulateFromBuffer(); + } + } + return (AMQTypedValue) _properties[name]; + } } - public void Remove(string key) + private void PopulateFromBuffer() { - object value = _hash[key]; - if (value != null) - { - AdjustEncodingSizeWhenRemoving(key, value); - } - _hash.Remove(key); + try + { + SetFromBuffer(_encodedForm, _encodedSize); + } catch ( AMQFrameDecodingException e ) + { + _log.Error("Error decoding FieldTable in deferred decoding mode ", e); + throw; + } } - public IDictionary AsDictionary() + private void SetFromBuffer(ByteBuffer buffer, uint length) { - return _hash; + bool trace = _log.IsDebugEnabled; + if ( length > 0 ) + { + int expectedRemaining = buffer.remaining() - (int)length; + _properties = new LinkedHashtable(); + + do + { + string key = EncodingUtils.ReadShortString(buffer); + AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer); + if ( trace ) + { + _log.Debug(string.Format("FieldTable::PropFieldTable(buffer,{0}): Read type '{1}', key '{2}', value '{3}'", length, value.Type, key, value.Value)); + } + _properties.Add(key, value); + + } while ( buffer.remaining() > expectedRemaining ); + _encodedSize = length; + } + if ( trace ) + { + _log.Debug("FieldTable::FieldTable(buffer," + length + "): Done."); + } } - public override string ToString() + private void InitMapIfNecessary() { - StringBuilder sb = new StringBuilder("FieldTable{"); + lock ( _syncLock ) + { + if ( _properties == null ) + { + if ( _encodedForm == null ) + { + _properties = new LinkedHashtable(); + } else + { + PopulateFromBuffer(); + } + } + } + } - bool first = true; - foreach (DictionaryEntry entry in _hash) - { - if (first) - { - first = !first; - } - else - { - sb.Append(", "); - } - sb.Append(entry.Key).Append(" => ").Append(entry.Value); - } + private AMQTypedValue SetProperty(string key, AMQTypedValue value) + { + InitMapIfNecessary(); + _encodedForm = null; + if ( value == null ) + { + RemoveKey(key); + } + AMQTypedValue oldVal = (AMQTypedValue)_properties[key]; + _properties.Add(key, value); + if ( oldVal != null ) + { + _encodedSize -= oldVal.EncodingLength; + } else + { + _encodedSize += EncodingUtils.EncodedShortStringLength(key) + (uint)1; + } + if ( value != null ) + { + _encodedSize += value.EncodingLength; + } - sb.Append("}"); - return sb.ToString(); + return oldVal; + } + + public void WritePayload(ByteBuffer buffer) + { + if ( _encodedForm != null ) + { + buffer.put(_encodedForm); + } else if ( _properties != null ) + { + foreach ( DictionaryEntry de in _properties ) + { + string key = (string)de.Key; + AMQTypedValue value = (AMQTypedValue)de.Value; + try + { + if ( _log.IsDebugEnabled ) + { + _log.Debug("Writing Property:" + key + + " Type:" + value.Type + + " Value:" + value.Value); + _log.Debug("Buffer Position:" + buffer.position() + + " Remaining:" + buffer.remaining()); + } + //Write the actual parameter name + EncodingUtils.WriteShortStringBytes(buffer, key); + value.WriteToBuffer(buffer); + } catch ( Exception ex ) + { + if ( _log.IsDebugEnabled ) + { + _log.Debug("Exception thrown:" + ex); + _log.Debug("Writing Property:" + key + + " Type:" + value.Type + + " Value:" + value.Value); + _log.Debug("Buffer Position:" + buffer.position() + + " Remaining:" + buffer.remaining()); + } + } + } + } } + #endregion // Private Methods } } diff --git a/dotnet/Qpid.Common/Qpid.Common.csproj b/dotnet/Qpid.Common/Qpid.Common.csproj index e0b5d22efb..626a889e0a 100644 --- a/dotnet/Qpid.Common/Qpid.Common.csproj +++ b/dotnet/Qpid.Common/Qpid.Common.csproj @@ -53,6 +53,7 @@ <Compile Include="Framing\AMQMethodBody.cs" />
<Compile Include="Framing\AMQMethodBodyFactory.cs" />
<Compile Include="Framing\AMQProtocolHeaderException.cs" />
+ <Compile Include="Framing\AMQType.cs" />
<Compile Include="Framing\BasicContentHeaderProperties.cs" />
<Compile Include="Framing\CompositeAMQDataBlock.cs" />
<Compile Include="Framing\ContentBody.cs" />
@@ -60,6 +61,8 @@ <Compile Include="Framing\ContentHeaderBody.cs" />
<Compile Include="Framing\ContentHeaderBodyFactory.cs" />
<Compile Include="Framing\ContentHeaderPropertiesFactory.cs" />
+ <Compile Include="Framing\AMQTypedValue.cs" />
+ <Compile Include="Framing\AMQTypeMap.cs" />
<Compile Include="Framing\EncodingUtils.cs" />
<Compile Include="Framing\FieldTable.cs" />
<Compile Include="Framing\HeartbeatBody.cs" />
diff --git a/dotnet/Qpid.Common/Qpid.Common.mdp b/dotnet/Qpid.Common/Qpid.Common.mdp index aa334cbb71..310b063d63 100644 --- a/dotnet/Qpid.Common/Qpid.Common.mdp +++ b/dotnet/Qpid.Common/Qpid.Common.mdp @@ -27,6 +27,9 @@ <File name="./Framing/AMQMethodBody.cs" subtype="Code" buildaction="Compile" /> <File name="./Framing/AMQMethodBodyFactory.cs" subtype="Code" buildaction="Compile" /> <File name="./Framing/AMQProtocolHeaderException.cs" subtype="Code" buildaction="Compile" /> + <File name="./Framing/AMQType.cs" subtype="Code" buildaction="Compile" /> + <File name="./Framing/AMQTypedValue.cs" subtype="Code" buildaction="Compile" /> + <File name="./Framing/AMQTypeMap.cs" subtype="Code" buildaction="Compile" /> <File name="./Framing/BasicContentHeaderProperties.cs" subtype="Code" buildaction="Compile" /> <File name="./Framing/CompositeAMQDataBlock.cs" subtype="Code" buildaction="Compile" /> <File name="./Framing/ContentBody.cs" subtype="Code" buildaction="Compile" /> @@ -151,4 +154,4 @@ <ProjectReference type="Project" localcopy="True" refto="Qpid.Messaging" /> <ProjectReference type="Gac" localcopy="True" refto="System.Xml, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </References> -</Project>
\ No newline at end of file +</Project> |