You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ta...@apache.org on 2026/07/31 14:56:12 UTC
(qpid-proton-dotnet) 01/03: Various codec correctness and performance improvements
This is an automated email from the ASF dual-hosted git repository.
tabish121 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton-dotnet.git
commit 5a0c8bd756243acea8bf81d0c01b7a0819ef6ac5
Author: Timothy Bish <ta...@gmail.com>
AuthorDate: Fri Jul 31 09:40:42 2026 -0400
Various codec correctness and performance improvements
---
.gitignore | 1 +
src/Proton.Client/Client/DecodeOptions.cs | 80 +
src/Proton.Client/Client/IDelivery.cs | 24 +
src/Proton.Client/Client/IStreamDelivery.cs | 22 +
.../Client/Implementation/ClientConnection.cs | 3 +-
.../Implementation/ClientConversionSupport.cs | 72 +
.../Client/Implementation/ClientDelivery.cs | 16 +
.../Client/Implementation/ClientMessageSupport.cs | 80 +-
.../Client/Implementation/ClientStreamDelivery.cs | 7 +-
.../Implementation/ClientStreamReceiverMessage.cs | 12 +-
src/Proton.Client/Client/StreamDecodeOptions.cs | 117 +
.../Decoders/AbstractDescribedListTypeDecoder.cs | 232 ++
.../Decoders/AbstractDescribedMapTypeDecoder.cs | 248 ++
.../Codec/Decoders/AbstractDescribedTypeDecoder.cs | 8 +-
.../Codec/Decoders/AbstractPrimitiveTypeDecoder.cs | 32 +-
.../Codec/Decoders/IPrimitiveArrayTypeDecoder.cs | 34 +
src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs | 4 +
.../Decoders/Messaging/AcceptedTypeDecoder.cs | 66 +-
.../Decoders/Messaging/AmqpSequenceTypeDecoder.cs | 16 +-
.../Decoders/Messaging/AmqpValueTypeDecoder.cs | 50 +-
.../Messaging/ApplicationPropertiesTypeDecoder.cs | 136 +-
.../Codec/Decoders/Messaging/DataTypeDecoder.cs | 22 +-
.../Decoders/Messaging/DeleteOnCloseTypeDecoder.cs | 66 +-
.../DeleteOnNoLinksOrMessagesTypeDecoder.cs | 66 +-
.../Messaging/DeleteOnNoLinksTypeDecoder.cs | 66 +-
.../Messaging/DeleteOnNoMessagesTypeDecoder.cs | 66 +-
.../Messaging/DeliveryAnnotationsTypeDecoder.cs | 136 +-
.../Codec/Decoders/Messaging/FooterTypeDecoder.cs | 136 +-
.../Codec/Decoders/Messaging/HeaderTypeDecoder.cs | 94 +-
.../Messaging/MessageAnnotationsTypeDecoder.cs | 136 +-
.../Decoders/Messaging/ModifiedTypeDecoder.cs | 94 +-
.../Decoders/Messaging/PropertiesTypeDecoder.cs | 94 +-
.../Decoders/Messaging/ReceivedTypeDecoder.cs | 84 +-
.../Decoders/Messaging/RejectedTypeDecoder.cs | 112 +-
.../Decoders/Messaging/ReleasedTypeDecoder.cs | 66 +-
.../Codec/Decoders/Messaging/SourceTypeDecoder.cs | 94 +-
.../Codec/Decoders/Messaging/TargetTypeDecoder.cs | 94 +-
.../Primitives/AbstractArrayTypeDecoder.cs | 154 +-
.../Decoders/Primitives/AbstractBinaryDecoder.cs | 39 +-
.../Decoders/Primitives/AbstractListTypeDecoder.cs | 134 +-
.../Decoders/Primitives/AbstractMapTypeDecoder.cs | 163 +-
.../Primitives/AbstractStringTypeDecoder.cs | 38 +-
.../Primitives/AbstractSymbolTypeDecoder.cs | 52 +-
.../Decoders/Primitives/BooleanFalseTypeDecoder.cs | 22 +
.../Decoders/Primitives/BooleanTrueTypeDecoder.cs | 22 +
.../Codec/Decoders/Primitives/List0TypeDecoder.cs | 82 +-
.../Codec/Decoders/Primitives/NullTypeDecoder.cs | 36 +
...llTypeDecoder.cs => SaslSymbol32TypeDecoder.cs} | 23 +-
...ullTypeDecoder.cs => SaslSymbol8TypeDecoder.cs} | 23 +-
.../Primitives/UnsignedInteger0TypeDecoder.cs | 24 +-
.../Primitives/UnsignedLong0TypeDecoder.cs | 24 +-
src/Proton/Codec/Decoders/ProtonDecoder.cs | 186 +-
src/Proton/Codec/Decoders/ProtonDecoderFactory.cs | 4 +-
src/Proton/Codec/Decoders/ProtonDecoderState.cs | 47 +-
src/Proton/Codec/Decoders/ProtonStreamDecoder.cs | 138 +-
.../Codec/Decoders/ProtonStreamDecoderFactory.cs | 4 +-
.../Codec/Decoders/ProtonStreamDecoderState.cs | 59 +-
src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs | 5 +
.../Decoders/Security/SaslChallengeTypeDecoder.cs | 92 +-
.../Codec/Decoders/Security/SaslInitTypeDecoder.cs | 96 +-
.../Decoders/Security/SaslMechanismsTypeDecoder.cs | 92 +-
.../Decoders/Security/SaslOutcomeTypeDecoder.cs | 120 +-
.../Decoders/Security/SaslResponseTypeDecoder.cs | 92 +-
.../Transactions/CoordinatorTypeDecoder.cs | 94 +-
.../Decoders/Transactions/DeclareTypeDecoder.cs | 94 +-
.../Decoders/Transactions/DeclaredTypeDecoder.cs | 100 +-
.../Decoders/Transactions/DischargeTypeDecoder.cs | 116 +-
.../Transactions/TransactionalStateTypeDecoder.cs | 116 +-
.../Codec/Decoders/Transport/AttachTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/BeginTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/CloseTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/DetachTypeDecoder.cs | 90 +-
.../Decoders/Transport/DispositionTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/EndTypeDecoder.cs | 108 +-
.../Transport/ErrorConditionTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/FlowTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/OpenTypeDecoder.cs | 90 +-
.../Decoders/Transport/TransferTypeDecoder.cs | 90 +-
.../Codec/Decoders/UnknownDescribedTypeDecoder.cs | 87 +-
.../Encoders/AbstractDescribedMapTypeEncoder.cs | 41 +-
.../Messaging/ApplicationPropertiesTypeEncoder.cs | 10 +-
.../Messaging/DeliveryAnnotationsTypeEncoder.cs | 10 +-
.../Codec/Encoders/Messaging/FooterTypeEncoder.cs | 10 +-
.../Messaging/MessageAnnotationsTypeEncoder.cs | 10 +-
src/Proton/Codec/Encoders/ProtonEncoder.cs | 26 +-
src/Proton/Codec/Encoders/ProtonEncoderFactory.cs | 4 +-
src/Proton/Codec/IDecoderState.cs | 46 +
src/Proton/Codec/IStreamDecoderState.cs | 106 +
.../Exceptions/ProtocolViolationException.cs | 3 +-
src/Proton/Engine/IEngineConfiguration.cs | 14 +
.../Engine/Implementation/ProtonConstants.cs | 6 +
.../Implementation/ProtonEngineConfiguration.cs | 2 +
.../Implementation/ProtonFrameDecodingHandler.cs | 10 +-
.../Implementation/ProtonIncomingDelivery.cs | 29 +-
src/Proton/Engine/Implementation/ProtonReceiver.cs | 33 +-
.../Implementation/ProtonSessionIncomingWindow.cs | 52 +-
.../Implementation/ProtonSessionOutgoingWindow.cs | 29 +-
.../Implementation/ProtonTransactionManager.cs | 2 +-
.../Sasl/ProtonDefaultSaslClientAuthenticator.cs | 3 +-
.../Sasl/ProtonDefaultSaslServerAuthenticator .cs | 2 +-
.../Engine/Sasl/Client/AnonymousMechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/ExternalMechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/IMechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/PlainMechanism.cs | 2 +-
.../Engine/Sasl/Client/SaslMechanismSelector.cs | 2 +-
.../Engine/Sasl/Client/ScramSHA1Mechanism.cs | 2 +-
.../Engine/Sasl/Client/ScramSHA256Mechanism.cs | 2 +-
.../Engine/Sasl/Client/ScramSHA512Mechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs | 2 +-
src/Proton/Types/Security/SaslChallenge.cs | 2 +-
src/Proton/Types/Security/SaslInit.cs | 2 +-
src/Proton/Types/Security/SaslMechanisms.cs | 2 +-
src/Proton/Types/Security/SaslOutcome.cs | 2 +-
src/Proton/Types/Security/SaslResponse.cs | 2 +-
src/Proton/Types/Symbol.cs | 239 +-
src/Proton/Types/UnknownDescribedType.cs | 2 +-
src/Proton/Utilities/StringUtils.cs | 48 +
src/Proton/Utilities/UnsettledDictionary.cs | 1722 +++++++++++++
.../Client/Implementation/ClientBaseTestFixture.cs | 56 +-
.../Client/Implementation/ClientReceiverTest.cs | 220 ++
.../Implementation/ClientStreamReceiverTest.cs | 276 +++
.../Implementation/ClilentTransactionsTest.cs | 3 +-
.../Codec/Decoders/ProtonDecoderTest.cs | 213 +-
.../Codec/Decoders/ProtonStreamDecoderTest.cs | 219 +-
.../Codec/Messaging/AcceptedTypeCodecTest.cs | 171 ++
.../Codec/Messaging/AmqpSequenceTypeCodecTest.cs | 79 +
.../Codec/Messaging/AmqpValueTypeCodecTest.cs | 295 +++
.../ApplicationPropertiesTypeCodecTest.cs | 674 ++++-
.../Codec/Messaging/DataTypeCodecTest.cs | 25 +
.../Codec/Messaging/DeleteOnCloseTypeCodecTest.cs | 170 ++
.../DeleteOnNoLinksOrMessagesCodecTest.cs | 170 ++
.../Messaging/DeleteOnNoLinksTypeCodecTest.cs | 169 ++
.../Messaging/DeleteOnNoMessagesTypeCodecTest.cs | 170 ++
.../Messaging/DeliveryAnnotationsTypeCodecTest.cs | 256 +-
.../Codec/Messaging/FooterTypeCodecTest.cs | 271 +-
.../Codec/Messaging/HeaderTypeCodecTest.cs | 233 ++
.../Messaging/MessageAnnotationsTypeCodecTest.cs | 268 +-
.../Codec/Messaging/ModifiedTypeCodecTest.cs | 8 +-
.../Codec/Messaging/RejectedTypeCodecTest.cs | 4 +-
.../Codec/Primitives/ArrayTypeCodecTest.cs | 320 +++
.../Codec/Primitives/BinaryTypeCodecTest.cs | 74 +
.../Codec/Primitives/BooleanTypeCodecTest.cs | 441 +++-
.../Codec/Primitives/ByteTypeCodecTest.cs | 189 ++
.../Codec/Primitives/CharacterTypeCodecTests.cs | 103 +
.../Codec/Primitives/DoubleTypeCodecTest.cs | 39 +
.../Codec/Primitives/FloatTypeCodecTest.cs | 39 +
.../Codec/Primitives/IntegerTypeCodecTest.cs | 81 +-
.../Codec/Primitives/ListTypeCodecTest.cs | 466 +++-
.../Codec/Primitives/LongTypeCodecTest.cs | 81 +-
.../Codec/Primitives/MapTypeCodecTest.cs | 323 ++-
.../Codec/Primitives/NullTypeCodecTest.cs | 229 +-
.../Codec/Primitives/ShortTypeCodecTest.cs | 39 +
.../Codec/Primitives/StringTypeCodecTest.cs | 109 +
.../Codec/Primitives/SymbolTypeCodecTest.cs | 109 +
.../Primitives/UnsignedIntegerTypeCodecTest.cs | 186 ++
.../Codec/Primitives/UnsignedLongTypeCodecTest.cs | 196 +-
.../Codec/Security/SaslChallengeTypeCodecTest.cs | 112 +
.../Codec/Security/SaslInitTypeCodecTest.cs | 30 +-
.../Codec/Security/SaslMechanismsTypeCodecTest.cs | 190 +-
.../Codec/Security/SaslOutcomeTypeCodecTest.cs | 112 +
.../Codec/Security/SaslResponseTypeCodecTest.cs | 112 +
.../Codec/UnknownDescribedTypeCodecTest.cs | 478 ++++
.../Engine/Implementation/ProtonDecodeErrorTest.cs | 30 +-
.../Engine/Implementation/ProtonReceiverTest.cs | 205 +-
.../Engine/Implementation/ProtonSessionTest.cs | 85 +
.../Implementation/Sasl/ProtonSaslHandlerTest.cs | 28 +-
.../Implementation/Sasl/ProtonSaslServerTest.cs | 8 +-
.../Engine/Sasl/Client/AbstractMechanismTest.cs | 2 +-
.../Engine/Sasl/Client/SaslMechanismsTest.cs | 2 +-
test/Proton.Tests/Types/Security/SaslInitTest.cs | 3 +-
.../Types/Security/SaslMechanismsTest.cs | 4 +-
test/Proton.Tests/Types/SymbolTest.cs | 166 ++
.../Utilities/UnsettledDictionaryTest.cs | 2592 ++++++++++++++++++++
174 files changed, 15507 insertions(+), 4097 deletions(-)
diff --git a/.gitignore b/.gitignore
index 20e91b6..14cec8b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,7 @@ bld/
.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
+*.lscache
# Visual Studio 2017 auto generated files
Generated\ Files/
diff --git a/src/Proton.Client/Client/DecodeOptions.cs b/src/Proton.Client/Client/DecodeOptions.cs
new file mode 100644
index 0000000..185d8ae
--- /dev/null
+++ b/src/Proton.Client/Client/DecodeOptions.cs
@@ -0,0 +1,80 @@
+/*
+ * 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.Generic;
+using Apache.Qpid.Proton.Codec.Decoders;
+
+namespace Apache.Qpid.Proton.Client
+{
+ public class DecodeOptions : ICloneable
+ {
+ /// <summary>
+ /// Creates a default Decode options instance.
+ /// </summary>
+ public DecodeOptions() : base()
+ {
+ }
+
+ /// <summary>
+ /// Create a new Decode options instance whose settings are copied from the instance provided.
+ /// </summary>
+ /// <param name="other">The decode options instance to copy</param>
+ public DecodeOptions(DecodeOptions other) : base()
+ {
+ other?.CopyInto(this);
+ }
+
+ /// <summary>
+ /// Clone this options instance, changes to the cloned options are not reflected
+ /// in this options instance.
+ /// </summary>
+ /// <returns>A deep copy of this options instance.</returns>
+ public object Clone()
+ {
+ return CopyInto(new DecodeOptions());
+ }
+
+ internal DecodeOptions CopyInto(DecodeOptions other)
+ {
+ other.MaxZeroWidthArrayElements = MaxZeroWidthArrayElements;
+ other.DepthLimit = DepthLimit;
+
+ return other;
+ }
+
+ /// <summary>
+ /// The configured maximum number of elements that can be decoded from an array
+ /// encoded with the zero width AMQP types (Null, UInt0. ULong0, List0, Boolean_False
+ /// and Boolean_True). These are uncommon encodings and can lead to small encodings
+ /// with large memory costs at decode which makes them discouraged for normal use.
+ /// It is recommended that for implementations that implement this limit configuration
+ /// the default be zero meaning zero width array encodings are disabled and will always
+ /// throw a NotImplementedException.
+ /// </summary>
+ public uint MaxZeroWidthArrayElements { get; set; } = ProtonDecoderState.DefaultMaxZeroWidthArrayElements;
+
+ /// <summary>
+ /// Access the configured maximum depth that nested types such as Lists, Maps and Arrays
+ /// can have before a DecodeException is thrown to allow the decoder to error
+ /// in cases where the depth of encoding exceeds what the environment is thought to be
+ /// able to support.
+ /// </summary>
+ public uint DepthLimit { get; set; } = ProtonDecoderState.DefaultMaxDecodeDepth;
+
+ }
+}
\ No newline at end of file
diff --git a/src/Proton.Client/Client/IDelivery.cs b/src/Proton.Client/Client/IDelivery.cs
index c0d8d11..b272954 100644
--- a/src/Proton.Client/Client/IDelivery.cs
+++ b/src/Proton.Client/Client/IDelivery.cs
@@ -53,6 +53,30 @@ namespace Apache.Qpid.Proton.Client
/// <returns>the decoded message from the delivery payload</returns>
IMessage<object> Message();
+ /// <summary>
+ /// Decodes the payload of the delivery and returns a new message.
+ ///
+ /// Calling this message claims the payload of the delivery for the returned Message
+ /// and excludes use of the RawInputStream method of the delivery object. Calling the
+ /// RawInputStream method after calling this method throws ClientIllegalStateException.
+ ///
+ /// The default implementation simply calls the normal message API without any options
+ /// to preserve backwards compatibility.
+ /// </summary>
+ /// <remarks>
+ /// If the incoming message carried any delivery annotations they can be accessed
+ /// via the Annotations method. Re-sending the returned message will not also
+ /// send the incoming delivery annotations, the sender must include them in the
+ /// sender's send call if they are to be forwarded onto the next recipient.
+ /// </remarks>
+ /// <typeparam name="T">Body type of the message</typeparam>
+ /// <param name="options">The decode options to use when decoding the message</param>
+ /// <returns>the decoded message from the delivery payload</returns>
+ IMessage<object> Message(DecodeOptions options)
+ {
+ return Message();
+ }
+
/// <summary>
/// Create and return an read-only Stream that reads the raw payload bytes of the
/// given delivery. Calling this method claims the payload of the delivery for the
diff --git a/src/Proton.Client/Client/IStreamDelivery.cs b/src/Proton.Client/Client/IStreamDelivery.cs
index 7261de3..3bb5309 100644
--- a/src/Proton.Client/Client/IStreamDelivery.cs
+++ b/src/Proton.Client/Client/IStreamDelivery.cs
@@ -54,6 +54,28 @@ namespace Apache.Qpid.Proton.Client
/// <returns>the decoded message from the delivery payload</returns>
IStreamReceiverMessage Message();
+ /// <summary>
+ /// Returns a stream receiver message type that will perform a decode of message
+ /// payload as portions of the streamed message arrive. The message API is inherently
+ /// a blocking API as the decoder will need to wait in some cases to decode a full
+ /// section the incoming message when it is requested.
+ ///
+ /// The default implementation of this method simply calls the original bare message
+ /// to preserve backwards compatibility.
+ /// </summary>
+ /// <remarks>
+ /// If the incoming message carried any delivery annotations they can be accessed
+ /// via the Annotations method. Re-sending the returned message will not also
+ /// send the incoming delivery annotations, the sender must include them in the
+ /// sender's send call if they are to be forwarded onto the next recipient.
+ /// </remarks>
+ /// <typeparam name="T">Body type of the message</typeparam>
+ /// <returns>the decoded message from the delivery payload</returns>
+ IStreamReceiverMessage Message(StreamDecodeOptions options)
+ {
+ return Message();
+ }
+
/// <summary>
/// Decodes the delivery payload and returns a dictionary containing a copy of any
/// associated delivery annotations that were transmitted with the message payload.
diff --git a/src/Proton.Client/Client/Implementation/ClientConnection.cs b/src/Proton.Client/Client/Implementation/ClientConnection.cs
index 751286e..a62727f 100644
--- a/src/Proton.Client/Client/Implementation/ClientConnection.cs
+++ b/src/Proton.Client/Client/Implementation/ClientConnection.cs
@@ -1002,8 +1002,7 @@ namespace Apache.Qpid.Proton.Client.Implementation
if (options.SaslOptions.SaslEnabled)
{
- SaslMechanismSelector mechSelector = new(
- ClientConversionSupport.ToSymbolSet(options.SaslOptions.AllowedMechanisms));
+ SaslMechanismSelector mechSelector = new(options.SaslOptions.AllowedMechanisms);
engine.SaslDriver.Client().Authenticator =
new SaslAuthenticator(mechSelector, new ClientSaslCredentialsProvider(this));
diff --git a/src/Proton.Client/Client/Implementation/ClientConversionSupport.cs b/src/Proton.Client/Client/Implementation/ClientConversionSupport.cs
index 31b7c21..f047825 100644
--- a/src/Proton.Client/Client/Implementation/ClientConversionSupport.cs
+++ b/src/Proton.Client/Client/Implementation/ClientConversionSupport.cs
@@ -44,6 +44,33 @@ namespace Apache.Qpid.Proton.Client.Implementation
return result;
}
+ /// <summary>
+ /// Convert the given string array into an array of Symbol instances
+ /// </summary>
+ /// <param name="stringArray"></param>
+ /// <returns></returns>
+ public static Symbol[] ToSaslSymbolArray(string[] stringArray)
+ {
+ Symbol[] result = null;
+
+ if (stringArray != null)
+ {
+ result = new Symbol[stringArray.Length];
+ for (int i = 0; i < stringArray.Length; ++i)
+ {
+ result[i] = Symbol.SaslLookup(stringArray[i]);
+ }
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Convert the given string array into an array of Symbol instances using the
+ /// SASL Symbol cache as the source of symbol values.
+ /// </summary>
+ /// <param name="stringArray"></param>
+ /// <returns></returns>
public static Symbol[] ToSymbolArray(IEnumerable<DeliveryStateType> stateTypeArray)
{
Symbol[] result = null;
@@ -96,6 +123,26 @@ namespace Apache.Qpid.Proton.Client.Implementation
return result;
}
+ public static Dictionary<Symbol, object> ToSaslSymbolKeyedMap<V>(IEnumerable<KeyValuePair<string, V>> stringsMap)
+ {
+ Dictionary<Symbol, object> result;
+
+ if (stringsMap != null)
+ {
+ result = new Dictionary<Symbol, object>();
+ foreach (KeyValuePair<string, V> entry in stringsMap)
+ {
+ result.Add(Symbol.SaslLookup(entry.Key), entry.Value);
+ }
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
public static Dictionary<string, object> ToStringKeyedMap<V>(IEnumerable<KeyValuePair<Symbol, V>> symbolMap)
{
Dictionary<string, object> result;
@@ -141,6 +188,31 @@ namespace Apache.Qpid.Proton.Client.Implementation
return result;
}
+ /// <summary>
+ /// Converts an enumeration of string values into a set of Symbol values.
+ /// </summary>
+ /// <param name="strings">an enumeration of string values</param>
+ /// <returns>a set of Symbol value that match the input strings</returns>
+ public static ISet<Symbol> ToSaslSymbolSet(in IEnumerable<string> strings)
+ {
+ ISet<Symbol> result;
+
+ if (strings != null)
+ {
+ result = new HashSet<Symbol>();
+ foreach (string value in strings)
+ {
+ result.Add(Symbol.SaslLookup(value));
+ }
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
/// <summary>
/// Converts an enumeration of Symbol values into a set of string values.
/// </summary>
diff --git a/src/Proton.Client/Client/Implementation/ClientDelivery.cs b/src/Proton.Client/Client/Implementation/ClientDelivery.cs
index 45a4bb4..b16efeb 100644
--- a/src/Proton.Client/Client/Implementation/ClientDelivery.cs
+++ b/src/Proton.Client/Client/Implementation/ClientDelivery.cs
@@ -104,6 +104,22 @@ namespace Apache.Qpid.Proton.Client.Implementation
return message;
}
+ public IMessage<object> Message(DecodeOptions options)
+ {
+ if (rawInputStream != null)
+ {
+ throw new ClientIllegalStateException("Cannot access Delivery Annotations API after requesting an InputStream");
+ }
+
+ IMessage<object> message = cachedMessage;
+ if (message == null && payload.IsReadable)
+ {
+ message = cachedMessage = ClientMessageSupport.DecodeMessage(payload, SetDeliveryAnnotations, options);
+ }
+
+ return message;
+ }
+
public IDelivery Disposition(IDeliveryState state, bool settled)
{
return receiver.DispositionAsync(this, state?.AsProtonType(), settled).ConfigureAwait(false).GetAwaiter().GetResult();
diff --git a/src/Proton.Client/Client/Implementation/ClientMessageSupport.cs b/src/Proton.Client/Client/Implementation/ClientMessageSupport.cs
index 9c35139..c3e0423 100644
--- a/src/Proton.Client/Client/Implementation/ClientMessageSupport.cs
+++ b/src/Proton.Client/Client/Implementation/ClientMessageSupport.cs
@@ -119,35 +119,42 @@ namespace Apache.Qpid.Proton.Client.Implementation
ApplicationProperties applicationProperties = message.ApplicationProperties;
Footer footer = message.Footer;
- if (header != null)
+ try
{
- encoder.WriteObject(buffer, encoderState, header);
- }
- if (deliveryAnnotations != null)
- {
- encoder.WriteObject(buffer, encoderState, new DeliveryAnnotations(ClientConversionSupport.ToSymbolKeyedMap(deliveryAnnotations)));
- }
- if (messageAnnotations != null)
- {
- encoder.WriteObject(buffer, encoderState, messageAnnotations);
- }
- if (properties != null)
- {
- encoder.WriteObject(buffer, encoderState, properties);
- }
- if (applicationProperties != null)
- {
- encoder.WriteObject(buffer, encoderState, applicationProperties);
- }
+ if (header != null)
+ {
+ encoder.WriteObject(buffer, encoderState, header);
+ }
+ if (deliveryAnnotations != null)
+ {
+ encoder.WriteObject(buffer, encoderState, new DeliveryAnnotations(ClientConversionSupport.ToSymbolKeyedMap(deliveryAnnotations)));
+ }
+ if (messageAnnotations != null)
+ {
+ encoder.WriteObject(buffer, encoderState, messageAnnotations);
+ }
+ if (properties != null)
+ {
+ encoder.WriteObject(buffer, encoderState, properties);
+ }
+ if (applicationProperties != null)
+ {
+ encoder.WriteObject(buffer, encoderState, applicationProperties);
+ }
- message.ForEachBodySection(section => encoder.WriteObject(buffer, encoderState, section));
+ message.ForEachBodySection(section => encoder.WriteObject(buffer, encoderState, section));
- if (footer != null)
+ if (footer != null)
+ {
+ encoder.WriteObject(buffer, encoderState, footer);
+ }
+
+ return buffer;
+ }
+ finally
{
- encoder.WriteObject(buffer, encoderState, footer);
+ encoderState.Reset();
}
-
- return buffer;
}
#endregion
@@ -159,15 +166,34 @@ namespace Apache.Qpid.Proton.Client.Implementation
return DecodeMessage(DEFAULT_DECODER, DEFAULT_DECODER.NewDecoderState(), buffer, daConsumer);
}
+ public static ClientMessage<object> DecodeMessage(IProtonBuffer buffer, Action<DeliveryAnnotations> daConsumer, DecodeOptions options)
+ {
+ IDecoderState state = DEFAULT_DECODER.NewDecoderState();
+
+ state.DepthLimit = options.DepthLimit;
+ state.MaxZeroWidthArrayElements = options.MaxZeroWidthArrayElements;
+
+ return DecodeMessage(DEFAULT_DECODER, state, buffer, daConsumer);
+ }
+
public static ClientMessage<object> DecodeMessage(IDecoder decoder, IProtonBuffer buffer, Action<DeliveryAnnotations> daConsumer)
{
return DecodeMessage(decoder, decoder.NewDecoderState(), buffer, daConsumer);
}
+ public static ClientMessage<object> DecodeMessage(IDecoder decoder, IProtonBuffer buffer, Action<DeliveryAnnotations> daConsumer, DecodeOptions options)
+ {
+ IDecoderState state = decoder.NewDecoderState();
+
+ state.DepthLimit = options.DepthLimit;
+ state.MaxZeroWidthArrayElements = options.MaxZeroWidthArrayElements;
+
+ return DecodeMessage(decoder, state, buffer, daConsumer);
+ }
+
public static ClientMessage<object> DecodeMessage(IDecoder decoder, IDecoderState decoderState,
IProtonBuffer buffer, Action<DeliveryAnnotations> daConsumer)
{
-
ClientMessage<object> message = new();
ISection section;
@@ -182,6 +208,10 @@ namespace Apache.Qpid.Proton.Client.Implementation
{
throw ClientExceptionSupport.CreateNonFatalOrPassthrough(e);
}
+ finally
+ {
+ decoderState.Reset();
+ }
switch (section.Type)
{
diff --git a/src/Proton.Client/Client/Implementation/ClientStreamDelivery.cs b/src/Proton.Client/Client/Implementation/ClientStreamDelivery.cs
index 2b4895b..cc51e4d 100644
--- a/src/Proton.Client/Client/Implementation/ClientStreamDelivery.cs
+++ b/src/Proton.Client/Client/Implementation/ClientStreamDelivery.cs
@@ -112,6 +112,11 @@ namespace Apache.Qpid.Proton.Client.Implementation
}
public IStreamReceiverMessage Message()
+ {
+ return Message(new StreamDecodeOptions());
+ }
+
+ public IStreamReceiverMessage Message(StreamDecodeOptions options)
{
if (rawInputStream != null && message == null)
{
@@ -120,7 +125,7 @@ namespace Apache.Qpid.Proton.Client.Implementation
if (message == null)
{
- message = new ClientStreamReceiverMessage(receiver, this, rawInputStream = new RawDeliveryInputStream(this));
+ message = new ClientStreamReceiverMessage(receiver, this, options, rawInputStream = new RawDeliveryInputStream(this));
}
return message;
diff --git a/src/Proton.Client/Client/Implementation/ClientStreamReceiverMessage.cs b/src/Proton.Client/Client/Implementation/ClientStreamReceiverMessage.cs
index bffddec..19562fc 100644
--- a/src/Proton.Client/Client/Implementation/ClientStreamReceiverMessage.cs
+++ b/src/Proton.Client/Client/Implementation/ClientStreamReceiverMessage.cs
@@ -51,7 +51,7 @@ namespace Apache.Qpid.Proton.Client.Implementation
private StreamState currentState = StreamState.IDLE;
private MessageBodyInputStream bodyStream;
- internal ClientStreamReceiverMessage(ClientStreamReceiver receiver, ClientStreamDelivery delivery, Stream deliveryStream)
+ internal ClientStreamReceiverMessage(ClientStreamReceiver receiver, ClientStreamDelivery delivery, StreamDecodeOptions decodeOptions, Stream deliveryStream)
{
this.receiver = receiver;
this.delivery = delivery;
@@ -60,6 +60,16 @@ namespace Apache.Qpid.Proton.Client.Implementation
this.protonDecoder = ProtonStreamDecoderFactory.Create();
this.decoderState = protonDecoder.NewDecoderState();
+
+ // Configure the decoder state here which will then apply to all decode operations
+ decoderState.DepthLimit = decodeOptions.DepthLimit;
+ decoderState.MaxZeroWidthArrayElements = decodeOptions.MaxZeroWidthArrayElements;
+ decoderState.MaxStringSize = decodeOptions.MaxStringSize;
+ decoderState.MaxArraySize = decodeOptions.MaxArraySize;
+ decoderState.MaxListSize = decodeOptions.MaxListSize;
+ decoderState.MaxMapSize = decodeOptions.MaxMapSize;
+ decoderState.MaxBinarySize = decodeOptions.MaxBinarySize;
+ decoderState.MaxSymbolSize = decodeOptions.MaxSymbolSize;
}
public IStreamDelivery Delivery => delivery;
diff --git a/src/Proton.Client/Client/StreamDecodeOptions.cs b/src/Proton.Client/Client/StreamDecodeOptions.cs
new file mode 100644
index 0000000..87cff97
--- /dev/null
+++ b/src/Proton.Client/Client/StreamDecodeOptions.cs
@@ -0,0 +1,117 @@
+/*
+ * 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.Generic;
+using Apache.Qpid.Proton.Codec;
+using Apache.Qpid.Proton.Codec.Decoders;
+
+namespace Apache.Qpid.Proton.Client
+{
+ public class StreamDecodeOptions : ICloneable
+ {
+ /// <summary>
+ /// A default used to limit reads from a stream for types that encode a count or
+ /// size of encoded elements.
+ /// </summary>
+ protected static readonly uint DefaultMaxAllocationLimit = int.MaxValue - 8;
+
+ /// <summary>
+ /// Creates a default Decode options instance.
+ /// </summary>
+ public StreamDecodeOptions() : base()
+ {
+ }
+
+ /// <summary>
+ /// Create a new Decode options instance whose settings are copied from the instance provided.
+ /// </summary>
+ /// <param name="other">The decode options instance to copy</param>
+ public StreamDecodeOptions(StreamDecodeOptions other) : base()
+ {
+ other?.CopyInto(this);
+ }
+
+ /// <summary>
+ /// Clone this options instance, changes to the cloned options are not reflected
+ /// in this options instance.
+ /// </summary>
+ /// <returns>A deep copy of this options instance.</returns>
+ public object Clone()
+ {
+ return CopyInto(new StreamDecodeOptions());
+ }
+
+ internal StreamDecodeOptions CopyInto(StreamDecodeOptions other)
+ {
+ other.MaxZeroWidthArrayElements = MaxZeroWidthArrayElements;
+ other.DepthLimit = DepthLimit;
+
+ return other;
+ }
+
+ /// <summary>
+ /// The configured maximum number of elements that can be decoded from an array
+ /// encoded with the zero width AMQP types (Null, UInt0. ULong0, List0, Boolean_False
+ /// and Boolean_True). These are uncommon encodings and can lead to small encodings
+ /// with large memory costs at decode which makes them discouraged for normal use.
+ /// It is recommended that for implementations that implement this limit configuration
+ /// the default be zero meaning zero width array encodings are disabled and will always
+ /// throw a NotImplementedException.
+ /// </summary>
+ public uint MaxZeroWidthArrayElements { get; set; } = ProtonStreamDecoderState.DefaultMaxZeroWidthArrayElements;
+
+ /// <summary>
+ /// Access the configured maximum depth that nested types such as Lists, Maps and Arrays
+ /// can have before a DecodeException is thrown to allow the decoder to error
+ /// in cases where the depth of encoding exceeds what the environment is thought to be
+ /// able to support.
+ /// </summary>
+ public uint DepthLimit { get; set; } = ProtonStreamDecoderState.DefaultMaxDecodeDepth;
+
+ /// <summary>
+ /// The configured maximum size of an encoded string that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxStringSize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum size of an encoded array that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxArraySize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum size of an encoded Binary that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxBinarySize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum size of an encoded Symbol that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxSymbolSize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum encoded list size that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxListSize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum encoded map size that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxMapSize { get; set; } = DefaultMaxAllocationLimit;
+
+ }
+}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/AbstractDescribedListTypeDecoder.cs b/src/Proton/Codec/Decoders/AbstractDescribedListTypeDecoder.cs
new file mode 100644
index 0000000..0666fc8
--- /dev/null
+++ b/src/Proton/Codec/Decoders/AbstractDescribedListTypeDecoder.cs
@@ -0,0 +1,232 @@
+/*
+ * 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.IO;
+using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Codec.Decoders.Primitives;
+using Apache.Qpid.Proton.Types;
+
+namespace Apache.Qpid.Proton.Codec.Decoders
+{
+ public abstract class AbstractDescribedListTypeDecoder : AbstractDescribedTypeDecoder
+ {
+ public sealed override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ {
+ state.IncreaseDepth();
+
+ try
+ {
+ ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+
+ return ReadSingle(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ public sealed override object ReadValue(Stream stream, IStreamDecoderState state)
+ {
+ state.IncreaseDepth();
+
+ try
+ {
+ IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+
+ return ReadSingle(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ public sealed override void SkipValue(IProtonBuffer buffer, IDecoderState state)
+ {
+ CheckIsExpectedType<IListTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state)).SkipValue(buffer, state);
+ }
+
+ public sealed override void SkipValue(Stream stream, IStreamDecoderState state)
+ {
+ CheckIsExpectedType<IListTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state)).SkipValue(stream, state);
+ }
+
+ public sealed override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
+
+ if (listDecoder.IsZeroWidth)
+ {
+ if (count > state.MaxZeroWidthArrayElements)
+ {
+ throw new DecodeException(
+ "Array element count " + count + " is specified to be greater than limit for zero sized " +
+ "encoded array types (" + state.MaxZeroWidthArrayElements + ")");
+ }
+ }
+ else if (count > buffer.ReadableBytes)
+ {
+ throw new DecodeException(
+ "Array encoded element count " + count + " is specified to be greater than the " +
+ "amount of data available " + buffer.ReadableBytes);
+ }
+
+ Array result = Array.CreateInstance(DecodesType, count);
+ for (int i = 0; i < count; ++i)
+ {
+ result.SetValue(ReadSingle(buffer, state, listDecoder), i);
+ }
+
+ return result;
+ }
+
+ public sealed override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ {
+ IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+ IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
+
+ if (listDecoder.IsZeroWidth && count > state.MaxZeroWidthArrayElements)
+ {
+ throw new DecodeException(
+ "Array element count " + count + " is specified to be greater than limit for zero sized " +
+ "encoded array types (" + state.MaxZeroWidthArrayElements + ")");
+ }
+ else if (count > state.MaxArraySize)
+ {
+ throw new DecodeException(
+ "Array encoded element count " + count + " is specified to be greater than the " +
+ "configured max array size " + state.MaxArraySize);
+ }
+
+ Array result = Array.CreateInstance(DecodesType, count);
+ for (int i = 0; i < count; ++i)
+ {
+ result.SetValue(ReadSingle(stream, state, listDecoder), i);
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Gets the minimum number of elements this described list is allowed to carry.
+ /// </summary>
+ protected abstract int MinListElements { get; }
+
+ /// <summary>
+ /// Gets the maximum number of elements this described list is allowed to carry.
+ /// </summary>
+ protected abstract int MaxListElements { get; }
+
+ protected virtual object ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ {
+ int size = listDecoder.ReadSize(buffer, state);
+ long expectedEndPos = buffer.ReadOffset + size;
+
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded size is specified to be greater than the amount " +
+ "of data available s:({0}) r:({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ int count = listDecoder.ReadCount(buffer, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded count is specified to be greater than the reported encoded size " +
+ "s:({0}) c:({1})", size, (uint) count));
+ }
+
+ if (count < MinListElements)
+ {
+ throw new DecodeException(String.Format(
+ "Not enough list elements indicated in the encoded count, expected {0} but got {1}",
+ MinListElements, count));
+ }
+
+ if (count > MaxListElements)
+ {
+ throw new DecodeException(String.Format(
+ "To many elements indicated in the encoded count, maximum {0} but got {1}",
+ MaxListElements, count));
+ }
+
+ object type = ReadType(count, buffer, state.Decoder, state);
+
+ if (buffer.ReadOffset != expectedEndPos)
+ {
+ throw new DecodeException("List decoding did not read the expected amount of bytes: " + size);
+ }
+
+ return type;
+ }
+
+ protected virtual object ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ {
+ int size = listDecoder.ReadSize(stream, state);
+
+ if (size > state.MaxListSize || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded size is specified to be greater than the configured maximum " +
+ "List size allowed s:({0}) c:({1})", (uint) size, state.MaxListSize));
+ }
+
+ int count = listDecoder.ReadCount(stream, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded count is specified to be greater than the reported encoded size " +
+ "s:(%d) c:(%d)", size, (uint) count));
+ }
+
+ if (count < MinListElements)
+ {
+ throw new DecodeException(String.Format(
+ "Not enough list elements indicated in the encoded count, expected {0} but got {1}",
+ MinListElements, count));
+ }
+
+ if (count > MaxListElements)
+ {
+ throw new DecodeException(String.Format(
+ "To many elements indicated in the encoded count, maximum {0} but got {1}",
+ MaxListElements, count));
+ }
+
+ return ReadType(count, stream, state.Decoder, state);
+ }
+
+ /// <summary>
+ /// Reads the actual type from the byte stream with the given number of encoded list elements populated
+ /// </summary>
+ /// <returns>The decoded described type</returns>
+ protected abstract object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state);
+
+ /// <summary>
+ /// Reads the actual type from the byte stream with the given number of encoded list elements populated
+ /// </summary>
+ /// <returns>The decoded described type</returns>
+ protected abstract object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state);
+
+ }
+}
diff --git a/src/Proton/Codec/Decoders/AbstractDescribedMapTypeDecoder.cs b/src/Proton/Codec/Decoders/AbstractDescribedMapTypeDecoder.cs
new file mode 100644
index 0000000..0a58a72
--- /dev/null
+++ b/src/Proton/Codec/Decoders/AbstractDescribedMapTypeDecoder.cs
@@ -0,0 +1,248 @@
+/*
+ * 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.Generic;
+using System.IO;
+using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Codec.Decoders.Primitives;
+using Apache.Qpid.Proton.Types;
+
+namespace Apache.Qpid.Proton.Codec.Decoders
+{
+ public abstract class AbstractDescribedMapTypeDecoder<K> : AbstractDescribedTypeDecoder
+ {
+ private static readonly int MAX_MAP_PREALLOCATION = 256;
+
+ public sealed override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ {
+ state.IncreaseDepth();
+
+ try
+ {
+ IMapTypeDecoder mapTypeDecoder =
+ CheckIsExpectedTypeAndCast<IMapTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state));
+
+ return CreateDescribed(ReadMap(buffer, state, mapTypeDecoder));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ public sealed override object ReadValue(Stream stream, IStreamDecoderState state)
+ {
+ state.IncreaseDepth();
+
+ try
+ {
+ IMapTypeDecoder mapTypeDecoder =
+ CheckIsExpectedTypeAndCast<IMapTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state));
+
+ return CreateDescribed(ReadMap(stream, state, mapTypeDecoder));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ public sealed override void SkipValue(IProtonBuffer buffer, IDecoderState state)
+ {
+ CheckIsExpectedType<IMapTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state)).SkipValue(buffer, state);
+ }
+
+ public sealed override void SkipValue(Stream stream, IStreamDecoderState state)
+ {
+ CheckIsExpectedType<IMapTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state)).SkipValue(stream, state);
+ }
+
+ public sealed override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+
+ ValidateArrayConstraints(count, buffer, state, decoder);
+
+ Array result = Array.CreateInstance(DecodesType, count);
+ for (int i = 0; i < count; ++i)
+ {
+ result.SetValue(CreateDescribed(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder))), i);
+ }
+
+ return result;
+ }
+
+ public sealed override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ {
+ IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+
+ ValidateArrayConstraints(count, stream, state, decoder);
+
+ Array result = Array.CreateInstance(DecodesType, count);
+ for (int i = 0; i < count; ++i)
+ {
+ result.SetValue(CreateDescribed(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder))), i);
+ }
+
+ return result;
+ }
+
+ protected abstract object CreateDescribed(IDictionary<K, object> map);
+
+ protected abstract K ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state);
+
+ protected abstract K ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state);
+
+ private IDictionary<K, Object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
+ {
+ int size = mapDecoder.ReadSize(buffer, state);
+ long expectedEndPos = buffer.ReadOffset + size;
+ int count = ValidateAndGetCount(size, buffer, state, mapDecoder);
+ IDecoder decoder = state.Decoder;
+ int entries = count / 2;
+
+ // Count include both key and value so we must include that in the loop
+ IDictionary<K, Object> map = new Dictionary<K, object>(Math.Min(MAX_MAP_PREALLOCATION, entries));
+
+ for (int i = 0; i < entries; i++)
+ {
+ map.TryAdd(ReadKey(buffer, decoder, state), decoder.ReadObject(buffer, state));
+ }
+
+ if (buffer.ReadOffset != expectedEndPos)
+ {
+ throw new DecodeException("Map decoding did not read the expected amount of bytes: " + size);
+ }
+
+ return map;
+ }
+
+ private IDictionary<K, Object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
+ {
+ int size = mapDecoder.ReadSize(stream, state);
+ int count = ValidateAndGetCount(size, stream, state, mapDecoder);
+ IStreamDecoder decoder = state.Decoder;
+ int entries = count / 2;
+
+ // Count include both key and value so we must include that in the loop
+ IDictionary<K, Object> map = new Dictionary<K, object>(Math.Min(MAX_MAP_PREALLOCATION, entries));
+
+ for (int i = 0; i < entries; i++)
+ {
+ map.TryAdd(ReadKey(stream, decoder, state), decoder.ReadObject(stream, state));
+ }
+
+ return map;
+ }
+
+ protected static int ValidateAndGetCount(int size, IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder decoder)
+ {
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded size is specified to be greater than the amount " +
+ "of data available s:({0}) r:({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ int count = decoder.ReadCount(buffer, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded count is specified to be greater than the reported encoded size " +
+ "s:({0}) c:({1})", size, (uint) count));
+ }
+
+ if (count % 2 != 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded number of elements {0} is not an even number.", count));
+ }
+
+ return count;
+ }
+
+ protected static int ValidateAndGetCount(int size, Stream stream, IStreamDecoderState state, IMapTypeDecoder decoder)
+ {
+ if (size > state.MaxMapSize || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded size is specified to be greater than the configured maximum " +
+ "map size allowed s:({0}) c:({1})", (uint) size, state.MaxMapSize));
+ }
+
+ int count = decoder.ReadCount(stream, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded count is specified to be greater than the reported encoded size " +
+ "s:({0}) c:({1})", size, (uint) count));
+ }
+
+ if (count % 2 != 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded number of elements {0} is not an even number.", count));
+ }
+
+ return count;
+ }
+
+ protected static void ValidateArrayConstraints(int count, IProtonBuffer buffer, IDecoderState state, ITypeDecoder decoder)
+ {
+ if (decoder.GetType() == typeof(void))
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded array count {0} is specified to be greater than limit for zero sized encoded array types (%d)",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+ else
+ {
+ if (count > buffer.ReadableBytes || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded array count {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) count, buffer.ReadableBytes));
+ }
+ }
+ }
+
+ protected static void ValidateArrayConstraints(int count, Stream stream, IStreamDecoderState state, IStreamTypeDecoder decoder)
+ {
+ if (decoder.GetType() == typeof(void))
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded array count {0} is specified to be greater than limit for zero sized encoded array types (%d)",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+ else if (count > state.MaxArraySize || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Array encoded length {0} is specified to be greater than the amount " +
+ "of the configured max array length ({1})", (uint) count, state.MaxStringSize));
+ }
+ }
+ }
+}
diff --git a/src/Proton/Codec/Decoders/AbstractDescribedTypeDecoder.cs b/src/Proton/Codec/Decoders/AbstractDescribedTypeDecoder.cs
index 903db6b..67b2d4e 100644
--- a/src/Proton/Codec/Decoders/AbstractDescribedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/AbstractDescribedTypeDecoder.cs
@@ -75,22 +75,26 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return (T)actual;
}
- protected static void CheckIsExpectedType<T>(ITypeDecoder actual)
+ protected static ITypeDecoder CheckIsExpectedType<T>(ITypeDecoder actual)
{
if (!typeof(T).IsAssignableFrom(actual.GetType()))
{
throw new DecodeException(
"Expected " + typeof(T) + "encoding but got decoder for type: " + actual.GetType().Name);
}
+
+ return actual;
}
- protected static void CheckIsExpectedType<T>(IStreamTypeDecoder actual)
+ protected static IStreamTypeDecoder CheckIsExpectedType<T>(IStreamTypeDecoder actual)
{
if (!typeof(T).IsAssignableFrom(actual.GetType()))
{
throw new DecodeException(
"Expected " + typeof(T) + "encoding but got decoder for type: " + actual.GetType().Name);
}
+
+ return actual;
}
}
}
diff --git a/src/Proton/Codec/Decoders/AbstractPrimitiveTypeDecoder.cs b/src/Proton/Codec/Decoders/AbstractPrimitiveTypeDecoder.cs
index 69204f5..92679ac 100644
--- a/src/Proton/Codec/Decoders/AbstractPrimitiveTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/AbstractPrimitiveTypeDecoder.cs
@@ -23,10 +23,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public abstract class AbstractPrimitiveTypeDecoder : IPrimitiveTypeDecoder
{
- public bool IsArrayType => false;
+ public virtual bool IsArrayType => false;
- public Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
+ public virtual bool IsZeroWidth => false;
+
+ public virtual Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
{
+ ValidateArrayPreconditions(buffer, state, count);
+
Array array = Array.CreateInstance(DecodesType, count);
for (int i = 0; i < count; ++i)
{
@@ -36,8 +40,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return array;
}
- public Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ public virtual Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
{
+ ValidateArrayPreconditions(stream, state, count);
+
Array array = Array.CreateInstance(DecodesType, count);
for (int i = 0; i < count; ++i)
{
@@ -47,6 +53,26 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return array;
}
+ protected virtual void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > buffer.ReadableBytes || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array count indicated {0} is greater than the amount of data available to decode ({1})",
+ (uint) count, buffer.ReadableBytes));
+ }
+ }
+
+ protected virtual void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxArraySize || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array count indicated {0} is greater than the amount of the configured max array size ({1})",
+ (uint) count, state.MaxArraySize));
+ }
+ }
+
#region Interface methods handed off to the subclass
public abstract EncodingCodes EncodingCode { get; }
diff --git a/src/Proton/Codec/Decoders/IPrimitiveArrayTypeDecoder.cs b/src/Proton/Codec/Decoders/IPrimitiveArrayTypeDecoder.cs
index f6efaae..65d768b 100644
--- a/src/Proton/Codec/Decoders/IPrimitiveArrayTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/IPrimitiveArrayTypeDecoder.cs
@@ -15,6 +15,10 @@
* limitations under the License.
*/
+using System;
+using System.IO;
+using Apache.Qpid.Proton.Buffer;
+
namespace Apache.Qpid.Proton.Codec
{
/// <summary>
@@ -22,5 +26,35 @@ namespace Apache.Qpid.Proton.Codec
/// </summary>
public interface IPrimitiveArrayTypeDecoder : IPrimitiveTypeDecoder
{
+ /// <summary>
+ /// Reads the given array from the bytes in the buffer but only if the type encoding
+ /// of the given array matches the given Type filter. This allows the caller to
+ /// effectively limit if the given array is decoded at all if the type encoding is
+ /// not a match and also can act to limit an array to only a single level as the type
+ /// encoding of nested arrays will not be the value type until the bottom of the array
+ /// is reached. To allow all types and any array nesting the caller should pass the
+ /// object Type.
+ /// </summary>
+ /// <param name="buffer"></param>
+ /// <param name="state"></param>
+ /// <param name="ofType"></param>
+ /// <returns>An array containing elements of the given type</returns>
+ object ReadValue(IProtonBuffer buffer, IDecoderState state, Type ofType);
+
+ /// <summary>
+ /// Reads the given array from the bytes in the buffer but only if the type encoding
+ /// of the given array matches the given Type filter. This allows the caller to
+ /// effectively limit if the given array is decoded at all if the type encoding is
+ /// not a match and also can act to limit an array to only a single level as the type
+ /// encoding of nested arrays will not be the value type until the bottom of the array
+ /// is reached. To allow all types and any array nesting the caller should pass the
+ /// object Type.
+ /// </summary>
+ /// <param name="stream"></param>
+ /// <param name="state"></param>
+ /// <param name="ofType"></param>
+ /// <returns>An array containing elements of the given type</returns>
+ object ReadValue(Stream stream, IStreamDecoderState state, Type ofType);
+
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs b/src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs
index 125c252..95f3283 100644
--- a/src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs
@@ -27,5 +27,9 @@ namespace Apache.Qpid.Proton.Codec
/// </summary>
EncodingCodes EncodingCode { get; }
+ /// <summary>
+ /// Returns true if this decoder return types that encode as zero width elements.
+ /// </summary>
+ bool IsZeroWidth { get; }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/AcceptedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/AcceptedTypeDecoder.cs
index d7609cf..b8dd432 100644
--- a/src/Proton/Codec/Decoders/Messaging/AcceptedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/AcceptedTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class AcceptedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class AcceptedTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => Accepted.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Accepted);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override Accepted ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return Accepted.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Accepted[] result = new Accepted[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = Accepted.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override Accepted ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return Accepted.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override Accepted ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Accepted[] result = new Accepted[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = Accepted.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override Accepted ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/AmqpSequenceTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/AmqpSequenceTypeDecoder.cs
index 3af4dca..36e54b2 100644
--- a/src/Proton/Codec/Decoders/Messaging/AmqpSequenceTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/AmqpSequenceTypeDecoder.cs
@@ -33,7 +33,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(AmqpSequence);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ public override AmqpSequence ReadValue(IProtonBuffer buffer, IDecoderState state)
{
ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
IListTypeDecoder valueDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
@@ -59,14 +59,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
+ CheckIsExpectedType<IListTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state)).SkipValue(buffer, state);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ public override AmqpSequence ReadValue(Stream stream, IStreamDecoderState state)
{
IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
IListTypeDecoder valueDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
@@ -92,11 +88,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ CheckIsExpectedType<IListTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state)).SkipValue(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/AmqpValueTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/AmqpValueTypeDecoder.cs
index afd0555..49e05d6 100644
--- a/src/Proton/Codec/Decoders/Messaging/AmqpValueTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/AmqpValueTypeDecoder.cs
@@ -31,10 +31,18 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(AmqpValue);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ public override AmqpValue ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- return new AmqpValue(decoder.ReadValue(buffer, state));
+ state.IncreaseDepth();
+
+ try
+ {
+ return new AmqpValue(state.Decoder.ReadNextTypeDecoder(buffer, state).ReadValue(buffer, state));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
@@ -53,13 +61,30 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- state.Decoder.ReadNextTypeDecoder(buffer, state).SkipValue(buffer, state);
+ state.IncreaseDepth();
+
+ try
+ {
+ state.Decoder.ReadNextTypeDecoder(buffer, state).SkipValue(buffer, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ public override AmqpValue ReadValue(Stream stream, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- return new AmqpValue(decoder.ReadValue(stream, state));
+ state.IncreaseDepth();
+
+ try
+ {
+ return new AmqpValue(state.Decoder.ReadNextTypeDecoder(stream, state).ReadValue(stream, state));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
@@ -78,7 +103,16 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- state.Decoder.ReadNextTypeDecoder(stream, state).SkipValue(stream, state);
+ state.IncreaseDepth();
+
+ try
+ {
+ state.Decoder.ReadNextTypeDecoder(stream, state).SkipValue(stream, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/ApplicationPropertiesTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/ApplicationPropertiesTypeDecoder.cs
index aecd636..544b773 100644
--- a/src/Proton/Codec/Decoders/Messaging/ApplicationPropertiesTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/ApplicationPropertiesTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class ApplicationPropertiesTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ApplicationPropertiesTypeDecoder : AbstractDescribedMapTypeDecoder<string>
{
public override Symbol DescriptorSymbol => ApplicationProperties.DescriptorSymbol;
@@ -33,141 +33,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(ApplicationProperties);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ protected override ApplicationProperties CreateDescribed(IDictionary<string, object> map)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new ApplicationProperties();
- }
-
- return new ApplicationProperties(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- ApplicationProperties[] result = new ApplicationProperties[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new ApplicationProperties();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new ApplicationProperties(
- ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(buffer, state);
- }
- }
-
- private static IDictionary<string, object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
- {
- int size = mapDecoder.ReadSize(buffer, state);
- int count = mapDecoder.ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
-
- IDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<string, object> map = new Dictionary<string, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- string key = decoder.ReadString(buffer, state);
- object value = decoder.ReadObject(buffer, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return new ApplicationProperties(map);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override string ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new ApplicationProperties();
- }
-
- return new ApplicationProperties(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
+ return decoder.ReadString(buffer, state);
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override string ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- ApplicationProperties[] result = new ApplicationProperties[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new ApplicationProperties();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new ApplicationProperties(
- ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(stream, state);
- }
- }
-
- private static IDictionary<string, object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
- {
- _ = mapDecoder.ReadSize(stream, state);
- int count = mapDecoder.ReadCount(stream, state);
-
- IStreamDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<string, object> map = new Dictionary<string, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- string key = decoder.ReadString(stream, state);
- object value = decoder.ReadObject(stream, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return decoder.ReadString(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DataTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DataTypeDecoder.cs
index a46d491..812382e 100644
--- a/src/Proton/Codec/Decoders/Messaging/DataTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DataTypeDecoder.cs
@@ -34,7 +34,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Data);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ public override Data ReadValue(IProtonBuffer buffer, IDecoderState state)
{
EncodingCodes encodingCode = (EncodingCodes)buffer.ReadByte();
int size;
@@ -88,14 +88,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IBinaryTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
+ CheckIsExpectedType<IBinaryTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state)).SkipValue(buffer, state);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ public override Data ReadValue(Stream stream, IStreamDecoderState state)
{
EncodingCodes encodingCode = (EncodingCodes)ProtonStreamReadUtils.ReadByte(stream);
int size;
@@ -114,6 +110,12 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
throw new DecodeException("Expected Binary type but found encoding: " + encodingCode);
}
+ if (size > state.MaxBinarySize)
+ {
+ throw new DecodeException("Binary data size " + size + " is specified to be greater than the " +
+ "configured max binary size (" + state.MaxBinarySize + ")");
+ }
+
return new Data(ProtonByteBufferAllocator.Instance.Wrap(ProtonStreamReadUtils.ReadBytes(stream, size)));
}
@@ -134,11 +136,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IBinaryTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ CheckIsExpectedType<IBinaryTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state)).SkipValue(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeleteOnCloseTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeleteOnCloseTypeDecoder.cs
index 4a3a6a3..daeaf2d 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeleteOnCloseTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeleteOnCloseTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeleteOnCloseTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeleteOnCloseTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => DeleteOnClose.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeleteOnClose);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override DeleteOnClose ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return DeleteOnClose.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnClose[] result = new DeleteOnClose[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = DeleteOnClose.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override DeleteOnClose ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return DeleteOnClose.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnClose[] result = new DeleteOnClose[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = DeleteOnClose.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksOrMessagesTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksOrMessagesTypeDecoder.cs
index 16a7df6..492e278 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksOrMessagesTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksOrMessagesTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeleteOnNoLinksOrMessagesTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeleteOnNoLinksOrMessagesTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => DeleteOnNoLinksOrMessages.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeleteOnNoLinksOrMessages);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override object ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return DeleteOnNoLinksOrMessages.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoLinksOrMessages[] result = new DeleteOnNoLinksOrMessages[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = DeleteOnNoLinksOrMessages.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override object ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return DeleteOnNoLinksOrMessages.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoLinksOrMessages[] result = new DeleteOnNoLinksOrMessages[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = DeleteOnNoLinksOrMessages.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksTypeDecoder.cs
index e53ea01..28d2180 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeleteOnNoLinksTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeleteOnNoLinksTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => DeleteOnNoLinks.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeleteOnNoLinks);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override object ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return DeleteOnNoLinks.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoLinks[] result = new DeleteOnNoLinks[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = DeleteOnNoLinks.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override object ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return DeleteOnNoLinks.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoLinks[] result = new DeleteOnNoLinks[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = DeleteOnNoLinks.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoMessagesTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoMessagesTypeDecoder.cs
index 2b56d15..8c8fd90 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoMessagesTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoMessagesTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeleteOnNoMessagesTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeleteOnNoMessagesTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => DeleteOnNoMessages.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeleteOnNoMessages);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override DeleteOnNoMessages ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return DeleteOnNoMessages.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoMessages[] result = new DeleteOnNoMessages[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = DeleteOnNoMessages.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override DeleteOnNoMessages ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return DeleteOnNoMessages.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override DeleteOnNoMessages ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoMessages[] result = new DeleteOnNoMessages[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = DeleteOnNoMessages.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override DeleteOnNoMessages ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeliveryAnnotationsTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeliveryAnnotationsTypeDecoder.cs
index e24c59b..c490df3 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeliveryAnnotationsTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeliveryAnnotationsTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeliveryAnnotationsTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeliveryAnnotationsTypeDecoder : AbstractDescribedMapTypeDecoder<Symbol>
{
public override Symbol DescriptorSymbol => DeliveryAnnotations.DescriptorSymbol;
@@ -33,141 +33,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeliveryAnnotations);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ protected override DeliveryAnnotations CreateDescribed(IDictionary<Symbol, object> map)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new DeliveryAnnotations();
- }
-
- return new DeliveryAnnotations(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- DeliveryAnnotations[] result = new DeliveryAnnotations[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new DeliveryAnnotations();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new DeliveryAnnotations(
- ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(buffer, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
- {
- int size = mapDecoder.ReadSize(buffer, state);
- int count = mapDecoder.ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
-
- IDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(buffer, state);
- object value = decoder.ReadObject(buffer, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return new DeliveryAnnotations(map);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new DeliveryAnnotations();
- }
-
- return new DeliveryAnnotations(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
+ return decoder.ReadSymbol(buffer, state);
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override Symbol ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- DeliveryAnnotations[] result = new DeliveryAnnotations[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new DeliveryAnnotations();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new DeliveryAnnotations(
- ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(stream, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
- {
- _ = mapDecoder.ReadSize(stream, state);
- int count = mapDecoder.ReadCount(stream, state);
-
- IStreamDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(stream, state);
- object value = decoder.ReadObject(stream, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return decoder.ReadSymbol(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/FooterTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/FooterTypeDecoder.cs
index 05203c3..434e039 100644
--- a/src/Proton/Codec/Decoders/Messaging/FooterTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/FooterTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class FooterTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class FooterTypeDecoder : AbstractDescribedMapTypeDecoder<Symbol>
{
public override Symbol DescriptorSymbol => Footer.DescriptorSymbol;
@@ -33,141 +33,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Footer);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ protected override Footer CreateDescribed(IDictionary<Symbol, object> map)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new Footer();
- }
-
- return new Footer(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- Footer[] result = new Footer[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new Footer();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new Footer(
- ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(buffer, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
- {
- int size = mapDecoder.ReadSize(buffer, state);
- int count = mapDecoder.ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
-
- IDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(buffer, state);
- object value = decoder.ReadObject(buffer, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return new Footer(map);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new Footer();
- }
-
- return new Footer(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
+ return decoder.ReadSymbol(buffer, state);
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override Symbol ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- Footer[] result = new Footer[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new Footer();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new Footer(
- ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(stream, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
- {
- _ = mapDecoder.ReadSize(stream, state);
- int count = mapDecoder.ReadCount(stream, state);
-
- IStreamDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(stream, state);
- object value = decoder.ReadObject(stream, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return decoder.ReadSymbol(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/HeaderTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/HeaderTypeDecoder.cs
index 74e5b67..2a39614 100644
--- a/src/Proton/Codec/Decoders/Messaging/HeaderTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/HeaderTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class HeaderTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class HeaderTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinHeaderListEntries = 0;
private static readonly int MaxHeaderListEntries = 5;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Header);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadHeader(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Header[] result = new Header[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadHeader(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinHeaderListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxHeaderListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Header ReadHeader(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Header ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Header result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinHeaderListEntries)
- {
- throw new DecodeException("Not enough entries in Header list encoding: " + count);
- }
-
- if (count > MaxHeaderListEntries)
- {
- throw new DecodeException("To many entries in Header list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -118,54 +78,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadHeader(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Header[] result = new Header[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadHeader(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Header ReadHeader(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Header ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Header result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinHeaderListEntries)
- {
- throw new DecodeException("Not enough entries in Header list encoding: " + count);
- }
-
- if (count > MaxHeaderListEntries)
- {
- throw new DecodeException("To many entries in Header list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Messaging/MessageAnnotationsTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/MessageAnnotationsTypeDecoder.cs
index 29066ab..0a0d075 100644
--- a/src/Proton/Codec/Decoders/Messaging/MessageAnnotationsTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/MessageAnnotationsTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class MessageAnnotationsTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class MessageAnnotationsTypeDecoder : AbstractDescribedMapTypeDecoder<Symbol>
{
public override Symbol DescriptorSymbol => MessageAnnotations.DescriptorSymbol;
@@ -33,141 +33,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(MessageAnnotations);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ protected override MessageAnnotations CreateDescribed(IDictionary<Symbol, object> map)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new MessageAnnotations();
- }
-
- return new MessageAnnotations(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- MessageAnnotations[] result = new MessageAnnotations[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new MessageAnnotations();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new MessageAnnotations(
- ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(buffer, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
- {
- int size = mapDecoder.ReadSize(buffer, state);
- int count = mapDecoder.ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
-
- IDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(buffer, state);
- object value = decoder.ReadObject(buffer, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return new MessageAnnotations(map);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new MessageAnnotations();
- }
-
- return new MessageAnnotations(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
+ return decoder.ReadSymbol(buffer, state);
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override Symbol ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- MessageAnnotations[] result = new MessageAnnotations[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new MessageAnnotations();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new MessageAnnotations(
- ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(stream, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
- {
- _ = mapDecoder.ReadSize(stream, state);
- int count = mapDecoder.ReadCount(stream, state);
-
- IStreamDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(stream, state);
- object value = decoder.ReadObject(stream, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return decoder.ReadSymbol(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/ModifiedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/ModifiedTypeDecoder.cs
index 313077e..842a21a 100644
--- a/src/Proton/Codec/Decoders/Messaging/ModifiedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/ModifiedTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class ModifiedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ModifiedTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinModifiedListEntries = 0;
private static readonly int MaxModifiedListEntries = 3;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Modified);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadModified(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Modified[] result = new Modified[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadModified(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinModifiedListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxModifiedListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Modified ReadModified(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Modified ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Modified result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinModifiedListEntries)
- {
- throw new DecodeException("Not enough entries in Modified list encoding: " + count);
- }
-
- if (count > MaxModifiedListEntries)
- {
- throw new DecodeException("To many entries in Modified list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -112,54 +72,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadModified(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Modified[] result = new Modified[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadModified(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Modified ReadModified(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Modified ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Modified result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinModifiedListEntries)
- {
- throw new DecodeException("Not enough entries in Modified list encoding: " + count);
- }
-
- if (count > MaxModifiedListEntries)
- {
- throw new DecodeException("To many entries in Modified list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Messaging/PropertiesTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/PropertiesTypeDecoder.cs
index eb4409f..fe3f830 100644
--- a/src/Proton/Codec/Decoders/Messaging/PropertiesTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/PropertiesTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class PropertiesTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class PropertiesTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinPropertiesListEntries = 0;
private static readonly int MaxPropertiesListEntries = 13;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Properties);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadProperties(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Properties[] result = new Properties[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadProperties(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinPropertiesListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxPropertiesListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Properties ReadProperties(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Properties ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Properties result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinPropertiesListEntries)
- {
- throw new DecodeException("Not enough entries in Properties list encoding: " + count);
- }
-
- if (count > MaxPropertiesListEntries)
- {
- throw new DecodeException("To many entries in Properties list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -142,54 +102,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadProperties(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Properties[] result = new Properties[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadProperties(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Properties ReadProperties(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Properties ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Properties result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinPropertiesListEntries)
- {
- throw new DecodeException("Not enough entries in Properties list encoding: " + count);
- }
-
- if (count > MaxPropertiesListEntries)
- {
- throw new DecodeException("To many entries in Properties list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Messaging/ReceivedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/ReceivedTypeDecoder.cs
index 5289887..3f0d578 100644
--- a/src/Proton/Codec/Decoders/Messaging/ReceivedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/ReceivedTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class ReceivedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ReceivedTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int RequiredReceivedListEntries = 2;
@@ -34,49 +34,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Received);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadReceived(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Received[] result = new Received[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadReceived(buffer, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => RequiredReceivedListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
+ protected override int MaxListElements => RequiredReceivedListEntries;
- private static Received ReadReceived(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Received ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Received result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count != RequiredReceivedListEntries)
- {
- throw new DecodeException("Invalid number of entries in Received list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -103,49 +68,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadReceived(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Received[] result = new Received[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadReceived(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Received ReadReceived(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Received ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Received result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count != RequiredReceivedListEntries)
- {
- throw new DecodeException("Invalid number of entries in Received list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Messaging/RejectedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/RejectedTypeDecoder.cs
index 3106475..3e37539 100644
--- a/src/Proton/Codec/Decoders/Messaging/RejectedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/RejectedTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class RejectedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class RejectedTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRejectedListEntries = 0;
private static readonly int MaxRejectedListEntries = 1;
@@ -36,123 +36,29 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Rejected);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadRejected(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Rejected[] result = new Rejected[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadRejected(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinRejectedListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxRejectedListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Rejected ReadRejected(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Rejected ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Rejected result = new Rejected();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinRejectedListEntries)
- {
- throw new DecodeException("Not enough entries in Rejected list encoding: " + count);
- }
-
- if (count > MaxRejectedListEntries)
- {
- throw new DecodeException("To many entries in Rejected list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadRejected(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Rejected[] result = new Rejected[count];
- for (int i = 0; i < count; ++i)
+ if (count == 1)
{
- result[i] = ReadRejected(stream, state, listDecoder);
+ result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Rejected ReadRejected(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Rejected ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Rejected result = new Rejected();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinRejectedListEntries)
- {
- throw new DecodeException("Not enough entries in Rejected list encoding: " + count);
- }
-
- if (count > MaxRejectedListEntries)
- {
- throw new DecodeException("To many entries in Rejected list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
+ if (count == 1)
{
- switch (index)
- {
- case 0:
- result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
- break;
- }
+ result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
}
return result;
diff --git a/src/Proton/Codec/Decoders/Messaging/ReleasedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/ReleasedTypeDecoder.cs
index 1ebcceb..885b0a3 100644
--- a/src/Proton/Codec/Decoders/Messaging/ReleasedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/ReleasedTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class ReleasedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ReleasedTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => Released.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Released);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override Released ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return Released.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Released[] result = new Released[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = Released.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override Released ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return Released.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Released[] result = new Released[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = Released.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/SourceTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/SourceTypeDecoder.cs
index 3a0586e..3ab9ff0 100644
--- a/src/Proton/Codec/Decoders/Messaging/SourceTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/SourceTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class SourceTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SourceTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinSourceListEntries = 0;
private static readonly int MaxSourceListEntries = 11;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Source);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadSource(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Source[] result = new Source[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadSource(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinSourceListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxSourceListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Source ReadSource(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Source ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Source result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinSourceListEntries)
- {
- throw new DecodeException("Not enough entries in Source list encoding: " + count);
- }
-
- if (count > MaxSourceListEntries)
- {
- throw new DecodeException("To many entries in Source list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
@@ -128,54 +88,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadSource(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Source[] result = new Source[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadSource(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Source ReadSource(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Source ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Source result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinSourceListEntries)
- {
- throw new DecodeException("Not enough entries in Source list encoding: " + count);
- }
-
- if (count > MaxSourceListEntries)
- {
- throw new DecodeException("To many entries in Source list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
diff --git a/src/Proton/Codec/Decoders/Messaging/TargetTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/TargetTypeDecoder.cs
index 1898ba5..80ba729 100644
--- a/src/Proton/Codec/Decoders/Messaging/TargetTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/TargetTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class TargetTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class TargetTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinTargetListEntries = 0;
private static readonly int MaxTargetListEntries = 7;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Target);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadTarget(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Target[] result = new Target[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadTarget(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinTargetListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxTargetListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Target ReadTarget(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Target ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Target result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinTargetListEntries)
- {
- throw new DecodeException("Not enough entries in Target list encoding: " + count);
- }
-
- if (count > MaxTargetListEntries)
- {
- throw new DecodeException("To many entries in Target list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
@@ -116,54 +76,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadTarget(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Target[] result = new Target[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadTarget(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Target ReadTarget(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Target ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Target result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinTargetListEntries)
- {
- throw new DecodeException("Not enough entries in Target list encoding: " + count);
- }
-
- if (count > MaxTargetListEntries)
- {
- throw new DecodeException("To many entries in Target list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractArrayTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractArrayTypeDecoder.cs
index 5ddacfc..d1ee35e 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractArrayTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractArrayTypeDecoder.cs
@@ -25,76 +25,160 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
public override Type DecodesType => typeof(Array);
+ public override bool IsArrayType => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- int size = ReadSize(buffer, state);
- int count = ReadCount(buffer, state);
+ return ReadValue(buffer, state, typeof(object));
+ }
- if (EncodingCode == EncodingCodes.Array32)
- {
- size -= 8; // 4 bytes each for size and count;
- }
- else
- {
- size -= 2; // 1 byte each for size and count;
- }
+ public object ReadValue(IProtonBuffer buffer, IDecoderState state, Type ofType)
+ {
+ state.IncreaseDepth();
- if (size > buffer.ReadableBytes)
+ try
{
- throw new DecodeException(string.Format(
- "Array size indicated {0} is greater than the amount of data available to decode ({1})",
- size, buffer.ReadableBytes));
- }
+ int size = ReadSize(buffer, state);
+
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of data available to decode ({1})",
+ (uint) size, buffer.ReadableBytes));
+ }
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ long startOffset = buffer.ReadOffset;
+ int count = ReadCount(buffer, state);
- if (decoder is IPrimitiveArrayTypeDecoder arrayDecoder)
- {
- object[] array = new object[count];
- for (int i = 0; i < count; i++)
+ ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+
+ if (!decoder.DecodesType.IsAssignableTo(ofType))
+ {
+ throw new DecodeException(String.Format(
+ "Unexpected type {0}. Expected a type assignable to {1}", decoder.DecodesType,ofType.Name));
+ }
+
+ Array array;
+
+ if (decoder is IPrimitiveArrayTypeDecoder arrayDecoder)
+ {
+ if (count > buffer.ReadableBytes || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array count indicated {0} is greater than the amount of data available to decode ({1})",
+ (uint) count, buffer.ReadableBytes));
+ }
+
+ array = Array.CreateInstance(decoder.DecodesType, count);
+
+ for (int i = 0; i < count; i++)
+ {
+ array.SetValue(arrayDecoder.ReadValue(buffer, state), i);
+ }
+ }
+ else
+ {
+ array = decoder.ReadArrayElements(buffer, state, count);
+ }
+
+ if (buffer.ReadOffset - startOffset != size)
{
- array[i] = arrayDecoder.ReadValue(buffer, state);
+ throw new DecodeException(
+ "Encoded size indicates the array encoding should have been " + size +
+ " bytes but the actual bytes read was " + (buffer.ReadOffset - startOffset));
}
return array;
}
- else
+ finally
{
- return decoder.ReadArrayElements(buffer, state, count);
+ state.DecreaseDepth();
}
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
{
- _ = ReadSize(stream, state);
- int count = ReadCount(stream, state);
+ return ReadValue(stream, state, typeof(object));
+ }
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+ public object ReadValue(Stream stream, IStreamDecoderState state, Type ofType)
+ {
+ state.IncreaseDepth();
- if (decoder is IPrimitiveArrayTypeDecoder arrayDecoder)
+ try
{
- object[] array = new object[count];
- for (int i = 0; i < count; i++)
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxArraySize || size < 0)
{
- array[i] = arrayDecoder.ReadValue(stream, state);
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the maximum encoded length to decode ({1})",
+ (uint) size, state.MaxArraySize));
}
- return array;
+ int count = ReadCount(stream, state);
+
+ IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+
+ if (!decoder.DecodesType.IsAssignableTo(ofType))
+ {
+ throw new DecodeException(String.Format(
+ "Unexpected type {0}. Expected a type assignable to {1}", decoder.DecodesType,ofType.Name));
+ }
+
+ if (decoder is IPrimitiveArrayTypeDecoder arrayDecoder)
+ {
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array length indicated {0} is greater than the encoded array size ({1})", (uint) count, size));
+ }
+
+ object[] array = new object[count];
+ for (int i = 0; i < count; i++)
+ {
+ array[i] = arrayDecoder.ReadValue(stream, state);
+ }
+
+ return array;
+ }
+ else
+ {
+ return decoder.ReadArrayElements(stream, state, count);
+ }
}
- else
+ finally
{
- return decoder.ReadArrayElements(stream, state, count);
+ state.DecreaseDepth();
}
}
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int size = ReadSize(buffer, state);
+
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of data available to decode ({1})",
+ (uint) size, buffer.ReadableBytes));
+ }
+
+ buffer.SkipBytes(size);
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxArraySize || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the maximum encoded length to decode ({1})",
+ (uint) size, state.MaxArraySize));
+ }
+
+ ProtonStreamReadUtils.SkipBytes(stream, size);
}
protected abstract int ReadSize(IProtonBuffer buffer, IDecoderState state);
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractBinaryDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractBinaryDecoder.cs
index 6a1ef27..a38cfe3 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractBinaryDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractBinaryDecoder.cs
@@ -29,11 +29,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
int length = ReadSize(buffer, state);
- if (length > buffer.ReadableBytes)
+ if (length > buffer.ReadableBytes || length < 0)
{
throw new DecodeException(
- string.Format("Binary data size {0} is specified to be greater than the amount " +
- "of data available ({1})", length, buffer.ReadableBytes));
+ string.Format("Binary data size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) length, buffer.ReadableBytes));
}
IProtonBuffer payload = buffer.Copy(buffer.ReadOffset, length);
@@ -45,10 +45,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override object ReadValue(Stream stream, IStreamDecoderState state)
{
+ int length = ReadSize(stream, state);
+
+ if (length > state.MaxBinarySize || length < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Binary encoded length is specified to be greater than the maximum allowed length " +
+ "l:(%d) m:(%d)", (uint) length, state.MaxBinarySize));
+ }
+
try
{
return ProtonByteBufferAllocator.Instance.Wrap(
- ProtonStreamReadUtils.ReadBytes(stream, ReadSize(stream, state)));
+ ProtonStreamReadUtils.ReadBytes(stream, length));
}
catch (IOException ex)
{
@@ -60,11 +69,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
int length = ReadSize(buffer, state);
- if (length > buffer.ReadableBytes)
+ if (length > buffer.ReadableBytes || length < 0)
{
throw new DecodeException(
string.Format("Binary data size {0} is specified to be greater than the amount " +
- "of data available ({1})", length, buffer.ReadableBytes));
+ "of data available ({1})", (uint) length, buffer.ReadableBytes));
}
buffer.SkipBytes(length);
@@ -72,18 +81,16 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- try
- {
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
- }
- catch (ArgumentOutOfRangeException ex)
- {
- throw new DecodeException("Error while skipping Binary payload bytes", ex);
- }
- catch (IOException ex)
+ int length = ReadSize(stream, state);
+
+ if (length > state.MaxBinarySize || length < 0)
{
- throw new DecodeException("Error while skipping Binary payload bytes", ex);
+ throw new DecodeException(String.Format(
+ "Binary encoded length is specified to be greater than the maximum allowed length " +
+ "l:(%d) m:(%d)", length, state.MaxBinarySize));
}
+
+ ProtonStreamReadUtils.SkipBytes(stream, (uint) length);
}
#region BinaryTypeDecoder abstract methods
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractListTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractListTypeDecoder.cs
index a48d08b..f149a9e 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractListTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractListTypeDecoder.cs
@@ -29,50 +29,91 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
/// </summary>
public abstract class AbstractListTypeDecoder : AbstractPrimitiveTypeDecoder, IListTypeDecoder
{
+ private static readonly int MAX_LIST_PREALLOCATION = 256;
+
public override Type DecodesType => typeof(IList);
public IList<T> ReadList<T>(IProtonBuffer buffer, IDecoderState state)
{
- int size = ReadSize(buffer, state);
+ state.IncreaseDepth();
- // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
- if (size > buffer.ReadableBytes)
+ try
{
- throw new DecodeException(string.Format(
- "List element size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
+ int size = ReadSize(buffer, state);
+ long expectedEndPos = buffer.ReadOffset + size;
+
+ // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "List element size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ int count = ReadCount(buffer, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded element count is specified to be greater than the encoded size " +
+ "s:(%d) c:(%d)", size, count));
+ }
+
+ IList<T> list = new List<T>(Math.Min(MAX_LIST_PREALLOCATION, count));
+ for (int i = 0; i < count; i++)
+ {
+ list.Add(state.Decoder.ReadObject<T>(buffer, state));
+ }
+
+ if (buffer.ReadOffset != expectedEndPos)
+ {
+ throw new DecodeException("List decoding did not read the expected amount of bytes: " + size);
+ }
+
+ return list;
}
-
- int count = ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
+ finally
{
- throw new DecodeException(string.Format(
- "List encoded element count {0} is specified to be greater than the amount " +
- "of data available ({1})", count, buffer.ReadableBytes));
+ state.DecreaseDepth();
}
-
- IList<T> list = new List<T>(count);
- for (int i = 0; i < count; i++)
- {
- list.Add(state.Decoder.ReadObject<T>(buffer, state));
- }
-
- return list;
}
public IList<T> ReadList<T>(Stream stream, IStreamDecoderState state)
{
- ReadSize(stream, state);
- int count = ReadCount(stream, state);
+ state.IncreaseDepth();
- IList<T> list = new List<T>(count);
- for (int i = 0; i < count; i++)
+ try
{
- list.Add(state.Decoder.ReadObject<T>(stream, state));
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxListSize || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoding size is specified to be greater than the maximum allowed size " +
+ "c:(%d) m:(%d)", (uint) size, state.MaxListSize));
+ }
+
+ int count = ReadCount(stream, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded element count is specified to be greater than the encoded size " +
+ "s:(%d) c:(%d)", size, count));
+ }
+
+ IList<T> list = new List<T>(Math.Min(MAX_LIST_PREALLOCATION, count));
+ for (int i = 0; i < count; i++)
+ {
+ list.Add(state.Decoder.ReadObject<T>(stream, state));
+ }
+
+ return list;
+ }
+ finally
+ {
+ state.DecreaseDepth();
}
-
- return list;
}
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
@@ -87,18 +128,47 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int size = ReadSize(buffer, state);
+
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "List element size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ state.IncreaseDepth();
+
+ try
+ {
+ buffer.SkipBytes(size);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxListSize || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoding size is specified to be greater than the maximum allowed size " +
+ "c:(%d) m:(%d)", (uint) size, state.MaxListSize));
+ }
+
+ state.IncreaseDepth();
+
try
{
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
+ ProtonStreamReadUtils.SkipBytes(stream, size);
}
- catch (IOException ex)
+ finally
{
- throw new DecodeException("Error while reading List payload bytes", ex);
+ state.DecreaseDepth();
}
}
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractMapTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractMapTypeDecoder.cs
index e2d1136..3358039 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractMapTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractMapTypeDecoder.cs
@@ -29,63 +29,110 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
/// </summary>
public abstract class AbstractMapTypeDecoder : AbstractPrimitiveTypeDecoder, IMapTypeDecoder
{
+ private static readonly int MAX_MAP_PREALLOCATION = 256;
+
public override Type DecodesType => typeof(IDictionary);
public IDictionary<K, V> ReadMap<K, V>(IProtonBuffer buffer, IDecoderState state)
{
- int size = ReadSize(buffer, state);
-
- // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
- if (size > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map element size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
+ state.IncreaseDepth();
- int count = ReadCount(buffer, state);
-
- if (count % 2 != 0)
+ try
{
- throw new DecodeException(string.Format(
- "Map encoded number of elements {0} is not an even number.", count));
+ int size = ReadSize(buffer, state);
+ long expectedEndPos = buffer.ReadOffset + size;
+
+ // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map element size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ int count = ReadCount(buffer, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map element count {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) count, size));
+ }
+
+ if (count % 2 != 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map encoded number of elements {0} is not an even number.", count));
+ }
+
+ int elements = count / 2;
+ IDictionary<K, V> map = new Dictionary<K, V>(Math.Min(MAX_MAP_PREALLOCATION, elements));
+ for (int i = 0; i < elements; i++)
+ {
+ K key = state.Decoder.ReadObject<K>(buffer, state);
+ V value = state.Decoder.ReadObject<V>(buffer, state);
+
+ map.Add(key, value);
+ }
+
+ if (buffer.ReadOffset != expectedEndPos)
+ {
+ throw new DecodeException("Map decoding did not read the expected amount of bytes: " + size);
+ }
+
+ return map;
}
-
- // Count include both key and value so we must include that in the loop
- IDictionary<K, V> map = new Dictionary<K, V>(count);
- for (int i = 0; i < count / 2; i++)
+ finally
{
- K key = state.Decoder.ReadObject<K>(buffer, state);
- V value = state.Decoder.ReadObject<V>(buffer, state);
-
- map.Add(key, value);
+ state.DecreaseDepth();
}
-
- return map;
}
public IDictionary<K, V> ReadMap<K, V>(Stream stream, IStreamDecoderState state)
{
- ReadSize(stream, state);
- int count = ReadCount(stream, state);
+ state.IncreaseDepth();
- if (count % 2 != 0)
+ try
{
- throw new DecodeException(string.Format(
- "Map encoded number of elements {0} is not an even number.", count));
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxMapSize || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map encoding size {0} is specified to be greater than the maximum " +
+ "allowed size value ({1})", (uint) size, state.MaxMapSize));
+ }
+
+ int count = ReadCount(stream, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map element count {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) count, size));
+ }
+
+ if (count % 2 != 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map encoded number of elements {0} is not an even number.", count));
+ }
+
+ int elements = count / 2;
+ IDictionary<K, V> map = new Dictionary<K, V>(Math.Min(MAX_MAP_PREALLOCATION, elements));
+ for (int i = 0; i < elements; i++)
+ {
+ K key = state.Decoder.ReadObject<K>(stream, state);
+ V value = state.Decoder.ReadObject<V>(stream, state);
+ map.Add(key, value);
+ }
+
+ return map;
}
-
- // Count include both key and value so we must include that in the loop
- IDictionary<K, V> map = new Dictionary<K, V>(count);
- for (int i = 0; i < count / 2; i++)
+ finally
{
- K key = state.Decoder.ReadObject<K>(stream, state);
- V value = state.Decoder.ReadObject<V>(stream, state);
-
- map.Add(key, value);
+ state.DecreaseDepth();
}
-
- return map;
}
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
@@ -100,18 +147,48 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int size = ReadSize(buffer, state);
+
+ // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map element size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ state.IncreaseDepth();
+
+ try
+ {
+ buffer.SkipBytes(size);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxMapSize || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map encoding size {0} is specified to be greater than the maximum " +
+ "allowed size value ({1})", (uint) size, state.MaxMapSize));
+ }
+
+ state.IncreaseDepth();
+
try
{
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
+ ProtonStreamReadUtils.SkipBytes(stream, size);
}
- catch (IOException ex)
+ finally
{
- throw new DecodeException("Error while reading List payload bytes", ex);
+ state.DecreaseDepth();
}
}
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractStringTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractStringTypeDecoder.cs
index 579c539..16ab578 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractStringTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractStringTypeDecoder.cs
@@ -30,11 +30,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
int length = ReadSize(buffer, state);
- if (length > buffer.ReadableBytes)
+ if (length > buffer.ReadableBytes || length < 0)
{
throw new DecodeException(string.Format(
- "String encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", length, buffer.ReadableBytes));
+ "String encoded size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) length, buffer.ReadableBytes));
}
if (length != 0)
@@ -51,6 +51,13 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
int length = ReadSize(stream, state);
+ if (length > state.MaxStringSize || length < 0)
+ {
+ throw new DecodeException(string.Format(
+ "String encoded size {0} is specified to be greater than the amount " +
+ "allowed by configuration ({1})", (uint) length, state.MaxStringSize));
+ }
+
if (length != 0)
{
return state.DecodeUtf8(stream, length);
@@ -63,19 +70,30 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int length = ReadSize(buffer, state);
+
+ if (length > buffer.ReadableBytes || length < 0)
+ {
+ throw new DecodeException(string.Format(
+ "String encoded size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) length, buffer.ReadableBytes));
+ }
+
+ buffer.SkipBytes(length);
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- try
- {
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
- }
- catch (IOException ex)
+ int length = ReadSize(stream, state);
+
+ if (length > state.MaxStringSize || length < 0)
{
- throw new DecodeException("Error while reading String payload bytes", ex);
+ throw new DecodeException(string.Format(
+ "String encoded size {0} is specified to be greater than the amount " +
+ "allowed by configuration ({1})", (uint) length, state.MaxStringSize));
}
+
+ ProtonStreamReadUtils.SkipBytes(stream, length);
}
protected abstract int ReadSize(IProtonBuffer buffer, IDecoderState state);
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractSymbolTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractSymbolTypeDecoder.cs
index 4fa7bf2..f4af667 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractSymbolTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractSymbolTypeDecoder.cs
@@ -39,18 +39,18 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
return Symbol.Lookup("");
}
- if (length > buffer.ReadableBytes)
+ if (length > buffer.ReadableBytes || length < 0)
{
throw new DecodeException(string.Format(
"Symbol encoded size {0} is specified to be greater than the amount " +
- "of data available {1}", length, buffer.ReadableBytes));
+ "of data available {1}", (uint) length, buffer.ReadableBytes));
}
IProtonBuffer symbolBuffer = buffer.Copy(buffer.ReadOffset, length);
buffer.SkipBytes(length);
- return Symbol.Lookup(symbolBuffer);
+ return SymbolLookup(symbolBuffer, true);
}
public override Symbol ReadValue(Stream stream, IStreamDecoderState state)
@@ -62,6 +62,13 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
return Symbol.Lookup("");
}
+ if (length > state.MaxSymbolSize || length < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Binary encoded length is specified to be greater than the maximum allowed length " +
+ "l:(%d) m:(%d)", (uint) length, state.MaxSymbolSize));
+ }
+
byte[] symbolBytes;
try
@@ -73,29 +80,52 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
throw new DecodeException("Error while reading Symbol payload bytes", ex);
}
- return Symbol.Lookup(ProtonByteBufferAllocator.Instance.Wrap(symbolBytes));
+ return SymbolLookup(ProtonByteBufferAllocator.Instance.Wrap(symbolBytes), false);
}
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int length = ReadSize(buffer, state);
+
+ if (length > buffer.ReadableBytes || length < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Symbol encoded size {0} is specified to be greater than the amount " +
+ "of data available {1}", (uint) length, buffer.ReadableBytes));
+ }
+
+ buffer.SkipBytes(length);
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- try
- {
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
- }
- catch (IOException ex)
+ int length = ReadSize(stream, state);
+
+ if (length > state.MaxSymbolSize || length < 0)
{
- throw new DecodeException("Error while reading String payload bytes", ex);
+ throw new DecodeException(String.Format(
+ "Binary encoded length is specified to be greater than the maximum allowed length " +
+ "l:(%d) m:(%d)", (uint) length, state.MaxSymbolSize));
}
+
+ ProtonStreamReadUtils.SkipBytes(stream, length);
}
protected abstract int ReadSize(IProtonBuffer buffer, IDecoderState state);
protected abstract int ReadSize(Stream stream, IStreamDecoderState state);
+ /// <summary>
+ /// Gets a singleton Symbol instance that matches the given IProtonBuffer byte view
+ /// of the Symbol. A subclass can override this to produce the Symbol singleton from
+ /// a source other than the default which is the general symbol cache.
+ /// </summary>
+ /// <param name="buffer"></param>
+ /// <param name="copyOnCreate"></param>
+ /// <returns>A Symbol object that is backed by the value in the buffer</returns>
+ protected virtual Symbol SymbolLookup(IProtonBuffer buffer, bool copyOnCreate)
+ {
+ return Symbol.Lookup(buffer, copyOnCreate);
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/BooleanFalseTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/BooleanFalseTypeDecoder.cs
index aee6d1a..df69626 100644
--- a/src/Proton/Codec/Decoders/Primitives/BooleanFalseTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/BooleanFalseTypeDecoder.cs
@@ -27,6 +27,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(bool);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state) => false;
public override object ReadValue(Stream stream, IStreamDecoderState state) => false;
@@ -38,5 +40,25 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/BooleanTrueTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/BooleanTrueTypeDecoder.cs
index d56c57b..9489d89 100644
--- a/src/Proton/Codec/Decoders/Primitives/BooleanTrueTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/BooleanTrueTypeDecoder.cs
@@ -27,6 +27,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(bool);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state) => true;
public override object ReadValue(Stream stream, IStreamDecoderState state) => true;
@@ -38,5 +40,25 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/List0TypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/List0TypeDecoder.cs
index edfd17f..6f9eb5f 100644
--- a/src/Proton/Codec/Decoders/Primitives/List0TypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/List0TypeDecoder.cs
@@ -29,6 +29,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(IList);
+ public override bool IsZeroWidth => true;
+
public int ReadCount(IProtonBuffer buffer, IDecoderState state)
{
return 0;
@@ -41,12 +43,30 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public IList<T> ReadList<T>(IProtonBuffer buffer, IDecoderState state)
{
- return (IList<T>) Array.Empty<T>();
+ state.IncreaseDepth();
+
+ try
+ {
+ return (IList<T>)Array.Empty<T>();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public IList<T> ReadList<T>(Stream stream, IStreamDecoderState state)
{
- return (IList<T>) Array.Empty<T>();
+ state.IncreaseDepth();
+
+ try
+ {
+ return (IList<T>)Array.Empty<T>();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public int ReadSize(IProtonBuffer buffer, IDecoderState state)
@@ -61,20 +81,74 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- return (IList) Array.Empty<object>();
+ state.IncreaseDepth();
+
+ try
+ {
+ return (IList) Array.Empty<object>();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
{
- return (IList) Array.Empty<object>();
+ state.IncreaseDepth();
+
+ try
+ {
+ return (IList) Array.Empty<object>();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
+ try
+ {
+ state.IncreaseDepth();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
+ try
+ {
+ state.IncreaseDepth();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
index dca1ea2..c99837c 100644
--- a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
@@ -27,6 +27,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(void);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
return null;
@@ -44,5 +46,39 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ ValidateArrayPreconditions(buffer, state, count);
+
+ return new object[count];
+ }
+
+ public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ {
+ ValidateArrayPreconditions(stream, state, count);
+
+ return new object[count];
+ }
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/SaslSymbol32TypeDecoder.cs
similarity index 68%
copy from src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
copy to src/Proton/Codec/Decoders/Primitives/SaslSymbol32TypeDecoder.cs
index dca1ea2..9f5ffc6 100644
--- a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/SaslSymbol32TypeDecoder.cs
@@ -15,34 +15,29 @@
* limitations under the License.
*/
-using System;
using System.IO;
using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Types;
namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
- public sealed class NullTypeDecoder : AbstractPrimitiveTypeDecoder
+ public sealed class SaslSymbol32TypeDecoder : AbstractSymbolTypeDecoder
{
- public override EncodingCodes EncodingCode => EncodingCodes.Null;
+ public override EncodingCodes EncodingCode => EncodingCodes.Sym32;
- public override Type DecodesType => typeof(void);
-
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- return null;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override int ReadSize(IProtonBuffer buffer, IDecoderState state)
{
- return null;
+ return buffer.ReadInt();
}
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
+ protected override int ReadSize(Stream stream, IStreamDecoderState state)
{
+ return ProtonStreamReadUtils.ReadInt(stream);
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol SymbolLookup(IProtonBuffer buffer, bool copyOnCreate)
{
+ return Symbol.SaslLookup(buffer, copyOnCreate);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/SaslSymbol8TypeDecoder.cs
similarity index 68%
copy from src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
copy to src/Proton/Codec/Decoders/Primitives/SaslSymbol8TypeDecoder.cs
index dca1ea2..bd85378 100644
--- a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/SaslSymbol8TypeDecoder.cs
@@ -15,34 +15,29 @@
* limitations under the License.
*/
-using System;
using System.IO;
using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Types;
namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
- public sealed class NullTypeDecoder : AbstractPrimitiveTypeDecoder
+ public sealed class SaslSymbol8TypeDecoder : AbstractSymbolTypeDecoder
{
- public override EncodingCodes EncodingCode => EncodingCodes.Null;
+ public override EncodingCodes EncodingCode => EncodingCodes.Sym8;
- public override Type DecodesType => typeof(void);
-
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- return null;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override int ReadSize(IProtonBuffer buffer, IDecoderState state)
{
- return null;
+ return buffer.ReadUnsignedByte();
}
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
+ protected override int ReadSize(Stream stream, IStreamDecoderState state)
{
+ return ProtonStreamReadUtils.ReadUnsignedByte(stream);
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol SymbolLookup(IProtonBuffer buffer, bool copyOnCreate)
{
+ return Symbol.SaslLookup(buffer, copyOnCreate);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/UnsignedInteger0TypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/UnsignedInteger0TypeDecoder.cs
index 336f53c..0721ba3 100644
--- a/src/Proton/Codec/Decoders/Primitives/UnsignedInteger0TypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/UnsignedInteger0TypeDecoder.cs
@@ -27,9 +27,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(uint);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- return (uint) 0;
+ return (uint)0;
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
@@ -44,5 +46,25 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/UnsignedLong0TypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/UnsignedLong0TypeDecoder.cs
index 36e18db..e4e1b2c 100644
--- a/src/Proton/Codec/Decoders/Primitives/UnsignedLong0TypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/UnsignedLong0TypeDecoder.cs
@@ -27,9 +27,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(ulong);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- return (ulong) 0;
+ return (ulong)0;
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
@@ -44,5 +46,25 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/ProtonDecoder.cs b/src/Proton/Codec/Decoders/ProtonDecoder.cs
index fc09b30..8c5baf4 100644
--- a/src/Proton/Codec/Decoders/ProtonDecoder.cs
+++ b/src/Proton/Codec/Decoders/ProtonDecoder.cs
@@ -25,6 +25,18 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public sealed class ProtonDecoder : IDecoder
{
+ /// <summary>
+ /// The number of unknown described type decoders that are cached for performance
+ /// but limited for memory protection.
+ /// </summary>
+ public static readonly int UnknownDescribedTypeCacheLimit = 16;
+
+ /// <summary>
+ /// If the descriptor for an unknown described type is a Symbol then it must have a
+ /// length shorter than this value to be cached for future lookup.
+ /// </summary>
+ public static readonly int UnknownDescribedTypeDescriptorSizeLimit = 64;
+
/// <summary>
/// The decoders for primitives are fixed and cannot be altered by users who want
/// to register custom decoders. The decoders created here are stateless and can be
@@ -32,6 +44,12 @@ namespace Apache.Qpid.Proton.Codec.Decoders
/// </summary>
private static readonly IPrimitiveTypeDecoder[] primitiveDecoders = new IPrimitiveTypeDecoder[256];
+ public enum DecoderMode
+ {
+ Sasl,
+ Default
+ }
+
static ProtonDecoder()
{
primitiveDecoders[(int)EncodingCodes.Boolean] = new BooleanTypeDecoder();
@@ -77,6 +95,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
// Initialize the locally used primitive type decoders for the main API
symbol8Decoder = (Symbol8TypeDecoder)primitiveDecoders[(int)EncodingCodes.Sym8];
symbol32Decoder = (Symbol32TypeDecoder)primitiveDecoders[(int)EncodingCodes.Sym32];
+ saslSymbol8Decoder = new SaslSymbol8TypeDecoder();
+ saslSymbol32Decoder = new SaslSymbol32TypeDecoder();
binary8Decoder = (Binary8TypeDecoder)primitiveDecoders[(int)EncodingCodes.VBin8];
binary32Decoder = (Binary32TypeDecoder)primitiveDecoders[(int)EncodingCodes.VBin32];
list8Decoder = (List8TypeDecoder)primitiveDecoders[(int)EncodingCodes.List8];
@@ -94,14 +114,28 @@ namespace Apache.Qpid.Proton.Codec.Decoders
private readonly IDictionary<object, IDescribedTypeDecoder> describedTypeDecoders =
new Dictionary<object, IDescribedTypeDecoder>();
+ /// <summary>
+ /// Registry of decoders for described types which are not registered which can be updated with a
+ /// limited number of cached decoders to speed up processing
+ /// </summary>
+ private readonly IDictionary<object, IDescribedTypeDecoder> unknownDescribedTypeDecoders =
+ new Dictionary<object, IDescribedTypeDecoder>();
+
/// <summary>
/// Quick access to decoders that handle AMQP types like Transfer, Properties etc.
/// </summary>
private readonly IDescribedTypeDecoder[] amqpTypeDecoders = new IDescribedTypeDecoder[256];
+ /// <summary>
+ /// User supplied callback to decode descriptors that are reserved types.
+ /// </summary>
+ private readonly Func<IProtonBuffer, IDecoderState, object> reservedDescriptorDecoder;
+
// Internal Decoders used to prevent user to access Proton specific decoding methods
private static readonly Symbol8TypeDecoder symbol8Decoder;
private static readonly Symbol32TypeDecoder symbol32Decoder;
+ private static readonly SaslSymbol8TypeDecoder saslSymbol8Decoder;
+ private static readonly SaslSymbol32TypeDecoder saslSymbol32Decoder;
private static readonly Binary8TypeDecoder binary8Decoder;
private static readonly Binary32TypeDecoder binary32Decoder;
private static readonly List8TypeDecoder list8Decoder;
@@ -113,6 +147,44 @@ namespace Apache.Qpid.Proton.Codec.Decoders
private ProtonDecoderState cachedDecoderState;
+ private readonly DecoderMode decoderMode;
+ private readonly IPrimitiveTypeDecoder[] localPrimitiveDecoders;
+ private readonly AbstractSymbolTypeDecoder localSymbol8Decoder;
+ private readonly AbstractSymbolTypeDecoder localSymbol32Decoder;
+
+ public ProtonDecoder() : this(DecoderMode.Default)
+ {
+ }
+
+ public ProtonDecoder(DecoderMode mode) : this(mode, null)
+ {
+ }
+
+ public ProtonDecoder(Func<IProtonBuffer, IDecoderState, object> descriptorDecoder) : this(DecoderMode.Default, descriptorDecoder)
+ {
+ }
+
+ public ProtonDecoder(DecoderMode mode, Func<IProtonBuffer, IDecoderState, object> descriptorDecoder)
+ {
+ decoderMode = mode;
+ reservedDescriptorDecoder = descriptorDecoder;
+
+ if (decoderMode == DecoderMode.Sasl)
+ {
+ localSymbol8Decoder = saslSymbol8Decoder;
+ localSymbol32Decoder = saslSymbol32Decoder;
+ localPrimitiveDecoders = (IPrimitiveTypeDecoder[])primitiveDecoders.Clone();
+ localPrimitiveDecoders[(int)EncodingCodes.Sym8] = saslSymbol8Decoder;
+ localPrimitiveDecoders[(int)EncodingCodes.Sym32] = saslSymbol32Decoder;
+ }
+ else
+ {
+ localSymbol8Decoder = symbol8Decoder;
+ localSymbol32Decoder = symbol32Decoder;
+ localPrimitiveDecoders = primitiveDecoders;
+ }
+ }
+
public IDecoderState NewDecoderState()
{
return new ProtonDecoderState(this);
@@ -492,8 +564,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return encodingCode switch
{
- EncodingCodes.Sym8 => symbol8Decoder.ReadValue(buffer, state),
- EncodingCodes.Sym32 => symbol32Decoder.ReadValue(buffer, state),
+ EncodingCodes.Sym8 => localSymbol8Decoder.ReadValue(buffer, state),
+ EncodingCodes.Sym32 => localSymbol32Decoder.ReadValue(buffer, state),
EncodingCodes.Null => null,
_ => throw new DecodeException("Expected Symbol type but found encoding: " + encodingCode),
};
@@ -569,9 +641,9 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public T ReadObject<T>(IProtonBuffer buffer, IDecoderState state)
{
- object result = ReadObject(buffer, state);
+ ITypeDecoder decoder = ReadNextTypeDecoder(buffer, state);
- if (result == null)
+ if (decoder.DecodesType == typeof(void))
{
if (typeof(T).IsValueType)
{
@@ -582,44 +654,48 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return default;
}
}
- else if (result.GetType().IsAssignableTo(typeof(T)))
+ else if (decoder.IsArrayType)
+ {
+ return (T)((IPrimitiveArrayTypeDecoder)decoder).ReadValue(buffer, state, typeof(T));
+ }
+ else if (decoder.DecodesType.IsAssignableTo(typeof(T)))
{
- return (T)result;
+ return (T)decoder.ReadValue(buffer, state);
}
else
{
- throw SignalUnexpectedType(result, typeof(T));
+ throw SignalUnexpectedType(decoder.DecodesType, typeof(T));
}
}
public T[] ReadMultiple<T>(IProtonBuffer buffer, IDecoderState state)
{
- object val = ReadObject(buffer, state);
+ ITypeDecoder decoder = ReadNextTypeDecoder(buffer, state);
- if (val == null)
+ if (decoder.DecodesType == typeof(void))
{
- return null;
- }
- else if (val.GetType().IsArray)
- {
- if (typeof(T).IsAssignableFrom(val.GetType().GetElementType()))
+ if (typeof(T).IsValueType)
{
- return (T[])val;
+ throw SignalUnexpectedType(typeof(T));
}
else
{
- throw SignalUnexpectedType(val, typeof(T).MakeArrayType());
+ return default;
}
}
- else if (typeof(T).IsAssignableFrom(val.GetType()))
+ else if (decoder.IsArrayType)
+ {
+ return (T[])((IPrimitiveArrayTypeDecoder)decoder).ReadValue(buffer, state, typeof(T));
+ }
+ else if (decoder.DecodesType.IsAssignableTo(typeof(T)))
{
T[] array = (T[])Array.CreateInstance(typeof(T), 1);
- array[0] = (T)val;
+ array[0] = (T) decoder.ReadValue(buffer, state);
return array;
}
else
{
- throw SignalUnexpectedType(val, typeof(T).MakeArrayType());
+ throw SignalUnexpectedType(decoder.DecodesType, typeof(T));
}
}
@@ -665,7 +741,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
}
else
{
- return primitiveDecoders[(byte)encodingCode];
+ return localPrimitiveDecoders[(byte)encodingCode];
}
}
@@ -680,13 +756,47 @@ namespace Apache.Qpid.Proton.Codec.Decoders
}
catch (Exception)
{
- buffer.ReadOffset = readPos;
- descriptor = ReadObject(buffer, state);
+ try
+ {
+ buffer.ReadOffset = readPos;
+ descriptor = ReadSymbol(buffer, state);
+ }
+ catch (Exception)
+ {
+ buffer.ReadOffset = readPos;
+ if (decoderMode != DecoderMode.Sasl)
+ {
+ if (reservedDescriptorDecoder != null)
+ {
+ state.IncreaseDepth();
+ try
+ {
+ descriptor = reservedDescriptorDecoder.Invoke(buffer, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+ else
+ {
+ throw new DecodeException(String.Format(
+ "Cannot decode a type that is using a reserved type descriptor: {}", PeekNextTypeDecoder(buffer, state).DecodesType));
+ }
+ }
+ else
+ {
+ throw new DecodeException("Cannot decode reserved descriptor type in SASL mode.");
+ }
+ }
}
if (!describedTypeDecoders.TryGetValue(descriptor, out IDescribedTypeDecoder typeDecoder))
{
- typeDecoder = HandleUnknownDescribedType(descriptor);
+ if (!unknownDescribedTypeDecoders.TryGetValue(descriptor, out typeDecoder))
+ {
+ typeDecoder = HandleUnknownDescribedType(descriptor);
+ }
}
return typeDecoder;
@@ -733,22 +843,42 @@ namespace Apache.Qpid.Proton.Codec.Decoders
}
}
- private static InvalidCastException SignalUnexpectedType(in Type type)
+ private static DecodeException SignalUnexpectedType(in Type type)
{
- return new InvalidCastException(
+ return new DecodeException(
"Unexpected null decoding, Expected " + type.Name + ".");
}
- private static InvalidCastException SignalUnexpectedType(in object val, in Type type)
+ private static DecodeException SignalUnexpectedType(in object val, in Type type)
{
- return new InvalidCastException(
+ return new DecodeException(
"Unexpected type " + val.GetType().Name + ". Expected " + type.Name + ".");
}
private IDescribedTypeDecoder HandleUnknownDescribedType(in object descriptor)
{
+ if (DecoderMode.Sasl == decoderMode)
+ {
+ throw new DecodeException("Cannot decode unknown described types from a SASL mode decoder");
+ }
+
+ bool canCache;
+
+ if (descriptor is Symbol symbol && symbol.Length > UnknownDescribedTypeDescriptorSizeLimit)
+ {
+ canCache = false;
+ }
+ else
+ {
+ canCache = descriptor is ulong;
+ }
+
UnknownDescribedTypeDecoder typeDecoder = new(descriptor);
- describedTypeDecoders.Add(descriptor, typeDecoder);
+
+ if (canCache && unknownDescribedTypeDecoders.Count < UnknownDescribedTypeCacheLimit)
+ {
+ unknownDescribedTypeDecoders.Add(descriptor, typeDecoder);
+ }
return typeDecoder;
}
diff --git a/src/Proton/Codec/Decoders/ProtonDecoderFactory.cs b/src/Proton/Codec/Decoders/ProtonDecoderFactory.cs
index 20440f4..3a548a3 100644
--- a/src/Proton/Codec/Decoders/ProtonDecoderFactory.cs
+++ b/src/Proton/Codec/Decoders/ProtonDecoderFactory.cs
@@ -29,7 +29,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public static ProtonDecoder Create()
{
- ProtonDecoder decoder = new();
+ ProtonDecoder decoder = new(ProtonDecoder.DecoderMode.Default);
AddMessagingTypeDecoders(decoder);
AddTransactionTypeDecoders(decoder);
@@ -40,7 +40,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public static ProtonDecoder CreateSasl()
{
- ProtonDecoder decoder = new();
+ ProtonDecoder decoder = new(ProtonDecoder.DecoderMode.Sasl);
AddSaslTypeDecoders(decoder);
diff --git a/src/Proton/Codec/Decoders/ProtonDecoderState.cs b/src/Proton/Codec/Decoders/ProtonDecoderState.cs
index b5cf861..a060e8b 100644
--- a/src/Proton/Codec/Decoders/ProtonDecoderState.cs
+++ b/src/Proton/Codec/Decoders/ProtonDecoderState.cs
@@ -22,8 +22,22 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public class ProtonDecoderState : IDecoderState
{
+ /// <summary>
+ /// The default number of elements a zero width array encoding is allowed to have
+ /// before an decoder exception is thrown.
+ /// </summary>
+ public static readonly uint DefaultMaxZeroWidthArrayElements = 0;
+
+ /// <summary>
+ /// The default maximum depth the decoder will allow before triggering an DecodeException when the
+ /// state depth value is increased during a decode process of complex types that can next objects.
+ /// </summary>
+ public static readonly uint DefaultMaxDecodeDepth = 32;
+
private readonly ProtonDecoder decoder;
+ private uint decodeDepth;
+
public ProtonDecoderState(ProtonDecoder decoder)
{
this.decoder = decoder;
@@ -38,7 +52,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public void Reset()
{
- // Nothing needed yet.
+ decodeDepth = 0;
}
public IDecoder Decoder
@@ -46,8 +60,39 @@ namespace Apache.Qpid.Proton.Codec.Decoders
get { return this.decoder; }
}
+ public uint MaxZeroWidthArrayElements { get; set; } = DefaultMaxZeroWidthArrayElements;
+
+ public uint DepthLimit { get; set; } = DefaultMaxDecodeDepth;
+
+ public void IncreaseDepth()
+ {
+ if (++decodeDepth > DepthLimit)
+ {
+ --decodeDepth; // Unwind decrement to ensure the depth returns to zero.
+ throw new DecodeException(
+ "The nesting of types in the object being decoded exceeded the configured limit: " + DepthLimit);
+ }
+ }
+
+ public void DecreaseDepth()
+ {
+ decodeDepth = decodeDepth > 0 ? decodeDepth - 1 : 0;
+ }
+
public string DecodeUtf8(IProtonBuffer buffer, int length)
{
+ if (length < 0)
+ {
+ throw new DecodeException("Specified UTF length:" + length + " cannot be negative.");
+ }
+
+ if (length > buffer.ReadableBytes)
+ {
+ throw new DecodeException(string.Format(
+ "String encoded size %d is specified to be greater than the amount " +
+ "of data available (%d)", length, buffer.ReadableBytes));
+ }
+
if (Utf8Decoder == null)
{
return InternalDecode(buffer, length);
diff --git a/src/Proton/Codec/Decoders/ProtonStreamDecoder.cs b/src/Proton/Codec/Decoders/ProtonStreamDecoder.cs
index 8bb36cc..e3663bf 100644
--- a/src/Proton/Codec/Decoders/ProtonStreamDecoder.cs
+++ b/src/Proton/Codec/Decoders/ProtonStreamDecoder.cs
@@ -26,6 +26,18 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public sealed class ProtonStreamDecoder : IStreamDecoder
{
+ /// <summary>
+ /// The number of unknown described type decoders that are cached for performance
+ /// but limited for memory protection.
+ /// </summary>
+ public static readonly int UnknownDescribedTypeCacheLimit = 16;
+
+ /// <summary>
+ /// If the descriptor for an unknown described type is a Symbol then it must have a
+ /// length shorter than this value to be cached for future lookup.
+ /// </summary>
+ public static readonly int UnknownDescribedTypeDescriptorSizeLimit = 64;
+
/// <summary>
/// The decoders for primitives are fixed and cannot be altered by users who want
/// to register custom decoders. The decoders created here are stateless and can be
@@ -33,6 +45,12 @@ namespace Apache.Qpid.Proton.Codec.Decoders
/// </summary>
private static readonly IPrimitiveTypeDecoder[] primitiveDecoders = new IPrimitiveTypeDecoder[256];
+ public enum DecoderMode
+ {
+ Sasl,
+ Default
+ }
+
static ProtonStreamDecoder()
{
primitiveDecoders[(int)EncodingCodes.Boolean] = new BooleanTypeDecoder();
@@ -78,6 +96,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
// Initialize the locally used primitive type decoders for the main API
symbol8Decoder = (Symbol8TypeDecoder)primitiveDecoders[(int)EncodingCodes.Sym8];
symbol32Decoder = (Symbol32TypeDecoder)primitiveDecoders[(int)EncodingCodes.Sym32];
+ saslSymbol8Decoder = new SaslSymbol8TypeDecoder();
+ saslSymbol32Decoder = new SaslSymbol32TypeDecoder();
binary8Decoder = (Binary8TypeDecoder)primitiveDecoders[(int)EncodingCodes.VBin8];
binary32Decoder = (Binary32TypeDecoder)primitiveDecoders[(int)EncodingCodes.VBin32];
list8Decoder = (List8TypeDecoder)primitiveDecoders[(int)EncodingCodes.List8];
@@ -95,6 +115,13 @@ namespace Apache.Qpid.Proton.Codec.Decoders
private readonly IDictionary<object, IStreamDescribedTypeDecoder> describedTypeDecoders =
new Dictionary<object, IStreamDescribedTypeDecoder>();
+ /// <summary>
+ /// Registry of decoders for described types which are not registered which can be updated with a
+ /// limited number of cached decoders to speed up processing
+ /// </summary>
+ private readonly IDictionary<object, IStreamDescribedTypeDecoder> unknownDescribedTypeDecoders =
+ new Dictionary<object, IStreamDescribedTypeDecoder>();
+
/// <summary>
/// Quick access to decoders that handle AMQP types like Transfer, Properties etc.
/// </summary>
@@ -103,6 +130,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
// Internal Decoders used to prevent user to access Proton specific decoding methods
private static readonly Symbol8TypeDecoder symbol8Decoder;
private static readonly Symbol32TypeDecoder symbol32Decoder;
+ private static readonly SaslSymbol8TypeDecoder saslSymbol8Decoder;
+ private static readonly SaslSymbol32TypeDecoder saslSymbol32Decoder;
private static readonly Binary8TypeDecoder binary8Decoder;
private static readonly Binary32TypeDecoder binary32Decoder;
private static readonly List8TypeDecoder list8Decoder;
@@ -112,6 +141,35 @@ namespace Apache.Qpid.Proton.Codec.Decoders
private static readonly String8TypeDecoder string8Decoder;
private static readonly String32TypeDecoder string32Decoder;
+ private readonly DecoderMode decoderMode;
+ private readonly IPrimitiveTypeDecoder[] localPrimitiveDecoders;
+ private readonly AbstractSymbolTypeDecoder localSymbol8Decoder;
+ private readonly AbstractSymbolTypeDecoder localSymbol32Decoder;
+
+ public ProtonStreamDecoder() : this(DecoderMode.Default)
+ {
+ }
+
+ public ProtonStreamDecoder(DecoderMode mode)
+ {
+ decoderMode = mode;
+
+ if (decoderMode == DecoderMode.Sasl)
+ {
+ localSymbol8Decoder = saslSymbol8Decoder;
+ localSymbol32Decoder = saslSymbol32Decoder;
+ localPrimitiveDecoders = (IPrimitiveTypeDecoder[])primitiveDecoders.Clone();
+ localPrimitiveDecoders[(int)EncodingCodes.Sym8] = saslSymbol8Decoder;
+ localPrimitiveDecoders[(int)EncodingCodes.Sym32] = saslSymbol32Decoder;
+ }
+ else
+ {
+ localSymbol8Decoder = symbol8Decoder;
+ localSymbol32Decoder = symbol32Decoder;
+ localPrimitiveDecoders = primitiveDecoders;
+ }
+ }
+
private ProtonStreamDecoderState cachedDecoderState;
public IStreamDecoderState NewDecoderState()
@@ -493,8 +551,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return encodingCode switch
{
- EncodingCodes.Sym8 => symbol8Decoder.ReadValue(stream, state),
- EncodingCodes.Sym32 => symbol32Decoder.ReadValue(stream, state),
+ EncodingCodes.Sym8 => localSymbol8Decoder.ReadValue(stream, state),
+ EncodingCodes.Sym32 => localSymbol32Decoder.ReadValue(stream, state),
EncodingCodes.Null => null,
_ => throw new DecodeException("Expected Symbol type but found encoding: " + encodingCode),
};
@@ -570,9 +628,9 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public T ReadObject<T>(Stream stream, IStreamDecoderState state)
{
- object result = ReadObject(stream, state);
+ IStreamTypeDecoder decoder = ReadNextTypeDecoder(stream, state);
- if (result == null)
+ if (decoder.DecodesType == typeof(void))
{
if (typeof(T).IsValueType)
{
@@ -583,44 +641,48 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return default;
}
}
- else if (result.GetType().IsAssignableTo(typeof(T)))
+ else if (decoder.IsArrayType)
+ {
+ return (T)((IPrimitiveArrayTypeDecoder)decoder).ReadValue(stream, state, typeof(T));
+ }
+ else if (decoder.DecodesType.IsAssignableTo(typeof(T)))
{
- return (T)result;
+ return (T)decoder.ReadValue(stream, state);
}
else
{
- throw SignalUnexpectedType(result, typeof(T));
+ throw SignalUnexpectedType(decoder.DecodesType, typeof(T));
}
}
public T[] ReadMultiple<T>(Stream stream, IStreamDecoderState state)
{
- object val = ReadObject(stream, state);
+ IStreamTypeDecoder decoder = ReadNextTypeDecoder(stream, state);
- if (val == null)
+ if (decoder.DecodesType == typeof(void))
{
- return null;
- }
- else if (val.GetType().IsArray)
- {
- if (typeof(T).IsAssignableFrom(val.GetType().GetElementType()))
+ if (typeof(T).IsValueType)
{
- return (T[])val;
+ throw SignalUnexpectedType(typeof(T));
}
else
{
- throw SignalUnexpectedType(val, typeof(T).MakeArrayType());
+ return default;
}
}
- else if (typeof(T).IsAssignableFrom(val.GetType()))
+ else if (decoder.IsArrayType)
+ {
+ return (T[])((IPrimitiveArrayTypeDecoder)decoder).ReadValue(stream, state, typeof(T));
+ }
+ else if (decoder.DecodesType.IsAssignableTo(typeof(T)))
{
T[] array = (T[])Array.CreateInstance(typeof(T), 1);
- array[0] = (T)val;
+ array[0] = (T) decoder.ReadValue(stream, state);
return array;
}
else
{
- throw SignalUnexpectedType(val, typeof(T).MakeArrayType());
+ throw SignalUnexpectedType(decoder.DecodesType, typeof(T));
}
}
@@ -673,7 +735,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
}
else
{
- return primitiveDecoders[(byte)encodingCode];
+ return localPrimitiveDecoders[(byte)encodingCode];
}
}
@@ -688,9 +750,13 @@ namespace Apache.Qpid.Proton.Codec.Decoders
EncodingCodes.Sym32 => symbol32Decoder.ReadValue(stream, state),
_ => throw new DecodeException("Expected Descriptor type but found encoding: " + encodingCode),
};
+
if (!describedTypeDecoders.TryGetValue(descriptor, out IStreamDescribedTypeDecoder streamTypeDecoder))
{
- streamTypeDecoder = HandleUnknownDescribedType(descriptor);
+ if (!unknownDescribedTypeDecoders.TryGetValue(descriptor, out streamTypeDecoder))
+ {
+ streamTypeDecoder = HandleUnknownDescribedType(descriptor);
+ }
}
return streamTypeDecoder;
@@ -739,22 +805,42 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return this;
}
- private static InvalidCastException SignalUnexpectedType(in Type type)
+ private static DecodeException SignalUnexpectedType(in Type type)
{
- return new InvalidCastException(
+ return new DecodeException(
"Unexpected null decoding, Expected " + type.Name + ".");
}
- private static InvalidCastException SignalUnexpectedType(in object val, in Type type)
+ private static DecodeException SignalUnexpectedType(in object val, in Type type)
{
- return new InvalidCastException(
+ return new DecodeException(
"Unexpected type " + val.GetType().Name + ". Expected " + type.Name + ".");
}
private IStreamDescribedTypeDecoder HandleUnknownDescribedType(in object descriptor)
{
+ if (DecoderMode.Sasl == decoderMode)
+ {
+ throw new DecodeException("Cannot decode unknown described types from a SASL mode decoder");
+ }
+
+ bool canCache;
+
+ if (descriptor is Symbol symbol && symbol.Length > UnknownDescribedTypeDescriptorSizeLimit)
+ {
+ canCache = false;
+ }
+ else
+ {
+ canCache = descriptor is ulong;
+ }
+
IStreamDescribedTypeDecoder typeDecoder = new UnknownDescribedTypeDecoder(descriptor);
- describedTypeDecoders.Add(descriptor, (UnknownDescribedTypeDecoder)typeDecoder);
+
+ if (canCache && unknownDescribedTypeDecoders.Count < UnknownDescribedTypeCacheLimit)
+ {
+ unknownDescribedTypeDecoders.Add(descriptor, typeDecoder);
+ }
return typeDecoder;
}
diff --git a/src/Proton/Codec/Decoders/ProtonStreamDecoderFactory.cs b/src/Proton/Codec/Decoders/ProtonStreamDecoderFactory.cs
index 7014b5c..861d8b2 100644
--- a/src/Proton/Codec/Decoders/ProtonStreamDecoderFactory.cs
+++ b/src/Proton/Codec/Decoders/ProtonStreamDecoderFactory.cs
@@ -29,7 +29,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public static ProtonStreamDecoder Create()
{
- ProtonStreamDecoder decoder = new();
+ ProtonStreamDecoder decoder = new(ProtonStreamDecoder.DecoderMode.Default);
AddMessagingTypeDecoders(decoder);
AddTransactionTypeDecoders(decoder);
@@ -40,7 +40,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public static ProtonStreamDecoder CreateSasl()
{
- ProtonStreamDecoder decoder = new();
+ ProtonStreamDecoder decoder = new(ProtonStreamDecoder.DecoderMode.Sasl);
AddSaslTypeDecoders(decoder);
diff --git a/src/Proton/Codec/Decoders/ProtonStreamDecoderState.cs b/src/Proton/Codec/Decoders/ProtonStreamDecoderState.cs
index 7c266d0..e51675e 100644
--- a/src/Proton/Codec/Decoders/ProtonStreamDecoderState.cs
+++ b/src/Proton/Codec/Decoders/ProtonStreamDecoderState.cs
@@ -22,10 +22,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public class ProtonStreamDecoderState : IStreamDecoderState
{
+ /// <summary>
+ /// The default number of elements a zero width array encoding is allowed to have
+ /// before an decoder exception is thrown.
+ /// </summary>
+ public static readonly uint DefaultMaxZeroWidthArrayElements = 0;
+
+ /// <summary>
+ /// The default maximum depth the decoder will allow before triggering an DecodeException when the
+ /// state depth value is increased during a decode process of complex types that can next objects.
+ /// </summary>
+ public static readonly uint DefaultMaxDecodeDepth = 32;
+
private readonly ProtonStreamDecoder decoder;
public IStreamDecoder Decoder => decoder;
+ private uint decodeDepth;
+
public ProtonStreamDecoderState(ProtonStreamDecoder parent) : base()
{
this.decoder = parent;
@@ -38,13 +52,56 @@ namespace Apache.Qpid.Proton.Codec.Decoders
/// </summary>
public IUtf8StreamDecoder Utf8Decoder { get; set; }
+ public uint MaxZeroWidthArrayElements { get; set; } = DefaultMaxZeroWidthArrayElements;
+
+ public uint MaxStringSize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxArraySize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxBinarySize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxSymbolSize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxListSize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxMapSize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
public void Reset()
{
- throw new NotImplementedException();
+ decodeDepth = 0;
+ }
+
+ public uint DepthLimit { get; set; } = DefaultMaxDecodeDepth;
+
+ public void IncreaseDepth()
+ {
+ if (++decodeDepth > DepthLimit)
+ {
+ --decodeDepth; // Unwind decrement to ensure the depth returns to zero.
+ throw new DecodeException(
+ "The nesting of types in the object being decoded exceeded the configured limit: " + DepthLimit);
+ }
+ }
+
+ public void DecreaseDepth()
+ {
+ decodeDepth = decodeDepth > 0 ? decodeDepth - 1 : 0;
}
public string DecodeUtf8(Stream stream, int length)
{
+ if (length < 0)
+ {
+ throw new DecodeException("Specified UTF length:" + length + " cannot be negative.");
+ }
+
+ if (length > MaxStringSize)
+ {
+ throw new DecodeException(string.Format(
+ "String encoded size %d is specified to be greater than the amount " +
+ "of data available (%d)", length, MaxStringSize));
+ }
+
if (Utf8Decoder == null)
{
return InternalDecode(stream, length);
diff --git a/src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs b/src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs
index 3e04ef3..8b97324 100644
--- a/src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs
+++ b/src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs
@@ -287,6 +287,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders
throw new DecodeException("Stream was not able to skip the requested amount of bytes: " + amount);
}
}
+ catch (ArgumentOutOfRangeException ex)
+ {
+ throw new DecodeException(
+ string.Format("Error while attempting to skip {0} bytes in the given InputStream", amount), ex);
+ }
catch (IOException ex)
{
throw new DecodeException(
diff --git a/src/Proton/Codec/Decoders/Security/SaslChallengeTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslChallengeTypeDecoder.cs
index 2895451..719f4ba 100644
--- a/src/Proton/Codec/Decoders/Security/SaslChallengeTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslChallengeTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslChallengeTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslChallengeTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int RequiredListEntries = 1;
@@ -34,102 +34,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslChallenge);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslChallenge[] result = new SaslChallenge[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => RequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => RequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static SaslChallenge ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslChallenge ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslChallenge result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Challenge must contain at least one entry: " + count);
- }
- else
- {
- result.Challenge = state.Decoder.ReadBinary(buffer, state);
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslChallenge[] result = new SaslChallenge[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ result.Challenge = state.Decoder.ReadBinary(buffer, state);
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslChallenge ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslChallenge ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslChallenge result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Challenge must contain at least one entry: " + count);
- }
- else
- {
- result.Challenge = state.Decoder.ReadBinary(stream, state);
- }
+ result.Challenge = state.Decoder.ReadBinary(stream, state);
return result;
}
diff --git a/src/Proton/Codec/Decoders/Security/SaslInitTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslInitTypeDecoder.cs
index f9004b5..42639d5 100644
--- a/src/Proton/Codec/Decoders/Security/SaslInitTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslInitTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslInitTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslInitTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinListEntries = 0;
private static readonly int MaxListEntries = 3;
@@ -35,55 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslInit);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslInit[] result = new SaslInit[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
+ protected override int MinListElements => MinListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
+ protected override int MaxListElements => MaxListEntries;
- private static SaslInit ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslInit ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslInit result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinListEntries)
- {
- throw new DecodeException("Not enough entries in SaslInit list encoding: " + count);
- }
-
- if (count > MaxListEntries)
- {
- throw new DecodeException("To many entries in SaslInit list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
@@ -103,55 +62,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslInit[] result = new SaslInit[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslInit ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslInit ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslInit result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinListEntries)
- {
- throw new DecodeException("Not enough entries in SaslInit list encoding: " + count);
- }
-
- if (count > MaxListEntries)
- {
- throw new DecodeException("To many entries in SaslInit list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
diff --git a/src/Proton/Codec/Decoders/Security/SaslMechanismsTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslMechanismsTypeDecoder.cs
index acedaba..65e3319 100644
--- a/src/Proton/Codec/Decoders/Security/SaslMechanismsTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslMechanismsTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslMechanismsTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslMechanismsTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int RequiredListEntries = 1;
@@ -34,102 +34,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslMechanisms);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslMechanisms[] result = new SaslMechanisms[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => RequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => RequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static SaslMechanisms ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslMechanisms ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslMechanisms result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Mechanisms must contain at least one entry: " + count);
- }
- else
- {
- result.Mechanisms = state.Decoder.ReadMultiple<Symbol>(buffer, state);
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslMechanisms[] result = new SaslMechanisms[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ result.Mechanisms = state.Decoder.ReadMultiple<Symbol>(buffer, state);
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslMechanisms ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslMechanisms ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslMechanisms result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Mechanisms must contain at least one entry: " + count);
- }
- else
- {
- result.Mechanisms = state.Decoder.ReadMultiple<Symbol>(stream, state);
- }
+ result.Mechanisms = state.Decoder.ReadMultiple<Symbol>(stream, state);
return result;
}
diff --git a/src/Proton/Codec/Decoders/Security/SaslOutcomeTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslOutcomeTypeDecoder.cs
index e863cca..cacd25c 100644
--- a/src/Proton/Codec/Decoders/Security/SaslOutcomeTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslOutcomeTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslOutcomeTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslOutcomeTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinListEntries = 1;
private static readonly int MaxListEntries = 2;
@@ -35,131 +35,33 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslOutcome);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MinListElements => MinListEntries;
- SaslOutcome[] result = new SaslOutcome[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
+ protected override int MaxListElements => MaxListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static SaslOutcome ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslOutcome ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslOutcome result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinListEntries)
- {
- throw new DecodeException("Not enough entries in SaslOutcome list encoding: " + count);
- }
-
- if (count > MaxListEntries)
- {
- throw new DecodeException("To many entries in SaslOutcome list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.Code = (SaslCode)state.Decoder.ReadUnsignedByte(buffer, state);
- break;
- case 1:
- result.AdditionalData = state.Decoder.ReadBinary(buffer, state);
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ result.Code = (SaslCode)state.Decoder.ReadUnsignedByte(buffer, state);
- SaslOutcome[] result = new SaslOutcome[count];
- for (int i = 0; i < count; ++i)
+ if (count == 2)
{
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ result.AdditionalData = state.Decoder.ReadBinary(buffer, state);
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslOutcome ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslOutcome ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslOutcome result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinListEntries)
- {
- throw new DecodeException("Not enough entries in SaslOutcome list encoding: " + count);
- }
-
- if (count > MaxListEntries)
- {
- throw new DecodeException("To many entries in SaslOutcome list encoding: " + count);
- }
+ result.Code = (SaslCode)state.Decoder.ReadUnsignedByte(stream, state);
- for (int index = 0; index < count; ++index)
+ if (count == 2)
{
- switch (index)
- {
- case 0:
- result.Code = (SaslCode)state.Decoder.ReadUnsignedByte(stream, state);
- break;
- case 1:
- result.AdditionalData = state.Decoder.ReadBinary(stream, state);
- break;
- }
+ result.AdditionalData = state.Decoder.ReadBinary(stream, state);
}
return result;
diff --git a/src/Proton/Codec/Decoders/Security/SaslResponseTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslResponseTypeDecoder.cs
index b6afef4..96b3fb0 100644
--- a/src/Proton/Codec/Decoders/Security/SaslResponseTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslResponseTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslResponseTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslResponseTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int RequiredListEntries = 1;
@@ -34,102 +34,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslResponse);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslResponse[] result = new SaslResponse[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => RequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => RequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static SaslResponse ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslResponse ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslResponse result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Response must contain at least one entry: " + count);
- }
- else
- {
- result.Response = state.Decoder.ReadBinary(buffer, state);
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslResponse[] result = new SaslResponse[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ result.Response = state.Decoder.ReadBinary(buffer, state);
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslResponse ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslResponse ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslResponse result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Response must contain at least one entry: " + count);
- }
- else
- {
- result.Response = state.Decoder.ReadBinary(stream, state);
- }
+ result.Response = state.Decoder.ReadBinary(stream, state);
return result;
}
diff --git a/src/Proton/Codec/Decoders/Transactions/CoordinatorTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/CoordinatorTypeDecoder.cs
index d2ac1a4..9c4a48a 100644
--- a/src/Proton/Codec/Decoders/Transactions/CoordinatorTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/CoordinatorTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transactions;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class CoordinatorTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class CoordinatorTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 0;
private static readonly int MaxRequiredListEntries = 1;
@@ -35,53 +35,15 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(Coordinator);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Coordinator[] result = new Coordinator[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static Coordinator ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Coordinator ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Coordinator result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Coordinator list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Coordinator list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.Capabilities = state.Decoder.ReadMultiple<Symbol>(buffer, state);
}
@@ -89,53 +51,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Coordinator[] result = new Coordinator[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Coordinator ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Coordinator ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Coordinator result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Coordinator list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Coordinator list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.Capabilities = state.Decoder.ReadMultiple<Symbol>(stream, state);
}
diff --git a/src/Proton/Codec/Decoders/Transactions/DeclareTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/DeclareTypeDecoder.cs
index a425ca1..71fc341 100644
--- a/src/Proton/Codec/Decoders/Transactions/DeclareTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/DeclareTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transactions;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class DeclareTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeclareTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 0;
private static readonly int MaxRequiredListEntries = 1;
@@ -35,53 +35,15 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(Declare);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Declare[] result = new Declare[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static Declare ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Declare ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Declare result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Declare list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Declare list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.GlobalTxnId = (IGlobalTxnId)state.Decoder.ReadObject(buffer, state);
}
@@ -89,53 +51,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Declare[] result = new Declare[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Declare ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Declare ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Declare result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Declare list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Declare list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.GlobalTxnId = (IGlobalTxnId)state.Decoder.ReadObject(stream, state);
}
diff --git a/src/Proton/Codec/Decoders/Transactions/DeclaredTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/DeclaredTypeDecoder.cs
index fd2cfe5..9b6aabd 100644
--- a/src/Proton/Codec/Decoders/Transactions/DeclaredTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/DeclaredTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transactions;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class DeclaredTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeclaredTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 1;
private static readonly int MaxRequiredListEntries = 1;
@@ -35,110 +35,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(Declared);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Declared[] result = new Declared[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static Declared ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Declared ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Declared result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("The txn-id field cannot be omitted");
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Declared list encoding: " + count);
- }
- else if (count == 1)
- {
- result.TxnId = state.Decoder.ReadBinary(buffer, state);
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Declared[] result = new Declared[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ result.TxnId = state.Decoder.ReadBinary(buffer, state);
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Declared ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Declared ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Declared result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("The txn-id field cannot be omitted");
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Declared list encoding: " + count);
- }
- else if (count == 1)
- {
- result.TxnId = state.Decoder.ReadBinary(stream, state);
- }
+ result.TxnId = state.Decoder.ReadBinary(stream, state);
return result;
}
diff --git a/src/Proton/Codec/Decoders/Transactions/DischargeTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/DischargeTypeDecoder.cs
index 64b5b97..5df5df2 100644
--- a/src/Proton/Codec/Decoders/Transactions/DischargeTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/DischargeTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transactions;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class DischargeTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DischargeTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 1;
private static readonly int MaxRequiredListEntries = 2;
@@ -35,127 +35,33 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(Discharge);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Discharge[] result = new Discharge[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static Discharge ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Discharge ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Discharge result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Discharge list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Discharge list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.TxnId = state.Decoder.ReadBinary(buffer, state);
- break;
- case 1:
- result.Fail = state.Decoder.ReadBoolean(buffer, state) ?? false;
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+ result.TxnId = state.Decoder.ReadBinary(buffer, state);
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Discharge[] result = new Discharge[count];
- for (int i = 0; i < count; ++i)
+ if (count == 2)
{
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ result.Fail = state.Decoder.ReadBoolean(buffer, state) ?? false;
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Discharge ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Discharge ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Discharge result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Discharge list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Discharge list encoding: " + count);
- }
+ result.TxnId = state.Decoder.ReadBinary(stream, state);
- for (int index = 0; index < count; ++index)
+ if (count == 2)
{
- switch (index)
- {
- case 0:
- result.TxnId = state.Decoder.ReadBinary(stream, state);
- break;
- case 1:
- result.Fail = state.Decoder.ReadBoolean(stream, state) ?? false;
- break;
- }
+ result.Fail = state.Decoder.ReadBoolean(stream, state) ?? false;
}
return result;
diff --git a/src/Proton/Codec/Decoders/Transactions/TransactionalStateTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/TransactionalStateTypeDecoder.cs
index 7ca6f42..bb2f61a 100644
--- a/src/Proton/Codec/Decoders/Transactions/TransactionalStateTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/TransactionalStateTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class TransactionalStateTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class TransactionalStateTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 1;
private static readonly int MaxRequiredListEntries = 2;
@@ -36,127 +36,33 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(TransactionalState);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- TransactionalState[] result = new TransactionalState[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static TransactionalState ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override TransactionalState ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
TransactionalState result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in TransactionalState list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in TransactionalState list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.TxnId = state.Decoder.ReadBinary(buffer, state);
- break;
- case 1:
- result.Outcome = state.Decoder.ReadObject<IOutcome>(buffer, state);
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+ result.TxnId = state.Decoder.ReadBinary(buffer, state);
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- TransactionalState[] result = new TransactionalState[count];
- for (int i = 0; i < count; ++i)
+ if (count == 2)
{
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ result.Outcome = state.Decoder.ReadObject<IOutcome>(buffer, state);
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static TransactionalState ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override TransactionalState ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
TransactionalState result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in TransactionalState list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in TransactionalState list encoding: " + count);
- }
+ result.TxnId = state.Decoder.ReadBinary(stream, state);
- for (int index = 0; index < count; ++index)
+ if (count == 2)
{
- switch (index)
- {
- case 0:
- result.TxnId = state.Decoder.ReadBinary(stream, state);
- break;
- case 1:
- result.Outcome = state.Decoder.ReadObject<IOutcome>(stream, state);
- break;
- }
+ result.Outcome = state.Decoder.ReadObject<IOutcome>(stream, state);
}
return result;
diff --git a/src/Proton/Codec/Decoders/Transport/AttachTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/AttachTypeDecoder.cs
index 9258f5d..f4d52d7 100644
--- a/src/Proton/Codec/Decoders/Transport/AttachTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/AttachTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class AttachTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class AttachTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinAttachListEntries = 3;
private static readonly int MaxAttachListEntries = 14;
@@ -36,52 +36,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Attach);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadAttach(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Attach[] result = new Attach[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadAttach(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinAttachListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxAttachListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Attach ReadAttach(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Attach ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Attach result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinAttachListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxAttachListEntries)
- {
- throw new DecodeException("To many entries in Attach list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -153,52 +115,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadAttach(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Attach[] result = new Attach[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadAttach(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Attach ReadAttach(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Attach ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Attach result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinAttachListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxAttachListEntries)
- {
- throw new DecodeException("To many entries in Attach list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/BeginTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/BeginTypeDecoder.cs
index e9e98e7..c19a642 100644
--- a/src/Proton/Codec/Decoders/Transport/BeginTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/BeginTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class BeginTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class BeginTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinBeginListEntries = 4;
private static readonly int MaxBeginListEntries = 8;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Begin);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadBegin(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Begin[] result = new Begin[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadBegin(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinBeginListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxBeginListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Begin ReadBegin(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Begin ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Begin result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinBeginListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxBeginListEntries)
- {
- throw new DecodeException("To many entries in Begin list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -132,52 +94,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadBegin(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Begin[] result = new Begin[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadBegin(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Begin ReadBegin(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Begin ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Begin result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinBeginListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxBeginListEntries)
- {
- throw new DecodeException("To many entries in Begin list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/CloseTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/CloseTypeDecoder.cs
index 672c957..23e9b23 100644
--- a/src/Proton/Codec/Decoders/Transport/CloseTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/CloseTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class CloseTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class CloseTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinCloseListEntries = 0;
private static readonly int MaxCloseListEntries = 1;
@@ -35,51 +35,15 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Close);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinCloseListEntries;
- return ReadClose(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MaxListElements => MaxCloseListEntries;
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Close[] result = new Close[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadClose(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Close ReadClose(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Close ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Close result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinCloseListEntries)
- {
- throw new DecodeException("Not enough entries in Close list encoding: " + count);
- }
- else if (count > MaxCloseListEntries)
- {
- throw new DecodeException("To many entries in Close list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
}
@@ -87,51 +51,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadClose(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Close[] result = new Close[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadClose(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Close ReadClose(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Close ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Close result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinCloseListEntries)
- {
- throw new DecodeException("Not enough entries in Close list encoding: " + count);
- }
- else if (count > MaxCloseListEntries)
- {
- throw new DecodeException("To many entries in Close list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
}
diff --git a/src/Proton/Codec/Decoders/Transport/DetachTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/DetachTypeDecoder.cs
index 86b9083..54e63bd 100644
--- a/src/Proton/Codec/Decoders/Transport/DetachTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/DetachTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class DetachTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DetachTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinDetachListEntries = 1;
private static readonly int MaxDetachListEntries = 3;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Detach);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadDetach(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Detach[] result = new Detach[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadDetach(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinDetachListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxDetachListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Detach ReadDetach(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Detach ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Detach result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinDetachListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxDetachListEntries)
- {
- throw new DecodeException("To many entries in Detach list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -116,52 +78,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadDetach(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Detach[] result = new Detach[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadDetach(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Detach ReadDetach(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Detach ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Detach result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinDetachListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxDetachListEntries)
- {
- throw new DecodeException("To many entries in Detach list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/DispositionTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/DispositionTypeDecoder.cs
index bba9d9f..cb8b5b7 100644
--- a/src/Proton/Codec/Decoders/Transport/DispositionTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/DispositionTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class DispositionTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DispositionTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinDispositionListEntries = 2;
private static readonly int MaxDispositionListEntries = 6;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Disposition);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadDisposition(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Disposition[] result = new Disposition[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadDisposition(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinDispositionListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxDispositionListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Disposition ReadDisposition(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Disposition ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Disposition result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinDispositionListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxDispositionListEntries)
- {
- throw new DecodeException("To many entries in Disposition list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -125,52 +87,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadDisposition(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Disposition[] result = new Disposition[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadDisposition(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Disposition ReadDisposition(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Disposition ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Disposition result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinDispositionListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxDispositionListEntries)
- {
- throw new DecodeException("To many entries in Disposition list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/EndTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/EndTypeDecoder.cs
index c68eb52..23704d7 100644
--- a/src/Proton/Codec/Decoders/Transport/EndTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/EndTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class EndTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class EndTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinEndListEntries = 0;
private static readonly int MaxEndListEntries = 1;
@@ -35,119 +35,29 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(End);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadEnd(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- End[] result = new End[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadEnd(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinEndListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxEndListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static End ReadEnd(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override End ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
End result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinEndListEntries)
- {
- throw new DecodeException("Not enough entries in End list encoding: " + count);
- }
-
- if (count > MaxEndListEntries)
- {
- throw new DecodeException("To many entries in End list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadEnd(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- End[] result = new End[count];
- for (int i = 0; i < count; ++i)
+ if (count == 1)
{
- result[i] = ReadEnd(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static End ReadEnd(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override End ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
End result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinEndListEntries)
- {
- throw new DecodeException("Not enough entries in End list encoding: " + count);
- }
-
- if (count > MaxEndListEntries)
- {
- throw new DecodeException("To many entries in End list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
+ if (count == 1)
{
- switch (index)
- {
- case 0:
- result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
- break;
- }
+ result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
}
return result;
diff --git a/src/Proton/Codec/Decoders/Transport/ErrorConditionTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/ErrorConditionTypeDecoder.cs
index ee7a254..45729d7 100644
--- a/src/Proton/Codec/Decoders/Transport/ErrorConditionTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/ErrorConditionTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class ErrorConditionTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ErrorConditionTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinErrorConditionListEntries = 1;
private static readonly int MaxErrorConditionListEntries = 3;
@@ -36,50 +36,12 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(ErrorCondition);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadErrorCondition(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- ErrorCondition[] result = new ErrorCondition[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadErrorCondition(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MinListElements => MinErrorConditionListEntries;
- decoder.SkipValue(buffer, state);
- }
+ protected override int MaxListElements => MaxErrorConditionListEntries;
- private static ErrorCondition ReadErrorCondition(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override ErrorCondition ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinErrorConditionListEntries)
- {
- throw new DecodeException("Not enough entries in ErrorCondition list encoding: " + count);
- }
-
- if (count > MaxErrorConditionListEntries)
- {
- throw new DecodeException("To many entries in ErrorCondition list encoding: " + count);
- }
-
Symbol condition = null;
string description = null;
IDictionary<Symbol, object> info = null;
@@ -103,50 +65,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return new ErrorCondition(condition, description, info);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadErrorCondition(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- ErrorCondition[] result = new ErrorCondition[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadErrorCondition(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static ErrorCondition ReadErrorCondition(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override ErrorCondition ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinErrorConditionListEntries)
- {
- throw new DecodeException("Not enough entries in ErrorCondition list encoding: " + count);
- }
-
- if (count > MaxErrorConditionListEntries)
- {
- throw new DecodeException("To many entries in ErrorCondition list encoding: " + count);
- }
-
Symbol condition = null;
string description = null;
IDictionary<Symbol, object> info = null;
diff --git a/src/Proton/Codec/Decoders/Transport/FlowTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/FlowTypeDecoder.cs
index 830fd31..3ad3fbe 100644
--- a/src/Proton/Codec/Decoders/Transport/FlowTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/FlowTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class FlowTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class FlowTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinFlowListEntries = 4;
private static readonly int MaxFlowListEntries = 11;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Flow);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadFlow(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Flow[] result = new Flow[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadFlow(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinFlowListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxFlowListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Flow ReadFlow(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Flow ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Flow result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinFlowListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxFlowListEntries)
- {
- throw new DecodeException("To many entries in Flow list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -141,52 +103,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadFlow(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Flow[] result = new Flow[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadFlow(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Flow ReadFlow(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Flow ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Flow result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinFlowListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxFlowListEntries)
- {
- throw new DecodeException("To many entries in Flow list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/OpenTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/OpenTypeDecoder.cs
index 7734a62..ad4fbb6 100644
--- a/src/Proton/Codec/Decoders/Transport/OpenTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/OpenTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class OpenTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class OpenTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinOpenListEntries = 1;
private static readonly int MaxOpenListEntries = 10;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Open);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadOpen(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Open[] result = new Open[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadOpen(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinOpenListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxOpenListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Open ReadOpen(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Open ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Open result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinOpenListEntries)
- {
- throw new DecodeException("The container-id field cannot be omitted from the Open");
- }
-
- if (count > MaxOpenListEntries)
- {
- throw new DecodeException("To many entries in Open list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -136,52 +98,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadOpen(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Open[] result = new Open[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadOpen(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Open ReadOpen(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Open ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Open result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinOpenListEntries)
- {
- throw new DecodeException("The container-id field cannot be omitted from the Open");
- }
-
- if (count > MaxOpenListEntries)
- {
- throw new DecodeException("To many entries in Open list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/TransferTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/TransferTypeDecoder.cs
index 904d410..9cbada0 100644
--- a/src/Proton/Codec/Decoders/Transport/TransferTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/TransferTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class TransferTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class TransferTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinTransferListEntries = 1;
private static readonly int MaxTransferListEntries = 11;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Transfer);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadTransfer(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Transfer[] result = new Transfer[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadTransfer(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinTransferListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxTransferListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Transfer ReadTransfer(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Transfer ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Transfer result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinTransferListEntries)
- {
- throw new DecodeException("The handle field cannot be omitted from the Transfer");
- }
-
- if (count > MaxTransferListEntries)
- {
- throw new DecodeException("To many entries in Transfer list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -140,52 +102,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadTransfer(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Transfer[] result = new Transfer[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadTransfer(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Transfer ReadTransfer(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Transfer ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Transfer result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinTransferListEntries)
- {
- throw new DecodeException("The handle field cannot be omitted from the Transfer");
- }
-
- if (count > MaxTransferListEntries)
- {
- throw new DecodeException("To many entries in Transfer list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/UnknownDescribedTypeDecoder.cs b/src/Proton/Codec/Decoders/UnknownDescribedTypeDecoder.cs
index 3804a97..89bf5d5 100644
--- a/src/Proton/Codec/Decoders/UnknownDescribedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/UnknownDescribedTypeDecoder.cs
@@ -18,6 +18,7 @@
using System;
using System.IO;
using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Codec.Decoders.Primitives;
using Apache.Qpid.Proton.Types;
namespace Apache.Qpid.Proton.Codec.Decoders
@@ -40,14 +41,42 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- object described = decoder.ReadValue(buffer, state);
- return new UnknownDescribedType(descriptor, described);
+ if (decoder is not IPrimitiveTypeDecoder)
+ {
+ throw new DecodeException("The described value must be an AMQP primitive type.");
+ }
+
+ return new UnknownDescribedType(descriptor, decoder.ReadValue(buffer, state));
}
public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
{
ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+
+ if (decoder is IPrimitiveTypeDecoder primitiveDecoder)
+ {
+ if (primitiveDecoder.IsZeroWidth)
+ {
+ if (count > state.MaxZeroWidthArrayElements)
+ {
+ throw new DecodeException(
+ "Array element count " + count + " is specified to be greater than limit for " +
+ "zero sized encoded array types (" + state.MaxZeroWidthArrayElements + ")");
+ }
+ }
+ else if (count > buffer.ReadableBytes)
+ {
+ throw new DecodeException(
+ "Array encoded length " + count + " is specified to be greater than the amount " +
+ "of the remaining readable bytes (" + buffer.ReadableBytes + ")");
+ }
+ }
+ else
+ {
+ throw new DecodeException("The described value must be an AMQP primitive type.");
+ }
+
UnknownDescribedType[] result = new UnknownDescribedType[count];
for (int i = 0; i < count; ++i)
@@ -61,20 +90,57 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- state.Decoder.ReadNextTypeDecoder(buffer, state).SkipValue(buffer, state);
+ state.IncreaseDepth();
+
+ try
+ {
+ state.Decoder.ReadNextTypeDecoder(buffer, state).SkipValue(buffer, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
{
IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- object described = decoder.ReadValue(stream, state);
- return new UnknownDescribedType(descriptor, described);
+ if (decoder is not IPrimitiveTypeDecoder)
+ {
+ throw new DecodeException("The described value must be an AMQP primitive type.");
+ }
+
+ return new UnknownDescribedType(descriptor, decoder.ReadValue(stream, state));
}
public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
{
IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+
+ if (decoder is IPrimitiveTypeDecoder primitiveDecoder)
+ {
+ if (primitiveDecoder.IsZeroWidth)
+ {
+ if (count > state.MaxZeroWidthArrayElements)
+ {
+ throw new DecodeException(
+ "Array element count " + count + " is specified to be greater than limit for " +
+ "zero sized encoded array types (" + state.MaxZeroWidthArrayElements + ")");
+ }
+ }
+ else if (count > state.MaxArraySize)
+ {
+ throw new DecodeException(
+ "Array encoded length " + count + " is specified to be greater than the amount " +
+ "of the configured max array length (" + state.MaxArraySize + ")");
+ }
+ }
+ else
+ {
+ throw new DecodeException("The described value must be an AMQP primitive type.");
+ }
+
UnknownDescribedType[] result = new UnknownDescribedType[count];
for (int i = 0; i < count; ++i)
@@ -88,7 +154,16 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- state.Decoder.ReadNextTypeDecoder(stream, state).SkipValue(stream, state);
+ state.IncreaseDepth();
+
+ try
+ {
+ state.Decoder.ReadNextTypeDecoder(stream, state).SkipValue(stream, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
}
}
diff --git a/src/Proton/Codec/Encoders/AbstractDescribedMapTypeEncoder.cs b/src/Proton/Codec/Encoders/AbstractDescribedMapTypeEncoder.cs
index 5ed21e8..9031771 100644
--- a/src/Proton/Codec/Encoders/AbstractDescribedMapTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/AbstractDescribedMapTypeEncoder.cs
@@ -40,14 +40,6 @@ namespace Apache.Qpid.Proton.Codec.Encoders
return EncodingCodes.Map32;
}
- /// <summary>
- /// Returns false when the value to be encoded has no Map body and can be
- /// written as a Null body type instead of a Map type.
- /// </summary>
- /// <param name="value">The value that is encoded as a map type</param>
- /// <returns>if the map type needs a map body or can be null</returns>
- protected abstract bool HasMap(M value);
-
/// <summary>
/// Gets the number of elements that will result when this type is encoded
/// into an AMQP Map type.
@@ -78,27 +70,20 @@ namespace Apache.Qpid.Proton.Codec.Encoders
state.Encoder.WriteUnsignedLong(buffer, state, DescriptorCode);
- if (HasMap(value))
- {
- int count = GetMapEntries(value);
- EncodingCodes encodingCode = GetMapEncoding(value);
-
- buffer.EnsureWritable(sizeof(byte));
- buffer.WriteUnsignedByte(((byte)encodingCode));
-
- switch (encodingCode)
- {
- case EncodingCodes.Map8:
- WriteSmallType(buffer, state, value, count);
- break;
- case EncodingCodes.Map32:
- WriteLargeType(buffer, state, value, count);
- break;
- }
- }
- else
+ int count = GetMapEntries(value);
+ EncodingCodes encodingCode = GetMapEncoding(value);
+
+ buffer.EnsureWritable(sizeof(byte));
+ buffer.WriteUnsignedByte(((byte)encodingCode));
+
+ switch (encodingCode)
{
- state.Encoder.WriteNull(buffer, state);
+ case EncodingCodes.Map8:
+ WriteSmallType(buffer, state, value, count);
+ break;
+ case EncodingCodes.Map32:
+ WriteLargeType(buffer, state, value, count);
+ break;
}
}
diff --git a/src/Proton/Codec/Encoders/Messaging/ApplicationPropertiesTypeEncoder.cs b/src/Proton/Codec/Encoders/Messaging/ApplicationPropertiesTypeEncoder.cs
index 03f439a..e4a54ca 100644
--- a/src/Proton/Codec/Encoders/Messaging/ApplicationPropertiesTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/Messaging/ApplicationPropertiesTypeEncoder.cs
@@ -30,12 +30,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders.Messaging
protected override int GetMapEntries(ApplicationProperties value)
{
- return value?.Value?.Count ?? 0;
- }
+ if (value == null || value.Value == null)
+ {
+ throw new EncodeException("ApplicationProperties must have an assigned Map payload");
+ }
- protected override bool HasMap(ApplicationProperties value)
- {
- return value?.Value != null;
+ return value.Value.Count;
}
protected override void WriteMapEntries(IProtonBuffer buffer, IEncoderState state, ApplicationProperties value)
diff --git a/src/Proton/Codec/Encoders/Messaging/DeliveryAnnotationsTypeEncoder.cs b/src/Proton/Codec/Encoders/Messaging/DeliveryAnnotationsTypeEncoder.cs
index f630c6b..585ec9a 100644
--- a/src/Proton/Codec/Encoders/Messaging/DeliveryAnnotationsTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/Messaging/DeliveryAnnotationsTypeEncoder.cs
@@ -30,12 +30,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders.Messaging
protected override int GetMapEntries(DeliveryAnnotations value)
{
- return value?.Value?.Count ?? 0;
- }
+ if (value == null || value.Value == null)
+ {
+ throw new EncodeException("DeliveryAnnotations must have an assigned Map payload");
+ }
- protected override bool HasMap(DeliveryAnnotations value)
- {
- return value?.Value != null;
+ return value.Value.Count;
}
protected override void WriteMapEntries(IProtonBuffer buffer, IEncoderState state, DeliveryAnnotations value)
diff --git a/src/Proton/Codec/Encoders/Messaging/FooterTypeEncoder.cs b/src/Proton/Codec/Encoders/Messaging/FooterTypeEncoder.cs
index b784300..d5d8f5e 100644
--- a/src/Proton/Codec/Encoders/Messaging/FooterTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/Messaging/FooterTypeEncoder.cs
@@ -30,12 +30,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders.Messaging
protected override int GetMapEntries(Footer value)
{
- return value?.Value?.Count ?? 0;
- }
+ if (value == null || value.Value == null)
+ {
+ throw new EncodeException("Footer must have an assigned Map payload");
+ }
- protected override bool HasMap(Footer value)
- {
- return value?.Value != null;
+ return value.Value.Count;
}
protected override void WriteMapEntries(IProtonBuffer buffer, IEncoderState state, Footer value)
diff --git a/src/Proton/Codec/Encoders/Messaging/MessageAnnotationsTypeEncoder.cs b/src/Proton/Codec/Encoders/Messaging/MessageAnnotationsTypeEncoder.cs
index a2ae4f3..e07fb2d 100644
--- a/src/Proton/Codec/Encoders/Messaging/MessageAnnotationsTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/Messaging/MessageAnnotationsTypeEncoder.cs
@@ -30,12 +30,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders.Messaging
protected override int GetMapEntries(MessageAnnotations value)
{
- return value?.Value?.Count ?? 0;
- }
+ if (value == null || value.Value == null)
+ {
+ throw new EncodeException("MessageAnnotations must have an assigned Map payload");
+ }
- protected override bool HasMap(MessageAnnotations value)
- {
- return value?.Value != null;
+ return value.Value.Count;
}
protected override void WriteMapEntries(IProtonBuffer buffer, IEncoderState state, MessageAnnotations value)
diff --git a/src/Proton/Codec/Encoders/ProtonEncoder.cs b/src/Proton/Codec/Encoders/ProtonEncoder.cs
index b167ac0..72c0e70 100644
--- a/src/Proton/Codec/Encoders/ProtonEncoder.cs
+++ b/src/Proton/Codec/Encoders/ProtonEncoder.cs
@@ -26,6 +26,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders
{
public sealed class ProtonEncoder : IEncoder
{
+ public enum EncoderMode
+ {
+ Sasl,
+ Default
+ }
+
// The encoders for primitives are fixed and cannot be altered by users who want
// to register custom encoders, these encoders are stateless so they can be safely
// made static to reduce overhead of creating and destroying this type.
@@ -91,6 +97,24 @@ namespace Apache.Qpid.Proton.Codec.Encoders
[deliveryTagEncoder.EncodesType] = deliveryTagEncoder
};
+ private readonly Func<string, Symbol> stringToSymbolSupplier;
+
+ public ProtonEncoder() : this(EncoderMode.Default)
+ {
+ }
+
+ public ProtonEncoder(EncoderMode mode)
+ {
+ if (mode == EncoderMode.Sasl)
+ {
+ stringToSymbolSupplier = Symbol.SaslLookup;
+ }
+ else
+ {
+ stringToSymbolSupplier = Symbol.Lookup;
+ }
+ }
+
public IEncoderState NewEncoderState()
{
return new ProtonEncoderState(this);
@@ -270,7 +294,7 @@ namespace Apache.Qpid.Proton.Codec.Encoders
}
else
{
- symbolEncoder.WriteType(buffer, state, Symbol.Lookup(value));
+ symbolEncoder.WriteType(buffer, state, stringToSymbolSupplier.Invoke(value));
}
}
diff --git a/src/Proton/Codec/Encoders/ProtonEncoderFactory.cs b/src/Proton/Codec/Encoders/ProtonEncoderFactory.cs
index 0067517..fc5e91d 100644
--- a/src/Proton/Codec/Encoders/ProtonEncoderFactory.cs
+++ b/src/Proton/Codec/Encoders/ProtonEncoderFactory.cs
@@ -29,7 +29,7 @@ namespace Apache.Qpid.Proton.Codec.Encoders
{
public static ProtonEncoder Create()
{
- ProtonEncoder encoder = new();
+ ProtonEncoder encoder = new(ProtonEncoder.EncoderMode.Default);
AddMessagingTypeEncoders(encoder);
AddTransactionTypeEncoders(encoder);
@@ -40,7 +40,7 @@ namespace Apache.Qpid.Proton.Codec.Encoders
public static ProtonEncoder CreateSasl()
{
- return AddSaslTypeEncoders(new ProtonEncoder());
+ return AddSaslTypeEncoders(new ProtonEncoder(ProtonEncoder.EncoderMode.Sasl));
}
private static ProtonEncoder AddMessagingTypeEncoders(ProtonEncoder encoder)
diff --git a/src/Proton/Codec/IDecoderState.cs b/src/Proton/Codec/IDecoderState.cs
index b29e516..97927be 100644
--- a/src/Proton/Codec/IDecoderState.cs
+++ b/src/Proton/Codec/IDecoderState.cs
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+using System;
using Apache.Qpid.Proton.Buffer;
namespace Apache.Qpid.Proton.Codec
@@ -37,6 +38,51 @@ namespace Apache.Qpid.Proton.Codec
/// </summary>
IDecoder Decoder { get; }
+ /// <summary>
+ /// The configured maximum number of elements that can be decoded from an array
+ /// encoded with the zero width AMQP types (Null, UInt0. ULong0, List0, Boolean_False
+ /// and Boolean_True). These are uncommon encodings and can lead to small encodings
+ /// with large memory costs at decode which makes them discouraged for normal use.
+ /// A value of zero (the default) should be handled by the implementation as meaning
+ /// that only an array of zero width types with zero elements can be decoded.
+ /// </summary>
+ uint MaxZeroWidthArrayElements
+ {
+ get => 0;
+ set => throw new NotImplementedException("Default implementation cannot set an array width limit");
+ }
+
+ /// <summary>
+ /// Access the configured maximum depth that nested types such as Lists, Maps and Arrays
+ /// can have before a DecodeException is thrown to allow the decoder to error
+ /// in cases where the depth of encoding exceeds what the environment is thought to be
+ /// able to support.
+ /// </summary>
+ uint DepthLimit
+ {
+ get => uint.MaxValue;
+ set => throw new NotSupportedException("Depth limits not supported by default");
+ }
+
+ /// <summary>
+ /// During decode of AMQP types which can be comprised of a nesting of other AMQP types
+ /// the such as Lists, Maps and Arrays, the depth is increased to track the amount of
+ /// type nesting that comprises the type being decoded. Implementations can use this
+ /// value to impose limits on the depth of nested objects within complex types and throw
+ /// an DecodeException if that depth value is reached.
+ /// </summary>
+ void IncreaseDepth()
+ {
+ }
+
+ /// <summary>
+ /// Called once decoding of one level of a nested type completes to reduce to the previous
+ /// level before proceeding to the next element on the current level if any.
+ /// </summary>
+ void DecreaseDepth()
+ {
+ }
+
/// <summary>
/// Decodes an encoded UTF-8 string value from the given buffer. The number of bytes
/// that comprise the encoding is provided by the caller, the decoder should not read
diff --git a/src/Proton/Codec/IStreamDecoderState.cs b/src/Proton/Codec/IStreamDecoderState.cs
index 8c26368..2812cc2 100644
--- a/src/Proton/Codec/IStreamDecoderState.cs
+++ b/src/Proton/Codec/IStreamDecoderState.cs
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+using System;
using System.IO;
namespace Apache.Qpid.Proton.Codec
@@ -26,6 +27,12 @@ namespace Apache.Qpid.Proton.Codec
/// </summary>
public interface IStreamDecoderState
{
+ /// <summary>
+ /// A default used to limit reads from a stream for types that encode a count or
+ /// size of encoded elements.
+ /// </summary>
+ protected static readonly uint DefaultMaxAllocationLimit = int.MaxValue - 8;
+
/// <summary>
/// Resets the decoder after a complete decode operation freeing any held
/// resources and preparing for a new decode operation.
@@ -47,5 +54,104 @@ namespace Apache.Qpid.Proton.Codec
/// <returns>A string value decoded from the UTF-8 bytes</returns>
string DecodeUtf8(Stream stream, int length);
+ /// <summary>
+ /// The configured maximum number of elements that can be decoded from an array
+ /// encoded with the zero width AMQP types (Null, UInt0. ULong0, List0, Boolean_False
+ /// and Boolean_True). These are uncommon encodings and can lead to small encodings
+ /// with large memory costs at decode which makes them discouraged for normal use.
+ /// It is recommended that for implementations that implement this limit configuration
+ /// the default be zero meaning zero width array encodings are disabled and will always
+ /// throw a NotImplementedException.
+ /// </summary>
+ uint MaxZeroWidthArrayElements
+ {
+ get => 0;
+ set => throw new NotImplementedException("Default implementation cannot set an array width limit");
+ }
+
+ /// <summary>
+ /// The configured maximum size of an encoded string that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxStringSize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum size of an encoded array that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxArraySize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum size of an encoded Binary that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxBinarySize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum size of an encoded Symbol that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxSymbolSize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum encoded list size that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxListSize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum encoded map size that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxMapSize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// Access the configured maximum depth that nested types such as Lists, Maps and Arrays
+ /// can have before a DecodeException is thrown to allow the decoder to error
+ /// in cases where the depth of encoding exceeds what the environment is thought to be
+ /// able to support.
+ /// </summary>
+ uint DepthLimit
+ {
+ get => uint.MaxValue;
+ set => throw new NotSupportedException("Depth limits not supported by default");
+ }
+
+ /// <summary>
+ /// During decode of AMQP types which can be comprised of a nesting of other AMQP types
+ /// the such as Lists, Maps and Arrays, the depth is increased to track the amount of
+ /// type nesting that comprises the type being decoded. Implementations can use this
+ /// value to impose limits on the depth of nested objects within complex types and throw
+ /// an DecodeException if that depth value is reached.
+ /// </summary>
+ void IncreaseDepth()
+ {
+ }
+
+ /// <summary>
+ /// Called once decoding of one level of a nested type completes to reduce to the previous
+ /// level before proceeding to the next element on the current level if any.
+ /// </summary>
+ void DecreaseDepth()
+ {
+ }
}
}
diff --git a/src/Proton/Engine/Exceptions/ProtocolViolationException.cs b/src/Proton/Engine/Exceptions/ProtocolViolationException.cs
index b4fb1f0..b4985a2 100644
--- a/src/Proton/Engine/Exceptions/ProtocolViolationException.cs
+++ b/src/Proton/Engine/Exceptions/ProtocolViolationException.cs
@@ -17,6 +17,7 @@
using System;
using Apache.Qpid.Proton.Types;
+using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Engine.Exceptions
{
@@ -100,7 +101,7 @@ namespace Apache.Qpid.Proton.Engine.Exceptions
/// <summary>
/// Returns the symbolic error condition that describes the violation error.
/// </summary>
- public Symbol ErrorCondition { get; internal set; }
+ public Symbol ErrorCondition { get; internal set; } = AmqpError.INTERNAL_ERROR;
}
}
\ No newline at end of file
diff --git a/src/Proton/Engine/IEngineConfiguration.cs b/src/Proton/Engine/IEngineConfiguration.cs
index 4b7d533..ce9f9ae 100644
--- a/src/Proton/Engine/IEngineConfiguration.cs
+++ b/src/Proton/Engine/IEngineConfiguration.cs
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+using System;
using Apache.Qpid.Proton.Buffer;
namespace Apache.Qpid.Proton.Engine
@@ -42,5 +43,18 @@ namespace Apache.Qpid.Proton.Engine
/// </summary>
bool TraceFrames { get; set; }
+ /// <summary>
+ /// Sets the configured maximum number of Transfer frames that can make up a single completed
+ /// incoming delivery. If the delivery is not completed within this number of transfer frames the
+ /// engine may either close the associated link or the connection in its entirety. An engine
+ /// implementation may opt not to implement this feature in which case the value should be fixed
+ /// at zero and any assignment should be ignored. If the value is configured as zero then the
+ /// behavior should be to treat that as no limit was assigned.
+ /// </summary>
+ uint MaxTransfersPerDelivery
+ {
+ get => 0;
+ set => throw new NotSupportedException("Default configuration does not support assigning a max transfers value");
+ }
}
}
diff --git a/src/Proton/Engine/Implementation/ProtonConstants.cs b/src/Proton/Engine/Implementation/ProtonConstants.cs
index c051421..ac078cb 100644
--- a/src/Proton/Engine/Implementation/ProtonConstants.cs
+++ b/src/Proton/Engine/Implementation/ProtonConstants.cs
@@ -27,6 +27,12 @@ namespace Apache.Qpid.Proton.Engine.Implementation
/// </summary>
public static readonly uint MinMaxAmqpFrameSize = 512;
+ /// <summary>
+ /// The engine default for the maximum number of transfer performatives allowed
+ /// before a delivery must be completed or the engine will consider it an error.
+ /// </summary>
+ public static readonly uint DefaultMaxTransfersPerDelivery = ushort.MaxValue;
+
/**
* The default AMQP max frame size used by the engine and connection if none is set
* by the client or remote peer.
diff --git a/src/Proton/Engine/Implementation/ProtonEngineConfiguration.cs b/src/Proton/Engine/Implementation/ProtonEngineConfiguration.cs
index 610d6e9..3ad354a 100644
--- a/src/Proton/Engine/Implementation/ProtonEngineConfiguration.cs
+++ b/src/Proton/Engine/Implementation/ProtonEngineConfiguration.cs
@@ -78,6 +78,8 @@ namespace Apache.Qpid.Proton.Engine.Implementation
public uint InboundMaxFrameSize => effectiveMaxInboundFrameSize;
+ public uint MaxTransfersPerDelivery { get; set; } = ProtonConstants.DefaultMaxTransfersPerDelivery;
+
#region Internal Engine API
internal void RecomputeEffectiveFrameSizeLimits()
diff --git a/src/Proton/Engine/Implementation/ProtonFrameDecodingHandler.cs b/src/Proton/Engine/Implementation/ProtonFrameDecodingHandler.cs
index 1f49ba5..2929059 100644
--- a/src/Proton/Engine/Implementation/ProtonFrameDecodingHandler.cs
+++ b/src/Proton/Engine/Implementation/ProtonFrameDecodingHandler.cs
@@ -381,7 +381,15 @@ namespace Apache.Qpid.Proton.Engine.Implementation
if (frameBodySize > 0)
{
long startReadIndex = input.ReadOffset;
- val = handler.decoder.ReadObject(input, handler.decoderState);
+
+ try
+ {
+ val = handler.decoder.ReadObject(input, handler.decoderState);
+ }
+ finally
+ {
+ handler.decoderState.Reset();
+ }
// Copy the payload portion of the incoming bytes for now as the incoming may be
// from a wrapped pooled buffer and for now we have no way of retaining or otherwise
diff --git a/src/Proton/Engine/Implementation/ProtonIncomingDelivery.cs b/src/Proton/Engine/Implementation/ProtonIncomingDelivery.cs
index fb7c186..3f8f325 100644
--- a/src/Proton/Engine/Implementation/ProtonIncomingDelivery.cs
+++ b/src/Proton/Engine/Implementation/ProtonIncomingDelivery.cs
@@ -259,8 +259,6 @@ namespace Apache.Qpid.Proton.Engine.Implementation
internal bool IsFirstTransfer => transferCount <= 1;
- internal uint IncrementAndGetTransferCount() => ++transferCount;
-
internal uint DeliveryId => deliveryId;
internal ProtonIncomingDelivery Aborted()
@@ -307,19 +305,24 @@ namespace Apache.Qpid.Proton.Engine.Implementation
internal ProtonIncomingDelivery AppendTransferPayload(IProtonBuffer buffer)
{
- if (payload == null)
- {
- payload = buffer;
- }
- else if (aggregate != null)
- {
- aggregate.Append(buffer);
- }
- else
+ ++transferCount;
+
+ if (buffer != null)
{
- IProtonBuffer previous = payload;
+ if (payload == null)
+ {
+ payload = buffer;
+ }
+ else if (aggregate != null)
+ {
+ aggregate.Append(buffer);
+ }
+ else
+ {
+ IProtonBuffer previous = payload;
- payload = aggregate = IProtonCompositeBuffer.Compose(ProtonByteBufferAllocator.Instance, previous, buffer);
+ payload = aggregate = IProtonCompositeBuffer.Compose(ProtonByteBufferAllocator.Instance, previous, buffer);
+ }
}
return this;
diff --git a/src/Proton/Engine/Implementation/ProtonReceiver.cs b/src/Proton/Engine/Implementation/ProtonReceiver.cs
index e641172..c60ffbf 100644
--- a/src/Proton/Engine/Implementation/ProtonReceiver.cs
+++ b/src/Proton/Engine/Implementation/ProtonReceiver.cs
@@ -39,7 +39,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
private Action<IIncomingDelivery> deliveryUpdatedEventHandler = null;
private readonly ProtonSessionIncomingWindow sessionWindow;
- private readonly LinkedSplayedDictionary<uint, ProtonIncomingDelivery> unsettled = new();
+ private readonly UnsettledDictionary<ProtonIncomingDelivery> unsettled = new(delivery => delivery.DeliveryId);
private uint? currentDeliveryId;
@@ -154,23 +154,22 @@ namespace Apache.Qpid.Proton.Engine.Implementation
IList<uint> toRemove = new List<uint>();
- foreach (KeyValuePair<uint, ProtonIncomingDelivery> delivery in unsettled)
+ unsettled.ForEach((deliveryId, delivery) =>
{
- if (filter.Invoke(delivery.Value))
+ if (filter.Invoke(delivery))
{
if (state != null)
{
- delivery.Value.LocalState(state);
+ delivery.LocalState(state);
}
if (settle)
{
- delivery.Value.LocallySettled();
- toRemove.Add(delivery.Key);
+ delivery.LocallySettled();
+ toRemove.Add(deliveryId);
}
-
- sessionWindow.ProcessDisposition(this, delivery.Value);
+ sessionWindow.ProcessDisposition(this, delivery);
}
- }
+ });
if (toRemove.Count > 0)
{
@@ -285,8 +284,6 @@ namespace Apache.Qpid.Proton.Engine.Implementation
currentDeliveryId = transfer.DeliveryId;
}
- delivery.IncrementAndGetTransferCount();
-
if (transfer.HasState())
{
delivery.RemoteState = transfer.DeliveryState;
@@ -297,12 +294,10 @@ namespace Apache.Qpid.Proton.Engine.Implementation
delivery.RemotelySettled();
}
- if (payload != null)
- {
- delivery.AppendTransferPayload(payload);
- }
+ delivery.AppendTransferPayload(payload);
bool done = transfer.Aborted || !transfer.More;
+
if (done)
{
CreditState.DecrementCredit();
@@ -318,6 +313,14 @@ namespace Apache.Qpid.Proton.Engine.Implementation
delivery.Completed();
}
}
+ else if (delivery.TransferCount >= engine.Configuration.MaxTransfersPerDelivery)
+ {
+ engine.EngineFailed(new ProtocolViolationException(LinkError.TRANSFER_LIMIT_EXCEEDED,
+ "Delivery not completed within configured max Transfers per delivery value: " +
+ engine.Configuration.MaxTransfersPerDelivery));
+
+ return;
+ }
if (transfer.Aborted)
{
diff --git a/src/Proton/Engine/Implementation/ProtonSessionIncomingWindow.cs b/src/Proton/Engine/Implementation/ProtonSessionIncomingWindow.cs
index d400153..42a7667 100644
--- a/src/Proton/Engine/Implementation/ProtonSessionIncomingWindow.cs
+++ b/src/Proton/Engine/Implementation/ProtonSessionIncomingWindow.cs
@@ -52,7 +52,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
private uint maxFrameSize;
private uint incomingBytes;
- private readonly SplayedDictionary<uint, ProtonIncomingDelivery> unsettled = new();
+ private readonly UnsettledDictionary<ProtonIncomingDelivery> unsettled = new(delivery => delivery.DeliveryId);
public ProtonSessionIncomingWindow(ProtonSession session)
{
@@ -133,15 +133,22 @@ namespace Apache.Qpid.Proton.Engine.Implementation
/// <returns></returns>
internal Transfer HandleTransfer(IProtonLink link, Transfer transfer, IProtonBuffer payload)
{
- incomingBytes += payload != null ? (uint)payload.ReadableBytes : 0;
- incomingWindow--;
- nextIncomingId++;
+ if (incomingWindow-- == 0)
+ {
+ engine.EngineFailed(new ProtocolViolationException(SessionError.WINDOW_VIOLATION,
+ "Sender violated session incoming window limit: " + link.Handle));
+ }
+ else
+ {
+ incomingBytes += payload != null ? (uint)payload.ReadableBytes : 0;
+ nextIncomingId++;
- link.RemoteTransfer(transfer, payload, out ProtonIncomingDelivery delivery);
+ link.RemoteTransfer(transfer, payload, out ProtonIncomingDelivery delivery);
- if (!delivery.IsSettled && !delivery.IsRemotelySettled && delivery.IsFirstTransfer)
- {
- unsettled.Add(delivery.DeliveryId, delivery);
+ if (!delivery.IsSettled && !delivery.IsRemotelySettled && delivery.IsFirstTransfer)
+ {
+ unsettled.Add(delivery.DeliveryId, delivery);
+ }
}
return transfer;
@@ -159,7 +166,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
if (disposition.HasLast() && disposition.Last != first)
{
- HandleRangedDisposition(disposition);
+ HandleRangedDisposition(disposition, unsettled);
}
else
{
@@ -177,27 +184,22 @@ namespace Apache.Qpid.Proton.Engine.Implementation
return disposition;
}
- private void HandleRangedDisposition(Disposition disposition)
+ private static void HandleRangedDisposition(Disposition disposition, UnsettledDictionary<ProtonIncomingDelivery> unsettled)
{
- uint first = disposition.First;
- uint last = disposition.Last;
- bool settled = disposition.Settled;
-
- uint index = first;
-
- do
+ if (disposition.Settled)
{
- if (unsettled.TryGetValue(index, out ProtonIncomingDelivery delivery))
+ unsettled.RemoveEach(disposition.First, disposition.Last, (delivery) =>
{
- if (settled)
- {
- unsettled.Remove(index);
- }
-
((IProtonLink)delivery.Link).RemoteDisposition(disposition, delivery);
- }
+ });
+ }
+ else
+ {
+ unsettled.ForEach(disposition.First, disposition.Last, (delivery) =>
+ {
+ ((IProtonLink)delivery.Link).RemoteDisposition(disposition, delivery);
+ });
}
- while (index++ != last);
}
internal uint UpdateIncomingWindow()
diff --git a/src/Proton/Engine/Implementation/ProtonSessionOutgoingWindow.cs b/src/Proton/Engine/Implementation/ProtonSessionOutgoingWindow.cs
index 2ad654b..23967c5 100644
--- a/src/Proton/Engine/Implementation/ProtonSessionOutgoingWindow.cs
+++ b/src/Proton/Engine/Implementation/ProtonSessionOutgoingWindow.cs
@@ -52,7 +52,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
private uint remoteIncomingWindow;
private uint remoteNextIncomingId = 0;
- private readonly SplayedDictionary<uint, ProtonOutgoingDelivery> unsettled = new();
+ private readonly UnsettledDictionary<ProtonOutgoingDelivery> unsettled = new(delivery => delivery.DeliveryId);
public ProtonSessionOutgoingWindow(ProtonSession session)
{
@@ -233,7 +233,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
if (disposition.HasLast() && disposition.Last != first)
{
- HandleRangedDisposition(disposition);
+ HandleRangedDisposition(disposition, unsettled);
}
else
{
@@ -250,25 +250,22 @@ namespace Apache.Qpid.Proton.Engine.Implementation
return disposition;
}
- private void HandleRangedDisposition(Disposition disposition)
+ private static void HandleRangedDisposition(Disposition disposition, UnsettledDictionary<ProtonOutgoingDelivery> unsettled)
{
- uint first = disposition.First;
- uint last = disposition.Last;
-
- uint index = first;
-
- do
+ if (disposition.Settled)
{
- if (unsettled.TryGetValue(index, out ProtonOutgoingDelivery delivery))
+ unsettled.RemoveEach(disposition.First, disposition.Last, (delivery) =>
{
- if (disposition.Settled)
- {
- unsettled.Remove(first);
- }
((IProtonLink)delivery.Link).RemoteDisposition(disposition, delivery);
- }
+ });
+ }
+ else
+ {
+ unsettled.ForEach(disposition.First, disposition.Last, (delivery) =>
+ {
+ ((IProtonLink)delivery.Link).RemoteDisposition(disposition, delivery);
+ });
}
- while (index++ != last);
}
#endregion
diff --git a/src/Proton/Engine/Implementation/ProtonTransactionManager.cs b/src/Proton/Engine/Implementation/ProtonTransactionManager.cs
index 317c771..8a6823e 100644
--- a/src/Proton/Engine/Implementation/ProtonTransactionManager.cs
+++ b/src/Proton/Engine/Implementation/ProtonTransactionManager.cs
@@ -335,7 +335,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
{
IProtonBuffer payload = delivery.ReadAll();
- AmqpValue container = (AmqpValue)payloadDecoder.ReadObject(payload, payloadDecoder.CachedDecoderState);
+ AmqpValue container = payloadDecoder.ReadObject<AmqpValue>(payload, payloadDecoder.CachedDecoderState);
if (container.Value is Declare)
{
diff --git a/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslClientAuthenticator.cs b/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslClientAuthenticator.cs
index a314e1f..0e395f2 100644
--- a/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslClientAuthenticator.cs
+++ b/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslClientAuthenticator.cs
@@ -31,7 +31,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation.Sasl
{
public static readonly ProtonDefaultSaslClientAuthenticator Instance = new();
- private readonly Symbol ANONYMOUS = Symbol.Lookup("ANONYMOUS");
+ private readonly Symbol ANONYMOUS = Symbol.SaslLookup("ANONYMOUS");
public void HandleSaslChallenge(ISaslClientContext context, IProtonBuffer challenge)
{
@@ -40,7 +40,6 @@ namespace Apache.Qpid.Proton.Engine.Implementation.Sasl
public void HandleSaslMechanisms(ISaslClientContext context, Symbol[] mechanisms)
{
-
if (mechanisms != null && Array.Find(mechanisms, element => ANONYMOUS.Equals(element)) != null)
{
context.SendChosenMechanism(ANONYMOUS, null, ProtonByteBufferAllocator.Instance.Allocate(0, 0));
diff --git a/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslServerAuthenticator .cs b/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslServerAuthenticator .cs
index 9411516..c01d298 100644
--- a/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslServerAuthenticator .cs
+++ b/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslServerAuthenticator .cs
@@ -33,7 +33,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation.Sasl
{
public static readonly ProtonDefaultSaslServerAuthenticator Instance = new();
- private static readonly Symbol[] PLAIN = { Symbol.Lookup("PLAIN") };
+ private static readonly Symbol[] PLAIN = { Symbol.SaslLookup("PLAIN") };
public void HandleSaslHeader(ISaslServerContext context, AmqpHeader header)
{
diff --git a/src/Proton/Engine/Sasl/Client/AnonymousMechanism.cs b/src/Proton/Engine/Sasl/Client/AnonymousMechanism.cs
index 118d6d1..8fbc05b 100644
--- a/src/Proton/Engine/Sasl/Client/AnonymousMechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/AnonymousMechanism.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class AnonymousMechanism : AbstractMechanism
{
- public static readonly Symbol ANONYMOUS = Symbol.Lookup("ANONYMOUS");
+ public static readonly Symbol ANONYMOUS = Symbol.SaslLookup("ANONYMOUS");
public override Symbol Name => ANONYMOUS;
diff --git a/src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs b/src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs
index b8189f9..90d97a2 100644
--- a/src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs
@@ -27,7 +27,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class CramMD5Mechanism : AbstractMechanism
{
- public static readonly Symbol CRAM_MD5 = Symbol.Lookup("CRAM-MD5");
+ public static readonly Symbol CRAM_MD5 = Symbol.SaslLookup("CRAM-MD5");
private bool sentResponse;
diff --git a/src/Proton/Engine/Sasl/Client/ExternalMechanism.cs b/src/Proton/Engine/Sasl/Client/ExternalMechanism.cs
index 0cafa91..3884311 100644
--- a/src/Proton/Engine/Sasl/Client/ExternalMechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/ExternalMechanism.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class ExternalMechanism : AbstractMechanism
{
- public static readonly Symbol EXTERNAL = Symbol.Lookup("EXTERNAL");
+ public static readonly Symbol EXTERNAL = Symbol.SaslLookup("EXTERNAL");
public override Symbol Name => EXTERNAL;
diff --git a/src/Proton/Engine/Sasl/Client/IMechanism.cs b/src/Proton/Engine/Sasl/Client/IMechanism.cs
index 57f6561..9d1fd48 100644
--- a/src/Proton/Engine/Sasl/Client/IMechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/IMechanism.cs
@@ -81,7 +81,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// authentication error if that mechanism matches the highest priority value offered by the remote
/// peer.
/// </remarks>
- /// <returns>true if the mechanim should used without it having been requested</returns>
+ /// <returns>true if the mechanism should used without it having been requested</returns>
bool IsEnabledByDefault();
}
diff --git a/src/Proton/Engine/Sasl/Client/PlainMechanism.cs b/src/Proton/Engine/Sasl/Client/PlainMechanism.cs
index 2ee6d3c..a7f9eb8 100644
--- a/src/Proton/Engine/Sasl/Client/PlainMechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/PlainMechanism.cs
@@ -27,7 +27,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class PlainMechanism : AbstractMechanism
{
- public static readonly Symbol PLAIN = Symbol.Lookup("PLAIN");
+ public static readonly Symbol PLAIN = Symbol.SaslLookup("PLAIN");
public override Symbol Name => PLAIN;
diff --git a/src/Proton/Engine/Sasl/Client/SaslMechanismSelector.cs b/src/Proton/Engine/Sasl/Client/SaslMechanismSelector.cs
index b7622ad..96ed2ea 100644
--- a/src/Proton/Engine/Sasl/Client/SaslMechanismSelector.cs
+++ b/src/Proton/Engine/Sasl/Client/SaslMechanismSelector.cs
@@ -46,7 +46,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// <param name="allowed">An enumeration of SASL mechanism names</param>
public SaslMechanismSelector(IEnumerable<string> allowed)
{
- this.allowedMechanisms = allowed != null ? StringUtils.ToSymbolSet(allowed) : new HashSet<Symbol>();
+ this.allowedMechanisms = allowed != null ? StringUtils.ToSaslSymbolSet(allowed) : new HashSet<Symbol>();
}
/// <summary>
diff --git a/src/Proton/Engine/Sasl/Client/ScramSHA1Mechanism.cs b/src/Proton/Engine/Sasl/Client/ScramSHA1Mechanism.cs
index 7e50ff5..963095f 100644
--- a/src/Proton/Engine/Sasl/Client/ScramSHA1Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/ScramSHA1Mechanism.cs
@@ -26,7 +26,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class ScramSHA1Mechanism : AbstractScramSHAMechanism
{
- public static readonly Symbol SCRAM_SHA_1 = Symbol.Lookup("SCRAM-SHA-1");
+ public static readonly Symbol SCRAM_SHA_1 = Symbol.SaslLookup("SCRAM-SHA-1");
public ScramSHA1Mechanism() : this(Guid.NewGuid().ToString())
{
diff --git a/src/Proton/Engine/Sasl/Client/ScramSHA256Mechanism.cs b/src/Proton/Engine/Sasl/Client/ScramSHA256Mechanism.cs
index 129a622..53b35f4 100644
--- a/src/Proton/Engine/Sasl/Client/ScramSHA256Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/ScramSHA256Mechanism.cs
@@ -26,7 +26,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class ScramSHA256Mechanism : AbstractScramSHAMechanism
{
- public static readonly Symbol SCRAM_SHA_256 = Symbol.Lookup("SCRAM-SHA-256");
+ public static readonly Symbol SCRAM_SHA_256 = Symbol.SaslLookup("SCRAM-SHA-256");
public ScramSHA256Mechanism() : this(Guid.NewGuid().ToString())
{
diff --git a/src/Proton/Engine/Sasl/Client/ScramSHA512Mechanism.cs b/src/Proton/Engine/Sasl/Client/ScramSHA512Mechanism.cs
index f84c706..19f1fe5 100644
--- a/src/Proton/Engine/Sasl/Client/ScramSHA512Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/ScramSHA512Mechanism.cs
@@ -26,7 +26,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class ScramSHA512Mechanism : AbstractScramSHAMechanism
{
- public static readonly Symbol SCRAM_SHA_512 = Symbol.Lookup("SCRAM-SHA-512");
+ public static readonly Symbol SCRAM_SHA_512 = Symbol.SaslLookup("SCRAM-SHA-512");
public ScramSHA512Mechanism() : this(Guid.NewGuid().ToString())
{
diff --git a/src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs b/src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs
index c94a691..8a1d432 100644
--- a/src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs
@@ -31,7 +31,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </remarks>
public sealed class XOauth2Mechanism : AbstractMechanism
{
- public static readonly Symbol XOAUTH2 = Symbol.Lookup("XOAUTH2");
+ public static readonly Symbol XOAUTH2 = Symbol.SaslLookup("XOAUTH2");
private readonly Regex ACCESS_TOKEN_PATTERN = new("^[\\x20-\\x7F]+$", RegexOptions.Compiled);
diff --git a/src/Proton/Types/Security/SaslChallenge.cs b/src/Proton/Types/Security/SaslChallenge.cs
index 02df9f0..e8366e7 100644
--- a/src/Proton/Types/Security/SaslChallenge.cs
+++ b/src/Proton/Types/Security/SaslChallenge.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Types.Security
public sealed class SaslChallenge : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000042UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-challenge:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-challenge:list");
private IProtonBuffer challenge;
diff --git a/src/Proton/Types/Security/SaslInit.cs b/src/Proton/Types/Security/SaslInit.cs
index d8ac09b..0107deb 100644
--- a/src/Proton/Types/Security/SaslInit.cs
+++ b/src/Proton/Types/Security/SaslInit.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Types.Security
public class SaslInit : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000041UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-init:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-init:list");
private Symbol mechanism;
private IProtonBuffer initialResponse;
diff --git a/src/Proton/Types/Security/SaslMechanisms.cs b/src/Proton/Types/Security/SaslMechanisms.cs
index 5fa051d..dd51851 100644
--- a/src/Proton/Types/Security/SaslMechanisms.cs
+++ b/src/Proton/Types/Security/SaslMechanisms.cs
@@ -22,7 +22,7 @@ namespace Apache.Qpid.Proton.Types.Security
public class SaslMechanisms : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000040UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-mechanisms:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-mechanisms:list");
private Symbol[] mechanisms;
diff --git a/src/Proton/Types/Security/SaslOutcome.cs b/src/Proton/Types/Security/SaslOutcome.cs
index 97c29a7..029ea1f 100644
--- a/src/Proton/Types/Security/SaslOutcome.cs
+++ b/src/Proton/Types/Security/SaslOutcome.cs
@@ -23,7 +23,7 @@ namespace Apache.Qpid.Proton.Types.Security
public class SaslOutcome : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000044UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-outcome:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-outcome:list");
public SaslOutcome() { }
diff --git a/src/Proton/Types/Security/SaslResponse.cs b/src/Proton/Types/Security/SaslResponse.cs
index eaaf5ef..1b8894e 100644
--- a/src/Proton/Types/Security/SaslResponse.cs
+++ b/src/Proton/Types/Security/SaslResponse.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Types.Security
public class SaslResponse : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000043UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-response:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-response:list");
private IProtonBuffer response;
diff --git a/src/Proton/Types/Symbol.cs b/src/Proton/Types/Symbol.cs
index 9d3acc7..96e1cf9 100644
--- a/src/Proton/Types/Symbol.cs
+++ b/src/Proton/Types/Symbol.cs
@@ -24,32 +24,42 @@ namespace Apache.Qpid.Proton.Types
{
public sealed class Symbol : IEquatable<Symbol>, IComparable, IComparable<Symbol>
{
- private static readonly ConcurrentDictionary<IProtonBuffer, Symbol> buffersToSymbols = new();
- private static readonly ConcurrentDictionary<string, Symbol> stringsToSymbols = new();
+ // Prevents the Symbol cache from growing overly large if abused by creating overly
+ // large Symbols which would all be stored in the symbol cache. The SASL symbol cache
+ // is kept considerably smaller since there shouldn't be many entries used for the
+ // mechanisms and descriptor symbols as compared to the main application level cache.
- private static readonly Symbol EMPTY_SYMBOL = new();
+ private static readonly uint MaxSymbolCacheEntries = 8192;
+ private static readonly uint MaxCachedSymbolSize = 64;
- // Prevents the Symbol cache from growing overly large if abused by creating overly
- // large Symbols which would all be stored in the symbol cache.
- private static readonly uint MAX_CACHED_SYMBOL_SIZE = 64;
+ private static readonly uint MaxSaslSymbolCacheEntries = 128;
+ private static readonly uint MaxCachedSaslSymbolSize = 32;
+
+ private static readonly SymbolCache CachedSymbols = new SymbolCache(MaxSymbolCacheEntries, MaxCachedSymbolSize);
+ private static readonly SymbolCache CachedSaslSymbols = new SymbolCache(MaxSaslSymbolCacheEntries, MaxCachedSaslSymbolSize);
+
+ private static readonly Symbol EMPTY_SYMBOL = new();
// Lazy allocated based on calls to stringify the given Symbol
private string symbolString;
private readonly IProtonBuffer underlying;
private readonly int hashCode;
+ private readonly SymbolCache symbolCache;
private Symbol()
{
underlying = ProtonByteBufferAllocator.Instance.Allocate(0, 0);
symbolString = "";
hashCode = 32;
+ symbolCache = null;
}
- private Symbol(IProtonBuffer buffer)
+ private Symbol(IProtonBuffer buffer, SymbolCache cache)
{
underlying = buffer;
hashCode = buffer.GetHashCode();
+ symbolCache = cache;
}
/// <summary>
@@ -82,19 +92,7 @@ namespace Apache.Qpid.Proton.Types
}
else
{
- if (!stringsToSymbols.TryGetValue(value, out Symbol symbol))
- {
- symbol = Lookup(ProtonByteBufferAllocator.Instance.Wrap(Encoding.ASCII.GetBytes(value)));
-
- if (symbol.Length <= MAX_CACHED_SYMBOL_SIZE)
- {
- // Try and keep the Symbol instance consistent with the one that is stored
- // in the buffer to symbol dictionary.
- stringsToSymbols[value] = symbol;
- }
- }
-
- return symbol;
+ return CachedSymbols.Lookup(value);
}
}
@@ -131,29 +129,69 @@ namespace Apache.Qpid.Proton.Types
}
else
{
- if (!buffersToSymbols.TryGetValue(value, out Symbol symbol))
- {
- if (copyOnCreate)
- {
- long symbolSize = value.ReadableBytes;
- IProtonBuffer copy = ProtonByteBufferAllocator.Instance.Allocate(symbolSize, symbolSize);
- value.CopyInto(value.ReadOffset, copy, 0, symbolSize);
- copy.WriteOffset = symbolSize;
- value = copy;
- }
+ return CachedSymbols.Lookup(value, copyOnCreate);
+ }
+ }
- symbol = new Symbol(value);
+ /// <summary>
+ /// Lookup or create a singleton instance of the given Symbol that has the
+ /// matching name to the string value provided. This method looks in the
+ /// smaller SASL symbol cache for the matching Symbol value.
+ /// </summary>
+ /// <param name="value">the stringified symbol name</param>
+ /// <returns>A singleton instance of the named Symbol</returns>
+ public static Symbol SaslLookup(string value)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+ else if (value.Length == 0)
+ {
+ return EMPTY_SYMBOL;
+ }
+ else
+ {
+ return CachedSaslSymbols.Lookup(value);
+ }
+ }
- if (symbol.Length <= MAX_CACHED_SYMBOL_SIZE)
- {
- if (!buffersToSymbols.TryAdd(value, symbol))
- {
- symbol = buffersToSymbols[value];
- }
- }
- }
+ /// <summary>
+ /// Lookup or create a singleton instance of the given Symbol that has the
+ /// matching byte contents as the given buffer, if none exists a new Symbol
+ /// is created using the given buffer which is not copied but used directly.
+ /// This method looks in the smaller SASL Symbol cache for the matching value.
+ /// </summary>
+ /// <param name="value">the stringified symbol name</param>
+ /// <returns>A singleton instance of the named Symbol</returns>
+ public static Symbol SaslLookup(IProtonBuffer value)
+ {
+ return SaslLookup(value, false);
+ }
- return symbol;
+ /// <summary>
+ /// Lookup or create a singleton instance of the given Symbol that has the
+ /// matching byte contents as the given buffer, if none exists a new Symbol
+ /// is created using the given buffer which is not copied if the provided
+ /// boolean option requests it. This method looks in the smaller SASL Symbol
+ /// cache for the matching value.
+ /// </summary>
+ /// <param name="value">the stringified symbol name</param>
+ /// <param name="copyOnCreate">should the given buffer be copied if a Symbol is created</param>
+ /// <returns>A singleton instance of the named Symbol</returns>
+ public static Symbol SaslLookup(IProtonBuffer value, bool copyOnCreate)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+ else if (!value.IsReadable)
+ {
+ return EMPTY_SYMBOL;
+ }
+ else
+ {
+ return CachedSaslSymbols.Lookup(value, copyOnCreate);
}
}
@@ -180,14 +218,7 @@ namespace Apache.Qpid.Proton.Types
{
if (symbolString == null && underlying.IsReadable)
{
- symbolString = underlying.ToString(Encoding.ASCII);
- if (symbolString.Length <= MAX_CACHED_SYMBOL_SIZE)
- {
- if (!stringsToSymbols.TryAdd(symbolString, this))
- {
- symbolString = stringsToSymbols[symbolString].symbolString;
- }
- }
+ symbolCache.ToString(this);
}
return symbolString ?? "";
@@ -227,5 +258,117 @@ namespace Apache.Qpid.Proton.Types
{
return CompareTo(other as Symbol);
}
+
+ private static Symbol CreateSymbol(SymbolCache cache, IProtonBuffer buffer, bool copyOnCreate)
+ {
+ if (copyOnCreate)
+ {
+ long symbolSize = buffer.ReadableBytes;
+ IProtonBuffer copy = ProtonByteBufferAllocator.Instance.Allocate(symbolSize, symbolSize);
+ buffer.CopyInto(buffer.ReadOffset, copy, 0, symbolSize);
+ copy.WriteOffset = symbolSize;
+ buffer = copy;
+ }
+
+ return new Symbol(buffer, cache);
+ }
+
+ private sealed class SymbolCache
+ {
+ private readonly ConcurrentDictionary<IProtonBuffer, Symbol> buffersToSymbols = new();
+ private readonly ConcurrentDictionary<string, Symbol> stringsToSymbols = new();
+
+ private readonly uint maxCachedSymbols;
+ private readonly uint maxCachedSymbolSize;
+
+ public SymbolCache(uint maxCachedSymbols, uint maxCachedSymbolSize)
+ {
+ this.maxCachedSymbols = maxCachedSymbols;
+ this.maxCachedSymbolSize = maxCachedSymbolSize;
+ }
+
+ public Symbol Lookup(string value)
+ {
+ if (!stringsToSymbols.TryGetValue(value, out Symbol symbol))
+ {
+ symbol = Lookup(ProtonByteBufferAllocator.Instance.Wrap(Encoding.ASCII.GetBytes(value)));
+
+ if (symbol.symbolString == null)
+ {
+ // In case of a new Symbol object being created we want to ensure the String value
+ // is loaded now since we know what it is and future calls won't need to access the
+ // cache for no reason.
+ symbol.symbolString = value;
+ }
+
+ if (symbol.Length <= maxCachedSymbolSize && stringsToSymbols.Count < maxCachedSymbols)
+ {
+ // Try and keep the Symbol instance consistent with the one that is stored
+ // in the buffer to symbol dictionary.
+ stringsToSymbols[value] = symbol;
+ }
+ }
+
+ return symbol;
+ }
+
+ public Symbol Lookup(IProtonBuffer value)
+ {
+ return Lookup(value, false);
+ }
+
+ public Symbol Lookup(IProtonBuffer value, bool copyOnCreate)
+ {
+ bool canCache = value.ReadableBytes <= maxCachedSymbolSize;
+
+ if (canCache)
+ {
+ if (!buffersToSymbols.TryGetValue(value, out Symbol symbol))
+ {
+ // Lock to prevent the cache from possibly growing beyond the max cache size
+ // due to races on early fills from multiple connection threads.
+ lock (EMPTY_SYMBOL)
+ {
+ if (!buffersToSymbols.TryGetValue(value, out symbol))
+ {
+ symbol = CreateSymbol(this, value, copyOnCreate);
+
+ if (buffersToSymbols.Count < maxCachedSymbols)
+ {
+ if (!buffersToSymbols.TryAdd(value, symbol))
+ {
+ symbol = buffersToSymbols[value];
+ }
+ }
+ }
+ }
+ }
+
+ return symbol;
+ }
+ else
+ {
+ return CreateSymbol(this, value, copyOnCreate);
+ }
+ }
+
+ public string ToString(Symbol symbol)
+ {
+ if (symbol.symbolString == null && symbol.underlying.IsReadable)
+ {
+ symbol.symbolString = symbol.underlying.ToString(Encoding.ASCII);
+
+ if (symbol.symbolString.Length <= maxCachedSymbolSize && stringsToSymbols.Count < maxCachedSymbols)
+ {
+ if (!stringsToSymbols.TryAdd(symbol.symbolString, symbol))
+ {
+ symbol.symbolString = stringsToSymbols[symbol.symbolString].symbolString;
+ }
+ }
+ }
+
+ return symbol.symbolString ?? "";
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Types/UnknownDescribedType.cs b/src/Proton/Types/UnknownDescribedType.cs
index 5e58186..967847b 100644
--- a/src/Proton/Types/UnknownDescribedType.cs
+++ b/src/Proton/Types/UnknownDescribedType.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Types
/// </summary>
public sealed class UnknownDescribedType : IDescribedType
{
- internal UnknownDescribedType(object descriptor, object described)
+ public UnknownDescribedType(object descriptor, object described)
{
Descriptor = descriptor;
Described = described;
diff --git a/src/Proton/Utilities/StringUtils.cs b/src/Proton/Utilities/StringUtils.cs
index 842848a..5a6631f 100644
--- a/src/Proton/Utilities/StringUtils.cs
+++ b/src/Proton/Utilities/StringUtils.cs
@@ -53,6 +53,28 @@ namespace Apache.Qpid.Proton.Utilities
return result;
}
+ /// <summary>
+ /// Given an array of string objects, convert them to a matching array of
+ /// their Symbol equivalent values using the SASL Symbol cache as the source.
+ /// </summary>
+ /// <param name="stringArray"></param>
+ /// <returns>A new Symbol array with values that correspond to the input stings</returns>
+ public static Symbol[] ToSaslSymbolArray(string[] stringArray)
+ {
+ Symbol[] result = null;
+
+ if (stringArray != null)
+ {
+ result = new Symbol[stringArray.Length];
+ for (int i = 0; i < stringArray.Length; ++i)
+ {
+ result[i] = Symbol.SaslLookup(stringArray[i]);
+ }
+ }
+
+ return result;
+ }
+
/// <summary>
/// Given an array of Symbol objects, convert them to a matching array of
/// their string equivalent values.
@@ -100,6 +122,32 @@ namespace Apache.Qpid.Proton.Utilities
return result;
}
+ /// <summary>
+ /// Converts an enumeration of string values into a set of Symbol values.
+ /// Uses the SASL Symbol cache as the source of cached value.
+ /// </summary>
+ /// <param name="strings">an enumeration of string values</param>
+ /// <returns>a set of Symbol value that match the input strings</returns>
+ public static ISet<Symbol> ToSaslSymbolSet(in IEnumerable<string> strings)
+ {
+ ISet<Symbol> result;
+
+ if (strings != null)
+ {
+ result = new HashSet<Symbol>();
+ foreach (string value in strings)
+ {
+ result.Add(Symbol.SaslLookup(value));
+ }
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
/// <summary>
/// Converts an enumeration of Symbol values into a set of string values.
/// </summary>
diff --git a/src/Proton/Utilities/UnsettledDictionary.cs b/src/Proton/Utilities/UnsettledDictionary.cs
... 14406 lines suppressed ...
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org