blob: 3b4b15c7a4c25b239daf19b52b474be5cbc19f6b [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.nio.charset.StandardCharsets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.qpid.bytebuffer.QpidByteBuffer;
public class EncodingUtils
{
private static final Logger _logger = LoggerFactory.getLogger(EncodingUtils.class);
private EncodingUtils()
{
}
public static int encodedShortStringLength(String s)
{
if (s == null)
{
return 1;
}
else
{
int size = 1 + getUTF8Length(s);
if(size > 256)
{
throw new IllegalArgumentException("String '"+s+"' is too long - over 255 octets to encode");
}
return (short) size;
}
}
public static int encodedShortStringLength(long l)
{
if (l == 0)
{
return 2;
}
else if(l>=1000000000000L && l<10000000000000L)
{
// this covers the common case of timestamps between Sep 2010 and Nov 2286
return 14;
}
else
{
return Long.toString(l).length()+1;
}
}
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 + getUTF8Length(s);
}
}
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 void writeLongAsShortString(QpidByteBuffer buffer, long l)
{
String s = Long.toString(l);
byte[] encodedString = new byte[1+s.length()];
char[] cha = s.toCharArray();
encodedString[0] = (byte) s.length();
for (int i = 0; i < cha.length; i++)
{
encodedString[i+1] = (byte) cha[i];
}
buffer.put(encodedString);
}
public static void writeShortStringBytes(QpidByteBuffer buffer, AMQShortString s)
{
if (s != null)
{
s.writeToBuffer(buffer);
}
else
{
// really writing out unsigned byte
buffer.put((byte) 0);
}
}
public static void writeLongStringBytes(QpidByteBuffer buffer, String s)
{
if (s != null)
{
int len = getUTF8Length(s);
buffer.putUnsignedInt((long) len);
buffer.put(asUTF8Bytes(s));
}
else
{
buffer.putUnsignedInt((long) 0);
}
}
public static int unsignedIntegerLength()
{
return 4;
}
public static void writeFieldTableBytes(QpidByteBuffer buffer, FieldTable table)
{
if (table != null)
{
table.writeToBuffer(buffer);
}
else
{
buffer.putUnsignedInt((long) 0);
}
}
public static void writeLongstr(QpidByteBuffer buffer, byte[] data)
{
if (data != null)
{
buffer.putUnsignedInt((long) data.length);
buffer.put(data);
}
else
{
buffer.putUnsignedInt((long) 0);
}
}
public static FieldTable readFieldTable(QpidByteBuffer input) throws AMQFrameDecodingException
{
long length = input.getUnsignedInt();
if (length == 0)
{
return null;
}
else
{
return new FieldTable(input, (int) length);
}
}
public static String readLongString(QpidByteBuffer buffer)
{
long length = ((long)(buffer.getInt())) & 0xFFFFFFFFL;
if (length == 0)
{
return "";
}
else
{
byte[] stringBytes = new byte[(int) length];
buffer.get(stringBytes, 0, (int) length);
return new String(stringBytes, StandardCharsets.UTF_8);
}
}
public static byte[] readLongstr(QpidByteBuffer buffer)
{
long length = ((long)(buffer.getInt())) & 0xFFFFFFFFL;
if (length == 0)
{
return null;
}
else
{
byte[] result = new byte[(int) length];
buffer.get(result);
return result;
}
}
// **** new methods
// AMQP_BOOLEAN_PROPERTY_PREFIX
public static void writeBoolean(QpidByteBuffer buffer, boolean aBoolean)
{
buffer.put(aBoolean ? (byte)1 : (byte)0);
}
public static int encodedBooleanLength()
{
return 1;
}
public static int encodedByteLength()
{
return 1;
}
public static int encodedShortLength()
{
return 2;
}
public static int encodedIntegerLength()
{
return 4;
}
public static int encodedLongLength()
{
return 8;
}
public static int encodedFloatLength()
{
return 4;
}
public static int encodedDoubleLength()
{
return 8;
}
public static byte[] readBytes(QpidByteBuffer buffer)
{
long length = buffer.getUnsignedInt();
if (length == 0)
{
return null;
}
else
{
byte[] dataBytes = new byte[(int)length];
buffer.get(dataBytes);
return dataBytes;
}
}
public static void writeBytes(QpidByteBuffer buffer, byte[] data)
{
if (data != null)
{
// TODO: check length fits in an unsigned byte
buffer.putUnsignedInt((long)data.length);
buffer.put(data);
}
else
{
buffer.putUnsignedInt(0L);
}
}
// CHAR_PROPERTY
public static int encodedCharLength()
{
return encodedByteLength();
}
public static long readLongAsShortString(QpidByteBuffer buffer)
{
short length = buffer.getUnsignedByte();
short pos = 0;
if (length == 0)
{
return 0L;
}
byte digit = buffer.get();
boolean isNegative;
long result = 0;
if (digit == (byte) '-')
{
isNegative = true;
pos++;
digit = buffer.get();
}
else
{
isNegative = false;
}
result = digit - (byte) '0';
pos++;
while (pos < length)
{
pos++;
digit = buffer.get();
result = (result << 3) + (result << 1);
result += digit - (byte) '0';
}
return isNegative ? -result : result;
}
public static byte[] asUTF8Bytes(CharSequence string)
{
byte[] bytes = new byte[getUTF8Length(string)];
int j = 0;
if(string != null)
{
final int length = string.length();
int c;
for (int i = 0; i < length; i++)
{
c = string.charAt(i);
if ((c & 0xFF80) == 0) /* U+0000..U+007F */
{
bytes[j++] = (byte) c;
}
else if ((c & 0xF800) == 0) /* U+0080..U+07FF */
{
bytes[j++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
bytes[j++] = (byte) (0x80 | (c & 0x3F));
}
else if ((c & 0xD800) != 0xD800 || (c > 0xDBFF)) /* U+0800..U+FFFF - excluding surrogate pairs */
{
bytes[j++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
bytes[j++] = (byte) (0x80 | ((c >> 6) & 0x3F));
bytes[j++] = (byte) (0x80 | (c & 0x3F));
}
else
{
int low;
if ((++i == length) || ((low = string.charAt(i)) & 0xDC00) != 0xDC00)
{
throw new IllegalArgumentException("String contains invalid Unicode code points");
}
c = 0x010000 + ((c & 0x03FF) << 10) + (low & 0x03FF);
bytes[j++] = (byte) (0xF0 | ((c >> 18) & 0x07));
bytes[j++] = (byte) (0x80 | ((c >> 12) & 0x3F));
bytes[j++] = (byte) (0x80 | ((c >> 6) & 0x3F));
bytes[j++] = (byte) (0x80 | (c & 0x3F));
}
}
}
return bytes;
}
public static int getUTF8Length(CharSequence string)
{
int size = 0;
if(string != null)
{
int c;
final int inputLength = string.length();
for (int i = 0; i < inputLength; i++)
{
c = string.charAt(i);
if ((c & 0xFF80) == 0) /* U+0000..U+007F */
{
size++;
}
else if ((c & 0xF800) == 0) /* U+0080..U+07FF */
{
size += 2;
}
else if ((c & 0xD800) != 0xD800 || (c > 0xDBFF)) /* U+0800..U+FFFF - excluding surrogate pairs */
{
size += 3;
}
else
{
if ((++i == size) || (string.charAt(i) & 0xDC00) != 0xDC00)
{
throw new IllegalArgumentException("String contains invalid Unicode code points");
}
size += 4;
}
}
}
return size;
}
}