summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Greig <rgreig@apache.org>2007-02-13 16:56:03 +0000
committerRobert Greig <rgreig@apache.org>2007-02-13 16:56:03 +0000
commitf1e37d08908f9dc1aa2728c8379091846bccbf13 (patch)
treec0a6fdd4b35416c552a8b5bc7847c1a85b3b6303
parentcd7311844c3058bcc7a0a73e26d31570da63bed7 (diff)
downloadqpid-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.cs22
-rw-r--r--dotnet/Qpid.Buffer/HeapByteBuffer.cs75
-rw-r--r--dotnet/Qpid.Buffer/Qpid.Buffer.csproj2
-rw-r--r--dotnet/Qpid.Buffer/Qpid.Buffer.mdp6
-rw-r--r--dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj6
-rw-r--r--dotnet/Qpid.Common.Tests/Qpid.Common.Tests.mdp4
-rw-r--r--dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs270
-rw-r--r--dotnet/Qpid.Common/Framing/AMQType.cs700
-rw-r--r--dotnet/Qpid.Common/Framing/AMQTypeMap.cs75
-rw-r--r--dotnet/Qpid.Common/Framing/AMQTypedValue.cs76
-rw-r--r--dotnet/Qpid.Common/Framing/EncodingUtils.cs607
-rw-r--r--dotnet/Qpid.Common/Framing/FieldTable.cs729
-rw-r--r--dotnet/Qpid.Common/Qpid.Common.csproj3
-rw-r--r--dotnet/Qpid.Common/Qpid.Common.mdp5
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>