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.ObjectId;
import static org.bson.BSON.*;
// Java
import java.io.IOException;
import java.io.InputStream;
import java.io.DataInputStream;
import java.io.UnsupportedEncodingException;
/**
* 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, 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(final byte [] pData, final BSONCallback pCallback) {
_data = pData;
_pos = 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, 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 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;
}