/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* LabelledByteArrayOutputStream.java
* Created: Feb 15, 2005
* By: Raymond Cypher
*/
package org.openquark.cal.internal.serialization;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* Output stream that writes to a byte array.
* Labelling allows for writing content at an earlier point in the stream.
*/
class LabelledByteArrayOutputStream extends ByteArrayOutputStream {
LabelledByteArrayOutputStream() {
super(1024);
}
/**
* Create a Label at the current write point.
* A Label is itself an OutputStream, backed by this LabelledByteArrayOutputStream
* starting at the current write point.
* @return a Label instance.
*/
public Label getLabel() {
return new Label(count);
}
void shiftBackBy(int startPos, int shiftBackBy, int length) {
System.arraycopy(buf, startPos, buf, startPos - shiftBackBy, length);
count -= 2;
}
/**
* Write a byte at a specific position.
* @param pos
* @param b
* @throws IOException
*/
private void writeAt(int pos, int b) throws IOException {
if (pos > count || pos < 0) {
throw new IllegalArgumentException("Invalid write position: " + pos);
}
int tempCount = count;
count = pos;
write(b);
if (tempCount > count) {
count = tempCount;
}
}
/**
* Writes the specified byte to this byte array output stream.
*
* @param b the byte to be written.
*/
@Override
public synchronized void write(int b) {
int newcount = count + 1;
if (newcount > buf.length) {
byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
System.arraycopy(buf, 0, newbuf, 0, count);
buf = newbuf;
}
buf[count] = (byte) b;
count = newcount;
}
/**
* Write the set of bytes to the specific position.
* @param pos
* @param b
* @param off
* @param len
* @throws IOException
*/
private void writeAt(int pos, byte[] b, int off, int len) throws IOException {
if (pos > count || pos < 0) {
throw new IllegalArgumentException("Invalid write position: " + pos);
}
int tempCount = count;
count = pos;
write(b, off, len);
if (tempCount > count) {
count = tempCount;
}
}
/**
* This is an output stream backed by the associated LabelledByteArrayOutputStream instance.
* Writing starts at the specified position in the backing stream.
* @author RCypher
*/
class Label extends OutputStream {
int startPosition;
int position;
private Label(int startPosition) {
this.startPosition = startPosition;
this.position = startPosition;
}
@Override
public void write(int b) throws IOException {
LabelledByteArrayOutputStream.this.writeAt(position, b);
position++;
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
LabelledByteArrayOutputStream.this.writeAt(position, b, off, len);
position += len;
}
public void reset() {
position = startPosition;
}
public int getStartPosition() {
return startPosition;
}
}
}