/** * Reads binary data from the input stream * * @return the json token read * @throws IOException if an I/O error occurs */ protected JsonToken handleBinary() throws IOException { int size = _in.readInt(); byte subtype = _in.readByte(); Context ctx = getContext(); switch (subtype) { case BsonConstants.SUBTYPE_BINARY_OLD: int size2 = _in.readInt(); byte[] buf2 = new byte[size2]; _in.readFully(buf2); ctx.value = buf2; break; case BsonConstants.SUBTYPE_UUID: long l1 = _in.readLong(); long l2 = _in.readLong(); ctx.value = new UUID(l1, l2); break; default: byte[] buf = new byte[size]; _in.readFully(buf); ctx.value = buf; break; } return JsonToken.VALUE_EMBEDDED_OBJECT; }
/** * Reads a string that consists of a integer denoting the number of bytes, the bytes (including a * terminating 0 byte) * * @return the string * @throws IOException if the string could not be read */ protected String readString() throws IOException { // read number of bytes int bytes = _in.readInt(); if (bytes <= 0) { throw new IOException("Invalid number of string bytes"); } String s; if (bytes > 1) { s = _in.readUTF(bytes - 1); } else { s = ""; } // read terminating zero _in.readByte(); return s; }
/** * Skips over a null-terminated string in the input stream * * @throws IOException if an I/O error occurs */ protected void skipCString() throws IOException { while (_in.readByte() != 0) ; }
@Override public JsonToken nextToken() throws IOException, JsonParseException { Context ctx = _contexts.peek(); if (_currToken == null && ctx == null) { _currToken = handleNewDocument(false); } else { _tokenPos = _counter.getPosition(); if (ctx == null) { if (_currToken == JsonToken.END_OBJECT) { // end of input return null; } throw new JsonParseException("Found element outside the document", getTokenLocation()); } if (ctx.state == State.DONE) { // next field ctx.reset(); } boolean readValue = true; if (ctx.state == State.FIELDNAME) { readValue = false; while (true) { // read field name or end of document ctx.type = _in.readByte(); if (ctx.type == BsonConstants.TYPE_END) { // end of document _currToken = (ctx.array ? JsonToken.END_ARRAY : JsonToken.END_OBJECT); _contexts.pop(); } else if (ctx.type == BsonConstants.TYPE_UNDEFINED) { // skip field name and then ignore this token skipCString(); continue; } else { ctx.state = State.VALUE; _currToken = JsonToken.FIELD_NAME; if (ctx.array) { // immediately read value of array element (discard field name) readValue = true; skipCString(); ctx.fieldName = null; } else { // read field name ctx.fieldName = readCString(); } } break; } } if (readValue) { // parse element's value switch (ctx.type) { case BsonConstants.TYPE_DOUBLE: ctx.value = _in.readDouble(); _currToken = JsonToken.VALUE_NUMBER_FLOAT; break; case BsonConstants.TYPE_STRING: ctx.value = readString(); _currToken = JsonToken.VALUE_STRING; break; case BsonConstants.TYPE_DOCUMENT: _currToken = handleNewDocument(false); break; case BsonConstants.TYPE_ARRAY: _currToken = handleNewDocument(true); break; case BsonConstants.TYPE_BINARY: _currToken = handleBinary(); break; case BsonConstants.TYPE_OBJECTID: ctx.value = readObjectId(); _currToken = JsonToken.VALUE_EMBEDDED_OBJECT; break; case BsonConstants.TYPE_BOOLEAN: boolean b = _in.readBoolean(); ctx.value = b; _currToken = (b ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE); break; case BsonConstants.TYPE_DATETIME: ctx.value = new Date(_in.readLong()); _currToken = JsonToken.VALUE_EMBEDDED_OBJECT; break; case BsonConstants.TYPE_NULL: _currToken = JsonToken.VALUE_NULL; break; case BsonConstants.TYPE_REGEX: _currToken = handleRegEx(); break; case BsonConstants.TYPE_DBPOINTER: _currToken = handleDBPointer(); break; case BsonConstants.TYPE_JAVASCRIPT: ctx.value = new JavaScript(readString()); _currToken = JsonToken.VALUE_EMBEDDED_OBJECT; break; case BsonConstants.TYPE_SYMBOL: ctx.value = readSymbol(); _currToken = JsonToken.VALUE_EMBEDDED_OBJECT; break; case BsonConstants.TYPE_JAVASCRIPT_WITH_SCOPE: _currToken = handleJavascriptWithScope(); break; case BsonConstants.TYPE_INT32: ctx.value = _in.readInt(); _currToken = JsonToken.VALUE_NUMBER_INT; break; case BsonConstants.TYPE_TIMESTAMP: ctx.value = readTimestamp(); _currToken = JsonToken.VALUE_EMBEDDED_OBJECT; break; case BsonConstants.TYPE_INT64: ctx.value = _in.readLong(); _currToken = JsonToken.VALUE_NUMBER_INT; break; case BsonConstants.TYPE_MINKEY: ctx.value = "MinKey"; _currToken = JsonToken.VALUE_STRING; break; case BsonConstants.TYPE_MAXKEY: ctx.value = "MaxKey"; _currToken = JsonToken.VALUE_STRING; break; default: throw new JsonParseException("Unknown element type " + ctx.type, getTokenLocation()); } ctx.state = State.DONE; } } return _currToken; }