You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2014/07/07 07:59:32 UTC

[5/5] git commit: forgotten files from Hendrik Saly patch - sorry

forgotten files from Hendrik Saly patch - sorry


Project: http://git-wip-us.apache.org/repos/asf/incubator-fleece/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-fleece/commit/9fc85e49
Tree: http://git-wip-us.apache.org/repos/asf/incubator-fleece/tree/9fc85e49
Diff: http://git-wip-us.apache.org/repos/asf/incubator-fleece/diff/9fc85e49

Branch: refs/heads/master
Commit: 9fc85e49ceb0ad28cf80a6556f5ecada46349527
Parents: 64b94e6
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Mon Jul 7 07:59:19 2014 +0200
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Mon Jul 7 07:59:19 2014 +0200

----------------------------------------------------------------------
 .../fleece/core/JsonBaseStreamParser.java       |   823 +
 .../fleece/core/JsonCharBufferStreamParser.java |   128 +
 .../src/test/resources/bench/big_600kb.json     | 21170 ++++++++
 .../src/test/resources/bench/huge_1mb.json      | 44003 +++++++++++++++++
 .../src/test/resources/bench/large_130kb.json   |  4328 ++
 .../src/test/resources/bench/medium_11kb.json   |   443 +
 .../src/test/resources/bench/small_3kb.json     |    86 +
 .../src/test/resources/bench/tiny_50b.json      |     5 +
 .../resources/bench/unicode_chars_170kb.json    |   Bin 0 -> 178048 bytes
 .../resources/bench/unicode_chars_huge.json     |   Bin 0 -> 1424384 bytes
 .../src/test/resources/bench/unicodes.json      |   Bin 0 -> 178048 bytes
 .../src/test/resources/bench/unicodes_big.json  |   Bin 0 -> 1424384 bytes
 fleece-core/src/test/resources/json/empty.json  |     1 +
 .../src/test/resources/json/emptyarray.json     |     3 +
 .../src/test/resources/json/fails/fail1.json    |     8 +
 .../src/test/resources/json/fails/fail10.json   |     7 +
 .../src/test/resources/json/fails/fail11.json   |     8 +
 .../src/test/resources/json/fails/fail12.json   |     8 +
 .../src/test/resources/json/fails/fail13.json   |     8 +
 .../src/test/resources/json/fails/fail14.json   |     8 +
 .../src/test/resources/json/fails/fail15.json   |    11 +
 .../src/test/resources/json/fails/fail16.json   |     9 +
 .../src/test/resources/json/fails/fail17.json   |     9 +
 .../src/test/resources/json/fails/fail18.json   |    11 +
 .../src/test/resources/json/fails/fail19.json   |    10 +
 .../src/test/resources/json/fails/fail2.json    |     8 +
 .../src/test/resources/json/fails/fail20.json   |    10 +
 .../src/test/resources/json/fails/fail21.json   |    10 +
 .../src/test/resources/json/fails/fail22.json   |     1 +
 .../src/test/resources/json/fails/fail23.json   |     8 +
 .../src/test/resources/json/fails/fail24.json   |     5 +
 .../src/test/resources/json/fails/fail25.json   |     8 +
 .../src/test/resources/json/fails/fail3.json    |     8 +
 .../src/test/resources/json/fails/fail4.json    |     8 +
 .../src/test/resources/json/fails/fail5.json    |     8 +
 .../src/test/resources/json/fails/fail6.json    |     8 +
 .../src/test/resources/json/fails/fail7.json    |     8 +
 .../src/test/resources/json/fails/fail8.json    |     8 +
 .../src/test/resources/json/fails/fail9.json    |     8 +
 .../src/test/resources/json/special.json        |    18 +
 .../src/test/resources/json/stringescape.json   |     3 +
 .../src/test/resources/json/unicode.json        |    10 +
 42 files changed, 71224 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/9fc85e49/fleece-core/src/main/java/org/apache/fleece/core/JsonBaseStreamParser.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonBaseStreamParser.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonBaseStreamParser.java
