org.bson.NewBSONDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sequoiadb-driver Show documentation
Show all versions of sequoiadb-driver Show documentation
Java client driver for SequoiaDB
/**
* Copyright (C) 2012 10gen 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;
import org.bson.io.Bits;
import org.bson.types.BSONDecimal;
import org.bson.types.ObjectId;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import static org.bson.BSON.*;
/**
* A new implementation of the bson decoder.
*/
public class NewBSONDecoder implements BSONDecoder {
//@Override
public BSONObject readObject(final byte [] pData) {
_length = pData.length;
final BasicBSONCallback c = new BasicBSONCallback();
_decode(pData, 0, c);
return (BSONObject)c.get();
}
@Override
public BSONObject readObject(byte[] b, int offset) {
_length = Bits.readInt(b, offset);
final BasicBSONCallback c = new BasicBSONCallback();
_decode(b, offset, c);
return (BSONObject)c.get();
}
//@Override
public BSONObject readObject(final InputStream pIn) throws IOException {
// Slurp in the data and convert to a byte array.
_length = Bits.readInt(pIn);
if (_data == null || _data.length < _length) {
_data = new byte[_length];
}
(new DataInputStream(pIn)).readFully(_data, 4, (_length - 4));
return readObject(_data);
}
@Override
public int decode(byte[] b, BSONCallback callback) {
_length = Bits.readInt(b);
return _decode(b, 0, callback);
}
@Override
public int decode(byte[] b, int offset, BSONCallback callback) {
_length = Bits.readInt(b, offset);
return _decode(b, offset, callback);
}
private int _decode(final byte[] pData, int offset, final BSONCallback pCallback) {
_data = pData;
_pos = offset + 4;
_callback = pCallback;
_decode();
return _length;
}
//@Override
public int decode(final InputStream pIn, final BSONCallback pCallback) throws IOException {
_length = Bits.readInt(pIn);
if (_data == null || _data.length < _length) {
_data = new byte[_length];
}
(new DataInputStream(pIn)).readFully(_data, 4, (_length - 4));
return _decode(_data, 0, pCallback);
}
private final void _decode() {
_callback.objectStart();
while (decodeElement());
_callback.objectDone();
}
private final String readCstr() {
int length = 0;
final int offset = _pos;
while (_data[_pos++] != 0) length++;
try {
return new String(_data, offset, length, DEFAULT_ENCODING);
} catch (final UnsupportedEncodingException uee) {
return new String(_data, offset, length);
}
}
private final String readUtf8Str() {
final int length = Bits.readInt(_data, _pos);
_pos += 4;
if (length <= 0 || length > MAX_STRING) throw new BSONException("String invalid - corruption");
try {
final String str = new String(_data, _pos, (length - 1), DEFAULT_ENCODING);
_pos += length;
return str;
} catch (final UnsupportedEncodingException uee) {
throw new BSONException("What is in the db", uee);
}
}
private final Object _readBasicObject() {
_pos += 4;
final BSONCallback save = _callback;
final BSONCallback _basic = _callback.createBSONCallback();
_callback = _basic;
_basic.reset();
_basic.objectStart(false);
while (decodeElement()) ;
_callback = save;
return _basic.get();
}
private final void _binary(final String pName) {
final int totalLen = Bits.readInt(_data, _pos);
_pos += 4;
final byte bType = _data[_pos];
_pos += 1;
switch (bType) {
case B_GENERAL: {
final byte[] data = new byte[totalLen];
System.arraycopy(_data, _pos, data, 0, totalLen);
_pos += totalLen;
_callback.gotBinary(pName, bType, data);
return;
}
case B_BINARY: {
final int len = Bits.readInt(_data, _pos);
_pos += 4;
if (len + 4 != totalLen)
throw new IllegalArgumentException("bad data size subtype 2 len: " + len + " totalLen: " + totalLen);
final byte[] data = new byte[len];
System.arraycopy(_data, _pos, data, 0, len);
_pos += len;
_callback.gotBinary(pName, bType, data);
return;
}
case B_UUID: {
if (totalLen != 16)
throw new IllegalArgumentException("bad data size subtype 3 len: " + totalLen + " != 16");
final long part1 = Bits.readLong(_data, _pos);
_pos += 8;
final long part2 = Bits.readLong(_data, _pos);
_pos += 8;
_callback.gotUUID(pName, part1, part2);
return;
}
}
final byte[] data = new byte[totalLen];
System.arraycopy(_data, _pos, data, 0, totalLen);
_pos += totalLen;
_callback.gotBinary(pName, bType, data);
}
private final boolean decodeElement() {
final byte type = _data[_pos];
_pos += 1;
if (type == EOO) return false;
final String name = readCstr();
switch (type) {
case NULL: {
_callback.gotNull(name);
return true;
}
case UNDEFINED: {
_callback.gotUndefined(name);
return true;
}
case BOOLEAN: {
_callback.gotBoolean(name, (_data[_pos] > 0));
_pos += 1;
return true;
}
case NUMBER: {
_callback.gotDouble(name, Double.longBitsToDouble(Bits.readLong(_data, _pos)));
_pos += 8;
return true;
}
case NUMBER_INT: {
_callback.gotInt(name, Bits.readInt(_data, _pos));
_pos += 4;
return true;
}
case NUMBER_LONG: {
_callback.gotLong(name, Bits.readLong(_data, _pos));
_pos += 8;
return true;
}
case SYMBOL: {
_callback.gotSymbol(name, readUtf8Str());
return true;
}
case STRING: {
_callback.gotString(name, readUtf8Str());
return true;
}
case OID: {
// OID is stored as big endian
final int p1 = Bits.readIntBE(_data, _pos);
_pos += 4;
final int p2 = Bits.readIntBE(_data, _pos);
_pos += 4;
final int p3 = Bits.readIntBE(_data, _pos);
_pos += 4;
_callback.gotObjectId(name, new ObjectId(p1, p2, p3));
return true;
}
case REF: {
_pos += 4;
final String ns = readCstr();
final int p1 = Bits.readInt(_data, _pos);
_pos += 4;
final int p2 = Bits.readInt(_data, _pos);
_pos += 4;
final int p3 = Bits.readInt(_data, _pos);
_pos += 4;
_callback.gotDBRef(name, ns, new ObjectId(p1, p2, p3));
return true;
}
case DATE: {
_callback.gotDate(name, Bits.readLong(_data, _pos));
_pos += 8;
return true;
}
case REGEX: {
_callback.gotRegex(name, readCstr(), readCstr());
return true;
}
case BINARY: {
_binary(name);
return true;
}
case CODE: {
_callback.gotCode(name, readUtf8Str());
return true;
}
case CODE_W_SCOPE: {
_pos += 4;
_callback.gotCodeWScope(name, readUtf8Str(), _readBasicObject());
return true;
}
case ARRAY:
_pos += 4;
_callback.arrayStart(name);
while (decodeElement()) ;
_callback.arrayDone();
return true;
case OBJECT:
_pos += 4;
_callback.objectStart(name);
while (decodeElement()) ;
_callback.objectDone();
return true;
case TIMESTAMP:
int i = Bits.readInt(_data, _pos);
_pos += 4;
int time = Bits.readInt(_data, _pos);
_pos += 4;
_callback.gotTimestamp(name, time, i);
return true;
case NUMBER_DECIMAL:
int size = Bits.readInt(_data, _pos);
_pos += 4;
int typeMod = Bits.readInt(_data, _pos);
_pos += 4;
short signScale = Bits.readShort(_data, _pos);
_pos += 2;
short weight = Bits.readShort(_data, _pos);
_pos += 2;
int nDigits = (size - BSONDecimal.DECIMAL_HEADER_SIZE) / (Short.SIZE / Byte.SIZE);
short[] digits = new short[nDigits];
for (int index = 0; index < nDigits; index++) {
digits[index] = Bits.readShort(_data, _pos);
_pos += 2;
}
BSONDecimal decimal = new BSONDecimal(size, typeMod, signScale, weight, digits);
_callback.gotDecimal(name, decimal);
return true;
case MINKEY:
_callback.gotMinKey(name);
return true;
case MAXKEY:
_callback.gotMaxKey(name);
return true;
default:
throw new UnsupportedOperationException("BSONDecoder doesn't understand type : " + type + " name: " + name);
}
}
private static final int MAX_STRING = (32 * 1024 * 1024);
private static final String DEFAULT_ENCODING = "UTF-8";
private byte[] _data;
private int _length;
private int _pos = 0;
private BSONCallback _callback;
}