--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.services.io;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import java.io.InputStream;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+/**\r
+ A DynamicByteArrayOutputStream allows writing to a dynamically resizable\r
+ array of bytes. In addition to dynamic resizing, this extension allows\r
+ the user of this class to have more control over the position of the stream\r
+ and can get a direct reference of the array.\r
+*/\r
+public class DynamicByteArrayOutputStream extends OutputStream {\r
+\r
+ private static int INITIAL_SIZE = 4096;\r
+\r
+ private byte[] buf;\r
+ private int position;\r
+ private int used; // how many bytes are used\r
+ private int beginPosition;\r
+\r
+ public DynamicByteArrayOutputStream() {\r
+ this(INITIAL_SIZE);\r
+ }\r
+\r
+ public DynamicByteArrayOutputStream(int size) {\r
+ super();\r
+\r
+ buf = new byte[size];\r
+ }\r
+\r
+ public DynamicByteArrayOutputStream(byte[] data) {\r
+ super();\r
+\r
+ buf = data;\r
+ }\r
+\r
+ public DynamicByteArrayOutputStream(DynamicByteArrayOutputStream toBeCloned) {\r
+\r
+ byte[] cbuf = toBeCloned.getByteArray();\r
+ buf = new byte[cbuf.length];\r
+\r
+ write(cbuf, 0, cbuf.length);\r
+ position = toBeCloned.getPosition();\r
+ used = toBeCloned.getUsed();\r
+ beginPosition = toBeCloned.getBeginPosition();\r
+ }\r
+\r
+ /*\r
+ * OutputStream methods\r
+ */\r
+ public void write(int b) \r
+ {\r
+ if (position >= buf.length)\r
+ expandBuffer(INITIAL_SIZE);\r
+\r
+ buf[position++] = (byte) b;\r
+\r
+ if (position > used)\r
+ used = position;\r
+ }\r
+ \r
+ public void write(byte[] b, int off, int len) \r
+ {\r
+ if ((position+len) > buf.length)\r
+ expandBuffer(len);\r
+\r
+ System.arraycopy(b, off, buf, position, len);\r
+ position += len;\r
+\r
+ if (position > used)\r
+ used = position;\r
+ }\r
+\r
+ void writeCompleteStream(InputStream dataIn, int len) throws IOException\r
+ {\r
+ if ((position+len) > buf.length)\r
+ expandBuffer(len);\r
+\r
+ org.apache.derby.iapi.services.io.InputStreamUtil.readFully(dataIn, buf, position, len);\r
+ position += len;\r
+\r
+ if (position > used)\r
+ used = position;\r
+ }\r
+\r
+ public void close()\r
+ {\r
+ buf = null;\r
+ reset();\r
+ }\r
+\r
+ /*\r
+ * Specific methods\r
+ */\r
+\r
+ /**\r
+ Reset the stream for reuse\r
+ */\r
+ public void reset()\r
+ {\r
+ position = 0;\r
+ beginPosition = 0;\r
+ used = 0;\r
+ }\r
+\r
+ /**\r
+ Get a reference to the byte array stored in the byte array output\r
+ stream. Note that the byte array may be longer that getPosition().\r
+ Bytes beyond and including the current poistion are invalid.\r
+ */\r
+ public byte[] getByteArray()\r
+ {\r
+ return buf;\r
+ }\r
+\r
+ /**\r
+ Get the number of bytes that was used.\r
+ */\r
+ public int getUsed()\r
+ {\r
+ return used;\r
+ }\r
+\r
+ /**\r
+ Get the current position in the stream\r
+ */\r
+ public int getPosition()\r
+ {\r
+ return position;\r
+ }\r
+\r
+ /**\r
+ Get the current position in the stream\r
+ */\r
+ public int getBeginPosition()\r
+ {\r
+ return beginPosition;\r
+ }\r
+\r
+ /**\r
+ Set the position of the stream pointer.\r
+ It is up to the caller to make sure the stream has no gap of garbage in\r
+ it or useful information is not left out at the end because the stream\r
+ does not remember anything about the previous position.\r
+ */\r
+ public void setPosition(int newPosition)\r
+ {\r
+ if (newPosition > position)\r
+ {\r
+ if (newPosition > buf.length)\r
+ expandBuffer(newPosition - buf.length);\r
+ }\r
+\r
+ position = newPosition;\r
+\r
+ if (position > used)\r
+ used = position;\r
+\r
+ return ;\r
+ }\r
+\r
+ /**\r
+ Set the begin position of the stream pointer.\r
+ If the newBeginPosition is larger than the stream itself,\r
+ then, the begin position is not set.\r
+ */\r
+ public void setBeginPosition(int newBeginPosition)\r
+ {\r
+\r
+ if (newBeginPosition > buf.length)\r
+ return;\r
+\r
+ beginPosition = newBeginPosition;\r
+ }\r
+\r
+ /**\r
+ Shrink the buffer left by the amount given. Ie.\r
+ bytes from 0 to amountToShrinkBy are thrown away\r
+ */\r
+ public void discardLeft(int amountToShrinkBy) {\r
+\r
+ System.arraycopy(buf, amountToShrinkBy, buf, 0,\r
+ used - amountToShrinkBy);\r
+\r
+ position -= amountToShrinkBy;\r
+ used -= amountToShrinkBy;\r
+ }\r
+\r
+ /**\r
+ Expand the buffer by at least the number of bytes requested in minExtension.\r
+\r
+ To optimize performance and reduce memory copies and allocation, we have a staged buffer\r
+ expansion.\r
+\r
+ <UL>\r
+ <LI> buf.length < 128k - increase by 4k\r
+ <LI> buf.length < 1Mb - increase by 128k\r
+ <LI> otherwise increase by 1Mb.\r
+ </UL>\r
+\r
+ In all cases, if minExpansion is greater than the value about then the buffer will\r
+ be increased by minExtension.\r
+ */\r
+ private void expandBuffer(int minExtension)\r
+ {\r
+ if (buf.length < (128 * 1024)) {\r
+ if (minExtension < INITIAL_SIZE)\r
+ minExtension = INITIAL_SIZE;\r
+ } else if (buf.length < (1024 * 1024)) {\r
+\r
+ if (minExtension < (128 * 1024))\r
+ minExtension = (128 * 1024);\r
+ } else {\r
+ if (minExtension < (1024 * 1024))\r
+ minExtension = 1024 * 1024;\r
+ }\r
+\r
+ int newsize = buf.length + minExtension;\r
+\r
+ byte[] newbuf = new byte[newsize];\r
+ System.arraycopy(buf, 0, newbuf, 0, buf.length);\r
+ buf = newbuf;\r
+ }\r
+\r
+}\r