new file mode 100644
index 0000000..fbec4a2
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonBaseStreamParser.java
@@ -0,0 +1,823 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import static org.apache.fleece.core.Strings.asEscapedChar;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.NoSuchElementException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.json.JsonException;
+import javax.json.stream.JsonLocation;
+import javax.json.stream.JsonParsingException;
+
+public abstract class JsonBaseStreamParser implements JsonChars,
+        EscapedStringAwareJsonParser {
+    private static final Logger LOGGER = Logger.getLogger(JsonBaseStreamParser.class.getName());
+    private static final boolean LOG = LOGGER.isLoggable(Level.FINE);
+
+    // private static BufferCache<char[]> VBUFFER_CACHE;
+
+    private final int maxStringSize;
+
+    // current state
+    private Event event = null;
+    private Event lastEvent = null;
+    private int lastSignificantChar = -1;
+
+    private final char[] currentValue;
+    private int valueLength = 0;
+
+    // location
+    private int line = 1;
+    private int column = 1;
+    private int offset = 0;
+
+    private boolean constructingStringValue = false;
+    private boolean withinArray = false;
+    private boolean stringValueIsKey = false;
+
+    private int openObjects = 0;
+    private int openArrays = 0;
+    private boolean escaped = false;
+
+    protected JsonBaseStreamParser(final int maxStringLength) {
+
+        /*
+         * if(VBUFFER_CACHE == null) { VBUFFER_CACHE = new BufferCache<char[]>(
+         * maxStringLength) {
+         * 
+         * @Override protected char[] newValue(final int defaultSize) { return
+         * new char[defaultSize]; } };}
+         */
+
+        this.maxStringSize = maxStringLength < 0 ? 8192 : maxStringLength;
+        // currentValue = VBUFFER_CACHE.getCache();
+        currentValue = new char[maxStringLength];
+    }
+
+    private void appendValue(final char c) {
+        if (valueLength >= maxStringSize) {
+            throw new JsonParsingException("to many chars", createLocation());
+        }
+
+        currentValue[valueLength] = c;
+        valueLength++;
+    }
+
+    private void resetValue() {
+        valueLength = 0;
+
+    }
+
+    private String getValue() {
+        return new String(currentValue, 0, valueLength);
+    }
+
+    @Override
+    public final boolean hasNext() {
+
+        if (event == null) {
+            return true;
+        }
+
+        return !(openArrays == 0 && openObjects == 0);
+
+    }
+
+    private static boolean isAsciiDigit(final char value) {
+        return value >= ZERO && value <= NINE;
+    }
+
+    private static boolean isHexDigit(final char value) {
+        return isAsciiDigit(value) || (value >= 'a' && value <= 'f')
+                || (value >= 'A' && value <= 'F');
+    }
+
+    private JsonLocationImpl createLocation() {
+        return new JsonLocationImpl(line, column, offset);
+    }
+
+    private boolean ifConstructingStringValueAdd(char c) throws IOException {
+        if (escaped) {
+
+            if (c == 'u') {
+                final char[] tmp = read(4);
+
+                for (int i = 0; i < tmp.length; i++) {
+                    if (!isHexDigit(tmp[i])) {
+                        throw new JsonParsingException("unexpected character "
+                                + tmp[i], createLocation());
+                    }
+                }
+
+                if (LOG) {
+                    LOGGER.fine((int) tmp[3] + "/" + (int) tmp[2] + "/"
+                            + (int) tmp[1] + "/" + (int) tmp[0]);
+                }
+
+                final int decimal = ((tmp[3]) - 48) * 1 + ((tmp[2]) - 48) * 16
+                        + ((tmp[1]) - 48) * 256 + ((tmp[0]) - 48) * 4096;
+                c = (char) decimal;
+
+            } else {
+                c = asEscapedChar(c);
+            }
+
+            escaped = false;
+        }
+
+        return ifConstructingStringValueAdd(c, false);
+    }
+
+    private boolean ifConstructingStringValueAdd(final char c,
+            final boolean escape) {
+        if (constructingStringValue) {
+
+            appendValue(escape ? Strings.asEscapedChar(c) : c);
+        }
+        return constructingStringValue;
+    }
+
+    protected abstract char readNextChar() throws IOException;
+
+    protected abstract void mark();
+
+    private void resetToMark() {
+
+        reset();
+        offset--;
+        column--;
+    }
+
+    protected abstract void reset();
+
+    private char read() throws IOException {
+        final char c = readNextChar();
+
+        if (LOG) {
+            LOGGER.fine("reading: " + c + " -> " + ((int) c));
+        }
+
+        if (c == -1) {
+            // hasNext = false;
+            throw new NoSuchElementException();
+        }
+
+        offset++;
+        column++;
+
+        return c;
+    }
+
+    private char[] read(final int count) throws IOException {
+        final char[] tmp = new char[count];
+
+        for (int i = 0; i < tmp.length; i++) {
+            tmp[i] = read();
+
+        }
+
+        return tmp;
+    }
+
+    // Event.START_ARRAY
+    // Event.START_OBJECT
+
+    // Event.END_ARRAY
+    // Event.END_OBJECT
+
+    // Event.KEY_NAME
+
+    // ** 5 Value Event
+    // Event.VALUE_FALSE
+    // Event.VALUE_NULL
+    // Event.VALUE_NUMBER
+    // Event.VALUE_STRING
+    // Event.VALUE_TRUE
+
+    // ***********************
+    // ***********************
+    // Significant chars (8)
+
+    // 0 - start doc
+    // " - quote
+    // , - comma
+
+    // : - separator
+    // { - start obj
+    // } - end obj
+    // [ - start arr
+    // ] - end arr
+
+    @Override
+    public final Event next() {
+
+        int dosCount = 0;
+        lastEvent = event;
+        event = null;
+
+        resetValue();
+
+        try {
+            while (true) {
+                final char c = read();
+
+                switch (c) {
+
+                case START_OBJECT_CHAR:
+
+                    if (ifConstructingStringValueAdd(c)) {
+                        continue;
+                    }
+
+                    handleStartObject(c);
+
+                    break;
+
+                case END_OBJECT_CHAR:
+
+                    if (ifConstructingStringValueAdd(c)) {
+                        continue;
+                    }
+
+                    handleEndObject(c);
+
+                    break;
+                case START_ARRAY_CHAR:
+
+                    if (ifConstructingStringValueAdd(c)) {
+                        continue;
+                    }
+
+                    handleStartArray(c);
+
+                    break;
+                case END_ARRAY_CHAR:
+
+                    if (ifConstructingStringValueAdd(c)) {
+                        continue;
+                    }
+
+                    handleEndArray(c);
+                    break;
+                case EOL:
+                    if (ifConstructingStringValueAdd(c)) {
+                        throw new JsonParsingException("Unexpected character "
+                                + c + " (" + (int) c + ")", createLocation());
+                    }
+                    line++;
+                    continue; // eol no allowed within a value
+
+                case TAB:
+                case CR:
+                case SPACE:
+                    if (ifConstructingStringValueAdd(c)) { // escaping
+
+                        continue;
+
+                    } else {
+                        // dos check
+                        if (dosCount >= maxStringSize) {
+                            throw new JsonParsingException(
+                                    "max string size reached", createLocation());
+                        }
+                        dosCount++;
+                    }
+
+                    break;
+                case COMMA:
+                    if (ifConstructingStringValueAdd(c)) {
+                        continue;
+                    }
+
+                    if (lastSignificantChar >= 0
+                            && (char) lastSignificantChar != QUOTE
+                            && (char) lastSignificantChar != END_ARRAY_CHAR
+                            && (char) lastSignificantChar != END_OBJECT_CHAR) {
+                        throw new JsonParsingException("Unexpected character "
+                                + c + " (last significant was "
+                                + lastSignificantChar + ")", createLocation());
+                    }
+
+                    lastSignificantChar = c;
+
+                    stringValueIsKey = true;
+                    if (LOG) {
+                        LOGGER.fine(" VAL_IS_KEY");
+                    }
+
+                    break;
+                case KEY_SEPARATOR:
+                    if (ifConstructingStringValueAdd(c)) {
+                        continue;
+                    }
+
+                    if (lastSignificantChar >= 0
+                            && (char) lastSignificantChar != QUOTE) {
+                        throw new JsonParsingException("Unexpected character "
+                                + c, createLocation());
+                    }
+
+                    lastSignificantChar = c;
+
+                    stringValueIsKey = false;
+                    if (LOG) {
+                        LOGGER.fine(" VAL_IS_VALUE");
+                    }
+
+                    break;
+
+                case QUOTE: // must be escaped within a value
+
+                    if (handleQuote(c)) {
+                        continue;
+                    } else {
+                        break;
+                    }
+
+                    // non string values (literals)
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                case MINUS:
+                case FALSE_F: // false
+                case TRUE_T: // true
+                case NULL_N: // null
+
+                    if (ifConstructingStringValueAdd(c)) {
+                        continue;
+                    }
+
+                    handleLiteral(c);
+
+                    break;
+
+                // escape char
+                case ESCAPE_CHAR:// must be escaped within a value
+                    if (!constructingStringValue) {
+                        throw new JsonParsingException("Unexpected character "
+                                + c, createLocation());
+                    }
+
+                    if (escaped) {
+                        if (LOG) {
+                            LOGGER.fine(" ESCAPEDESCAPED");
+                        }
+
+                        appendValue(ESCAPE_CHAR);
+                        escaped = false;
+                    } else {
+                        if (LOG) {
+                            LOGGER.fine(" ESCAPECHAR");
+                        }
+                        escaped = true;
+                    }
+
+                    break;
+
+                // eof
+                case EOF:
+
+                    throw new NoSuchElementException();
+
+                default:
+                    if (ifConstructingStringValueAdd(c)) {
+                        continue;
+                    }
+                    lastSignificantChar = -2;
+                    throw new JsonParsingException("Unexpected character " + c,
+                            createLocation());
+
+                }
+
+                if (event != null) {
+
+                    if (LOG) {
+                        LOGGER.fine(" +++ +++ +++ +++ +++ +++" + event
+                                + "::" + getValue());
+                    }
+
+                    return event;
+
+                }
+
+            }
+        } catch (final IOException e) {
+            new JsonParsingException("Unexpected IO Excpetion", e,
+                    createLocation());
+        }
+
+        throw new JsonParsingException("Unexpected error due to invalid json",
+                createLocation());
+    }
+
+    private void handleStartObject(final char c) {
+
+        if (LOG) {
+            LOGGER.fine(" LASIC " + lastSignificantChar);
+        }
+
+        if (lastSignificantChar == -2
+                || (lastSignificantChar != -1
+                        && (char) lastSignificantChar != KEY_SEPARATOR
+                        && (char) lastSignificantChar != COMMA && (char) lastSignificantChar != START_ARRAY_CHAR)) {
+            throw new JsonParsingException("Unexpected character " + c
+                    + " (last significant was " + lastSignificantChar + ")",
+                    createLocation());
+        }
+
+        stringValueIsKey = true;
+        withinArray = false;
+        if (LOG) {
+            LOGGER.fine(" VAL_IS_KEY");
+        }
+
+        lastSignificantChar = c;
+        openObjects++;
+        event = Event.START_OBJECT;
+
+    }
+
+    private void handleEndObject(final char c) {
+        if (lastSignificantChar >= 0
+                && (char) lastSignificantChar != START_OBJECT_CHAR
+                && (char) lastSignificantChar != END_ARRAY_CHAR
+                && (char) lastSignificantChar != QUOTE
+                && (char) lastSignificantChar != END_OBJECT_CHAR) {
+            throw new JsonParsingException("Unexpected character " + c
+                    + " (last significant was " + lastSignificantChar + ")",
+                    createLocation());
+        }
+
+        if (openObjects == 0) {
+            throw new JsonParsingException("Unexpected character " + c,
+                    createLocation());
+        }
+
+        lastSignificantChar = c;
+        openObjects--;
+        event = Event.END_OBJECT;
+    }
+
+    private void handleStartArray(final char c) {
+        withinArray = true;
+
+        if (lastSignificantChar == -2
+                || (lastSignificantChar != -1
+                        && (char) lastSignificantChar != KEY_SEPARATOR
+                        && (char) lastSignificantChar != COMMA && (char) lastSignificantChar != START_ARRAY_CHAR)) {
+            throw new JsonParsingException("Unexpected character " + c
+                    + " (last significant was " + lastSignificantChar + ")",
+                    createLocation());
+        }
+
+        lastSignificantChar = c;
+        openArrays++;
+        event = Event.START_ARRAY;
+    }
+
+    private void handleEndArray(final char c) {
+        withinArray = false;
+
+        if (lastSignificantChar >= 0
+                && (char) lastSignificantChar != START_ARRAY_CHAR
+                && (char) lastSignificantChar != END_ARRAY_CHAR
+                && (char) lastSignificantChar != END_OBJECT_CHAR
+                && (char) lastSignificantChar != QUOTE) {
+            throw new JsonParsingException("Unexpected character " + c
+                    + " (last significant was " + lastSignificantChar + ")",
+                    createLocation());
+        }
+
+        if (openArrays == 0) {
+            throw new JsonParsingException("Unexpected character " + c,
+                    createLocation());
+        }
+
+        lastSignificantChar = c;
+        openArrays--;
+
+        event = Event.END_ARRAY;
+    }
+
+    private boolean handleQuote(final char c) {
+
+        if (lastSignificantChar >= 0 && (char) lastSignificantChar != QUOTE
+                && (char) lastSignificantChar != KEY_SEPARATOR
+                && (char) lastSignificantChar != START_OBJECT_CHAR
+                && (char) lastSignificantChar != START_ARRAY_CHAR
+                && (char) lastSignificantChar != COMMA) {
+            throw new JsonParsingException("Unexpected character " + c
+                    + " (last significant was " + lastSignificantChar + ")",
+                    createLocation());
+        }
+
+        lastSignificantChar = c;
+
+        if (constructingStringValue) {
+
+            if (escaped) {
+                appendValue(QUOTE);
+                escaped = false;
+                return true;
+            } else {
+
+                if (!withinArray && stringValueIsKey) {
+                    event = Event.KEY_NAME;
+                    stringValueIsKey = false;
+                    if (LOG) {
+                        LOGGER.fine(" VAL_IS_VALUE");
+                    }
+                } else {
+
+                    if (lastEvent != Event.KEY_NAME && !withinArray) {
+                        throw new JsonParsingException("Unexpected character "
+                                + c + " (lastevent " + lastEvent
+                                + ", comma missing)", createLocation());
+                    }
+
+                    // string value end
+                    event = Event.VALUE_STRING;
+                }
+
+                constructingStringValue = false;
+
+                return false;
+            }
+        } else {
+
+            if (escaped) {
+                throw new JsonParsingException("Unexpected character " + c,
+                        createLocation());
+            }
+
+            // string value start
+            resetValue();
+            constructingStringValue = true;
+            return false;
+        }
+
+    }
+
+    private void handleLiteral(final char c) throws IOException {
+        if (lastSignificantChar >= 0 && lastSignificantChar != KEY_SEPARATOR
+                && lastSignificantChar != COMMA
+                && lastSignificantChar != START_ARRAY_CHAR) {
+            throw new JsonParsingException("unexpected character " + c,
+                    createLocation());
+        }
+
+        lastSignificantChar = -2;
+
+        resetValue();
+
+        if (lastSignificantChar != QUOTE) {
+            // probe literals
+            switch (c) {
+            case TRUE_T:
+                final char[] tmpt = read(3);
+                if (tmpt[0] != TRUE_R || tmpt[1] != TRUE_U || tmpt[2] != TRUE_E) {
+                    throw new JsonParsingException("Unexpected literal " + c
+                            + new String(tmpt), createLocation());
+                }
+                event = Event.VALUE_TRUE;
+                break;
+            case FALSE_F:
+                final char[] tmpf = read(4);
+                if (tmpf[0] != FALSE_A || tmpf[1] != FALSE_L
+                        || tmpf[2] != FALSE_S || tmpf[3] != FALSE_E) {
+                    throw new JsonParsingException("Unexpected literal " + c
+                            + new String(tmpf), createLocation());
+                }
+
+                event = Event.VALUE_FALSE;
+                break;
+            case NULL_N:
+                final char[] tmpn = read(3);
+                if (tmpn[0] != NULL_U || tmpn[1] != NULL_L || tmpn[2] != NULL_L) {
+                    throw new JsonParsingException("Unexpected literal " + c
+                            + new String(tmpn), createLocation());
+                }
+                event = Event.VALUE_NULL;
+                break;
+
+            default: // number
+                appendValue(c);
+
+                boolean endExpected = false;
+                final boolean zeropassed = c == '0';
+                boolean dotpassed = false;
+                boolean epassed = false;
+                char last = c;
+                int i = -1;
+
+                while (true) {
+                    i++;
+
+                    if (LOG) {
+                        LOGGER.fine("while i:" + i);
+                    }
+
+                    final char n = read();
+                    mark();
+
+                    if (n == COMMA || n == END_ARRAY_CHAR
+                            || n == END_OBJECT_CHAR) {
+                        resetToMark();
+
+                        event = Event.VALUE_NUMBER;
+                        break;
+                    }
+
+                    if (n == EOL) {
+                        last = n;
+                        continue;
+                    }
+
+                    if (endExpected && n != SPACE && n != TAB && n != CR) {
+                        throw new JsonParsingException("unexpected character "
+                                + n + " (" + (int) n + ")", createLocation());
+                    }
+
+                    if (n == SPACE || n == TAB || n == CR) {
+                        endExpected = true;
+                        last = n;
+                        continue;
+                    }
+
+                    if (!isNumber(n)) {
+                        throw new JsonParsingException("unexpected character "
+                                + n, createLocation());
+                    }
+
+                    // minus only allowed as first char or after e/E
+                    if (n == MINUS && i != 0 && last != EXP_LOWERCASE
+                            && last != EXP_UPPERCASE) {
+                        throw new JsonParsingException("unexpected character "
+                                + n, createLocation());
+                    }
+
+                    // plus only allowed after e/E
+                    if (n == PLUS && last != EXP_LOWERCASE
+                            && last != EXP_UPPERCASE) {
+                        throw new JsonParsingException("unexpected character "
+                                + n, createLocation());
+                    }
+
+                    if (!dotpassed && zeropassed && i == 0 && n != DOT) {
+                        throw new JsonParsingException("unexpected character "
+                                + n + " (no leading zeros allowed)",
+                                createLocation());
+                    }
+
+                    if (LOG) {
+                        LOGGER.fine("dotpassed:" + dotpassed
+                                + "/zeropassed:" + zeropassed + "/i:" + i
+                                + "/n:" + n);
+                    }
+
+                    if (n == DOT) {
+
+                        if (dotpassed) {
+                            throw new JsonParsingException("more than one dot",
+                                    createLocation());
+                        }
+
+                        dotpassed = true;
+
+                    }
+
+                    if (n == EXP_LOWERCASE || n == EXP_UPPERCASE) {
+
+                        if (epassed) {
+                            throw new JsonParsingException("more than one e/E",
+                                    createLocation());
+                        }
+
+                        epassed = true;
+                    }
+
+                    appendValue(n);
+                    last = n;
+
+                }
+
+                break;
+
+            }
+
+        } else {
+            throw new JsonParsingException("Unexpected character " + c,
+                    createLocation());
+        }
+
+    }
+
+    private boolean isNumber(final char c) {
+        return isAsciiDigit(c) || c == DOT || c == MINUS || c == PLUS
+                || c == EXP_LOWERCASE || c == EXP_UPPERCASE;
+    }
+
+    @Override
+    public String getString() {
+        if (event == Event.KEY_NAME || event == Event.VALUE_STRING
+                || event == Event.VALUE_NUMBER) {
+            return getValue();
+        }
+        throw new IllegalStateException(event + " doesn't support getString()");
+    }
+
+    @Override
+    public boolean isIntegralNumber() {
+
+        if (event != Event.VALUE_NUMBER) {
+            throw new IllegalStateException(event
+                    + " doesn't supportisIntegralNumber()");
+        }
+
+        for (int i = 0; i < valueLength; i++) {
+            if (!isAsciiDigit(currentValue[i])) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public int getInt() {
+        if (event != Event.VALUE_NUMBER) {
+            throw new IllegalStateException(event + " doesn't supportgetInt()");
+        }
+        return Integer.parseInt(getValue());
+    }
+
+    @Override
+    public long getLong() {
+        if (event != Event.VALUE_NUMBER) {
+            throw new IllegalStateException(event + " doesn't supporgetLong()");
+        }
+        return Long.parseLong(getValue());
+    }
+
+    @Override
+    public BigDecimal getBigDecimal() {
+        if (event != Event.VALUE_NUMBER) {
+            throw new IllegalStateException(event
+                    + " doesn't support getBigDecimal()");
+        }
+        return new BigDecimal(getValue());
+    }
+
+    @Override
+    public JsonLocation getLocation() {
+        return createLocation();
+    }
+
+    protected abstract void closeUnderlyingSource() throws IOException;
+
+    @Override
+    public void close() {
+
+        // VBUFFER_CACHE.release(currentValue);
+
+        try {
+            closeUnderlyingSource();
+        } catch (final IOException e) {
+            throw new JsonException(e.getMessage(), e);
+        }
+    }
+     
+    @Override
+    public String getEscapedString() {
+        return Strings.escape(getValue());
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/9fc85e49/fleece-core/src/main/java/org/apache/fleece/core/JsonCharBufferStreamParser.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonCharBufferStreamParser.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonCharBufferStreamParser.java
new file mode 100644
index 0000000..8c84f51
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonCharBufferStreamParser.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class JsonCharBufferStreamParser extends JsonBaseStreamParser {
+    private static final Logger LOGGER = Logger.getLogger(JsonCharBufferStreamParser.class.getName());
+    private static final boolean LOG = LOGGER.isLoggable(Level.FINE);
+
+    /*
+     * private static final BufferCache<char[]> BUFFER_CACHE = new
+     * BufferCache<char[]>(
+     * Integer.getInteger("org.apache.fleece.default-char-buffer", 8192) ) {
+     * 
+     * @Override protected char[] newValue(final int defaultSize) { return new
+     * char[defaultSize]; } };
+     */
+
+    private final char[] buffer0;// BUFFER_CACHE.getCache();
+    private final Reader in;
+    private int pointer = -1;
+    private int avail;
+    private char mark;
+    private boolean reset;
+
+    // private int availOnMark;
+
+    // Test increment buffer sizes
+
+    public JsonCharBufferStreamParser(final Reader reader,
+            final int maxStringLength, final int bufferSize) {
+        super(maxStringLength);
+        in = reader;
+        buffer0 = new char[bufferSize];
+    }
+
+    public JsonCharBufferStreamParser(final InputStream stream,
+            final int maxStringLength, final int bufferSize) {
+        this(new InputStreamReader(stream), maxStringLength, bufferSize);
+    }
+
+    public JsonCharBufferStreamParser(final InputStream in,
+            final Charset charset, final int maxStringLength, final int bufferSize) {
+        this(new InputStreamReader(in, charset), maxStringLength, bufferSize);
+    }
+
+    @Override
+    protected char readNextChar() throws IOException {
+        if (reset) {
+            reset = false;
+            return mark;
+        }
+
+        if (avail <= 0) {
+            if (LOG) {
+                LOGGER.fine("avail:" + avail + "/pointer:" + pointer);
+            }
+
+            avail = in.read(buffer0, 0, buffer0.length);
+
+            pointer = -1;
+
+            if (LOG) {
+                LOGGER.fine("******* Fill buffer with " + avail
+                        + " chars");
+            }
+
+            if (avail <= 0) {
+                throw new IOException("EOF");
+            }
+
+        }
+
+        pointer++;
+        avail--;
+        return buffer0[pointer];
+
+    }
+
+    @Override
+    protected void mark() {
+        if (LOG) {
+            LOGGER.fine("    MARK " + buffer0[pointer] + " ("
+                    + (int) buffer0[pointer] + ")");
+        }
+        mark = buffer0[pointer];
+    }
+
+    @Override
+    protected void reset() {
+        if (LOG) {
+            LOGGER.fine("    RESET ");
+        }
+        reset = true;
+    }
+
+    @Override
+    protected void closeUnderlyingSource() throws IOException {
+        // BUFFER_CACHE.release(buffer0);
+        if (in != null) {
+            in.close();
+        }
+    }
+
+}