예제 #1
0
 /**
  * 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;
 }
예제 #2
0
  /**
   * Can be called when a new embedded document is found. Reads the document's header and creates a
   * new context on the stack.
   *
   * @param array true if the document is an embedded array
   * @return the json token read
   * @throws IOException if an I/O error occurs
   */
  protected JsonToken handleNewDocument(boolean array) throws IOException {
    if (_in == null) {
      // this means Feature.HONOR_DOCUMENT_LENGTH is enabled, and w
      // haven't yet started reading. Read the first int to find out the
      // length of the document.
      byte[] buf = new byte[Integer.SIZE / Byte.SIZE];
      int len = 0;
      while (len < buf.length) {
        int l = _rawInputStream.read(buf, len, buf.length - len);
        if (l == -1) {
          throw new IOException("Not enough bytes for length of document");
        }
        len += l;
      }

      // wrap the input stream by a bounded stream, subtract buf.length from the
      // length because the size itself is included in the length
      int documentLength = ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN).getInt();
      InputStream in = new BoundedInputStream(_rawInputStream, documentLength - buf.length);

      // buffer if the raw input stream is not already buffered
      if (!(_rawInputStream instanceof BufferedInputStream)) {
        in = new StaticBufferedInputStream(in);
      }
      _counter = new CountingInputStream(in);
      _in = new LittleEndianInputStream(_counter);
    } else {
      // read document header (skip size, we're not interested)
      _in.readInt();
    }

    _contexts.push(new Context(array));
    return (array ? JsonToken.START_ARRAY : JsonToken.START_OBJECT);
  }
예제 #3
0
 @Override
 public void close() throws IOException {
   if (isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE)) {
     _in.close();
   }
   _closed = true;
 }
예제 #4
0
 /**
  * Can be called when embedded javascript code with scope is found. Reads the code and the
  * embedded document.
  *
  * @return the json token read
  * @throws IOException if an I/O error occurs
  */
 protected JsonToken handleJavascriptWithScope() throws IOException {
   // skip size
   _in.readInt();
   String code = readString();
   Map<String, Object> doc = readDocument();
   getContext().value = new JavaScript(code, doc);
   return JsonToken.VALUE_EMBEDDED_OBJECT;
 }
예제 #5
0
  /**
   * 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;
  }
예제 #6
0
 /**
  * Reads a ObjectID from the input stream
  *
  * @return the ObjectID
  * @throws IOException if the ObjectID could not be read
  */
 protected ObjectId readObjectId() throws IOException {
   int time = ByteOrderUtil.flip(_in.readInt());
   int machine = ByteOrderUtil.flip(_in.readInt());
   int inc = ByteOrderUtil.flip(_in.readInt());
   return new ObjectId(time, machine, inc);
 }
예제 #7
0
 /**
  * Reads a timestamp object from the input stream
  *
  * @return the timestamp
  * @throws IOException if the timestamp could not be read
  */
 protected Timestamp readTimestamp() throws IOException {
   int inc = _in.readInt();
   int time = _in.readInt();
   return new Timestamp(time, inc);
 }
예제 #8
0
 /**
  * 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) ;
 }
예제 #9
0
 /**
  * @return a null-terminated string read from the input stream
  * @throws IOException if the string could not be read
  */
 protected String readCString() throws IOException {
   return _in.readUTF(-1);
 }
예제 #10
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;
  }