blob: 2d7e27405c45e263facbc40a28a6991299ef3727 [file] [log] [blame]
/*
*
* 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.
*
*/
package org.apache.qpid.framing;
import java.io.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
public class EncodingUtils
{
private static final Logger _logger = LoggerFactory.getLogger(EncodingUtils.class);
private static final String STRING_ENCODING = "iso8859-15";
private static final Charset _charset = Charset.forName("iso8859-15");
public static final int SIZEOF_UNSIGNED_SHORT = 2;
public static final int SIZEOF_UNSIGNED_INT = 4;
private static final boolean[] ALL_FALSE_ARRAY = new boolean[8];
public static int encodedShortStringLength(String s)
{
if (s == null)
{
return 1;
}
else
{
return (short) (1 + s.length());
}
}
public static int encodedShortStringLength(short s)
{
if (s == 0)
{
return 1 + 1;
}
int len = 0;
if (s < 0)
{
len = 1;
// sloppy - doesn't work of Integer.MIN_VALUE
s = (short) -s;
}
if (s > 9999)
{
return 1 + 5;
}
else if (s > 999)
{
return 1 + 4;
}
else if (s > 99)
{
return 1 + 3;
}
else if (s > 9)
{
return 1 + 2;
}
else
{
return 1 + 1;
}
}
public static int encodedShortStringLength(int i)
{
if (i == 0)
{
return 1 + 1;
}
int len = 0;
if (i < 0)
{
len = 1;
// sloppy - doesn't work of Integer.MIN_VALUE
i = -i;
}
// range is now 1 - 2147483647
if (i < Short.MAX_VALUE)
{
return len + encodedShortStringLength((short) i);
}
else if (i > 999999)
{
return len + 6 + encodedShortStringLength((short) (i / 1000000));
}
else // if (i > 99999)
{
return len + 5 + encodedShortStringLength((short) (i / 100000));
}
}
public static int encodedShortStringLength(long l)
{
if (l == 0)
{
return 1 + 1;
}
int len = 0;
if (l < 0)
{
len = 1;
// sloppy - doesn't work of Long.MIN_VALUE
l = -l;
}
if (l < Integer.MAX_VALUE)
{
return len + encodedShortStringLength((int) l);
}
else if (l > 9999999999L)
{
return len + 10 + encodedShortStringLength((int) (l / 10000000000L));
}
else
{
return len + 1 + encodedShortStringLength((int) (l / 10L));
}
}
public static int encodedShortStringLength(AMQShortString s)
{
if (s == null)
{
return 1;
}
else
{
return (1 + s.length());
}
}
public static int encodedLongStringLength(String s)
{
if (s == null)
{
return 4;
}
else
{
return 4 + s.length();
}
}
public static int encodedLongStringLength(char[] s)
{
if (s == null)
{
return 4;
}
else
{
return 4 + s.length;
}
}
public static int encodedLongstrLength(byte[] bytes)
{
if (bytes == null)
{
return 4;
}
else
{
return 4 + bytes.length;
}
}
public static int encodedFieldTableLength(FieldTable table)
{
if (table == null)
{
// length is encoded as 4 octets
return 4;
}
else
{
// length of the table plus 4 octets for the length
return (int) table.getEncodedSize() + 4;
}
}
public static int encodedContentLength(Content table)
{
// TODO: New Content class required for AMQP 0-9.
return 0;
}
public static void writeShortStringBytes(DataOutputStream buffer, String s) throws IOException
{
if (s != null)
{
byte[] encodedString = new byte[s.length()];
char[] cha = s.toCharArray();
for (int i = 0; i < cha.length; i++)
{
encodedString[i] = (byte) cha[i];
}
// TODO: check length fits in an unsigned byte
writeUnsignedByte(buffer, (short)encodedString.length);
buffer.write(encodedString);
}
else
{
// really writing out unsigned byte
buffer.write((byte) 0);
}
}
public static void writeShortStringBytes(DataOutputStream buffer, AMQShortString s) throws IOException
{
if (s != null)
{
s.writeToBuffer(buffer);
}
else
{
// really writing out unsigned byte
buffer.write((byte) 0);
}
}
public static void writeLongStringBytes(DataOutputStream buffer, String s) throws IOException
{
assert (s == null) || (s.length() <= 0xFFFE);
if (s != null)
{
int len = s.length();
writeUnsignedInteger(buffer, s.length());
byte[] encodedString = new byte[len];
char[] cha = s.toCharArray();
for (int i = 0; i < cha.length; i++)
{
encodedString[i] = (byte) cha[i];
}
buffer.write(encodedString);
}
else
{
writeUnsignedInteger(buffer, 0);
}
}
public static void writeLongStringBytes(DataOutputStream buffer, char[] s) throws IOException
{
assert (s == null) || (s.length <= 0xFFFE);
if (s != null)
{
int len = s.length;
writeUnsignedInteger(buffer, s.length);
byte[] encodedString = new byte[len];
for (int i = 0; i < s.length; i++)
{
encodedString[i] = (byte) s[i];
}
buffer.write(encodedString);
}
else
{
writeUnsignedInteger(buffer, 0);
}
}
public static void writeLongStringBytes(DataOutputStream buffer, byte[] bytes) throws IOException
{
assert (bytes == null) || (bytes.length <= 0xFFFE);
if (bytes != null)
{
writeUnsignedInteger(buffer, bytes.length);
buffer.write(bytes);
}
else
{
writeUnsignedInteger(buffer, 0);
}
}
public static void writeUnsignedByte(DataOutputStream buffer, short b) throws IOException
{
byte bv = (byte) b;
buffer.write(bv);
}
public static void writeUnsignedShort(DataOutputStream buffer, int s) throws IOException
{
// TODO: Is this comparison safe? Do I need to cast RHS to long?
if (s < Short.MAX_VALUE)
{
buffer.writeShort(s);
}
else
{
short sv = (short) s;
buffer.write((byte) (0xFF & (sv >> 8)));
buffer.write((byte) (0xFF & sv));
}
}
public static int unsignedIntegerLength()
{
return 4;
}
public static void writeUnsignedInteger(DataOutputStream buffer, long l) throws IOException
{
// TODO: Is this comparison safe? Do I need to cast RHS to long?
if (l < Integer.MAX_VALUE)
{
buffer.writeInt((int) l);
}
else
{
int iv = (int) l;
// FIXME: This *may* go faster if we build this into a local 4-byte array and then
// put the array in a single call.
buffer.write((byte) (0xFF & (iv >> 24)));
buffer.write((byte) (0xFF & (iv >> 16)));
buffer.write((byte) (0xFF & (iv >> 8)));
buffer.write((byte) (0xFF & iv));
}
}
public static void writeFieldTableBytes(DataOutputStream buffer, FieldTable table) throws IOException
{
if (table != null)
{
table.writeToBuffer(buffer);
}
else
{
EncodingUtils.writeUnsignedInteger(buffer, 0);
}
}
public static void writeContentBytes(DataOutputStream buffer, Content content)
{
// TODO: New Content class required for AMQP 0-9.
}
public static void writeBooleans(DataOutputStream buffer, boolean[] values) throws IOException
{
byte packedValue = 0;
for (int i = 0; i < values.length; i++)
{
if (values[i])
{
packedValue = (byte) (packedValue | (1 << i));
}
}
buffer.write(packedValue);
}
public static void writeBooleans(DataOutputStream buffer, boolean value) throws IOException
{
buffer.write(value ? (byte) 1 : (byte) 0);
}
public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1) throws IOException
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
if (value1)
{
packedValue = (byte) (packedValue | (byte) (1 << 1));
}
buffer.write(packedValue);
}
public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2) throws IOException
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
if (value1)
{
packedValue = (byte) (packedValue | (byte) (1 << 1));
}
if (value2)
{
packedValue = (byte) (packedValue | (byte) (1 << 2));
}
buffer.write(packedValue);
}
public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3) throws IOException
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
if (value1)
{
packedValue = (byte) (packedValue | (byte) (1 << 1));
}
if (value2)
{
packedValue = (byte) (packedValue | (byte) (1 << 2));
}
if (value3)
{
packedValue = (byte) (packedValue | (byte) (1 << 3));
}
buffer.write(packedValue);
}
public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
boolean value4) throws IOException
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
if (value1)
{
packedValue = (byte) (packedValue | (byte) (1 << 1));
}
if (value2)
{
packedValue = (byte) (packedValue | (byte) (1 << 2));
}
if (value3)
{
packedValue = (byte) (packedValue | (byte) (1 << 3));
}
if (value4)
{
packedValue = (byte) (packedValue | (byte) (1 << 4));
}
buffer.write(packedValue);
}
public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
boolean value4, boolean value5) throws IOException
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
if (value1)
{
packedValue = (byte) (packedValue | (byte) (1 << 1));
}
if (value2)
{
packedValue = (byte) (packedValue | (byte) (1 << 2));
}
if (value3)
{
packedValue = (byte) (packedValue | (byte) (1 << 3));
}
if (value4)
{
packedValue = (byte) (packedValue | (byte) (1 << 4));
}
if (value5)
{
packedValue = (byte) (packedValue | (byte) (1 << 5));
}
buffer.write(packedValue);
}
public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
boolean value4, boolean value5, boolean value6) throws IOException
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
if (value1)
{
packedValue = (byte) (packedValue | (byte) (1 << 1));
}
if (value2)
{
packedValue = (byte) (packedValue | (byte) (1 << 2));
}
if (value3)
{
packedValue = (byte) (packedValue | (byte) (1 << 3));
}
if (value4)
{
packedValue = (byte) (packedValue | (byte) (1 << 4));
}
if (value5)
{
packedValue = (byte) (packedValue | (byte) (1 << 5));
}
if (value6)
{
packedValue = (byte) (packedValue | (byte) (1 << 6));
}
buffer.write(packedValue);
}
public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
boolean value4, boolean value5, boolean value6, boolean value7) throws IOException
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
if (value1)
{
packedValue = (byte) (packedValue | (byte) (1 << 1));
}
if (value2)
{
packedValue = (byte) (packedValue | (byte) (1 << 2));
}
if (value3)
{
packedValue = (byte) (packedValue | (byte) (1 << 3));
}
if (value4)
{
packedValue = (byte) (packedValue | (byte) (1 << 4));
}
if (value5)
{
packedValue = (byte) (packedValue | (byte) (1 << 5));
}
if (value6)
{
packedValue = (byte) (packedValue | (byte) (1 << 6));
}
if (value7)
{
packedValue = (byte) (packedValue | (byte) (1 << 7));
}
buffer.write(packedValue);
}
/**
* This is used for writing longstrs.
*
* @param buffer
* @param data
*/
public static void writeLongstr(DataOutputStream buffer, byte[] data) throws IOException
{
if (data != null)
{
writeUnsignedInteger(buffer, data.length);
buffer.write(data);
}
else
{
writeUnsignedInteger(buffer, 0);
}
}
public static void writeTimestamp(DataOutputStream buffer, long timestamp) throws IOException
{
writeLong(buffer, timestamp);
}
public static boolean[] readBooleans(DataInputStream buffer) throws IOException
{
final byte packedValue = buffer.readByte();
if (packedValue == 0)
{
return ALL_FALSE_ARRAY;
}
final boolean[] result = new boolean[8];
result[0] = ((packedValue & 1) != 0);
result[1] = ((packedValue & (1 << 1)) != 0);
result[2] = ((packedValue & (1 << 2)) != 0);
result[3] = ((packedValue & (1 << 3)) != 0);
if ((packedValue & 0xF0) == 0)
{
result[0] = ((packedValue & 1) != 0);
}
result[4] = ((packedValue & (1 << 4)) != 0);
result[5] = ((packedValue & (1 << 5)) != 0);
result[6] = ((packedValue & (1 << 6)) != 0);
result[7] = ((packedValue & (1 << 7)) != 0);
return result;
}
public static FieldTable readFieldTable(DataInputStream buffer) throws AMQFrameDecodingException, IOException
{
long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
if (length == 0)
{
return null;
}
else
{
return FieldTableFactory.newFieldTable(buffer, length);
}
}
public static Content readContent(DataInputStream buffer) throws AMQFrameDecodingException
{
// TODO: New Content class required for AMQP 0-9.
return null;
}
public static AMQShortString readAMQShortString(DataInputStream buffer) throws IOException
{
return AMQShortString.readFromBuffer(buffer);
}
public static String readShortString(DataInputStream buffer) throws IOException
{
short length = (short) (((short)buffer.readByte()) & 0xFF);
if (length == 0)
{
return null;
}
else
{
// this may seem rather odd to declare two array but testing has shown
// that constructing a string from a byte array is 5 (five) times slower
// than constructing one from a char array.
// this approach here is valid since we know that all the chars are
// ASCII (0-127)
byte[] stringBytes = new byte[length];
buffer.read(stringBytes, 0, length);
char[] stringChars = new char[length];
for (int i = 0; i < stringChars.length; i++)
{
stringChars[i] = (char) stringBytes[i];
}
return new String(stringChars);
}
}
public static String readLongString(DataInputStream buffer) throws IOException
{
long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
if (length == 0)
{
return "";
}
else
{
// this may seem rather odd to declare two array but testing has shown
// that constructing a string from a byte array is 5 (five) times slower
// than constructing one from a char array.
// this approach here is valid since we know that all the chars are
// ASCII (0-127)
byte[] stringBytes = new byte[(int) length];
buffer.read(stringBytes, 0, (int) length);
char[] stringChars = new char[(int) length];
for (int i = 0; i < stringChars.length; i++)
{
stringChars[i] = (char) stringBytes[i];
}
return new String(stringChars);
}
}
public static byte[] readLongstr(DataInputStream buffer) throws IOException
{
long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
if (length == 0)
{
return null;
}
else
{
byte[] result = new byte[(int) length];
buffer.read(result);
return result;
}
}
public static long readTimestamp(DataInputStream buffer) throws IOException
{
// Discard msb from AMQ timestamp
// buffer.getUnsignedInt();
return buffer.readLong();
}
static byte[] hexToByteArray(String id)
{
// Should check param for null, long enough for this check, upper-case and trailing char
String s = (id.charAt(1) == 'x') ? id.substring(2) : id; // strip 0x
int len = s.length();
int byte_len = len / 2;
byte[] b = new byte[byte_len];
for (int i = 0; i < byte_len; i++)
{
// fixme: refine these repetitive subscript calcs.
int ch = i * 2;
byte b1 = Byte.parseByte(s.substring(ch, ch + 1), 16);
byte b2 = Byte.parseByte(s.substring(ch + 1, ch + 2), 16);
b[i] = (byte) ((b1 * 16) + b2);
}
return (b);
}
public static char[] convertToHexCharArray(byte[] from)
{
int length = from.length;
char[] result_buff = new char[(length * 2) + 2];
result_buff[0] = '0';
result_buff[1] = 'x';
int bite;
int dest = 2;
for (int i = 0; i < length; i++)
{
bite = from[i];
if (bite < 0)
{
bite += 256;
}
result_buff[dest++] = hex_chars[bite >> 4];
result_buff[dest++] = hex_chars[bite & 0x0f];
}
return (result_buff);
}
public static String convertToHexString(byte[] from)
{
return (new String(convertToHexCharArray(from)));
}
public static String convertToHexString(ByteBuffer bb)
{
int size = bb.limit();
byte[] from = new byte[size];
// Is this not the same.
// bb.get(from, 0, length);
for (int i = 0; i < size; i++)
{
from[i] = bb.get(i);
}
return (new String(convertToHexCharArray(from)));
}
private static char[] hex_chars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
// **** new methods
// AMQP_BOOLEAN_PROPERTY_PREFIX
public static void writeBoolean(DataOutputStream buffer, Boolean aBoolean) throws IOException
{
buffer.write(aBoolean ? 1 : 0);
}
public static boolean readBoolean(DataInputStream buffer) throws IOException
{
byte packedValue = buffer.readByte();
return (packedValue == 1);
}
public static int encodedBooleanLength()
{
return 1;
}
// AMQP_BYTE_PROPERTY_PREFIX
public static void writeByte(DataOutputStream buffer, Byte aByte) throws IOException
{
buffer.writeByte(aByte);
}
public static byte readByte(DataInputStream buffer) throws IOException
{
return buffer.readByte();
}
public static int encodedByteLength()
{
return 1;
}
// AMQP_SHORT_PROPERTY_PREFIX
public static void writeShort(DataOutputStream buffer, Short aShort) throws IOException
{
buffer.writeShort(aShort);
}
public static short readShort(DataInputStream buffer) throws IOException
{
return buffer.readShort();
}
public static int encodedShortLength()
{
return 2;
}
// INTEGER_PROPERTY_PREFIX
public static void writeInteger(DataOutputStream buffer, Integer aInteger) throws IOException
{
buffer.writeInt(aInteger);
}
public static int readInteger(DataInputStream buffer) throws IOException
{
return buffer.readInt();
}
public static int encodedIntegerLength()
{
return 4;
}
// AMQP_LONG_PROPERTY_PREFIX
public static void writeLong(DataOutputStream buffer, Long aLong) throws IOException
{
buffer.writeLong(aLong);
}
public static long readLong(DataInputStream buffer) throws IOException
{
return buffer.readLong();
}
public static int encodedLongLength()
{
return 8;
}
// Float_PROPERTY_PREFIX
public static void writeFloat(DataOutputStream buffer, Float aFloat) throws IOException
{
buffer.writeFloat(aFloat);
}
public static float readFloat(DataInputStream buffer) throws IOException
{
return buffer.readFloat();
}
public static int encodedFloatLength()
{
return 4;
}
// Double_PROPERTY_PREFIX
public static void writeDouble(DataOutputStream buffer, Double aDouble) throws IOException
{
buffer.writeDouble(aDouble);
}
public static double readDouble(DataInputStream buffer) throws IOException
{
return buffer.readDouble();
}
public static int encodedDoubleLength()
{
return 8;
}
public static byte[] readBytes(DataInputStream buffer) throws IOException
{
long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
if (length == 0)
{
return null;
}
else
{
byte[] dataBytes = new byte[(int)length];
buffer.read(dataBytes, 0, (int) length);
return dataBytes;
}
}
public static void writeBytes(DataOutputStream buffer, byte[] data) throws IOException
{
if (data != null)
{
// TODO: check length fits in an unsigned byte
writeUnsignedInteger(buffer, (long)data.length);
buffer.write(data);
}
else
{
// really writing out unsigned byte
//buffer.put((byte) 0);
writeUnsignedInteger(buffer, 0L);
}
}
// CHAR_PROPERTY
public static int encodedCharLength()
{
return encodedByteLength();
}
public static char readChar(DataInputStream buffer) throws IOException
{
// This is valid as we know that the Character is ASCII 0..127
return (char) buffer.read();
}
public static void writeChar(DataOutputStream buffer, char character) throws IOException
{
// This is valid as we know that the Character is ASCII 0..127
writeByte(buffer, (byte) character);
}
public static long readLongAsShortString(DataInputStream buffer) throws IOException
{
short length = (short) buffer.readUnsignedByte();
short pos = 0;
if (length == 0)
{
return 0L;
}
byte digit = buffer.readByte();
boolean isNegative;
long result = 0;
if (digit == (byte) '-')
{
isNegative = true;
pos++;
digit = buffer.readByte();
}
else
{
isNegative = false;
}
result = digit - (byte) '0';
pos++;
while (pos < length)
{
pos++;
digit = buffer.readByte();
result = (result << 3) + (result << 1);
result += digit - (byte) '0';
}
return result;
}
public static long readUnsignedInteger(DataInputStream buffer) throws IOException
{
long l = 0xFF & buffer.readByte();
l <<= 8;
l = l | (0xFF & buffer.readByte());
l <<= 8;
l = l | (0xFF & buffer.readByte());
l <<= 8;
l = l | (0xFF & buffer.readByte());
return l;
}
}