aQute.lib.io.ByteBufferDataOutput Maven / Gradle / Ivy
package aQute.lib.io;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InputStream;
import java.io.UTFDataFormatException;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class ByteBufferDataOutput implements DataOutput {
private ByteBuffer bb;
public ByteBufferDataOutput() {
this(IOConstants.PAGE_SIZE);
}
public ByteBufferDataOutput(int size) {
bb = ByteBuffer.allocate(size);
}
public ByteBuffer toByteBuffer() {
return ByteBuffer.wrap(toByteArray());
}
public byte[] toByteArray() {
ByteBuffer obb = bb;
int offset = obb.arrayOffset();
return Arrays.copyOfRange(obb.array(), offset, offset + obb.position());
}
private ByteBuffer bb(int len) {
ByteBuffer obb = bb;
if (obb.remaining() - len >= 0) {
return obb;
}
int minCap = obb.position() + len;
int newCap = obb.capacity() << 1;
if ((newCap - minCap) < 0) {
newCap = minCap;
}
obb.flip();
return bb = ByteBuffer.allocate(newCap)
.put(obb);
}
@Override
public void write(int b) {
bb(Byte.BYTES).put((byte) b);
}
@Override
public void write(byte[] b) {
int len = b.length;
bb(len).put(b, 0, len);
}
@Override
public void write(byte[] b, int off, int len) {
bb(len).put(b, off, len);
}
public void write(ByteBuffer src) {
bb(src.remaining()).put(src);
}
public void write(InputStream in) throws IOException {
if (in instanceof ByteBufferInputStream bbin) {
write(bbin.buffer());
return;
}
ByteBuffer obb;
do {
obb = bb(in.available() + 1);
byte[] buffer = obb.array();
for (int size, position; obb.hasRemaining()
&& (size = in.read(buffer, position = obb.position(), obb.remaining())) > 0;) {
obb.position(position + size);
}
} while (!obb.hasRemaining());
}
@Override
public void writeBoolean(boolean v) {
bb(Byte.BYTES).put(v ? (byte) 1 : (byte) 0);
}
@Override
public void writeByte(int v) {
bb(Byte.BYTES).put((byte) v);
}
@Override
public void writeShort(int v) {
bb(Short.BYTES).putShort((short) v);
}
@Override
public void writeChar(int v) {
bb(Character.BYTES).putChar((char) v);
}
@Override
public void writeInt(int v) {
bb(Integer.BYTES).putInt(v);
}
@Override
public void writeLong(long v) {
bb(Long.BYTES).putLong(v);
}
@Override
public void writeFloat(float v) {
bb(Float.BYTES).putFloat(v);
}
@Override
public void writeDouble(double v) {
bb(Double.BYTES).putDouble(v);
}
@Override
public void writeBytes(String s) {
final int len = s.length();
ByteBuffer b = bb(len * Byte.BYTES);
for (int i = 0; i < len; i++) {
b.put((byte) s.charAt(i));
}
}
@Override
public void writeChars(String s) {
final int len = s.length();
ByteBuffer b = bb(len * Character.BYTES);
for (int i = 0; i < len; i++) {
b.putChar(s.charAt(i));
}
}
@Override
public void writeUTF(String s) throws IOException {
final int len = s.length();
int size = len;
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if (c >= 0x0800) {
size += 2;
} else if ((c >= 0x0080) || (c == 0x0000)) {
size++;
}
}
if (size > 0xffff) {
throw new UTFDataFormatException("encoding too long: " + size);
}
ByteBuffer b = bb(Short.BYTES + size);
b.putShort((short) size);
if (size == len) { // all chars single byte
for (int i = 0; i < len; i++) {
b.put((byte) s.charAt(i));
}
} else {
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if ((c > 0x0000) && (c < 0x0080)) {
b.put((byte) c);
} else if (c >= 0x0800) {
b.put((byte) (0b1110_0000 | ((c >> 12) & 0x0F)));
b.put((byte) (0b1000_0000 | ((c >> 6) & 0x3F)));
b.put((byte) (0b1000_0000 | (c & 0x3F)));
} else {
b.put((byte) (0b1100_0000 | ((c >> 6) & 0x1F)));
b.put((byte) (0b1000_0000 | (c & 0x3F)));
}
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getName());
sb.append("[pos=");
sb.append(bb.position());
sb.append(" lim=");
sb.append(bb.limit());
sb.append(" cap=");
sb.append(bb.capacity());
sb.append("]");
return sb.toString();
}
}