| /* |
| * 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.Globalization; |
| using System.Runtime.InteropServices.ComTypes; |
| using Apache.NMS.AMQP.Message.Facade; |
| using Apache.NMS.AMQP.Util; |
| |
| namespace Apache.NMS.AMQP.Message |
| { |
| public class NmsStreamMessage : NmsMessage, IStreamMessage |
| { |
| private const int NO_BYTES_IN_FLIGHT = -1; |
| private readonly INmsStreamMessageFacade facade; |
| |
| private int remainingBytes = NO_BYTES_IN_FLIGHT; |
| private byte[] bytes; |
| |
| public NmsStreamMessage(INmsStreamMessageFacade facade) : base(facade) |
| { |
| this.facade = facade; |
| } |
| |
| public override string ToString() |
| { |
| return "NmsStreamMessage { " + facade + " }"; |
| } |
| |
| public bool ReadBoolean() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| bool result; |
| object value = facade.Peek(); |
| |
| if (value is bool boolResult) |
| result = boolResult; |
| else if (value is string stringValue) |
| result = stringValue.Equals(bool.TrueString); |
| else if (value is null) |
| result = false; |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to boolean."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| private void CheckBytesInFlight() |
| { |
| if (remainingBytes != NO_BYTES_IN_FLIGHT) |
| { |
| throw new MessageFormatException("Partially read byte[] entry still being retrieved using readBytes(byte[] dest)"); |
| } |
| } |
| |
| public byte ReadByte() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| byte result; |
| object value = facade.Peek(); |
| if (value is byte byteValue) |
| result = byteValue; |
| else if (value is string stringValue && byte.TryParse(stringValue, out var parsedValue)) |
| result = parsedValue; |
| else if (value is null) |
| throw new NullReferenceException("Cannot convert null value to byte."); |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to byte."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| public int ReadBytes(byte[] value) |
| { |
| CheckWriteOnlyBody(); |
| |
| if (value == null) |
| { |
| throw new ArgumentNullException(nameof(value), "Target byte array was null"); |
| } |
| |
| if (remainingBytes == NO_BYTES_IN_FLIGHT) |
| { |
| object data = facade.Peek(); |
| if (data == null) |
| { |
| return -1; |
| } |
| else if (!(data is byte[])) |
| { |
| throw new MessageFormatException("Next stream value is not a byte array."); |
| } |
| bytes = data as byte[]; |
| remainingBytes = bytes.Length; |
| } |
| else if (remainingBytes == 0) |
| { |
| // We previously read all the bytes, but must have filled the destination array. |
| remainingBytes = NO_BYTES_IN_FLIGHT; |
| bytes = null; |
| facade.Pop(); |
| return -1; |
| } |
| |
| int previouslyRead = bytes.Length - remainingBytes; |
| int lengthToCopy = Math.Min(value.Length, remainingBytes); |
| |
| if (lengthToCopy > 0) |
| { |
| Array.Copy(bytes, previouslyRead, value, 0, lengthToCopy); |
| } |
| |
| remainingBytes -= lengthToCopy; |
| |
| if (remainingBytes == 0 && lengthToCopy < value.Length) |
| { |
| // All bytes have been read and the destination array was not filled on this |
| // call, so the return will enable the caller to determine completion immediately. |
| remainingBytes = NO_BYTES_IN_FLIGHT; |
| bytes = null; |
| facade.Pop(); |
| } |
| |
| return lengthToCopy; |
| } |
| |
| public char ReadChar() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| char result; |
| object value = facade.Peek(); |
| if (value is char charValue) |
| result = charValue; |
| else if (value is null) |
| throw new NullReferenceException("Cannot convert null value to char."); |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to char."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| public short ReadInt16() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| short result; |
| object value = facade.Peek(); |
| if (value is short shortValue) |
| result = shortValue; |
| else if (value is byte byteValue) |
| result = byteValue; |
| else if (value is string stringValue && short.TryParse(stringValue, out var parsedValue)) |
| result = parsedValue; |
| else if (value is null) |
| throw new NullReferenceException("Cannot convert null value to short."); |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to short."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| public int ReadInt32() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| int result; |
| object value = facade.Peek(); |
| if (value is int intValue) |
| result = intValue; |
| else if (value is short shortValue) |
| result = shortValue; |
| else if (value is byte byteValue) |
| result = byteValue; |
| else if (value is string stringValue && int.TryParse(stringValue, out var parsedValue)) |
| result = parsedValue; |
| else if (value is null) |
| throw new NullReferenceException("Cannot convert null value to int."); |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to int."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| public long ReadInt64() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| long result; |
| object value = facade.Peek(); |
| if (value is long longValue) |
| result = longValue; |
| else if (value is int intValue) |
| result = intValue; |
| else if (value is short shortValue) |
| result = shortValue; |
| else if (value is byte byteValue) |
| result = byteValue; |
| else if (value is string stringValue && long.TryParse(stringValue, out var parsedValue)) |
| result = parsedValue; |
| else if (value is null) |
| throw new NullReferenceException("Cannot convert null value to long."); |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to long."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| public float ReadSingle() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| float result; |
| object value = facade.Peek(); |
| if (value is float floatValue) |
| result = floatValue; |
| else if (value is string stringValue && float.TryParse(stringValue, out var parsedValue)) |
| result = parsedValue; |
| else if (value is null) |
| throw new NullReferenceException("Cannot convert null value to float."); |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to float."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| public double ReadDouble() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| double result; |
| object value = facade.Peek(); |
| if (value is double doubleValue) |
| result = doubleValue; |
| else if (value is float floatValue) |
| result = floatValue; |
| else if (value is string stringValue && float.TryParse(stringValue, out var parsedValue)) |
| result = parsedValue; |
| else if (value is null) |
| throw new NullReferenceException("Cannot convert null value to long."); |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to double."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| public string ReadString() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| string result; |
| object value = facade.Peek(); |
| if (value == null) |
| result = null; |
| else if (value is string stringValue) |
| result = stringValue; |
| else if (value is float floatValue) |
| result = floatValue.ToString(CultureInfo.InvariantCulture); |
| else if (value is double doubleValue) |
| result = doubleValue.ToString(CultureInfo.InvariantCulture); |
| else if (value is long longValue) |
| result = longValue.ToString(); |
| else if (value is int intValue) |
| result = intValue.ToString(); |
| else if (value is short shortValue) |
| result = shortValue.ToString(); |
| else if (value is byte byteValue) |
| result = byteValue.ToString(); |
| else if (value is bool boolValue) |
| result = boolValue.ToString(); |
| else if (value is char charValue) |
| result = charValue.ToString(); |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to int."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| public object ReadObject() |
| { |
| CheckWriteOnlyBody(); |
| CheckBytesInFlight(); |
| |
| object result; |
| object value = facade.Peek(); |
| if (value == null) |
| result = null; |
| else if (value is string) |
| result = value; |
| else if (value is float) |
| result = value; |
| else if (value is double) |
| result = value; |
| else if (value is long) |
| result = value; |
| else if (value is int) |
| result = value; |
| else if (value is short) |
| result = value; |
| else if (value is byte) |
| result = value; |
| else if (value is bool) |
| result = value; |
| else if (value is char) |
| result = value; |
| else if (value is byte[] original) |
| { |
| byte[] bytesResult = new byte[original.Length]; |
| Array.Copy(original, 0, bytesResult, 0, original.Length); |
| result = bytesResult; |
| } |
| else |
| throw new MessageFormatException("stream value: " + value.GetType().Name + " cannot be converted to int."); |
| |
| facade.Pop(); |
| return result; |
| } |
| |
| public void WriteBoolean(bool value) |
| { |
| CheckReadOnlyBody(); |
| facade.Put(value); |
| } |
| |
| public void WriteByte(byte value) |
| { |
| CheckReadOnlyBody(); |
| facade.Put(value); |
| } |
| |
| public void WriteBytes(byte[] value) |
| { |
| WriteBytes(value, 0, value.Length); |
| } |
| |
| public void WriteBytes(byte[] value, int offset, int length) |
| { |
| CheckReadOnlyBody(); |
| |
| byte[] entry = new byte[length]; |
| Array.Copy(value, offset, entry, 0, length); |
| facade.Put(entry); |
| } |
| |
| public void WriteChar(char value) |
| { |
| CheckReadOnlyBody(); |
| facade.Put(value); |
| } |
| |
| public void WriteInt16(short value) |
| { |
| CheckReadOnlyBody(); |
| facade.Put(value); |
| } |
| |
| public void WriteInt32(int value) |
| { |
| CheckReadOnlyBody(); |
| facade.Put(value); |
| } |
| |
| public void WriteInt64(long value) |
| { |
| CheckReadOnlyBody(); |
| facade.Put(value); |
| } |
| |
| public void WriteSingle(float value) |
| { |
| CheckReadOnlyBody(); |
| facade.Put(value); |
| } |
| |
| public void WriteDouble(double value) |
| { |
| CheckReadOnlyBody(); |
| facade.Put(value); |
| } |
| |
| public void WriteString(string value) |
| { |
| CheckReadOnlyBody(); |
| facade.Put(value); |
| } |
| |
| public void WriteObject(object value) |
| { |
| CheckReadOnlyBody(); |
| |
| switch (value) |
| { |
| case null: |
| case string _: |
| case char _: |
| case bool _: |
| case byte _: |
| case short _: |
| case int _: |
| case long _: |
| case float _: |
| case double _: |
| facade.Put(value); |
| break; |
| case byte[] bytesValue: |
| WriteBytes(bytesValue); |
| break; |
| default: |
| throw new MessageFormatException("Unsupported Object type: " + value.GetType().Name); |
| } |
| } |
| |
| public override void ClearBody() |
| { |
| base.ClearBody(); |
| bytes = null; |
| remainingBytes = NO_BYTES_IN_FLIGHT; |
| } |
| |
| public void Reset() |
| { |
| bytes = null; |
| remainingBytes = NO_BYTES_IN_FLIGHT; |
| IsReadOnlyBody = true; |
| facade.Reset(); |
| } |
| |
| public override NmsMessage Copy() |
| { |
| NmsStreamMessage copy = new NmsStreamMessage(facade.Copy() as INmsStreamMessageFacade); |
| CopyInto(copy); |
| return copy; |
| } |
| |
| public override bool IsBodyAssignableTo(Type type) |
| { |
| return false; |
| } |
| |
| } |
| } |