org.bson.io.OutputBuffer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mongo-java-driver Show documentation
Show all versions of mongo-java-driver Show documentation
The MongoDB Java Driver uber-artifact, containing mongodb-driver, mongodb-driver-core, and bson
/*
* Copyright 2008-present MongoDB, Inc.
*
* Licensed 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.bson.io;
import org.bson.BsonSerializationException;
import org.bson.ByteBuf;
import org.bson.types.ObjectId;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import static java.lang.String.format;
/**
* An abstract base class for classes implementing {@code BsonOutput}.
*/
public abstract class OutputBuffer extends OutputStream implements BsonOutput {
@Override
public void write(final byte[] b) {
write(b, 0, b.length);
}
@Override
public void close() {
}
@Override
public void write(final byte[] bytes, final int offset, final int length) {
writeBytes(bytes, offset, length);
}
@Override
public void writeBytes(final byte[] bytes) {
writeBytes(bytes, 0, bytes.length);
}
@Override
public void writeInt32(final int value) {
write(value >> 0);
write(value >> 8);
write(value >> 16);
write(value >> 24);
}
@Override
public void writeInt32(final int position, final int value) {
write(position, value >> 0);
write(position + 1, value >> 8);
write(position + 2, value >> 16);
write(position + 3, value >> 24);
}
@Override
public void writeInt64(final long value) {
write((byte) (0xFFL & (value >> 0)));
write((byte) (0xFFL & (value >> 8)));
write((byte) (0xFFL & (value >> 16)));
write((byte) (0xFFL & (value >> 24)));
write((byte) (0xFFL & (value >> 32)));
write((byte) (0xFFL & (value >> 40)));
write((byte) (0xFFL & (value >> 48)));
write((byte) (0xFFL & (value >> 56)));
}
@Override
public void writeDouble(final double x) {
writeLong(Double.doubleToRawLongBits(x));
}
@Override
public void writeString(final String str) {
writeInt(0); // making space for size
int strLen = writeCharacters(str, false);
writeInt32(getPosition() - strLen - 4, strLen);
}
@Override
public void writeCString(final String value) {
writeCharacters(value, true);
}
@Override
public void writeObjectId(final ObjectId value) {
write(value.toByteArray());
}
/**
* Gets the output size in bytes.
* @return the size
*/
public int size() {
return getSize();
}
/**
* Pipe the contents of this output buffer into the given output stream
*
* @param out the stream to pipe to
* @return number of bytes written to the stream
* @throws java.io.IOException if the stream throws an exception
*/
public abstract int pipe(OutputStream out) throws IOException;
/**
* Get a list of byte buffers that are prepared to be read from; in other words, whose position is 0 and whose limit is the number of
* bytes that should read. Note that the byte buffers may be read-only.
*
* @return the non-null list of byte buffers, in LITTLE_ENDIAN order
*/
public abstract List getByteBuffers();
@Override
public abstract void truncateToPosition(int newPosition);
/**
* Gets a copy of the buffered bytes.
*
* @return the byte array
* @see org.bson.io.OutputBuffer#pipe(java.io.OutputStream)
*/
public byte[] toByteArray() {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream(size());
pipe(bout);
return bout.toByteArray();
} catch (IOException ioe) {
throw new RuntimeException("should be impossible", ioe);
}
}
@Override
public void write(final int value) {
writeByte(value);
}
/**
* Writes the given integer value to the buffer.
*
* @param value the value to write
* @see #writeInt32
*/
public void writeInt(final int value) {
writeInt32(value);
}
@Override
public String toString() {
return getClass().getName() + " size: " + size() + " pos: " + getPosition();
}
/**
* Write the specified byte at the specified position.
*
* @param position the position, which must be greater than equal to 0 and at least 4 less than the stream size
* @param value the value to write. The 24 high-order bits of the value are ignored.
*/
protected abstract void write(int position, int value);
/**
* Writes the given long value to the buffer.
*
* @param value the value to write
* @see #writeInt64
*/
public void writeLong(final long value) {
writeInt64(value);
}
private int writeCharacters(final String str, final boolean checkForNullCharacters) {
int len = str.length();
int total = 0;
for (int i = 0; i < len;) {
int c = Character.codePointAt(str, i);
if (checkForNullCharacters && c == 0x0) {
throw new BsonSerializationException(format("BSON cstring '%s' is not valid because it contains a null character "
+ "at index %d", str, i));
}
if (c < 0x80) {
write((byte) c);
total += 1;
} else if (c < 0x800) {
write((byte) (0xc0 + (c >> 6)));
write((byte) (0x80 + (c & 0x3f)));
total += 2;
} else if (c < 0x10000) {
write((byte) (0xe0 + (c >> 12)));
write((byte) (0x80 + ((c >> 6) & 0x3f)));
write((byte) (0x80 + (c & 0x3f)));
total += 3;
} else {
write((byte) (0xf0 + (c >> 18)));
write((byte) (0x80 + ((c >> 12) & 0x3f)));
write((byte) (0x80 + ((c >> 6) & 0x3f)));
write((byte) (0x80 + (c & 0x3f)));
total += 4;
}
i += Character.charCount(c);
}
write((byte) 0);
total++;
return total;
}
}