001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.util; 018 019import java.io.DataOutput; 020import java.io.IOException; 021import java.io.OutputStream; 022import java.io.UTFDataFormatException; 023 024/** 025 * Optimized ByteArrayOutputStream 026 * 027 * 028 */ 029public final class DataByteArrayOutputStream extends OutputStream implements DataOutput { 030 private static final int DEFAULT_SIZE = 2048; 031 private byte buf[]; 032 private int pos; 033 034 /** 035 * Creates a new byte array output stream, with a buffer capacity of the 036 * specified size, in bytes. 037 * 038 * @param size the initial size. 039 * @exception IllegalArgumentException if size is negative. 040 */ 041 public DataByteArrayOutputStream(int size) { 042 if (size < 0) { 043 throw new IllegalArgumentException("Invalid size: " + size); 044 } 045 buf = new byte[size]; 046 } 047 048 /** 049 * Creates a new byte array output stream. 050 */ 051 public DataByteArrayOutputStream() { 052 this(DEFAULT_SIZE); 053 } 054 055 /** 056 * start using a fresh byte array 057 * 058 * @param size 059 */ 060 public void restart(int size) { 061 buf = new byte[size]; 062 pos = 0; 063 } 064 065 /** 066 * start using a fresh byte array 067 */ 068 public void restart() { 069 restart(DEFAULT_SIZE); 070 } 071 072 /** 073 * Get a ByteSequence from the stream 074 * 075 * @return the byte sequence 076 */ 077 public ByteSequence toByteSequence() { 078 return new ByteSequence(buf, 0, pos); 079 } 080 081 /** 082 * Writes the specified byte to this byte array output stream. 083 * 084 * @param b the byte to be written. 085 */ 086 public void write(int b) { 087 int newcount = pos + 1; 088 ensureEnoughBuffer(newcount); 089 buf[pos] = (byte)b; 090 pos = newcount; 091 } 092 093 /** 094 * Writes <code>len</code> bytes from the specified byte array starting at 095 * offset <code>off</code> to this byte array output stream. 096 * 097 * @param b the data. 098 * @param off the start offset in the data. 099 * @param len the number of bytes to write. 100 */ 101 public void write(byte b[], int off, int len) { 102 if (len == 0) { 103 return; 104 } 105 int newcount = pos + len; 106 ensureEnoughBuffer(newcount); 107 System.arraycopy(b, off, buf, pos, len); 108 pos = newcount; 109 } 110 111 /** 112 * @return the underlying byte[] buffer 113 */ 114 public byte[] getData() { 115 return buf; 116 } 117 118 /** 119 * reset the output stream 120 */ 121 public void reset() { 122 pos = 0; 123 } 124 125 /** 126 * Set the current position for writing 127 * 128 * @param offset 129 */ 130 public void position(int offset) { 131 ensureEnoughBuffer(offset); 132 pos = offset; 133 } 134 135 public int size() { 136 return pos; 137 } 138 139 public void writeBoolean(boolean v) { 140 ensureEnoughBuffer(pos + 1); 141 buf[pos++] = (byte)(v ? 1 : 0); 142 } 143 144 public void writeByte(int v) { 145 ensureEnoughBuffer(pos + 1); 146 buf[pos++] = (byte)(v >>> 0); 147 } 148 149 public void writeShort(int v) { 150 ensureEnoughBuffer(pos + 2); 151 buf[pos++] = (byte)(v >>> 8); 152 buf[pos++] = (byte)(v >>> 0); 153 } 154 155 public void writeChar(int v) { 156 ensureEnoughBuffer(pos + 2); 157 buf[pos++] = (byte)(v >>> 8); 158 buf[pos++] = (byte)(v >>> 0); 159 } 160 161 public void writeInt(int v) { 162 ensureEnoughBuffer(pos + 4); 163 buf[pos++] = (byte)(v >>> 24); 164 buf[pos++] = (byte)(v >>> 16); 165 buf[pos++] = (byte)(v >>> 8); 166 buf[pos++] = (byte)(v >>> 0); 167 } 168 169 public void writeLong(long v) { 170 ensureEnoughBuffer(pos + 8); 171 buf[pos++] = (byte)(v >>> 56); 172 buf[pos++] = (byte)(v >>> 48); 173 buf[pos++] = (byte)(v >>> 40); 174 buf[pos++] = (byte)(v >>> 32); 175 buf[pos++] = (byte)(v >>> 24); 176 buf[pos++] = (byte)(v >>> 16); 177 buf[pos++] = (byte)(v >>> 8); 178 buf[pos++] = (byte)(v >>> 0); 179 } 180 181 public void writeFloat(float v) throws IOException { 182 writeInt(Float.floatToIntBits(v)); 183 } 184 185 public void writeDouble(double v) throws IOException { 186 writeLong(Double.doubleToLongBits(v)); 187 } 188 189 public void writeBytes(String s) { 190 int length = s.length(); 191 for (int i = 0; i < length; i++) { 192 write((byte)s.charAt(i)); 193 } 194 } 195 196 public void writeChars(String s) { 197 int length = s.length(); 198 for (int i = 0; i < length; i++) { 199 int c = s.charAt(i); 200 write((c >>> 8) & 0xFF); 201 write((c >>> 0) & 0xFF); 202 } 203 } 204 205 public void writeUTF(String str) throws IOException { 206 int strlen = str.length(); 207 int encodedsize = 0; 208 int c; 209 for (int i = 0; i < strlen; i++) { 210 c = str.charAt(i); 211 if ((c >= 0x0001) && (c <= 0x007F)) { 212 encodedsize++; 213 } else if (c > 0x07FF) { 214 encodedsize += 3; 215 } else { 216 encodedsize += 2; 217 } 218 } 219 if (encodedsize > 65535) { 220 throw new UTFDataFormatException("encoded string too long: " + encodedsize + " bytes"); 221 } 222 ensureEnoughBuffer(pos + encodedsize + 2); 223 writeShort(encodedsize); 224 int i = 0; 225 for (i = 0; i < strlen; i++) { 226 c = str.charAt(i); 227 if (!((c >= 0x0001) && (c <= 0x007F))) { 228 break; 229 } 230 buf[pos++] = (byte)c; 231 } 232 for (; i < strlen; i++) { 233 c = str.charAt(i); 234 if ((c >= 0x0001) && (c <= 0x007F)) { 235 buf[pos++] = (byte)c; 236 } else if (c > 0x07FF) { 237 buf[pos++] = (byte)(0xE0 | ((c >> 12) & 0x0F)); 238 buf[pos++] = (byte)(0x80 | ((c >> 6) & 0x3F)); 239 buf[pos++] = (byte)(0x80 | ((c >> 0) & 0x3F)); 240 } else { 241 buf[pos++] = (byte)(0xC0 | ((c >> 6) & 0x1F)); 242 buf[pos++] = (byte)(0x80 | ((c >> 0) & 0x3F)); 243 } 244 } 245 } 246 247 private void ensureEnoughBuffer(int newcount) { 248 if (newcount > buf.length) { 249 byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)]; 250 System.arraycopy(buf, 0, newbuf, 0, pos); 251 buf = newbuf; 252 } 253 } 254}