| /* |
| * |
| * 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.server.protocol.v0_8; |
| |
| import java.nio.charset.StandardCharsets; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import org.apache.qpid.server.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 writeShortStringBytes(QpidByteBuffer buffer, String s) |
| { |
| if (s != null) |
| { |
| AMQShortString.writeShortString(buffer, s); |
| } |
| else |
| { |
| 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 FieldTableFactory.createFieldTable(input, (int) length); |
| } |
| } |
| |
| public static void skipFieldTable(QpidByteBuffer buffer) |
| { |
| long length = buffer.getUnsignedInt(); |
| if (length > 0) |
| { |
| buffer.position(buffer.position() + (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 void skipLongString(final QpidByteBuffer buffer) |
| { |
| long length = buffer.getUnsignedInt(); |
| if (length > 0) |
| { |
| buffer.position(buffer.position() + (int)length); |
| } |
| } |
| |
| 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) throws AMQFrameDecodingException |
| { |
| 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 = toNumber(digit); |
| pos++; |
| |
| while (pos < length) |
| { |
| pos++; |
| digit = buffer.get(); |
| result = (result << 3) + (result << 1); |
| result += toNumber(digit); |
| } |
| |
| return isNegative ? -result : result; |
| } |
| |
| private static int toNumber(final byte digit) throws AMQFrameDecodingException |
| { |
| if (digit >= '0' && digit <= '9') |
| { |
| return digit - (byte) '0'; |
| } |
| throw new AMQFrameDecodingException(String.format("Unexpected character '%c' in string representing long value", |
| digit)); |
| } |
| |
| 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; |
| } |
| |
| } |