| /** |
| * 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.activemq.util; |
| |
| import java.io.DataInput; |
| import java.io.DataInputStream; |
| import java.io.DataOutput; |
| import java.io.DataOutputStream; |
| import java.io.IOException; |
| import java.io.UTFDataFormatException; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import org.fusesource.hawtbuf.UTF8Buffer; |
| |
| /** |
| * The fixed version of the UTF8 encoding function. Some older JVM's UTF8 |
| * encoding function breaks when handling large strings. |
| */ |
| public final class MarshallingSupport { |
| |
| public static final byte NULL = 0; |
| public static final byte BOOLEAN_TYPE = 1; |
| public static final byte BYTE_TYPE = 2; |
| public static final byte CHAR_TYPE = 3; |
| public static final byte SHORT_TYPE = 4; |
| public static final byte INTEGER_TYPE = 5; |
| public static final byte LONG_TYPE = 6; |
| public static final byte DOUBLE_TYPE = 7; |
| public static final byte FLOAT_TYPE = 8; |
| public static final byte STRING_TYPE = 9; |
| public static final byte BYTE_ARRAY_TYPE = 10; |
| public static final byte MAP_TYPE = 11; |
| public static final byte LIST_TYPE = 12; |
| public static final byte BIG_STRING_TYPE = 13; |
| |
| private MarshallingSupport() {} |
| |
| public static void marshalPrimitiveMap(Map<String, Object> map, DataOutputStream out) throws IOException { |
| if (map == null) { |
| out.writeInt(-1); |
| } else { |
| out.writeInt(map.size()); |
| for (String name : map.keySet()) { |
| out.writeUTF(name); |
| Object value = map.get(name); |
| marshalPrimitive(out, value); |
| } |
| } |
| } |
| |
| public static Map<String, Object> unmarshalPrimitiveMap(DataInputStream in) throws IOException { |
| return unmarshalPrimitiveMap(in, Integer.MAX_VALUE); |
| } |
| |
| public static Map<String, Object> unmarshalPrimitiveMap(DataInputStream in, boolean force) throws IOException { |
| return unmarshalPrimitiveMap(in, Integer.MAX_VALUE, force); |
| } |
| |
| public static Map<String, Object> unmarshalPrimitiveMap(DataInputStream in, int maxPropertySize) throws IOException { |
| return unmarshalPrimitiveMap(in, maxPropertySize, false); |
| } |
| |
| /** |
| * @param in |
| * @return |
| * @throws IOException |
| * @throws IOException |
| */ |
| public static Map<String, Object> unmarshalPrimitiveMap(DataInputStream in, int maxPropertySize, boolean force) throws IOException { |
| int size = in.readInt(); |
| if (size > maxPropertySize) { |
| throw new IOException("Primitive map is larger than the allowed size: " + size); |
| } |
| if (size < 0) { |
| return null; |
| } else { |
| Map<String, Object> rc = new HashMap<String, Object>(size); |
| for (int i = 0; i < size; i++) { |
| String name = in.readUTF(); |
| rc.put(name, unmarshalPrimitive(in, force)); |
| } |
| return rc; |
| } |
| } |
| |
| public static void marshalPrimitiveList(List<Object> list, DataOutputStream out) throws IOException { |
| out.writeInt(list.size()); |
| for (Object element : list) { |
| marshalPrimitive(out, element); |
| } |
| } |
| |
| public static List<Object> unmarshalPrimitiveList(DataInputStream in) throws IOException { |
| return unmarshalPrimitiveList(in, false); |
| } |
| |
| public static List<Object> unmarshalPrimitiveList(DataInputStream in, boolean force) throws IOException { |
| int size = in.readInt(); |
| List<Object> answer = new ArrayList<Object>(size); |
| while (size-- > 0) { |
| answer.add(unmarshalPrimitive(in, force)); |
| } |
| return answer; |
| } |
| |
| public static void marshalPrimitive(DataOutputStream out, Object value) throws IOException { |
| if (value == null) { |
| marshalNull(out); |
| } else if (value.getClass() == Boolean.class) { |
| marshalBoolean(out, ((Boolean)value).booleanValue()); |
| } else if (value.getClass() == Byte.class) { |
| marshalByte(out, ((Byte)value).byteValue()); |
| } else if (value.getClass() == Character.class) { |
| marshalChar(out, ((Character)value).charValue()); |
| } else if (value.getClass() == Short.class) { |
| marshalShort(out, ((Short)value).shortValue()); |
| } else if (value.getClass() == Integer.class) { |
| marshalInt(out, ((Integer)value).intValue()); |
| } else if (value.getClass() == Long.class) { |
| marshalLong(out, ((Long)value).longValue()); |
| } else if (value.getClass() == Float.class) { |
| marshalFloat(out, ((Float)value).floatValue()); |
| } else if (value.getClass() == Double.class) { |
| marshalDouble(out, ((Double)value).doubleValue()); |
| } else if (value.getClass() == byte[].class) { |
| marshalByteArray(out, (byte[])value); |
| } else if (value.getClass() == String.class) { |
| marshalString(out, (String)value); |
| } else if (value.getClass() == UTF8Buffer.class) { |
| marshalString(out, value.toString()); |
| } else if (value instanceof Map) { |
| out.writeByte(MAP_TYPE); |
| marshalPrimitiveMap((Map<String, Object>)value, out); |
| } else if (value instanceof List) { |
| out.writeByte(LIST_TYPE); |
| marshalPrimitiveList((List<Object>)value, out); |
| } else { |
| throw new IOException("Object is not a primitive: " + value); |
| } |
| } |
| |
| public static Object unmarshalPrimitive(DataInputStream in) throws IOException { |
| return unmarshalPrimitive(in, false); |
| } |
| |
| public static Object unmarshalPrimitive(DataInputStream in, boolean force) throws IOException { |
| Object value = null; |
| byte type = in.readByte(); |
| switch (type) { |
| case BYTE_TYPE: |
| value = Byte.valueOf(in.readByte()); |
| break; |
| case BOOLEAN_TYPE: |
| value = in.readBoolean() ? Boolean.TRUE : Boolean.FALSE; |
| break; |
| case CHAR_TYPE: |
| value = Character.valueOf(in.readChar()); |
| break; |
| case SHORT_TYPE: |
| value = Short.valueOf(in.readShort()); |
| break; |
| case INTEGER_TYPE: |
| value = Integer.valueOf(in.readInt()); |
| break; |
| case LONG_TYPE: |
| value = Long.valueOf(in.readLong()); |
| break; |
| case FLOAT_TYPE: |
| value = new Float(in.readFloat()); |
| break; |
| case DOUBLE_TYPE: |
| value = new Double(in.readDouble()); |
| break; |
| case BYTE_ARRAY_TYPE: |
| value = new byte[in.readInt()]; |
| in.readFully((byte[])value); |
| break; |
| case STRING_TYPE: |
| if (force) { |
| value = in.readUTF(); |
| } else { |
| value = readUTF(in, in.readUnsignedShort()); |
| } |
| break; |
| case BIG_STRING_TYPE: { |
| if (force) { |
| value = readUTF8(in); |
| } else { |
| value = readUTF(in, in.readInt()); |
| } |
| break; |
| } |
| case MAP_TYPE: |
| value = unmarshalPrimitiveMap(in, true); |
| break; |
| case LIST_TYPE: |
| value = unmarshalPrimitiveList(in, true); |
| break; |
| case NULL: |
| value = null; |
| break; |
| default: |
| throw new IOException("Unknown primitive type: " + type); |
| } |
| return value; |
| } |
| |
| public static UTF8Buffer readUTF(DataInputStream in, int length) throws IOException { |
| byte data[] = new byte[length]; |
| in.readFully(data); |
| return new UTF8Buffer(data); |
| } |
| |
| public static void marshalNull(DataOutputStream out) throws IOException { |
| out.writeByte(NULL); |
| } |
| |
| public static void marshalBoolean(DataOutputStream out, boolean value) throws IOException { |
| out.writeByte(BOOLEAN_TYPE); |
| out.writeBoolean(value); |
| } |
| |
| public static void marshalByte(DataOutputStream out, byte value) throws IOException { |
| out.writeByte(BYTE_TYPE); |
| out.writeByte(value); |
| } |
| |
| public static void marshalChar(DataOutputStream out, char value) throws IOException { |
| out.writeByte(CHAR_TYPE); |
| out.writeChar(value); |
| } |
| |
| public static void marshalShort(DataOutputStream out, short value) throws IOException { |
| out.writeByte(SHORT_TYPE); |
| out.writeShort(value); |
| } |
| |
| public static void marshalInt(DataOutputStream out, int value) throws IOException { |
| out.writeByte(INTEGER_TYPE); |
| out.writeInt(value); |
| } |
| |
| public static void marshalLong(DataOutputStream out, long value) throws IOException { |
| out.writeByte(LONG_TYPE); |
| out.writeLong(value); |
| } |
| |
| public static void marshalFloat(DataOutputStream out, float value) throws IOException { |
| out.writeByte(FLOAT_TYPE); |
| out.writeFloat(value); |
| } |
| |
| public static void marshalDouble(DataOutputStream out, double value) throws IOException { |
| out.writeByte(DOUBLE_TYPE); |
| out.writeDouble(value); |
| } |
| |
| public static void marshalByteArray(DataOutputStream out, byte[] value) throws IOException { |
| marshalByteArray(out, value, 0, value.length); |
| } |
| |
| public static void marshalByteArray(DataOutputStream out, byte[] value, int offset, int length) throws IOException { |
| out.writeByte(BYTE_ARRAY_TYPE); |
| out.writeInt(length); |
| out.write(value, offset, length); |
| } |
| |
| public static void marshalString(DataOutputStream out, String s) throws IOException { |
| // If it's too big, out.writeUTF may not able able to write it out. |
| if (s.length() < Short.MAX_VALUE / 4) { |
| out.writeByte(STRING_TYPE); |
| out.writeUTF(s); |
| } else { |
| out.writeByte(BIG_STRING_TYPE); |
| writeUTF8(out, s); |
| } |
| } |
| |
| public static void writeUTF8(DataOutput dataOut, String text) throws IOException { |
| if (text != null) { |
| long utfCount = countUTFBytes(text); |
| dataOut.writeInt((int)utfCount); |
| |
| byte[] buffer = new byte[(int)utfCount]; |
| int len = writeUTFBytesToBuffer(text, (int) utfCount, buffer, 0); |
| dataOut.write(buffer, 0, len); |
| |
| assert utfCount==len; |
| } else { |
| dataOut.writeInt(-1); |
| } |
| } |
| |
| /** |
| * From: http://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/classlib/modules/luni/src/main/java/java/io/DataOutputStream.java |
| */ |
| public static long countUTFBytes(String str) { |
| int utfCount = 0, length = str.length(); |
| for (int i = 0; i < length; i++) { |
| int charValue = str.charAt(i); |
| if (charValue > 0 && charValue <= 127) { |
| utfCount++; |
| } else if (charValue <= 2047) { |
| utfCount += 2; |
| } else { |
| utfCount += 3; |
| } |
| } |
| return utfCount; |
| } |
| |
| /** |
| * From: http://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/classlib/modules/luni/src/main/java/java/io/DataOutputStream.java |
| */ |
| public static int writeUTFBytesToBuffer(String str, long count, |
| byte[] buffer, int offset) throws IOException { |
| int length = str.length(); |
| for (int i = 0; i < length; i++) { |
| int charValue = str.charAt(i); |
| if (charValue > 0 && charValue <= 127) { |
| buffer[offset++] = (byte) charValue; |
| } else if (charValue <= 2047) { |
| buffer[offset++] = (byte) (0xc0 | (0x1f & (charValue >> 6))); |
| buffer[offset++] = (byte) (0x80 | (0x3f & charValue)); |
| } else { |
| buffer[offset++] = (byte) (0xe0 | (0x0f & (charValue >> 12))); |
| buffer[offset++] = (byte) (0x80 | (0x3f & (charValue >> 6))); |
| buffer[offset++] = (byte) (0x80 | (0x3f & charValue)); |
| } |
| } |
| return offset; |
| } |
| |
| public static String readUTF8(DataInput dataIn) throws IOException { |
| int utflen = dataIn.readInt(); |
| if (utflen > -1) { |
| byte bytearr[] = new byte[utflen]; |
| char chararr[] = new char[utflen]; |
| dataIn.readFully(bytearr, 0, utflen); |
| return convertUTF8WithBuf(bytearr, chararr, 0, utflen); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * From: http://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/classlib/modules/luni/src/main/java/org/apache/harmony/luni/util/Util.java |
| */ |
| public static String convertUTF8WithBuf(byte[] buf, char[] out, int offset, |
| int utfSize) throws UTFDataFormatException { |
| int count = 0, s = 0, a; |
| while (count < utfSize) { |
| if ((out[s] = (char) buf[offset + count++]) < '\u0080') |
| s++; |
| else if (((a = out[s]) & 0xe0) == 0xc0) { |
| if (count >= utfSize) |
| throw new UTFDataFormatException(); |
| int b = buf[offset + count++]; |
| if ((b & 0xC0) != 0x80) |
| throw new UTFDataFormatException(); |
| out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F)); |
| } else if ((a & 0xf0) == 0xe0) { |
| if (count + 1 >= utfSize) |
| throw new UTFDataFormatException(); |
| int b = buf[offset + count++]; |
| int c = buf[offset + count++]; |
| if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) |
| throw new UTFDataFormatException(); |
| out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F)); |
| } else { |
| throw new UTFDataFormatException(); |
| } |
| } |
| return new String(out, 0, s); |
| } |
| |
| public static String propertiesToString(Properties props) throws IOException { |
| String result = ""; |
| if (props != null) { |
| DataByteArrayOutputStream dataOut = new DataByteArrayOutputStream(); |
| props.store(dataOut, ""); |
| result = new String(dataOut.getData(), 0, dataOut.size()); |
| dataOut.close(); |
| } |
| return result; |
| } |
| |
| public static Properties stringToProperties(String str) throws IOException { |
| Properties result = new Properties(); |
| if (str != null && str.length() > 0) { |
| DataByteArrayInputStream dataIn = new DataByteArrayInputStream(str.getBytes()); |
| result.load(dataIn); |
| dataIn.close(); |
| } |
| return result; |
| } |
| |
| public static String truncate64(String text) { |
| if (text.length() > 63) { |
| text = text.substring(0, 45) + "..." + text.substring(text.length() - 12); |
| } |
| return text; |
| } |
| } |