com.rabbitmq.client.impl.ValueReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of amqp-client Show documentation
Show all versions of amqp-client Show documentation
The RabbitMQ Java client library allows Java applications to interface with RabbitMQ.
// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
//
// This software, the RabbitMQ Java client library, is triple-licensed under the
// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL,
// please see LICENSE-APACHE2.
//
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
// either express or implied. See the LICENSE file for specific language governing
// rights and limitations of this software.
//
// If you have any questions regarding licensing, please contact us at
// [email protected].
package com.rabbitmq.client.impl;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import com.rabbitmq.client.LongString;
import com.rabbitmq.client.MalformedFrameException;
/**
* Helper class to read AMQP wire-protocol encoded values.
*/
public class ValueReader
{
private static final long INT_MASK = 0xffffffffL;
/**
* Protected API - Cast an int to a long without extending the
* sign bit of the int out into the high half of the long.
*/
private static long unsignedExtend(int value)
{
long extended = value;
return extended & INT_MASK;
}
/** The stream we are reading from. */
private final DataInputStream in;
/**
* Construct a MethodArgumentReader streaming over the given DataInputStream.
*/
public ValueReader(DataInputStream in)
{
this.in = in;
}
/** Convenience method - reads a short string from a DataInput
* Stream.
*/
private static String readShortstr(DataInputStream in)
throws IOException
{
byte [] b = new byte[in.readUnsignedByte()];
in.readFully(b);
return new String(b, "utf-8");
}
/** Public API - reads a short string. */
public final String readShortstr()
throws IOException
{
return readShortstr(this.in);
}
/** Convenience method - reads a 32-bit-length-prefix
* byte vector from a DataInputStream.
*/
private static byte[] readBytes(final DataInputStream in)
throws IOException
{
final long contentLength = unsignedExtend(in.readInt());
if(contentLength < Integer.MAX_VALUE) {
final byte [] buffer = new byte[(int)contentLength];
in.readFully(buffer);
return buffer;
} else {
throw new UnsupportedOperationException
("Very long byte vectors and strings not currently supported");
}
}
/** Convenience method - reads a long string argument
* from a DataInputStream.
*/
private static LongString readLongstr(final DataInputStream in)
throws IOException
{
return LongStringHelper.asLongString(readBytes(in));
}
/** Public API - reads a long string. */
public final LongString readLongstr()
throws IOException
{
return readLongstr(this.in);
}
/** Public API - reads a short integer. */
public final int readShort()
throws IOException
{
return in.readUnsignedShort();
}
/** Public API - reads an integer. */
public final int readLong()
throws IOException
{
return in.readInt();
}
/** Public API - reads a long integer. */
public final long readLonglong()
throws IOException
{
return in.readLong();
}
/**
* Reads a table argument from a given stream. Also
* called by {@link ContentHeaderPropertyReader}.
*/
private static Map readTable(DataInputStream in)
throws IOException
{
long tableLength = unsignedExtend(in.readInt());
if (tableLength == 0) return Collections.emptyMap();
Map table = new HashMap();
DataInputStream tableIn = new DataInputStream
(new TruncatedInputStream(in, tableLength));
while(tableIn.available() > 0) {
String name = readShortstr(tableIn);
Object value = readFieldValue(tableIn);
if(!table.containsKey(name))
table.put(name, value);
}
return table;
}
// package protected for testing
static Object readFieldValue(DataInputStream in)
throws IOException {
Object value = null;
switch(in.readUnsignedByte()) {
case 'S':
value = readLongstr(in);
break;
case 'I':
value = in.readInt();
break;
case 'i':
value = readUnsignedInt(in);
break;
case 'D':
int scale = in.readUnsignedByte();
byte [] unscaled = new byte[4];
in.readFully(unscaled);
value = new BigDecimal(new BigInteger(unscaled), scale);
break;
case 'T':
value = readTimestamp(in);
break;
case 'F':
value = readTable(in);
break;
case 'A':
value = readArray(in);
break;
case 'b':
value = in.readByte();
break;
case 'B':
value = in.readUnsignedByte();
break;
case 'd':
value = in.readDouble();
break;
case 'f':
value = in.readFloat();
break;
case 'l':
value = in.readLong();
break;
case 's':
value = in.readShort();
break;
case 'u':
value = in.readUnsignedShort();
break;
case 't':
value = in.readBoolean();
break;
case 'x':
value = readBytes(in);
break;
case 'V':
value = null;
break;
default:
throw new MalformedFrameException
("Unrecognised type in table");
}
return value;
}
/** Read an unsigned int */
private static long readUnsignedInt(DataInputStream in)
throws IOException
{
long ch1 = in.read();
long ch2 = in.read();
long ch3 = in.read();
long ch4 = in.read();
if ((ch1 | ch2 | ch3 | ch4) < 0)
throw new EOFException();
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
}
/** Read a field-array */
private static List