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/24 18:59:28 UTC

[1/2] FLEECE-9 patch from Hendrik Saly enhancing perfs and compliancy, thank you so much

Repository: incubator-fleece
Updated Branches:
  refs/heads/master 43319043e -> 675ec9d39


http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayBuilderImplTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayBuilderImplTest.java b/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayBuilderImplTest.java
index 65244c3..fd443c5 100644
--- a/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayBuilderImplTest.java
+++ b/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayBuilderImplTest.java
@@ -18,17 +18,17 @@
  */
 package org.apache.fleece.core;
 
+import static org.junit.Assert.assertEquals;
+
 import java.math.BigDecimal;
 import java.math.BigInteger;
 
-import org.junit.Test;
-
 import javax.json.Json;
 import javax.json.JsonArrayBuilder;
 import javax.json.JsonObjectBuilder;
 import javax.json.JsonValue;
 
-import static org.junit.Assert.assertEquals;
+import org.junit.Test;
 
 public class JsonArrayBuilderImplTest {
     @Test
@@ -39,12 +39,46 @@ public class JsonArrayBuilderImplTest {
     }
     
     @Test
+    public void escapedStringArray() {
+        final JsonArrayBuilder builder = Json.createArrayBuilder();
+        builder.add("a\"").add("\u0000");
+        assertEquals("[\"a\\\"\",\"\\u0000\"]", builder.build().toString());
+    }
+    
+    @Test
     public void emptyArray() {
         final JsonArrayBuilder builder = Json.createArrayBuilder();
         assertEquals("[]", builder.build().toString());
     }
     
     @Test
+    public void emptyArrayInEmtyArray() {
+        final JsonArrayBuilder builder = Json.createArrayBuilder();
+        builder.add(Json.createArrayBuilder());
+        assertEquals("[[]]", builder.build().toString());
+    }
+    
+    @Test
+    public void arrayInArray() {
+        final JsonArrayBuilder builder = Json.createArrayBuilder();
+        builder.add(3).add(4);
+        final JsonArrayBuilder builder2 = Json.createArrayBuilder();
+        builder2.add(1).add(2).add(builder);
+        assertEquals("[1,2,[3,4]]", builder2.build().toString());
+    }
+    
+    @Test
+    public void arrayObjectInArray() {
+        final JsonObjectBuilder objectBuilder = Json.createObjectBuilder();
+        objectBuilder.add("key", "val");
+        final JsonArrayBuilder builder = Json.createArrayBuilder();
+        builder.add(3).add(4).add(objectBuilder);
+        final JsonArrayBuilder builder2 = Json.createArrayBuilder();
+        builder2.add(1).add(2).add(builder);
+        assertEquals("[1,2,[3,4,{\"key\":\"val\"}]]", builder2.build().toString());
+    }
+    
+    @Test
     public void nullArray() {
         final JsonArrayBuilder builder = Json.createArrayBuilder();
         builder.addNull().addNull();
@@ -52,6 +86,14 @@ public class JsonArrayBuilderImplTest {
     }
     
     @Test
+    public void nullArrayNonChaining() {
+        final JsonArrayBuilder builder = Json.createArrayBuilder();
+        builder.addNull();
+        builder.addNull();
+        assertEquals("[null,null]", builder.build().toString());
+    }
+    
+    @Test
     public void nullJsonValueArray() {
         final JsonArrayBuilder builder = Json.createArrayBuilder();
         builder.add(JsonValue.NULL).add(JsonValue.NULL);
@@ -65,6 +107,13 @@ public class JsonArrayBuilderImplTest {
         assertEquals("[true,false]", builder.build().toString());
     }
     
+    @Test
+    public void numJsonValueArray() {
+        final JsonArrayBuilder builder = Json.createArrayBuilder();
+        builder.add(123.12d).add(new BigDecimal("456.789E-12")).add(-0).add(0).add((short)1).add((byte)1);
+        assertEquals("[123.12,4.56789E-10,0,0,1,1]", builder.build().toString());
+    }
+    
     @Test(expected=NullPointerException.class)
     public void addStringNpeIfNull() {
         final JsonArrayBuilder builder = Json.createArrayBuilder();

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayImplTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayImplTest.java b/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayImplTest.java
index 0b89de4..59b74d2 100644
--- a/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayImplTest.java
+++ b/fleece-core/src/test/java/org/apache/fleece/core/JsonArrayImplTest.java
@@ -18,11 +18,13 @@
  */
 package org.apache.fleece.core;
 
-import org.apache.fleece.core.JsonArrayImpl;
-import org.apache.fleece.core.JsonStringImpl;
-import org.junit.Test;
-
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import javax.json.JsonArray;
+
+import org.junit.Test;
 
 public class JsonArrayImplTest {
     @Test
@@ -32,4 +34,25 @@ public class JsonArrayImplTest {
         object.addInternal(new JsonStringImpl("b"));
         assertEquals("[\"a\",\"b\"]", object.toString());
     }
+    
+    @Test
+    public void arrayIndex() {
+        final JsonArrayImpl object = new JsonArrayImpl();
+        object.addInternal(new JsonStringImpl("a"));
+        object.addInternal(new JsonStringImpl("b"));
+        object.addInternal(new JsonLongImpl(5));
+        final JsonArray array = (JsonArray) object;
+        assertFalse(array.isEmpty());
+        assertEquals("a", object.getJsonString(0).getString());
+        assertEquals("b", object.getJsonString(1).getString());
+        assertEquals(5, object.getJsonNumber(2).longValue());
+        assertEquals("[\"a\",\"b\",5]", object.toString());
+    }
+    
+    @Test
+    public void emptyArray() {
+        final JsonArray array = new JsonArrayImpl();
+        assertTrue(array.isEmpty());
+        assertEquals("[]", array.toString());
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/JsonGeneratorImplTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/JsonGeneratorImplTest.java b/fleece-core/src/test/java/org/apache/fleece/core/JsonGeneratorImplTest.java
index a6e750f..374526f 100644
--- a/fleece-core/src/test/java/org/apache/fleece/core/JsonGeneratorImplTest.java
+++ b/fleece-core/src/test/java/org/apache/fleece/core/JsonGeneratorImplTest.java
@@ -18,16 +18,16 @@
  */
 package org.apache.fleece.core;
 
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.util.HashMap;
 
 import javax.json.Json;
 import javax.json.JsonValue;
 import javax.json.stream.JsonGenerator;
 
-import java.io.ByteArrayOutputStream;
-import java.util.HashMap;
-
-import static org.junit.Assert.assertEquals;
+import org.junit.Test;
 
 public class JsonGeneratorImplTest {
     @Test
@@ -67,8 +67,15 @@ public class JsonGeneratorImplTest {
     @Test
     public void stringArrayEscapes() {
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        Json.createGenerator(baos).writeStartArray().write("\"val1\t\u0080").write("val2\\").writeEnd().close();
-        assertEquals("[\"\\\"val1\\t\\u0080\",\"val2\\\\\"]", new String(baos.toByteArray()));
+        Json.createGenerator(baos).writeStartArray().write("\"val1\t\u0010").write("val2\\").writeEnd().close();
+        assertEquals("[\"\\\"val1\\t\\u0010\",\"val2\\\\\"]", new String(baos.toByteArray()));
+    }
+    
+    @Test
+    public void stringArrayEscapes2() {
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Json.createGenerator(baos).writeStartArray().write("\"val1\t\u0067").write("val2\\").writeEnd().close();
+        assertEquals("[\"\\\"val1\\tg\",\"val2\\\\\"]", new String(baos.toByteArray()));
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/JsonNumberTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/JsonNumberTest.java b/fleece-core/src/test/java/org/apache/fleece/core/JsonNumberTest.java
new file mode 100644
index 0000000..7c95827
--- /dev/null
+++ b/fleece-core/src/test/java/org/apache/fleece/core/JsonNumberTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.math.BigInteger;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+
+
+public class JsonNumberTest {
+    
+    @Test(expected=ArithmeticException.class)
+    public void testBigIntegerExact() {
+       
+        JsonArray array = Json.createArrayBuilder().add(100.0200).build();
+        array.getJsonNumber(0).bigIntegerValueExact();
+
+       
+    }
+    
+    @Test
+    public void testBigInteger() {
+       
+        JsonArray array = Json.createArrayBuilder().add(100.0200).build();
+        Assert.assertEquals(new BigInteger("100"), array.getJsonNumber(0).bigIntegerValue());
+
+       
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectBuilderImplTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectBuilderImplTest.java b/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectBuilderImplTest.java
index ea14a71..3462a41 100644
--- a/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectBuilderImplTest.java
+++ b/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectBuilderImplTest.java
@@ -18,12 +18,12 @@
  */
 package org.apache.fleece.core;
 
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
 
 import javax.json.Json;
 import javax.json.JsonObjectBuilder;
 
-import static org.junit.Assert.assertEquals;
+import org.junit.Test;
 
 public class JsonObjectBuilderImplTest {
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectImplTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectImplTest.java b/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectImplTest.java
index a7aff07..6ebb3e5 100644
--- a/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectImplTest.java
+++ b/fleece-core/src/test/java/org/apache/fleece/core/JsonObjectImplTest.java
@@ -18,12 +18,10 @@
  */
 package org.apache.fleece.core;
 
-import org.apache.fleece.core.JsonObjectImpl;
-import org.apache.fleece.core.JsonStringImpl;
-import org.junit.Test;
-
 import static org.junit.Assert.assertEquals;
 
+import org.junit.Test;
+
 public class JsonObjectImplTest {
     @Test
     public void objectToString() {

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/JsonParserTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/JsonParserTest.java b/fleece-core/src/test/java/org/apache/fleece/core/JsonParserTest.java
index dd6b534..a5027b5 100644
--- a/fleece-core/src/test/java/org/apache/fleece/core/JsonParserTest.java
+++ b/fleece-core/src/test/java/org/apache/fleece/core/JsonParserTest.java
@@ -25,21 +25,43 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.ByteArrayInputStream;
+import java.io.CharArrayReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
+import java.nio.charset.Charset;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.NoSuchElementException;
 
 import javax.json.Json;
 import javax.json.JsonArray;
+import javax.json.JsonException;
 import javax.json.JsonReader;
 import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParser.Event;
+import javax.json.stream.JsonParserFactory;
 import javax.json.stream.JsonParsingException;
 
 import org.junit.Test;
 
 public class JsonParserTest {
+    
+    
+    static final Charset UTF_8 = Charset.forName("UTF-8");
+    static final Charset UTF_16BE = Charset.forName("UTF-16BE");
+    static final Charset UTF_16LE = Charset.forName("UTF-16LE");
+    static final Charset UTF_16 = Charset.forName("UTF-16");
+    static final Charset UTF_32LE = Charset.forName("UTF-32LE");
+    static final Charset UTF_32BE = Charset.forName("UTF-32BE");
+    
+    public JsonParserTest() {
+        super();
+        if (!Charset.defaultCharset().equals(Charset.forName("UTF-8"))) {
+            throw new RuntimeException("Default charset is " + Charset.defaultCharset() + ", must must be UTF-8");
+        }
+    }
+
     private void assertSimple(final JsonParser parser) {
         {
             assertTrue(parser.hasNext());
@@ -216,6 +238,21 @@ public class JsonParserTest {
         assertNotNull(parser);
         assertSimple(parser);
     }
+    
+    @Test
+    public void simpleUTF16LE() {
+        final JsonParser parser = Json.createParserFactory(null).createParser(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/simple_utf16le.json"),UTF_16LE);
+        assertNotNull(parser);
+        assertSimple(parser);
+    }
+    
+    @Test
+    public void simpleUTF16LEAutoDetect() {
+        final JsonParser parser = Json.createParserFactory(null).createParser(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/simple_utf16le.json"));
+        assertNotNull(parser);
+        assertSimple(parser);
+    }
+    
 
     @Test
     public void nested() {
@@ -713,13 +750,80 @@ public class JsonParserTest {
         Json.createReader(new ByteArrayInputStream("{\"z\":nulll}".getBytes())).read();
     }
     
-    @Test(expected = JsonParsingException.class)
+    @Test(expected = JsonException.class)
     public void zeroByteInput() {
         // using a reader as wrapper of parser
   
         Json.createReader(new ByteArrayInputStream(new byte[]{})).read();
     }
     
+    @Test(expected = JsonParsingException.class)
+    public void zeroCharInput() {
+        // using a reader as wrapper of parser
+  
+        Json.createReader(new CharArrayReader(new char[]{})).read();
+    }
+    
+    @Test
+    public void testUTF32LEStream() {
+        ByteArrayInputStream bin = new ByteArrayInputStream("[\"UTF32LE\"]".getBytes(UTF_32LE));
+        JsonParser parser = Json.createParser(bin);
+        parser.next();
+        parser.next();
+        assertEquals("UTF32LE", parser.getString());
+        parser.next();
+        assertTrue(!parser.hasNext());
+        parser.close();
+    }
+    
+    @Test
+    public void testUTF32BEStream() {
+        ByteArrayInputStream bin = new ByteArrayInputStream("[\"UTF32BE\"]".getBytes(UTF_32BE));
+        JsonParser parser = Json.createParser(bin);
+        parser.next();
+        parser.next();
+        assertEquals("UTF32BE", parser.getString());
+        parser.next();
+        assertTrue(!parser.hasNext());
+        parser.close();
+    }
+    
+    @Test
+    public void testUTF16BEStream() {
+        ByteArrayInputStream bin = new ByteArrayInputStream("[\"UTF16BE\"]".getBytes(UTF_16BE));
+        JsonParser parser = Json.createParser(bin);
+        parser.next();
+        parser.next();
+        assertEquals("UTF16BE", parser.getString());
+        parser.next();
+        assertTrue(!parser.hasNext());
+        parser.close();
+    }
+    
+    @Test
+    public void testUTF16LEStream() {
+        ByteArrayInputStream bin = new ByteArrayInputStream("[\"UTF16LE\"]".getBytes(UTF_16LE));
+        JsonParser parser = Json.createParser(bin);
+        parser.next();
+        parser.next();
+        assertEquals("UTF16LE", parser.getString());
+        parser.next();
+        assertTrue(!parser.hasNext());
+        parser.close();
+    }
+    
+    @Test
+    public void testUTF8Stream() {
+        ByteArrayInputStream bin = new ByteArrayInputStream("[\"UTF8\"]".getBytes(UTF_8));
+        JsonParser parser = Json.createParser(bin);
+        parser.next();
+        parser.next();
+        assertEquals("UTF8", parser.getString());
+        parser.next();
+        assertTrue(!parser.hasNext());
+        parser.close();
+    }
+    
     @Test
     public void shortestNonEmtyJsonFile() {
         // using a reader as wrapper of parser
@@ -735,6 +839,109 @@ public class JsonParserTest {
         assertEquals(0L, Json.createReader(new ByteArrayInputStream("  \n\n   [   0  ]  \n\n".getBytes())).readArray().getJsonNumber(0).longValue());
     }
     
+    @Test
+    public void escapeStart() {
+        // using a reader as wrapper of parser
+  
+        assertEquals("\\abcdef", Json.createReader(new ByteArrayInputStream("[\"\\\\abcdef\"]".getBytes())).readArray().getString(0));
+    }
+    
+    @Test
+    public void escapeStart2() {
+        // using a reader as wrapper of parser
+  
+        assertEquals("\"abcdef", Json.createReader(new ByteArrayInputStream("[\"\\\"abcdef\"]".getBytes())).readArray().getString(0));
+    }
+    
+    @Test
+    public void threeLiterals() {
+        final JsonParser parser = Json.createParserFactory(new HashMap<String, Object>() {{
+            put(JsonParserFactoryImpl.MAX_STRING_LENGTH, 10);
+        }}).createParser(new ByteArrayInputStream("{\"a\":true,\"b\":null,\"c\":false,\"arr\":[false, true, null]}".getBytes()));
+        parser.next();
+        parser.next();
+        assertEquals(JsonParser.Event.VALUE_TRUE, parser.next());
+        parser.next();
+        assertEquals(JsonParser.Event.VALUE_NULL, parser.next());
+        parser.next();
+        assertEquals(JsonParser.Event.VALUE_FALSE, parser.next());
+        parser.next();
+        parser.next();
+        assertEquals(JsonParser.Event.VALUE_FALSE, parser.next());
+        assertEquals(JsonParser.Event.VALUE_TRUE, parser.next());
+        assertEquals(JsonParser.Event.VALUE_NULL, parser.next());
+        parser.close();
+    }
+    
+    @Test
+    public void maxStringStringOK() {
+        // using a reader as wrapper of parser
+        Json.createReaderFactory(new HashMap<String, Object>() {
+            {
+                put("org.apache.fleece.max-string-length", "5");
+            }
+        }).createReader(new ByteArrayInputStream("[\"abcde\"]".getBytes())).read();
+       
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void maxStringStringFail() {
+        // using a reader as wrapper of parser
+        Json.createReaderFactory(new HashMap<String, Object>() {
+            {
+                put("org.apache.fleece.max-string-length", "5");
+            }
+        }).createReader(new ByteArrayInputStream("[\"abcdef\"]".getBytes())).read();
+       
+    }
+    
+    @Test
+    public void maxStringNumberOK() {
+        // using a reader as wrapper of parser
+        Json.createReaderFactory(new HashMap<String, Object>() {
+            {
+                put("org.apache.fleece.max-string-length", "5");
+            }
+        }).createReader(new ByteArrayInputStream("[12.3]".getBytes())).read();
+       
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void maxStringNumberFail() {
+        // using a reader as wrapper of parser
+        Json.createReaderFactory(new HashMap<String, Object>() {
+            {
+                put("org.apache.fleece.max-string-length", "5");
+            }
+        }).createReader(new ByteArrayInputStream("[12.333]".getBytes())).read();
+       
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void maxStringWhitespace() {
+        // using a reader as wrapper of parser
+        Json.createReaderFactory(new HashMap<String, Object>() {
+            {
+                put("org.apache.fleece.max-string-length", "5");
+            }
+        }).createReader(new ByteArrayInputStream("[\"12\"           ]".getBytes())).read();
+       
+    }
+    
+    
+    @Test
+    public void testEmptyArray() {
+       JsonParser parser = Json.createParser(new ByteArrayInputStream("[]".getBytes()));
+        assertEquals(Event.START_ARRAY, parser.next());
+        assertEquals(Event.END_ARRAY, parser.next());
+        assertEquals(false, parser.hasNext());
+        try {
+            parser.next();
+            fail("Should have thrown a NoSuchElementException");
+        } catch (NoSuchElementException ne) {
+        }
+    }
+    
     
     @Test(expected = JsonParsingException.class)
     public void fail1() {
@@ -886,4 +1093,288 @@ public class JsonParserTest {
         Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail25.json")).read();
     }
     
+    @Test(expected = JsonParsingException.class)
+    public void fail26() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail26.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail27() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail27.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail28() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail28.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail29() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail29.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail30() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail30.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail31() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail31.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail32() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail32.json")).read();
+    }
+    
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail33() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail33.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail34() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail34.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail35() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail35.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail36() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail36.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail37() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail37.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail38() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail38.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail39() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail39.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail40() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail40.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail41() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail41.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail42() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail42.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail43() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail43.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail44() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail44.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail45() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail45.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail46() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail46.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail47() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail47.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail48() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail48.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail49() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail49.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail50() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail50.json")).read();
+    }
+    
+    //@Test(expected = JsonParsingException.class)
+    public void fail51() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail51.json")).read();
+    }
+    
+    //@Test(expected = JsonParsingException.class)
+    public void fail52() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail52.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail53() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail53.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail54() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail54.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail55() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail55.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail56() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail56.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail57() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail57.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail58() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail58.json")).read();
+    }
+    
+    @Test(expected = JsonException.class)
+    public void fail59() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail59.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail60() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail60.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail61() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail61.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail62() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail62.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail63() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail63.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail64() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail64.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail65() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail65.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail66() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail66.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail67() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail67.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail68() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail68.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail69() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail69.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail70() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail70.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail71() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail71.json")).read();
+    }
+    
+    @Test(expected = JsonParsingException.class)
+    public void fail72() {
+        
+        Json.createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/fails/fail72.json")).read();
+    }
+    
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/JsonReaderImplTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/JsonReaderImplTest.java b/fleece-core/src/test/java/org/apache/fleece/core/JsonReaderImplTest.java
index 2cb95c1..abad642 100644
--- a/fleece-core/src/test/java/org/apache/fleece/core/JsonReaderImplTest.java
+++ b/fleece-core/src/test/java/org/apache/fleece/core/JsonReaderImplTest.java
@@ -42,6 +42,15 @@ import org.junit.Test;
 
 public class JsonReaderImplTest {
     
+    
+    
+    public JsonReaderImplTest() {
+        super();
+        if (!Charset.defaultCharset().equals(Charset.forName("UTF-8"))) {
+            throw new RuntimeException("Default charset is " + Charset.defaultCharset() + ", must must be UTF-8");
+        }
+    }
+
     protected static Charset utf8Charset = Charset.forName("UTF8");
     protected static Charset asciiCharset = Charset.forName("ASCII");
 
@@ -125,6 +134,7 @@ public class JsonReaderImplTest {
         assertTrue(object.getJsonNumber("w").doubleValue() > 4 && object.getJsonNumber("w").doubleValue() < 5);
         assertEquals(110, object.getInt("1.4312"));
         assertEquals("\"", object.getString("\""));
+        assertTrue(object.isNull("\u0044"));
         assertEquals("ন:4::,[{", object.getString("থii:üäöÖ.,;.-<>!§$%&()=?ß´'`*+#"));
         reader.close();
     }
@@ -319,6 +329,28 @@ public class JsonReaderImplTest {
         assertEquals(-2, array.getInt(1));
         reader.close();
     }
+    
+    @Test
+    public void simple2BadBufferSize8() {
+        final JsonReader reader = Json.createReaderFactory(new HashMap<String, Object>() {
+            {
+                put("org.apache.fleece.default-char-buffer", "8");
+            }
+        }).createReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/simple2.json"), utf8Charset);
+        assertNotNull(reader);
+        final JsonObject object = reader.readObject();
+        assertNotNull(object);
+        assertEquals(3, object.size());
+        assertEquals("b", object.getString("a"));
+        assertEquals(4, object.getInt("c"));
+        assertThat(object.get("d"), instanceOf(JsonArray.class));
+        final JsonArray array = object.getJsonArray("d");
+        assertNotNull(array);
+        assertEquals(2, array.size());
+        assertEquals(1, array.getInt(0));
+        assertEquals(-2, array.getInt(1));
+        reader.close();
+    }
 
     @Test
     public void simpleBadBufferSize9() {

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/JsonWriterImplTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/JsonWriterImplTest.java b/fleece-core/src/test/java/org/apache/fleece/core/JsonWriterImplTest.java
index 8c3d921..8887570 100644
--- a/fleece-core/src/test/java/org/apache/fleece/core/JsonWriterImplTest.java
+++ b/fleece-core/src/test/java/org/apache/fleece/core/JsonWriterImplTest.java
@@ -18,15 +18,14 @@
  */
 package org.apache.fleece.core;
 
-import org.apache.fleece.core.JsonObjectImpl;
-import org.apache.fleece.core.JsonStringImpl;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
 
 import javax.json.Json;
 import javax.json.JsonWriter;
-import java.io.ByteArrayOutputStream;
 
-import static org.junit.Assert.assertEquals;
+import org.junit.Test;
 
 public class JsonWriterImplTest {
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/java/org/apache/fleece/core/LocationTest.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/java/org/apache/fleece/core/LocationTest.java b/fleece-core/src/test/java/org/apache/fleece/core/LocationTest.java
new file mode 100644
index 0000000..1d73d3d
--- /dev/null
+++ b/fleece-core/src/test/java/org/apache/fleece/core/LocationTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.StringReader;
+import java.util.HashMap;
+
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonWriter;
+import javax.json.stream.JsonLocation;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParsingException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class LocationTest {
+    @Test
+    public void failBytesInput() {
+  
+        try {
+            JsonReader reader = Json.createReader(new StringReader("{\"z\":nulll}"));
+            reader.read();
+            Assert.fail("Exception expected");
+        } catch (JsonParsingException e) {
+            JsonLocation location = e.getLocation();
+            Assert.assertNotNull(location);
+            Assert.assertEquals(new JsonLocationImpl(1, 11, 10), location);
+            
+        }
+        
+        
+        try {
+            JsonReader reader = Json.createReader(new StringReader("{\"z\":\nnulll}"));
+            reader.read();
+            Assert.fail("Exception expected");
+        } catch (JsonParsingException e) {
+            JsonLocation location = e.getLocation();
+            Assert.assertNotNull(location);
+            Assert.assertEquals(new JsonLocationImpl(2, 6, 11), location);
+            
+        }
+        
+        try {
+            JsonReader reader = Json.createReader(new StringReader("aaa"));
+            reader.read();
+            Assert.fail("Exception expected");
+        } catch (JsonParsingException e) {
+            JsonLocation location = e.getLocation();
+            Assert.assertNotNull(location);
+            Assert.assertEquals(new JsonLocationImpl(1, 2, 1), location);
+            
+        }
+    }
+    
+    
+    @Test
+    public void simpleLocation() {
+  
+  
+        JsonParser parser = Json.createParser(new StringReader("{\n    \"ö \uffff c\": null ,\n    \"test\"  :\"testval\",\n    \"num\": 45.1e-12  \n}"));
+        
+        /*
+         
+         
+{
+    "z a c": null ,
+    "test"  :"testval",
+    "num": 45.1e-12  //2 ws
+}
+         
+         
+         */
+        
+        Assert.assertEquals(new JsonLocationImpl(1, 1, 0), parser.getLocation());
+        parser.next(); //after first {
+        Assert.assertEquals(new JsonLocationImpl(1, 2, 1), parser.getLocation());
+        parser.next(); //after "ö \uffff c"
+        Assert.assertEquals(new JsonLocationImpl(2, 12, 13), parser.getLocation());
+        parser.next(); //after null   
+        Assert.assertEquals(new JsonLocationImpl(2, 18, 19), parser.getLocation());
+        parser.next(); //after test
+        Assert.assertEquals(new JsonLocationImpl(3, 11, 32), parser.getLocation());    
+        parser.next(); //after testval
+        Assert.assertEquals(new JsonLocationImpl(3, 23, 44), parser.getLocation());    
+        parser.next(); //after num
+        Assert.assertEquals(new JsonLocationImpl(4, 10, 55), parser.getLocation());    
+        parser.next(); //after 45.1e-12
+        Assert.assertEquals(new JsonLocationImpl(4, 20, 65), parser.getLocation());    
+        parser.next(); //after }
+        Assert.assertEquals(new JsonLocationImpl(5, 2, 69), parser.getLocation());    
+       
+    }
+    
+    /*@Test
+    public void simpleLocationBytes() {
+  
+        JsonParser parser = Json.createParser(new ByteArrayInputStream("{\n    \"ö \uffff c\": null ,\n    \"test\"  :\"testval\",\n    \"num\": 45.1e-12  \n}".getBytes()));
+        
+        Assert.assertEquals(new JsonLocationImpl(1, 1, 0), parser.getLocation());
+        parser.next(); //after first {
+        Assert.assertEquals(new JsonLocationImpl(1, 2, 2), parser.getLocation());
+        parser.next(); //after "ö \uffff c"
+        Assert.assertEquals(new JsonLocationImpl(2, 12, 26), parser.getLocation());
+        parser.next(); //after null   
+        Assert.assertEquals(new JsonLocationImpl(2, 18, 38), parser.getLocation());
+        parser.next(); //after test
+        Assert.assertEquals(new JsonLocationImpl(3, 11, 64), parser.getLocation());    
+        parser.next(); //after testval
+        Assert.assertEquals(new JsonLocationImpl(3, 23, 88), parser.getLocation());    
+        parser.next(); //after num
+        Assert.assertEquals(new JsonLocationImpl(4, 10, 110), parser.getLocation());    
+        parser.next(); //after 45.1e-12
+        Assert.assertEquals(new JsonLocationImpl(4, 20, 130), parser.getLocation());    
+        parser.next(); //after }
+        Assert.assertEquals(new JsonLocationImpl(5, 2, 138), parser.getLocation());    
+       
+    }*/
+    
+    @Test
+    public void simpleLocationCrossingBufferBoundaries() {
+ 
+
+        for (int i = 1; i <= 100; i++) {
+            final String value = String.valueOf(i);
+            final JsonParser parser = Json.createParserFactory(new HashMap<String, Object>() {
+                {
+                    put("org.apache.fleece.default-char-buffer", value);
+                }
+            }).createParser(new StringReader("{\n    \"z a c\": null ,\n    \"test\"  :\"testval\",\n    \"num\": 45.1e-12  \n}"));
+
+             
+            /*
+             
+             
+    {
+        "z a c": null ,
+        "test"  :"testval",
+        "num": 45.1e-12  //2 ws
+    }
+             
+             
+             */
+            
+           
+            
+            Assert.assertEquals(new JsonLocationImpl(1, 1, 0), parser.getLocation());
+            parser.next(); //after first {
+            Assert.assertEquals(new JsonLocationImpl(1, 2, 1), parser.getLocation());
+            parser.next(); //after "z a c"
+            Assert.assertEquals(new JsonLocationImpl(2, 12, 13), parser.getLocation());
+            parser.next(); //after null   
+            Assert.assertEquals(new JsonLocationImpl(2, 18, 19), parser.getLocation());
+            parser.next(); //after test
+            Assert.assertEquals(new JsonLocationImpl(3, 11, 32), parser.getLocation());    
+            parser.next(); //after testval
+            Assert.assertEquals(new JsonLocationImpl(3, 23, 44), parser.getLocation());    
+            parser.next(); //after num
+            Assert.assertEquals(new JsonLocationImpl(4, 10, 55), parser.getLocation());    
+            parser.next(); //after 45.1e-12
+            Assert.assertEquals(new JsonLocationImpl(4, 20, 65), parser.getLocation());    
+            parser.next(); //after }
+            Assert.assertEquals(new JsonLocationImpl(5, 2, 69), parser.getLocation());   
+            
+            Assert.assertFalse(parser.hasNext());
+            Assert.assertFalse(parser.hasNext());
+        }
+        
+        
+         
+       
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail23.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail23.json b/fleece-core/src/test/resources/json/fails/fail23.json
index 489c56b..b10e1d9 100644
--- a/fleece-core/src/test/resources/json/fails/fail23.json
+++ b/fleece-core/src/test/resources/json/fails/fail23.json
@@ -1,8 +1,8 @@
 {
     "a": "\u6565",
-    "c": "\u000",
+    "c": "\u123",
     "d": [
         
-        -2, "\u0020"
+        -2, "\u0048"
     ]
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail25.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail25.json b/fleece-core/src/test/resources/json/fails/fail25.json
index ceadcbe..f72b803 100644
--- a/fleece-core/src/test/resources/json/fails/fail25.json
+++ b/fleece-core/src/test/resources/json/fails/fail25.json
@@ -3,6 +3,6 @@
     "c": "\up000",
     "d": [
         
-        -2, "\u0020"
+        -2, "\u0044"
     ]
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail26.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail26.json b/fleece-core/src/test/resources/json/fails/fail26.json
new file mode 100644
index 0000000..128454e
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail26.json
@@ -0,0 +1,7 @@
+,{
+    "a": "\u6565",
+    "d": [
+        
+        -2, "\u0044"
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail27.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail27.json b/fleece-core/src/test/resources/json/fails/fail27.json
new file mode 100644
index 0000000..3ae9085
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail27.json
@@ -0,0 +1,7 @@
+"{
+    "a": "\u6565",
+    "d": [
+        
+        -2, "\u0044"
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail28.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail28.json b/fleece-core/src/test/resources/json/fails/fail28.json
new file mode 100644
index 0000000..11ba875
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail28.json
@@ -0,0 +1,7 @@
+true, {
+    "a": "\u6565",
+    "d": [
+        
+        -2, "\u0044"
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail29.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail29.json b/fleece-core/src/test/resources/json/fails/fail29.json
new file mode 100644
index 0000000..8eff000
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail29.json
@@ -0,0 +1,7 @@
+  :   {
+    "a": "\u6565",
+    "d": [
+        
+        -2, "\u0044"
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail30.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail30.json b/fleece-core/src/test/resources/json/fails/fail30.json
new file mode 100644
index 0000000..555e395
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail30.json
@@ -0,0 +1,7 @@
+null{
+    "a": "\u6565",
+    "d": [
+        
+        -2, "\u0044"
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail31.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail31.json b/fleece-core/src/test/resources/json/fails/fail31.json
new file mode 100644
index 0000000..f1c8332
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail31.json
@@ -0,0 +1,7 @@
+"string":{
+    "a": "\u6565",
+    "d": [
+        
+        -2, "\u0044"
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail32.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail32.json b/fleece-core/src/test/resources/json/fails/fail32.json
new file mode 100644
index 0000000..7883a28
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail32.json
@@ -0,0 +1,7 @@
+{
+    "a": "\u6565",
+    "d": [
+        
+        -2, 20e-1.2
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail33.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail33.json b/fleece-core/src/test/resources/json/fails/fail33.json
new file mode 100644
index 0000000..308571d
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail33.json
@@ -0,0 +1,7 @@
+14{
+    "a": "\u6565",
+    "d": [
+        
+        -2, "\u0044"
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail34.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail34.json b/fleece-core/src/test/resources/json/fails/fail34.json
new file mode 100644
index 0000000..619a684
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail34.json
@@ -0,0 +1,7 @@
+{
+    "a": "\u6565",
+    "d": [
+        
+        -2, 2.0e-1.2
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail35.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail35.json b/fleece-core/src/test/resources/json/fails/fail35.json
new file mode 100644
index 0000000..cfda2b8
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail35.json
@@ -0,0 +1,7 @@
+ ,   {
+    "a": "\u6565",
+    "d": [
+        
+        -2, "\u0044"
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail36.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail36.json b/fleece-core/src/test/resources/json/fails/fail36.json
new file mode 100644
index 0000000..57fff2f
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail36.json
@@ -0,0 +1,3 @@
+{
+    "a": "	"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail37.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail37.json b/fleece-core/src/test/resources/json/fails/fail37.json
new file mode 100644
index 0000000..6e894f9
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail37.json
@@ -0,0 +1,4 @@
+{
+    "a
+    ": "x"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail38.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail38.json b/fleece-core/src/test/resources/json/fails/fail38.json
new file mode 100644
index 0000000..0c90427
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail38.json
@@ -0,0 +1,3 @@
+{
+    "a": 12.2e-
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail39.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail39.json b/fleece-core/src/test/resources/json/fails/fail39.json
new file mode 100644
index 0000000..ac47891
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail39.json
@@ -0,0 +1,3 @@
+{
+    "a": 12.2e
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail40.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail40.json b/fleece-core/src/test/resources/json/fails/fail40.json
new file mode 100644
index 0000000..7a503fb
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail40.json
@@ -0,0 +1,4 @@
+{
+    "a": "v"
+}
+some garbage
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail41.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail41.json b/fleece-core/src/test/resources/json/fails/fail41.json
new file mode 100644
index 0000000..352963d
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail41.json
@@ -0,0 +1,3 @@
+{
+    "a": "\vbadescape"
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail42.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail42.json b/fleece-core/src/test/resources/json/fails/fail42.json
new file mode 100644
index 0000000..ed6e301
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail42.json
@@ -0,0 +1,3 @@
+{
+    "a": -055
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail43.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail43.json b/fleece-core/src/test/resources/json/fails/fail43.json
new file mode 100644
index 0000000..46fcf2e
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail43.json
@@ -0,0 +1,3 @@
+{
+    "a": -01.55
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail44.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail44.json b/fleece-core/src/test/resources/json/fails/fail44.json
new file mode 100644
index 0000000..4e963bb
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail44.json
@@ -0,0 +1,3 @@
+{
+    "a": -00001.55
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail45.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail45.json b/fleece-core/src/test/resources/json/fails/fail45.json
new file mode 100644
index 0000000..ccc49ff
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail45.json
@@ -0,0 +1,3 @@
+{
+    "a": " before this word the is a u+0001 char"
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail46.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail46.json b/fleece-core/src/test/resources/json/fails/fail46.json
new file mode 100644
index 0000000..54b8681
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail46.json
@@ -0,0 +1,3 @@
+{
+    "a": "before this is a u+00031 char"
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail47.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail47.json b/fleece-core/src/test/resources/json/fails/fail47.json
new file mode 100644
index 0000000..13f6f1d
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail47.json
@@ -0,0 +1 @@
+[1,]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail48.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail48.json b/fleece-core/src/test/resources/json/fails/fail48.json
new file mode 100644
index 0000000..e4d4ddd
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail48.json
@@ -0,0 +1,6 @@
+[1,
+2,
+3,
+4,
+5,
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail49.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail49.json b/fleece-core/src/test/resources/json/fails/fail49.json
new file mode 100644
index 0000000..3acaa8f
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail49.json
@@ -0,0 +1 @@
+{"a":1,}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail50.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail50.json b/fleece-core/src/test/resources/json/fails/fail50.json
new file mode 100644
index 0000000..c7e2925
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail50.json
@@ -0,0 +1,4 @@
+{
+"a":1,
+"b":2,
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail51.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail51.json b/fleece-core/src/test/resources/json/fails/fail51.json
new file mode 100644
index 0000000..dec2b86
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail51.json
@@ -0,0 +1 @@
+["\uDFAA (missing high surrogate)"]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail52.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail52.json b/fleece-core/src/test/resources/json/fails/fail52.json
new file mode 100644
index 0000000..eeea18b
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail52.json
@@ -0,0 +1 @@
+["\uD888\u3210 (invalid second surrogate)"]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail53.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail53.json b/fleece-core/src/test/resources/json/fails/fail53.json
new file mode 100644
index 0000000..5819cae
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail53.json
@@ -0,0 +1,11 @@
+{
+    "0": 0,
+    "0": -0,
+    "1": 1,
+    "-1": -1,
+    "9": 9,
+    "-9": -9,
+    "10": 10,
+    "-10", -10,
+    "100": 100
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail54.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail54.json b/fleece-core/src/test/resources/json/fails/fail54.json
new file mode 100644
index 0000000..0fffc9b
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail54.json
@@ -0,0 +1,12 @@
+{
+    "0": 0,
+    "0": -0,
+    "1": 1,
+    "-1": -1,
+    "9": 9,
+    "-9": -9,
+    "10": 10,
+    "-10"  -10,
+    "100": 100,
+    "-100", -100
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail55.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail55.json b/fleece-core/src/test/resources/json/fails/fail55.json
new file mode 100644
index 0000000..a3a4074
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail55.json
@@ -0,0 +1,12 @@
+{
+    "0": 0,
+    "0": -0,
+    "1": 1,
+    "-1": -1,
+    "9": 9,
+    "-9": -9,
+    "10": 10,
+    -10  -10,
+    "100": 100,
+    "-100", -100
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail56.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail56.json b/fleece-core/src/test/resources/json/fails/fail56.json
new file mode 100644
index 0000000..820d41e
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail56.json
@@ -0,0 +1,11 @@
+{
+    "0": 0,
+    "0": -0,
+    "1": 1,
+    "-1": -1,
+    "9": 9,
+    "-9": -9,
+    "10": 10,
+    "-10", "-10",
+    "100": 100
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail57.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail57.json b/fleece-core/src/test/resources/json/fails/fail57.json
new file mode 100644
index 0000000..ffe9c1c
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail57.json
@@ -0,0 +1 @@
+["a":3]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail58.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail58.json b/fleece-core/src/test/resources/json/fails/fail58.json
new file mode 100644
index 0000000..270b5d5
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail58.json
@@ -0,0 +1,3 @@
+{
+  "0":["a":3]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail59.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail59.json b/fleece-core/src/test/resources/json/fails/fail59.json
new file mode 100644
index 0000000..81750b9
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail59.json
@@ -0,0 +1 @@
+{
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail60.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail60.json b/fleece-core/src/test/resources/json/fails/fail60.json
new file mode 100644
index 0000000..17be25b
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail60.json
@@ -0,0 +1 @@
+[ {}, [] }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail61.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail61.json b/fleece-core/src/test/resources/json/fails/fail61.json
new file mode 100644
index 0000000..0b9fc5b
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail61.json
@@ -0,0 +1,3 @@
+{
+    "a": -
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail62.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail62.json b/fleece-core/src/test/resources/json/fails/fail62.json
new file mode 100644
index 0000000..ac5e00d
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail62.json
@@ -0,0 +1,3 @@
+{
+    "a":
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail63.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail63.json b/fleece-core/src/test/resources/json/fails/fail63.json
new file mode 100644
index 0000000..29bdc57
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail63.json
@@ -0,0 +1,3 @@
+{
+    "a"
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail64.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail64.json b/fleece-core/src/test/resources/json/fails/fail64.json
new file mode 100644
index 0000000..3edb81e
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail64.json
@@ -0,0 +1,3 @@
+{
+    "a": 1.,
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail65.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail65.json b/fleece-core/src/test/resources/json/fails/fail65.json
new file mode 100644
index 0000000..3adb8bb
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail65.json
@@ -0,0 +1,3 @@
+{
+    "a": .5,
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail66.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail66.json b/fleece-core/src/test/resources/json/fails/fail66.json
new file mode 100644
index 0000000..129cac0
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail66.json
@@ -0,0 +1,3 @@
+{
+    "a": 1-,
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail67.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail67.json b/fleece-core/src/test/resources/json/fails/fail67.json
new file mode 100644
index 0000000..5df5fe3
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail67.json
@@ -0,0 +1,3 @@
+{
+    "a": 1.-,
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail68.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail68.json b/fleece-core/src/test/resources/json/fails/fail68.json
new file mode 100644
index 0000000..2c44166
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail68.json
@@ -0,0 +1,3 @@
+{
+    "a": 1.9e-1.2,
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail69.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail69.json b/fleece-core/src/test/resources/json/fails/fail69.json
new file mode 100644
index 0000000..349826b
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail69.json
@@ -0,0 +1,3 @@
+{
+    12
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail70.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail70.json b/fleece-core/src/test/resources/json/fails/fail70.json
new file mode 100644
index 0000000..0c90165
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail70.json
@@ -0,0 +1,3 @@
+{
+    null null
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail71.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail71.json b/fleece-core/src/test/resources/json/fails/fail71.json
new file mode 100644
index 0000000..819e165
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail71.json
@@ -0,0 +1,3 @@
+{
+    null
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/fail72.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/fail72.json b/fleece-core/src/test/resources/json/fails/fail72.json
new file mode 100644
index 0000000..02beb05
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/fail72.json
@@ -0,0 +1,3 @@
+{
+    "a","b"
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/fails/numbers.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/fails/numbers.json b/fleece-core/src/test/resources/json/fails/numbers.json
new file mode 100644
index 0000000..d300022
--- /dev/null
+++ b/fleece-core/src/test/resources/json/fails/numbers.json
@@ -0,0 +1,18 @@
+{
+    "0": 0,
+    "0": -0,
+    "1": 1,
+    "-1": -1,
+    "9": 9,
+    "-9": -9,
+    "10": 10,
+    "-10", -10,
+    "100": 100,
+    "-100", -100,
+    "456": 456,
+    "-456": -456,
+    "123.12345": 123.12345,
+    "-123.12345": -123.12345,
+    "999999999999999999999999999999": 999999999999999999999999999999,
+    "-999999999999999999999999999999": -999999999999999999999999999999
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/numbers.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/numbers.json b/fleece-core/src/test/resources/json/numbers.json
index d300022..847a9f8 100644
--- a/fleece-core/src/test/resources/json/numbers.json
+++ b/fleece-core/src/test/resources/json/numbers.json
@@ -6,9 +6,9 @@
     "9": 9,
     "-9": -9,
     "10": 10,
-    "-10", -10,
+    "-10": -10,
     "100": 100,
-    "-100", -100,
+    "-100": -100,
     "456": 456,
     "-456": -456,
     "123.12345": 123.12345,

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/simple2.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/simple2.json b/fleece-core/src/test/resources/json/simple2.json
new file mode 100644
index 0000000..2578a23
--- /dev/null
+++ b/fleece-core/src/test/resources/json/simple2.json
@@ -0,0 +1,8 @@
+{
+ "a": "b",
+ "c": 4,
+ "d": [
+  1,
+  -2
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/test/resources/json/simple_utf16le.json
----------------------------------------------------------------------
diff --git a/fleece-core/src/test/resources/json/simple_utf16le.json b/fleece-core/src/test/resources/json/simple_utf16le.json
new file mode 100644
index 0000000..c2e2137
Binary files /dev/null and b/fleece-core/src/test/resources/json/simple_utf16le.json differ


[2/2] git commit: FLEECE-9 patch from Hendrik Saly enhancing perfs and compliancy, thank you so much

Posted by rm...@apache.org.
FLEECE-9 patch from Hendrik Saly enhancing perfs and compliancy, thank you so much


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

Branch: refs/heads/master
Commit: 675ec9d39a0e448e1775ac191893008f8880bcbb
Parents: 4331904
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Thu Jul 24 18:59:09 2014 +0200
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Thu Jul 24 18:59:09 2014 +0200

----------------------------------------------------------------------
 .../fleece/core/JsonBaseStreamParser.java       | 830 ----------------
 .../fleece/core/JsonCharBufferStreamParser.java |  93 --
 .../java/org/apache/fleece/core/JsonChars.java  |  28 +-
 .../org/apache/fleece/core/JsonDoubleImpl.java  |   4 +-
 .../apache/fleece/core/JsonLocationImpl.java    |   6 +-
 .../fleece/core/JsonParserFactoryImpl.java      |  25 +-
 .../org/apache/fleece/core/JsonReaderImpl.java  |  11 +-
 .../fleece/core/JsonStreamParserImpl.java       | 968 +++++++++++++++++++
 .../core/RFC4627AwareInputStreamReader.java     | 110 +++
 .../java/org/apache/fleece/core/Strings.java    |  14 +-
 .../fleece/core/JsonArrayBuilderImplTest.java   |  55 +-
 .../apache/fleece/core/JsonArrayImplTest.java   |  31 +-
 .../fleece/core/JsonGeneratorImplTest.java      |  21 +-
 .../org/apache/fleece/core/JsonNumberTest.java  |  51 +
 .../fleece/core/JsonObjectBuilderImplTest.java  |   4 +-
 .../apache/fleece/core/JsonObjectImplTest.java  |   6 +-
 .../org/apache/fleece/core/JsonParserTest.java  | 493 +++++++++-
 .../apache/fleece/core/JsonReaderImplTest.java  |  32 +
 .../apache/fleece/core/JsonWriterImplTest.java  |   9 +-
 .../org/apache/fleece/core/LocationTest.java    | 196 ++++
 .../src/test/resources/json/fails/fail23.json   |   4 +-
 .../src/test/resources/json/fails/fail25.json   |   2 +-
 .../src/test/resources/json/fails/fail26.json   |   7 +
 .../src/test/resources/json/fails/fail27.json   |   7 +
 .../src/test/resources/json/fails/fail28.json   |   7 +
 .../src/test/resources/json/fails/fail29.json   |   7 +
 .../src/test/resources/json/fails/fail30.json   |   7 +
 .../src/test/resources/json/fails/fail31.json   |   7 +
 .../src/test/resources/json/fails/fail32.json   |   7 +
 .../src/test/resources/json/fails/fail33.json   |   7 +
 .../src/test/resources/json/fails/fail34.json   |   7 +
 .../src/test/resources/json/fails/fail35.json   |   7 +
 .../src/test/resources/json/fails/fail36.json   |   3 +
 .../src/test/resources/json/fails/fail37.json   |   4 +
 .../src/test/resources/json/fails/fail38.json   |   3 +
 .../src/test/resources/json/fails/fail39.json   |   3 +
 .../src/test/resources/json/fails/fail40.json   |   4 +
 .../src/test/resources/json/fails/fail41.json   |   3 +
 .../src/test/resources/json/fails/fail42.json   |   3 +
 .../src/test/resources/json/fails/fail43.json   |   3 +
 .../src/test/resources/json/fails/fail44.json   |   3 +
 .../src/test/resources/json/fails/fail45.json   |   3 +
 .../src/test/resources/json/fails/fail46.json   |   3 +
 .../src/test/resources/json/fails/fail47.json   |   1 +
 .../src/test/resources/json/fails/fail48.json   |   6 +
 .../src/test/resources/json/fails/fail49.json   |   1 +
 .../src/test/resources/json/fails/fail50.json   |   4 +
 .../src/test/resources/json/fails/fail51.json   |   1 +
 .../src/test/resources/json/fails/fail52.json   |   1 +
 .../src/test/resources/json/fails/fail53.json   |  11 +
 .../src/test/resources/json/fails/fail54.json   |  12 +
 .../src/test/resources/json/fails/fail55.json   |  12 +
 .../src/test/resources/json/fails/fail56.json   |  11 +
 .../src/test/resources/json/fails/fail57.json   |   1 +
 .../src/test/resources/json/fails/fail58.json   |   3 +
 .../src/test/resources/json/fails/fail59.json   |   1 +
 .../src/test/resources/json/fails/fail60.json   |   1 +
 .../src/test/resources/json/fails/fail61.json   |   3 +
 .../src/test/resources/json/fails/fail62.json   |   3 +
 .../src/test/resources/json/fails/fail63.json   |   3 +
 .../src/test/resources/json/fails/fail64.json   |   3 +
 .../src/test/resources/json/fails/fail65.json   |   3 +
 .../src/test/resources/json/fails/fail66.json   |   3 +
 .../src/test/resources/json/fails/fail67.json   |   3 +
 .../src/test/resources/json/fails/fail68.json   |   3 +
 .../src/test/resources/json/fails/fail69.json   |   3 +
 .../src/test/resources/json/fails/fail70.json   |   3 +
 .../src/test/resources/json/fails/fail71.json   |   3 +
 .../src/test/resources/json/fails/fail72.json   |   3 +
 .../src/test/resources/json/fails/numbers.json  |  18 +
 .../src/test/resources/json/numbers.json        |   4 +-
 .../src/test/resources/json/simple2.json        |   8 +
 .../src/test/resources/json/simple_utf16le.json | Bin 0 -> 136 bytes
 73 files changed, 2258 insertions(+), 972 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/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
deleted file mode 100644
index d4ba437..0000000
--- a/fleece-core/src/main/java/org/apache/fleece/core/JsonBaseStreamParser.java
+++ /dev/null
@@ -1,830 +0,0 @@
-/*
- * 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 javax.json.JsonException;
-import javax.json.stream.JsonLocation;
-import javax.json.stream.JsonParsingException;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.util.NoSuchElementException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import static org.apache.fleece.core.Strings.asEscapedChar;
-
-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 final int maxStringSize;
-
-    // current state
-    private Event event = null;
-    private Event lastEvent = null;
-    private int lastSignificantChar = -1;
-
-    protected 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 boolean isCurrentNumberIntegral = false;
-    private Integer currentIntegralNumber = null; //for number from 0 - 9
-    private BigDecimal currentBigDecimalNumber = null;
-
-    private int openObjects = 0;
-    private int openArrays = 0;
-    private boolean escaped = false;
-
-    protected JsonBaseStreamParser(final int maxStringLength, final char[] valueBuffer) {
-        this.maxStringSize = maxStringLength <= 0 ? 8192 : maxStringLength;
-        this.currentValue = valueBuffer;
-    }
-
-    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() {
-        return event == null || !(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(!constructingStringValue) {
-            return false;
-        }
-        
-        if (escaped) {
-
-            if (c == 'u') {
-                final char[] tmp = read(4);
-
-                for (final char aTmp : tmp) {
-                    if (!isHexDigit(aTmp)) {
-                        throw new JsonParsingException("unexpected character " + aTmp, createLocation());
-                    }
-                }
-
-                if (LOG) {
-                    LOGGER.fine((int) tmp[3] + "/" + (int) tmp[2] + "/"
-                            + (int) tmp[1] + "/" + (int) tmp[0]);
-                }
-
-                final int decimal = ((tmp[3]) - 48) + ((tmp[2]) - 48) * 16
-                        + ((tmp[1]) - 48) * 256 + ((tmp[0]) - 48) * 4096;
-                c = (char) decimal;
-
-            } else {
-                c = asEscapedChar(c);
-            }
-
-            escaped = false;
-        }
-        
-        appendValue(c);
-
-        return true;
-    }
-
-    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;
-        isCurrentNumberIntegral = false;
-        currentBigDecimalNumber = null;
-        currentIntegralNumber = 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++;
-                    column = 1;
-                    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;
-                    }
-
-                    final char lastSignificant = (char) lastSignificantChar;
-                    if (lastSignificantChar >= 0
-                            && lastSignificant != QUOTE
-                            && lastSignificant != END_ARRAY_CHAR
-                            && lastSignificant != END_OBJECT_CHAR) {
-                        throw new JsonParsingException("Unexpected character "
-                                + c + " (last significant was "
-                                + lastSignificantChar + ")", createLocation());
-                    }
-
-                    lastSignificantChar = c;
-
-                    stringValueIsKey = true;
-
-                    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;
-
-                    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) {
-                        appendValue(ESCAPE_CHAR);
-                        escaped = false;
-                    } else {
-                        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) {
-                    return event;
-                }
-            }
-        } catch (final IOException e) {
-            throw new JsonParsingException("Unexpected IO Exception", e, createLocation());
-        }
-    }
-
-    private void handleStartObject(final char c) {
-        final char significantChar = (char) lastSignificantChar; // cast eagerly means we avoid 2 castings and are slwoer in error case only
-        if (lastSignificantChar == -2
-                || (lastSignificantChar != -1
-                        && significantChar != KEY_SEPARATOR
-                        && significantChar != COMMA && significantChar != START_ARRAY_CHAR)) {
-            throw new JsonParsingException("Unexpected character " + c
-                    + " (last significant was " + lastSignificantChar + ")",
-                    createLocation());
-        }
-
-        stringValueIsKey = true;
-        withinArray = false;
-
-        lastSignificantChar = c;
-        openObjects++;
-        event = Event.START_OBJECT;
-
-    }
-
-    private void handleEndObject(final char c) {
-        final char significantChar = (char) lastSignificantChar;
-        if (lastSignificantChar >= 0
-                && significantChar != START_OBJECT_CHAR
-                && significantChar != END_ARRAY_CHAR
-                && significantChar != QUOTE
-                && significantChar != 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;
-
-        final char significantChar = (char) lastSignificantChar;
-        if (lastSignificantChar == -2
-                || (lastSignificantChar != -1
-                        && significantChar != KEY_SEPARATOR
-                        && significantChar != COMMA
-                        && significantChar != 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;
-
-        final char significantChar = (char) lastSignificantChar;
-        if (lastSignificantChar >= 0
-                && significantChar != START_ARRAY_CHAR
-                && significantChar != END_ARRAY_CHAR
-                && significantChar != END_OBJECT_CHAR
-                && significantChar != 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) {
-
-        final char significantChar = (char) lastSignificantChar;
-        if (lastSignificantChar >= 0
-                && significantChar != QUOTE
-                && significantChar != KEY_SEPARATOR
-                && significantChar != START_OBJECT_CHAR
-                && significantChar != START_ARRAY_CHAR
-                && significantChar != 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;
-                } 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';
-                final boolean beginningMinusPassed = c == '-';
-                boolean dotpassed = false;
-                boolean epassed = false;
-                char last = c;
-                int i = -1;
-
-                while (true) {
-                    i++;
-
-                    final char n = read();
-                    mark();
-
-                    if (n == COMMA || n == END_ARRAY_CHAR
-                            || n == END_OBJECT_CHAR) {
-                        resetToMark();
-                        
-                        isCurrentNumberIntegral=(!dotpassed && !epassed);
-                        
-                        if(isCurrentNumberIntegral && beginningMinusPassed && i==1 && last >= '0' && last <= '9')
-                        {
-                            currentIntegralNumber=-((int)last - 48); //optimize -0 till -99
-                        }
-                        
-                        if(isCurrentNumberIntegral && !beginningMinusPassed && i==0 && last >= '0' && last <= '9')
-                        {
-                            currentIntegralNumber=((int)last - 48); //optimize 0 till 9
-                        }
-                        
-                        
-                        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 static 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 support isIntegralNumber()");
-        }
-
-        return isCurrentNumberIntegral;
-    }
-
-    @Override
-    public int getInt() {
-        if (event != Event.VALUE_NUMBER) {
-            throw new IllegalStateException(event + " doesn't support getInt()");
-        }
-
-        if (isCurrentNumberIntegral && currentIntegralNumber != null) {
-            return currentIntegralNumber;
-        }
-
-        if(isCurrentNumberIntegral) {
-            return (int) parseLongFromChars(currentValue, 0, valueLength);
-        }
-        
-        return getBigDecimal().intValue();
-    }
-
-    @Override
-    public long getLong() {
-        if (event != Event.VALUE_NUMBER) {
-            throw new IllegalStateException(event + " doesn't support getLong()");
-        }
-
-        if (isCurrentNumberIntegral && currentIntegralNumber != null) {
-            return currentIntegralNumber;
-        } // int is ok, its only from 0-9
-
-        if (isCurrentNumberIntegral) {
-            return parseLongFromChars(currentValue, 0, valueLength);
-        }
-        
-        return getBigDecimal().longValue();
-    }
-
-    @Override
-    public BigDecimal getBigDecimal() {
-        if (event != Event.VALUE_NUMBER) {
-            throw new IllegalStateException(event + " doesn't support getBigDecimal()");
-        }
-
-        if (currentBigDecimalNumber != null) {
-            return currentBigDecimalNumber;
-        }
-
-        return (currentBigDecimalNumber = new BigDecimal(getString()));
-    }
-
-    @Override
-    public JsonLocation getLocation() {
-        return createLocation();
-    }
-
-    protected abstract void closeUnderlyingSource() throws IOException;
-
-    @Override
-    public void close() {
-        try {
-            closeUnderlyingSource();
-        } catch (final IOException e) {
-            throw new JsonException(e.getMessage(), e);
-        }
-    }
-     
-    @Override
-    public String getEscapedString() {
-        return Strings.escape(getValue());
-    }
-    
-    private static long parseLongFromChars(char[] chars, int start, int end) {
-
-        if (chars == null 
-                || chars.length == 0 
-                || start < 0 
-                || end <= start 
-                || end > chars.length - 1 
-                || start > chars.length - 1) {
-            throw new IllegalArgumentException();
-        }
-
-        long retVal = 0;
-        boolean negative = chars[start] == MINUS;
-        for (int i = negative ? start + 1 : start; i < end; i++) {
-
-            //int this context we know its an integral number, so skip this due to perf reasons
-            /*if (chars[i] < ZERO || chars[i] > NINE) {
-                throw new IllegalArgumentException("Not a integral number");
-            }*/
-            retVal = retVal * 10 + (chars[i] - ZERO);
-        }
-
-        return negative ? -retVal : retVal;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/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
deleted file mode 100644
index 3bd3af0..0000000
--- a/fleece-core/src/main/java/org/apache/fleece/core/JsonCharBufferStreamParser.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.Reader;
-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 final char[] buffer;
-    private final Reader in;
-    private final BufferStrategy.BufferProvider<char[]> bufferProvider;
-    private final BufferStrategy.BufferProvider<char[]> valueProvider;
-    private int pointer = -1;
-    private int avail;
-    private char mark;
-    private boolean reset;
-
-    public JsonCharBufferStreamParser(final Reader reader, final int maxStringLength,
-                                      final BufferStrategy.BufferProvider<char[]> bufferProvider,
-                                      final BufferStrategy.BufferProvider<char[]> valueBuffer) {
-        super(maxStringLength, valueBuffer.newBuffer());
-        this.in = reader;
-        this.buffer = bufferProvider.newBuffer();
-        this.bufferProvider = bufferProvider;
-        this.valueProvider = valueBuffer;
-    }
-
-    @Override
-    protected char readNextChar() throws IOException {
-        if (reset) {
-            reset = false;
-            return mark;
-        }
-
-        if (avail <= 0) {
-            avail = in.read(buffer, 0, buffer.length);
-
-            pointer = -1;
-
-            if (LOG) {
-                LOGGER.fine("******* Fill buffer with " + avail
-                        + " chars");
-            }
-
-            if (avail <= 0) {
-                throw new IOException("EOF");
-            }
-        }
-
-        pointer++;
-        avail--;
-        return buffer[pointer];
-
-    }
-
-    @Override
-    protected void mark() {
-        mark = buffer[pointer];
-    }
-
-    @Override
-    protected void reset() {
-        reset = true;
-    }
-
-    @Override
-    protected void closeUnderlyingSource() throws IOException {
-        bufferProvider.release(buffer);
-        valueProvider.release(currentValue);
-        in.close();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/main/java/org/apache/fleece/core/JsonChars.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonChars.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonChars.java
index d812f08..3a92c9b 100644
--- a/fleece-core/src/main/java/org/apache/fleece/core/JsonChars.java
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonChars.java
@@ -18,6 +18,8 @@
  */
 package org.apache.fleece.core;
 
+import javax.json.stream.JsonParser.Event;
+
 public interface JsonChars {
     char EOF = Character.MIN_VALUE;
 
@@ -25,10 +27,13 @@ public interface JsonChars {
     char END_OBJECT_CHAR = '}';
     char START_ARRAY_CHAR = '[';
     char END_ARRAY_CHAR = ']';
-    char EOL = '\n';
+    char QUOTE = '"';
     char COMMA = ',';
-    char SPACE = ' ';
     char KEY_SEPARATOR = ':';
+    
+    char EOL = '\n';
+    char SPACE = ' ';
+    
     char TRUE_T = 't';
     char TRUE_R = 'r';
     char TRUE_U = 'u';
@@ -41,7 +46,7 @@ public interface JsonChars {
     char NULL_N = 'n';
     char NULL_U = 'u';
     char NULL_L = 'l';
-    char QUOTE = '"';
+ 
     char ZERO = '0';
     char NINE = '9';
     char DOT = '.';
@@ -57,4 +62,21 @@ public interface JsonChars {
     char CR = '\r';
 
     String NULL = "null";
+    
+    static final byte START_ARRAY = (byte) Event.START_ARRAY.ordinal();
+    static final byte START_OBJECT = (byte) Event.START_OBJECT.ordinal();
+    static final byte KEY_NAME=(byte) Event.KEY_NAME.ordinal();
+    static final byte VALUE_STRING=(byte) Event.VALUE_STRING.ordinal(); 
+    static final byte VALUE_NUMBER=(byte) Event.VALUE_NUMBER.ordinal(); 
+    static final byte VALUE_TRUE=(byte) Event.VALUE_TRUE.ordinal();
+    static final byte VALUE_FALSE=(byte) Event.VALUE_FALSE.ordinal(); 
+    static final byte VALUE_NULL=(byte) Event.VALUE_NULL.ordinal();
+    static final byte END_OBJECT=(byte) Event.END_OBJECT.ordinal();
+    static final byte END_ARRAY=(byte) Event.END_ARRAY.ordinal();
+    
+    static final byte COMMA_EVENT=Byte.MAX_VALUE;
+    static final byte KEY_SEPARATOR_EVENT=Byte.MIN_VALUE;
+    
+    static final Event[] EVT_MAP =Event.values();
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/main/java/org/apache/fleece/core/JsonDoubleImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonDoubleImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonDoubleImpl.java
index 6d9d370..5b63d41 100644
--- a/fleece-core/src/main/java/org/apache/fleece/core/JsonDoubleImpl.java
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonDoubleImpl.java
@@ -56,12 +56,12 @@ public class JsonDoubleImpl implements JsonNumber {
 
     @Override
     public BigInteger bigIntegerValue() {
-        return new BigInteger(toString());
+        return new BigDecimal(toString()).toBigInteger();
     }
 
     @Override
     public BigInteger bigIntegerValueExact() {
-        return bigIntegerValue();
+        return new BigDecimal(toString()).toBigIntegerExact();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java
index d76ce39..c1c094e 100644
--- a/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java
@@ -19,9 +19,13 @@
 package org.apache.fleece.core;
 
 import javax.json.stream.JsonLocation;
+
 import java.io.Serializable;
 
 public class JsonLocationImpl implements JsonLocation, Serializable {
+    
+    public static final JsonLocation UNKNOW_LOCATION = new JsonLocationImpl(-1, -1, -1);
+    
     private final long lineNumber;
     private final long columnNumber;
     private final long streamOffset;
@@ -71,6 +75,6 @@ public class JsonLocationImpl implements JsonLocation, Serializable {
 
     @Override
     public String toString() {
-        return "JsonLocationImpl [lineNumber=" + lineNumber + ", columnNumber=" + columnNumber + ", streamOffset=" + streamOffset + "]";
+        return "[lineNumber=" + lineNumber + ", columnNumber=" + columnNumber + ", streamOffset=" + streamOffset + "]";
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java
index 6195d83..505542e 100644
--- a/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java
@@ -23,7 +23,6 @@ import javax.json.JsonObject;
 import javax.json.stream.JsonParser;
 import javax.json.stream.JsonParserFactory;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.Serializable;
 import java.nio.charset.Charset;
@@ -35,7 +34,7 @@ public class JsonParserFactoryImpl implements JsonParserFactory, Serializable {
     public static final String BUFFER_STRATEGY = "org.apache.fleece.buffer-strategy";
     public static final String MAX_STRING_LENGTH = "org.apache.fleece.max-string-length";
     public static final String BUFFER_LENGTH = "org.apache.fleece.default-char-buffer";
-    public static final int DEFAULT_MAX_SIZE = Integer.getInteger(MAX_STRING_LENGTH, 8192);
+    public static final int DEFAULT_MAX_SIZE = Integer.getInteger(MAX_STRING_LENGTH, 8192*32);
 
     private final Map<String, ?> config;
     private final int maxSize;
@@ -56,6 +55,9 @@ public class JsonParserFactoryImpl implements JsonParserFactory, Serializable {
     }
 
     private BufferStrategy getBufferProvider() {
+        if(config==null) {
+            return BufferStrategy.QUEUE;
+        }
         final Object name = config.get(BUFFER_STRATEGY);
         if (name != null) {
             return BufferStrategy.valueOf(name.toString().toUpperCase(Locale.ENGLISH));
@@ -64,6 +66,9 @@ public class JsonParserFactoryImpl implements JsonParserFactory, Serializable {
     }
 
     private int getInt(final String key) {
+        if(config==null) {
+            return DEFAULT_MAX_SIZE;
+        }
         final Object maxStringSize = config.get(key);
         if (maxStringSize == null) {
             return DEFAULT_MAX_SIZE;
@@ -73,17 +78,19 @@ public class JsonParserFactoryImpl implements JsonParserFactory, Serializable {
         return Integer.parseInt(maxStringSize.toString());
     }
 
-    private JsonCharBufferStreamParser getDefaultJsonParserImpl(final InputStream in) {
-        return new JsonCharBufferStreamParser(
-            new InputStreamReader(in, Charset.defaultCharset()), maxSize, bufferProvider, valueBufferProvider);
+    private EscapedStringAwareJsonParser getDefaultJsonParserImpl(final InputStream in) {
+        //UTF Auto detection RFC 4627
+        return new JsonStreamParserImpl(in, maxSize, bufferProvider, valueBufferProvider);
     }
 
-    private JsonCharBufferStreamParser getDefaultJsonParserImpl(final InputStream in, final Charset charset) {
-        return new JsonCharBufferStreamParser(new InputStreamReader(in, charset), maxSize, bufferProvider, valueBufferProvider);
+    private EscapedStringAwareJsonParser getDefaultJsonParserImpl(final InputStream in, final Charset charset) {
+        //use provided charset
+        return new JsonStreamParserImpl(in, charset, maxSize, bufferProvider, valueBufferProvider);
     }
 
-    private JsonCharBufferStreamParser getDefaultJsonParserImpl(final Reader in) {
-        return new JsonCharBufferStreamParser(in, maxSize, bufferProvider, valueBufferProvider);
+    private EscapedStringAwareJsonParser getDefaultJsonParserImpl(final Reader in) {
+        //no charset necessary
+        return new JsonStreamParserImpl(in, maxSize, bufferProvider, valueBufferProvider);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java
index 15a9d0f..0bc3850 100644
--- a/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java
@@ -25,6 +25,7 @@ import javax.json.JsonStructure;
 import javax.json.JsonValue;
 import javax.json.stream.JsonParser;
 import javax.json.stream.JsonParsingException;
+
 import java.math.BigDecimal;
 
 public class JsonReaderImpl implements JsonReader {
@@ -43,20 +44,28 @@ public class JsonReaderImpl implements JsonReader {
     @Override
     public JsonStructure read() {
         if (!parser.hasNext()) {
-            throw new JsonParsingException("Nothing to read", new JsonLocationImpl(1, 1, 0));
+            throw new IllegalStateException("Nothing to read");
         }
         switch (parser.next()) {
             case START_OBJECT:
                 final JsonReaderListener subObject = listenerFactory.subObject();
                 parseObject(subObject);
+                if (parser.hasNext()) {
+                    throw new JsonParsingException("Expected end of file", parser.getLocation());
+                }
                 return JsonObject.class.cast(subObject.getObject());
             case START_ARRAY:
                 final JsonReaderListener subArray = listenerFactory.subArray();
                 parseArray(subArray);
+                if (parser.hasNext()) {
+                    throw new JsonParsingException("Expected end of file", parser.getLocation());
+                }
                 return JsonArray.class.cast(subArray.getObject());
             default:
                 throw new JsonParsingException("Unknown structure: " + parser.next(), parser.getLocation());
         }
+        
+        
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/main/java/org/apache/fleece/core/JsonStreamParserImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonStreamParserImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonStreamParserImpl.java
new file mode 100644
index 0000000..b6e1e32
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonStreamParserImpl.java
@@ -0,0 +1,968 @@
+/*
+ * 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.math.BigDecimal;
+import java.nio.charset.Charset;
+import java.util.NoSuchElementException;
+
+import javax.json.JsonException;
+import javax.json.stream.JsonLocation;
+import javax.json.stream.JsonParsingException;
+
+//This class represents either the Json tokenizer and the Json parser.
+public class JsonStreamParserImpl implements JsonChars, EscapedStringAwareJsonParser {
+
+    //the main buffer where the stream will be buffered
+    private final char[] buffer;
+
+    //current parser position within the buffer
+    //Initial MIN_VALUE will trigger buffer refill, normally bufferPos is >= -1
+    //-1 would cause a re-read of the first character in the buffer (which is at zero index)
+    private int bufferPos = Integer.MIN_VALUE;
+
+    //available character in the buffer
+    //normally this is buffer.length, except for the last buffer page it might be <= buffer.length
+    private int availableCharsInBuffer;
+
+    //start and end position of values in the buffer
+    //may cross boundaries, then value is in fallBackCopyBuffer
+    private int startOfValueInBuffer = -1;
+    private int endOfValueInBuffer = -1;
+
+    private final Reader in;
+
+    //do we read from a character stream or a byte stream
+    //not used at the moment but maybe relevant in future to calculate the JsonLocation offset
+    @SuppressWarnings("unused")
+    private final boolean readBytes;
+    private final BufferStrategy.BufferProvider<char[]> bufferProvider;
+    private final BufferStrategy.BufferProvider<char[]> valueProvider;
+
+    //max length for strings and numbers (max count of characters)
+    private final int maxValueLength;
+
+    //we use a byte here, because comparing bytes
+    //is more efficient than comparing enums
+    //Additionally we handle internally two more event: COMMA_EVENT and KEY_SEPARATOR_EVENT
+    private byte previousEvent;
+
+    //this buffer is used to store current String or Number value in case that
+    //within the value a buffer boundary is crossed or the string contains escaped characters
+    private final char[] fallBackCopyBuffer;
+    private int fallBackCopyBufferLength;
+
+    // location (line, column, offset)
+    // We try to calculate this efficiently so we do not just increment the values per char read
+    // Instead we calculate the column and offset relative to the pastBufferReadCount and/or lastLineBreakPosition.
+    private long currentLine = 1;
+    private long lastLineBreakPosition;
+    private long pastBufferReadCount;
+
+    //cache (if current value is a number) integral state and the number itself if its only one digit    
+    private boolean isCurrentNumberIntegral = true;
+    private Integer currentIntegralNumber; //for number from 0 - 9
+
+    //maybe we want also cache BigDecimals
+    //private BigDecimal currentBigDecimalNumber = null;
+
+    //We need a stack if we want detect bad formatted Json do determine if we are within an array or not
+    //example
+    //     Streamparser sees: ],1  <-- we look from here
+    //the 1 is only allowed if we are within an array
+    //This can only be determined by build up a stack which tracks the trail of Json objects and arrays
+    //This stack here is only needed for validating the above mentioned case, if we want to be lenient we can skip suing the stack.
+    //Stack can cause out of memory issues when the nesting depth of a Json stream is too deep.
+    private StructureElement currentStructureElement = null;
+
+    //minimal stack implementation
+    private static final class StructureElement {
+        final StructureElement previous;
+        final boolean isArray;
+
+        StructureElement(final StructureElement previous, final boolean isArray) {
+            super();
+            this.previous = previous;
+            this.isArray = isArray;
+        }
+    }
+
+    //detect charset according to RFC 4627
+    public JsonStreamParserImpl(final InputStream inputStream, final int maxStringLength,
+            final BufferStrategy.BufferProvider<char[]> bufferProvider, final BufferStrategy.BufferProvider<char[]> valueBuffer) {
+
+        this(inputStream, null, null, maxStringLength, bufferProvider, valueBuffer);
+    }
+
+    //use charset provided
+    public JsonStreamParserImpl(final InputStream inputStream, final Charset encoding, final int maxStringLength,
+            final BufferStrategy.BufferProvider<char[]> bufferProvider, final BufferStrategy.BufferProvider<char[]> valueBuffer) {
+
+        this(inputStream, null, encoding, maxStringLength, bufferProvider, valueBuffer);
+    }
+
+    public JsonStreamParserImpl(final Reader reader, final int maxStringLength, final BufferStrategy.BufferProvider<char[]> bufferProvider,
+            final BufferStrategy.BufferProvider<char[]> valueBuffer) {
+
+        this(null, reader, null, maxStringLength, bufferProvider, valueBuffer);
+    }
+
+    private JsonStreamParserImpl(final InputStream inputStream, final Reader reader, final Charset encoding, final int maxStringLength,
+            final BufferStrategy.BufferProvider<char[]> bufferProvider, final BufferStrategy.BufferProvider<char[]> valueBuffer) {
+
+        this.maxValueLength = maxStringLength <= 0 ? 8192 : maxStringLength;
+        this.fallBackCopyBuffer = valueBuffer.newBuffer();
+        this.buffer = bufferProvider.newBuffer();
+        this.bufferProvider = bufferProvider;
+        this.valueProvider = valueBuffer;
+
+        if (fallBackCopyBuffer.length < maxStringLength) {
+            throw cust("Size of value buffer cannot be smaller than maximum string length");
+        }
+
+        if (reader != null) {
+            this.in = reader;
+            readBytes = false;
+        } else if (encoding == null) {
+            this.in = new RFC4627AwareInputStreamReader(inputStream);
+            readBytes = true;
+
+        } else {
+            this.in = new InputStreamReader(inputStream, encoding.newDecoder());
+            readBytes = true;
+        }
+
+    }
+
+    //append a single char to the value buffer
+    private void appendToCopyBuffer(final char c) {
+        fallBackCopyBuffer[fallBackCopyBufferLength] = c;
+        fallBackCopyBufferLength++;
+    }
+
+    //copy content between "start" and "end" from buffer to value buffer 
+    private void copyCurrentValue() {
+
+        if ((endOfValueInBuffer - startOfValueInBuffer) > 0) {
+
+            if ((endOfValueInBuffer - startOfValueInBuffer) > maxValueLength) {
+                throw tmc();
+            }
+
+            System.arraycopy(buffer, startOfValueInBuffer, fallBackCopyBuffer, fallBackCopyBufferLength,
+                    (endOfValueInBuffer - startOfValueInBuffer));
+            fallBackCopyBufferLength += (endOfValueInBuffer - startOfValueInBuffer);
+
+        }
+
+        startOfValueInBuffer = endOfValueInBuffer = -1;
+    }
+
+    @Override
+    public final boolean hasNext() {
+
+        if (currentStructureElement != null || (previousEvent != END_ARRAY && previousEvent != END_OBJECT) || previousEvent == 0) {
+            return true;
+        }
+
+        //detect garbage at the end of the file after last object or array is closed
+        if (bufferPos < availableCharsInBuffer - 2) {
+
+            final char c = readNextNonWhitespaceChar();
+
+            if (c == EOF) {
+                return false;
+            }
+
+            if (bufferPos < availableCharsInBuffer) {
+                throw uexc("EOF expected");
+            }
+
+        }
+
+        return false;
+
+    }
+
+    private static boolean isAsciiDigit(final char value) {
+        return value <= NINE && value >= ZERO;
+    }
+
+    //check if value is a valid hex digit and return the numeric value
+    private int parseHexDigit(final char value) {
+
+        if (isAsciiDigit(value)) {
+            return value - 48;
+        } else if (value <= 'f' && value >= 'a') {
+            return (value) - 87;
+        } else if ((value <= 'F' && value >= 'A')) {
+            return (value) - 55;
+        } else {
+            throw uexc("Invalid hex character");
+        }
+    }
+
+    private JsonLocation createLocation() {
+
+        //we start with column = 1, so column is always >= 1
+        //APi is not clear in this, but starting column with 1 is convenient
+        long column = 1;
+        long charOffset = 0;
+
+        if (bufferPos >= -1) {
+
+            charOffset = pastBufferReadCount + bufferPos + 1;
+            column = lastLineBreakPosition == 0 ? charOffset + 1 : charOffset - lastLineBreakPosition;
+        }
+
+        //For now its unclear how to calculate offset for (byte) inputsream.
+        //API says count bytes but thats dependent on encoding and not efficient
+        //skip this for now, count always bytes and defer this until the JSR TCK arrives.
+
+        return new JsonLocationImpl(currentLine, column, charOffset);
+    }
+
+    //read the next char from the stream and set/increment the bufferPos
+    //will also refill buffer if neccessary
+    //if we are currently processing a value (string or number) and buffer 
+    //refill is neccessary copy the already readed value part into the value buffer
+    private char readNextChar() {
+
+        if ((buffer.length - bufferPos) <= 1) {
+            //fillbuffer
+
+            //copy content from old buffer to valuebuffer
+            //correct start end mark
+            if (startOfValueInBuffer > -1 && endOfValueInBuffer == -1) {
+                endOfValueInBuffer = availableCharsInBuffer;
+                copyCurrentValue();
+
+                startOfValueInBuffer = 0;
+            }
+
+            if (bufferPos >= -1) {
+                pastBufferReadCount += availableCharsInBuffer;
+            }
+
+            try {
+                availableCharsInBuffer = in.read(buffer, 0, buffer.length);
+                if (availableCharsInBuffer <= 0) {
+                    return EOF;
+                }
+
+            } catch (final IOException e) {
+                close();
+                throw uexio(e);
+            }
+
+            bufferPos = 0;
+            //end fillbuffer
+        } else {
+            bufferPos++;
+        }
+
+        return buffer[bufferPos];
+    }
+
+    //skip whitespaces
+    //tracks location informations (line, column)
+    //returns the first non whitespace character
+    private char readNextNonWhitespaceChar() {
+
+        int dosCount = 0;
+        char c = readNextChar();
+
+        while (c == SPACE || c == TAB || c == CR || c == EOL) {
+
+            if (c == EOL) {
+                currentLine++;
+                lastLineBreakPosition = pastBufferReadCount + bufferPos;
+            }
+
+            //prevent DOS (denial of service) attack
+            if (dosCount >= maxValueLength) {
+                throw tmc();
+            }
+            dosCount++;
+
+            //read next character
+            c = readNextChar();
+
+        }
+
+        return c;
+    }
+
+    @Override
+    public final Event next() {
+        //main entry, make decision how to handle the current character in the stream
+
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+
+        if (previousEvent != 0 && currentStructureElement == null) {
+            throw uexc("Unexpected end of structure");
+        }
+
+        final char c = readNextNonWhitespaceChar();
+
+        if (c == COMMA) {
+
+            //last event must one of the following-> " ] } LITERAL
+            if (previousEvent == START_ARRAY || previousEvent == START_OBJECT || previousEvent == COMMA_EVENT || previousEvent == KEY_NAME) {
+                throw uexc("Expected \" ] } LITERAL");
+            }
+
+            previousEvent = COMMA_EVENT;
+            return next();
+
+        }
+
+        if (c == KEY_SEPARATOR) {
+
+            if (previousEvent != KEY_NAME) {
+                throw uexc("A : can only follow a key name");
+            }
+
+            previousEvent = KEY_SEPARATOR_EVENT;
+            return next();
+
+        }
+
+        if (!isCurrentNumberIntegral) {
+            isCurrentNumberIntegral = true;
+        }
+        //        if (currentBigDecimalNumber != null) {
+        //            currentBigDecimalNumber = null;
+        //        }
+        if (currentIntegralNumber != null) {
+            currentIntegralNumber = null;
+        }
+
+        if (fallBackCopyBufferLength != 0) {
+            fallBackCopyBufferLength = 0;
+        }
+
+        startOfValueInBuffer = endOfValueInBuffer = -1;
+
+        switch (c) {
+
+            case START_OBJECT_CHAR:
+
+                return handleStartObject();
+
+            case END_OBJECT_CHAR:
+
+                return handleEndObject();
+
+            case START_ARRAY_CHAR:
+
+                return handleStartArray();
+
+            case END_ARRAY_CHAR:
+
+                return handleEndArray();
+
+            case QUOTE:
+
+                return handleQuote();
+
+            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
+
+                return handleLiteral(c);
+            default:
+                throw uexc("Excpected structural character or digit or 't' or 'n' or 'f' or '-'");
+
+        }
+
+    }
+
+    private Event handleStartObject() {
+
+        //last event must one of the following-> : , [
+        if (previousEvent != 0 && previousEvent != KEY_SEPARATOR_EVENT && previousEvent != START_ARRAY && previousEvent != COMMA_EVENT) {
+            throw uexc("Excpected : , [");
+        }
+
+        //push upon the stack
+        if (currentStructureElement == null) {
+            currentStructureElement = new StructureElement(null, false);
+        } else {
+            final StructureElement localStructureElement = new StructureElement(currentStructureElement, false);
+            currentStructureElement = localStructureElement;
+        }
+
+        return EVT_MAP[previousEvent = START_OBJECT];
+
+    }
+
+    private Event handleEndObject() {
+
+        //last event must one of the following-> " ] { } LITERAL
+        if (previousEvent == START_ARRAY || previousEvent == COMMA_EVENT || previousEvent == KEY_NAME
+                || previousEvent == KEY_SEPARATOR_EVENT || currentStructureElement == null) {
+            throw uexc("Expected \" ] { } LITERAL");
+        }
+
+        if (currentStructureElement.isArray) {
+            throw uexc("Expected : ]");
+        }
+
+        //pop from stack
+        currentStructureElement = currentStructureElement.previous;
+
+        return EVT_MAP[previousEvent = END_OBJECT];
+    }
+
+    private Event handleStartArray() {
+
+        //last event must one of the following-> : , [
+        if (previousEvent != 0 && previousEvent != KEY_SEPARATOR_EVENT && previousEvent != START_ARRAY && previousEvent != COMMA_EVENT) {
+            throw uexc("Expected : , [");
+        }
+
+        //push upon the stack
+        if (currentStructureElement == null) {
+            currentStructureElement = new StructureElement(null, true);
+        } else {
+            final StructureElement localStructureElement = new StructureElement(currentStructureElement, true);
+            currentStructureElement = localStructureElement;
+        }
+
+        return EVT_MAP[previousEvent = START_ARRAY];
+    }
+
+    private Event handleEndArray() {
+
+        //last event must one of the following-> [ ] } " LITERAL
+        if (previousEvent == START_OBJECT || previousEvent == COMMA_EVENT || previousEvent == KEY_SEPARATOR_EVENT
+                || currentStructureElement == null) {
+            throw uexc("Expected [ ] } \" LITERAL");
+        }
+
+        if (!currentStructureElement.isArray) {
+            throw uexc("Expected : }");
+        }
+
+        //pop from stack
+        currentStructureElement = currentStructureElement.previous;
+
+        return EVT_MAP[previousEvent = END_ARRAY];
+    }
+
+    //read a string, gets called recursively
+    //Handles escape/d characters
+    //if string contains escape chars and/or cross buffer boundary then copy in the value buffer
+    //if not then denote string start and end in startOfValueInBuffer and endOfValueInBuffer and read directly from buffer
+    private void readString() {
+
+        char n = readNextChar();
+        //when first called n its first char after the starting quote
+        //after that its the next character after the while loop below
+
+        if (n == QUOTE) {
+            endOfValueInBuffer = startOfValueInBuffer = bufferPos; //->"" case
+            return;
+        } else if (n == EOL) {
+            throw uexc("Unexpected linebreak");
+
+        } else if (n >= '\u0000' && n <= '\u001F') {
+            throw uexc("Unescaped control character");
+
+        } else if (n == ESCAPE_CHAR) {
+
+            n = readNextChar();
+
+            //  \ u XXXX -> unicode char
+            if (n == 'u') {
+                n = parseUnicodeHexChars();
+                appendToCopyBuffer(n);
+
+                // \\ -> \
+            } else if (n == ESCAPE_CHAR) {
+                appendToCopyBuffer(n);
+
+                //another escape chars, for example \t
+            } else {
+                appendToCopyBuffer(Strings.asEscapedChar(n));
+
+            }
+
+        } else {
+
+            startOfValueInBuffer = bufferPos;
+            endOfValueInBuffer = -1;
+
+            while ((n = readNextChar()) > '\u001F' && n != ESCAPE_CHAR && n != EOL && n != QUOTE) {
+                //read fast
+            }
+
+            endOfValueInBuffer = bufferPos;
+
+            if (n == QUOTE) {
+
+                if (fallBackCopyBufferLength > 0) {
+                    copyCurrentValue();
+                } else {
+                    if ((endOfValueInBuffer - startOfValueInBuffer) > maxValueLength) {
+                        throw tmc();
+                    }
+
+                }
+
+                return;
+            } else if (n == EOL) {
+                throw uexc("Unexpected linebreak");
+
+            } else if (n >= '\u0000' && n <= '\u001F') {
+                throw uexc("Unescaped control character");
+            }
+
+            copyCurrentValue();
+
+            //current n is one of < '\u001F' -OR- ESCAPE_CHAR -OR- EOL -OR- QUOTE
+
+            bufferPos--; //unread one char
+
+        }
+
+        //recurse until string is terminated by a non escaped quote
+        readString();
+
+    }
+
+    //maybe we want to check invalid utf encoding
+    //not clear yet if the InputStreamReader is doing that
+
+    /*
+    private char checkSurrogates(char n, char highSurrogate) {
+        //check for invalid surrogates
+        //high followed by low       
+        if (Character.isHighSurrogate(n)) {
+
+            if (highSurrogate != 0) {
+                throw uexc("Unexpected high surrogate");
+            }
+            return n;
+        } else if (Character.isLowSurrogate(n)) {
+
+            if (highSurrogate == 0) {
+                throw uexc("Unexpected low surrogate");
+            } else if (!Character.isSurrogatePair(highSurrogate, n)) {
+                throw uexc("Invalid surrogate pair");
+            }
+            return 0;
+        } else if (highSurrogate != 0 && !Character.isLowSurrogate(n)) {
+            throw uexc("Expected low surrogate");
+        }
+        
+        return highSurrogate;
+    }*/
+
+    //read the next four chars, check them and treat them as an single unicode char
+    private char parseUnicodeHexChars() {
+        // \u08Ac etc       
+        return (char) (((parseHexDigit(readNextChar())) * 4096) + ((parseHexDigit(readNextChar())) * 256)
+                + ((parseHexDigit(readNextChar())) * 16) + ((parseHexDigit(readNextChar()))));
+
+    }
+
+    private Event handleQuote() {
+
+        //always the beginning quote of a key or value  
+
+        //last event must one of the following-> : { [ ,
+        if (previousEvent != KEY_SEPARATOR_EVENT && previousEvent != START_OBJECT && previousEvent != START_ARRAY
+                && previousEvent != COMMA_EVENT) {
+            throw uexc("Expected : { [ ,");
+        }
+        //starting quote already consumed
+        readString();
+        //end quote already consumed
+
+        //make the decision if its an key or value
+        if (previousEvent == KEY_SEPARATOR_EVENT) {
+            //must be value
+
+            if (currentStructureElement != null && currentStructureElement.isArray) {
+                //not in array, only allowed within array
+                throw uexc("Key value pair not allowed in an array");
+            }
+
+            return EVT_MAP[previousEvent = VALUE_STRING];
+
+        } else { //Event is  START_OBJECT  OR START_ARRAY OR COMMA_EVENT
+            //must be a key if we are in an object, if not its a value 
+
+            if (currentStructureElement != null && currentStructureElement.isArray) {
+                return EVT_MAP[previousEvent = VALUE_STRING];
+            }
+
+            return EVT_MAP[previousEvent = KEY_NAME];
+        }
+
+    }
+
+    //read a number
+    //if a number cross buffer boundary then copy in the value buffer
+    //if not then denote string start and end in startOfValueInBuffer and endOfValueInBuffer and read directly from buffer
+    private void readNumber(final char c) {
+
+        //start can change on any read() if we cross buffer boundary
+        startOfValueInBuffer = bufferPos;
+        endOfValueInBuffer = -1;
+
+        char y = EOF;
+
+        //sum up the digit values 
+        int cumulatedDigitValue = 0;
+        while (isAsciiDigit(y = readNextChar())) {
+
+            if (c == ZERO) {
+                throw uexc("Leading zeros not allowed");
+            }
+
+            if (c == MINUS && cumulatedDigitValue == 48) {
+                throw uexc("Leading zeros after minus not allowed");
+            }
+
+            cumulatedDigitValue += y;
+
+        }
+
+        if (c == MINUS && cumulatedDigitValue == 0) {
+
+            throw uexc("Unexpected premature end of number");
+        }
+
+        if (y == DOT) {
+            isCurrentNumberIntegral = false;
+            cumulatedDigitValue = 0;
+            while (isAsciiDigit(y = readNextChar())) {
+                cumulatedDigitValue++;
+            }
+
+            if (cumulatedDigitValue == 0) {
+
+                throw uexc("Unexpected premature end of number");
+            }
+
+        }
+
+        if (y == EXP_LOWERCASE || y == EXP_UPPERCASE) {
+            isCurrentNumberIntegral = false;
+
+            y = readNextChar(); //+ or - or digit
+
+            if (!isAsciiDigit(y) && y != MINUS && y != PLUS) {
+                throw uexc("Expected DIGIT or + or -");
+            }
+
+            if (y == MINUS || y == PLUS) {
+                y = readNextChar();
+                if (!isAsciiDigit(y)) {
+                    throw uexc("Unexpected premature end of number");
+                }
+
+            }
+
+            while (isAsciiDigit(y = readNextChar())) {
+                //no-op
+            }
+
+        }
+
+        endOfValueInBuffer = bufferPos;
+
+        if (y == COMMA || y == END_ARRAY_CHAR || y == END_OBJECT_CHAR || y == EOL || y == SPACE || y == TAB || y == CR) {
+
+            bufferPos--;//unread one char
+
+            //['-', DIGIT]
+            if (isCurrentNumberIntegral && c == MINUS && cumulatedDigitValue >= 48 && cumulatedDigitValue <= 57) {
+
+                currentIntegralNumber = -(cumulatedDigitValue - 48); //optimize -0 till -9
+                return;
+            }
+
+            //[DIGIT]
+            if (isCurrentNumberIntegral && c != MINUS && cumulatedDigitValue == 0) {
+
+                currentIntegralNumber = (c - 48); //optimize 0 till 9
+                return;
+            }
+
+            if (fallBackCopyBufferLength > 0) {
+
+                //we crossed a buffer boundary, use value buffer
+                copyCurrentValue();
+
+            } else {
+                if ((endOfValueInBuffer - startOfValueInBuffer) >= maxValueLength) {
+                    throw tmc();
+                }
+            }
+
+            return;
+
+        }
+
+        throw uexc("Unexpected premature end of number");
+
+    }
+
+    //handles false, true, null and numbers
+    private Event handleLiteral(final char c) {
+
+        //last event must one of the following-> : , [
+        if (previousEvent != KEY_SEPARATOR_EVENT && previousEvent != START_ARRAY && previousEvent != COMMA_EVENT) {
+            throw uexc("Excpected : , [");
+        }
+
+        if (previousEvent == COMMA_EVENT && !currentStructureElement.isArray) {
+            //only allowed within array
+            throw uexc("Not in an array context");
+        }
+
+        // probe literals
+        switch (c) {
+            case TRUE_T:
+
+                if (readNextChar() != TRUE_R || readNextChar() != TRUE_U || readNextChar() != TRUE_E) {
+                    throw uexc("Expected LITERAL: true");
+                }
+                return EVT_MAP[previousEvent = VALUE_TRUE];
+            case FALSE_F:
+
+                if (readNextChar() != FALSE_A || readNextChar() != FALSE_L || readNextChar() != FALSE_S || readNextChar() != FALSE_E) {
+                    throw uexc("Expected LITERAL: false");
+                }
+
+                return EVT_MAP[previousEvent = VALUE_FALSE];
+
+            case NULL_N:
+
+                if (readNextChar() != NULL_U || readNextChar() != NULL_L || readNextChar() != NULL_L) {
+                    throw uexc("Expected LITERAL: null");
+                }
+                return EVT_MAP[previousEvent = VALUE_NULL];
+
+            default:
+                readNumber(c);
+                return EVT_MAP[previousEvent = VALUE_NUMBER];
+        }
+
+    }
+
+    @Override
+    public String getString() {
+        if (previousEvent == KEY_NAME || previousEvent == VALUE_STRING || previousEvent == VALUE_NUMBER) {
+
+            //if there a content in the value buffer read from them, if not use main buffer
+            return fallBackCopyBufferLength > 0 ? new String(fallBackCopyBuffer, 0, fallBackCopyBufferLength) : new String(buffer,
+                    startOfValueInBuffer, endOfValueInBuffer - startOfValueInBuffer);
+        } else {
+            throw new IllegalStateException(EVT_MAP[previousEvent] + " doesn't support getString()");
+        }
+    }
+
+    @Override
+    public boolean isIntegralNumber() {
+
+        if (previousEvent != VALUE_NUMBER) {
+            throw new IllegalStateException(EVT_MAP[previousEvent] + " doesn't support isIntegralNumber()");
+        } else {
+            return isCurrentNumberIntegral;
+        }
+    }
+
+    @Override
+    public int getInt() {
+        if (previousEvent != VALUE_NUMBER) {
+            throw new IllegalStateException(EVT_MAP[previousEvent] + " doesn't support getInt()");
+        } else if (isCurrentNumberIntegral && currentIntegralNumber != null) {
+            return currentIntegralNumber;
+        } else if (isCurrentNumberIntegral) {
+            //if there a content in the value buffer read from them, if not use main buffer
+            final Integer retVal = fallBackCopyBufferLength > 0 ? parseIntegerFromChars(fallBackCopyBuffer, 0, fallBackCopyBufferLength)
+                    : parseIntegerFromChars(buffer, startOfValueInBuffer, endOfValueInBuffer);
+            if (retVal == null) {
+                return getBigDecimal().intValue();
+            } else {
+                return retVal.intValue();
+            }
+        } else {
+            return getBigDecimal().intValue();
+        }
+    }
+
+    @Override
+    public long getLong() {
+        if (previousEvent != VALUE_NUMBER) {
+            throw new IllegalStateException(EVT_MAP[previousEvent] + " doesn't support getLong()");
+        } else if (isCurrentNumberIntegral && currentIntegralNumber != null) {
+            return currentIntegralNumber;
+        } else if (isCurrentNumberIntegral) {
+            //if there a content in the value buffer read from them, if not use main buffer
+            final Long retVal = fallBackCopyBufferLength > 0 ? parseLongFromChars(fallBackCopyBuffer, 0, fallBackCopyBufferLength)
+                    : parseLongFromChars(buffer, startOfValueInBuffer, endOfValueInBuffer);
+            if (retVal == null) {
+                return getBigDecimal().longValue();
+            } else {
+                return retVal.longValue();
+            }
+        } else {
+            return getBigDecimal().longValue();
+        }
+
+    }
+
+    @Override
+    public BigDecimal getBigDecimal() {
+        if (previousEvent != VALUE_NUMBER) {
+            throw new IllegalStateException(EVT_MAP[previousEvent] + " doesn't support getBigDecimal()");
+            //        } else if (currentBigDecimalNumber != null) {
+            //            return currentBigDecimalNumber;
+        } else if (isCurrentNumberIntegral && currentIntegralNumber != null) {
+            return new BigDecimal(currentIntegralNumber);
+        } else if (isCurrentNumberIntegral) {
+            //if there a content in the value buffer read from them, if not use main buffer
+            final Long retVal = fallBackCopyBufferLength > 0 ? parseLongFromChars(fallBackCopyBuffer, 0, fallBackCopyBufferLength)
+                    : parseLongFromChars(buffer, startOfValueInBuffer, endOfValueInBuffer);
+            if (retVal == null) {
+                return (/*currentBigDecimalNumber = */fallBackCopyBufferLength > 0 ? new BigDecimal(fallBackCopyBuffer, 0,
+                        fallBackCopyBufferLength) : new BigDecimal(buffer, startOfValueInBuffer,
+                        (endOfValueInBuffer - startOfValueInBuffer)));
+            } else {
+                return (/*currentBigDecimalNumber = */new BigDecimal(retVal.longValue()));
+            }
+        } else {
+            //if there a content in the value buffer read from them, if not use main buffer
+            return (/*currentBigDecimalNumber = */fallBackCopyBufferLength > 0 ? new BigDecimal(fallBackCopyBuffer, 0,
+                    fallBackCopyBufferLength) : new BigDecimal(buffer, startOfValueInBuffer, (endOfValueInBuffer - startOfValueInBuffer)));
+        }
+
+    }
+
+    @Override
+    public JsonLocation getLocation() {
+        return createLocation();
+    }
+
+    @Override
+    public void close() {
+        bufferProvider.release(buffer);
+        valueProvider.release(fallBackCopyBuffer);
+
+        try {
+            in.close();
+        } catch (final IOException e) {
+            throw new JsonException("Unexpected IO exception " + e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public String getEscapedString() {
+        return Strings.escape(getString());
+    }
+
+    //parse a char[] to long while checking overflow
+    //if overflowed return null
+    //no additional checks since we are sure here that there are no non digits in the array
+    private static Long parseLongFromChars(final char[] chars, final int start, final int end) {
+
+        long retVal = 0;
+        final boolean negative = chars[start] == MINUS;
+        for (int i = negative ? start + 1 : start; i < end; i++) {
+            final long tmp = retVal * 10 + (chars[i] - ZERO);
+            if (tmp < retVal) { //check overflow
+                return null;
+            } else {
+                retVal = tmp;
+            }
+        }
+
+        return negative ? -retVal : retVal;
+    }
+
+    //parse a char[] to int while checking overflow
+    //if overflowed return null
+    //no additional checks since we are sure here that there are no non digits in the array
+    private static Integer parseIntegerFromChars(final char[] chars, final int start, final int end) {
+
+        int retVal = 0;
+        final boolean negative = chars[start] == MINUS;
+        for (int i = negative ? start + 1 : start; i < end; i++) {
+            final int tmp = retVal * 10 + (chars[i] - ZERO);
+            if (tmp < retVal) { //check overflow
+                return null;
+            } else {
+                retVal = tmp;
+            }
+        }
+
+        return negative ? -retVal : retVal;
+    }
+
+    private JsonParsingException uexc(final char c, final String message) {
+        final JsonLocation location = createLocation();
+        return new JsonParsingException("Unexpected character '" + c + "' (Codepoint: " + String.valueOf(c).codePointAt(0) + ") on "
+                + location + ". Reason is [[" + message + "]]", location);
+    }
+
+    private JsonParsingException uexc(final String message) {
+        final char c = bufferPos < 0 ? 0 : buffer[bufferPos];
+        return uexc(c, message);
+    }
+
+    private JsonParsingException tmc() {
+        final JsonLocation location = createLocation();
+        return new JsonParsingException("Too many characters. Maximum string/number length of " + maxValueLength + " exceeded on "
+                + location, location);
+    }
+
+    private JsonParsingException uexio(final IOException e) {
+        final JsonLocation location = createLocation();
+        return new JsonParsingException("Unexpected IO exception on " + location, e, location);
+    }
+
+    private JsonParsingException cust(final String message) {
+        final JsonLocation location = createLocation();
+        return new JsonParsingException("General exception on " + location + ". Reason is [[" + message + "]]", location);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/main/java/org/apache/fleece/core/RFC4627AwareInputStreamReader.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/RFC4627AwareInputStreamReader.java b/fleece-core/src/main/java/org/apache/fleece/core/RFC4627AwareInputStreamReader.java
new file mode 100644
index 0000000..78d3f57
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/RFC4627AwareInputStreamReader.java
@@ -0,0 +1,110 @@
+/*
+ * 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.PushbackInputStream;
+import java.nio.charset.Charset;
+
+import javax.json.JsonException;
+
+final class RFC4627AwareInputStreamReader extends InputStreamReader {
+
+    public RFC4627AwareInputStreamReader(final InputStream in) {
+        this(new PushbackInputStream(in,4));
+    }
+    
+    private RFC4627AwareInputStreamReader(final PushbackInputStream in) {
+        super(in, getCharset(in).newDecoder());
+       
+    }
+
+
+    /*
+        * RFC 4627
+
+          JSON text SHALL be encoded in Unicode.  The default encoding is
+          UTF-8.
+       
+          Since the first two characters of a JSON text will always be ASCII
+          characters [RFC0020], it is possible to determine whether an octet
+          stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
+          at the pattern of nulls in the first four octets.
+
+          00 00 00 xx  UTF-32BE
+          00 xx 00 xx  UTF-16BE
+          xx 00 00 00  UTF-32LE
+          xx 00 xx 00  UTF-16LE
+          xx xx xx xx  UTF-8
+
+        */
+
+    private static Charset getCharset(final PushbackInputStream inputStream) {
+        Charset charset = Charset.forName("UTF-8");
+        final byte[] utfBytes = new byte[4];
+
+        try {
+            final int read = inputStream.read(utfBytes);
+            if (read < 2) {
+                throw new JsonException("Invalid Json. Valid Json has at least 2 bytes");
+            } else {
+
+                int first = (utfBytes[0] & 0xFF);
+                int second = (utfBytes[1] & 0xFF);
+                
+                if (first == 0x00) {
+                    charset = (second == 0x00) ? Charset.forName("UTF-32BE") : Charset.forName("UTF-16BE");
+                } else if (read > 2 && second == 0x00) {
+                    int third = (utfBytes[2] & 0xFF);
+                    charset = (third  == 0x00) ? Charset.forName("UTF-32LE") : Charset.forName("UTF-16LE");
+                } else {
+                  
+                    //check BOM
+                    if(first == 0xFE && second == 0xFF) {
+                        charset = Charset.forName("UTF-16BE");
+                    } else if(read > 3 && first == 0x00 && second == 0x00 && (utfBytes[2]&0xff) == 0xFE && (utfBytes[3]&0xff) == 0xFF){
+                        charset = Charset.forName("UTF-32BE");
+                    } else if(first == 0xFF && second == 0xFE) {
+                        
+                        if(read > 3 && (utfBytes[2]&0xff) == 0x00 && (utfBytes[3]&0xff) == 0x00) {
+                            charset = Charset.forName("UTF-32LE");
+                        }else {
+                            charset = Charset.forName("UTF-16LE");
+                        }
+                        
+                    }
+                    
+                }
+
+            }
+            
+            
+            inputStream.unread(utfBytes);
+            
+
+        } catch (final IOException e) {
+            throw new JsonException("Unable to detect charset due to "+e.getMessage(), e);
+        }
+
+        return charset;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/675ec9d3/fleece-core/src/main/java/org/apache/fleece/core/Strings.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/Strings.java b/fleece-core/src/main/java/org/apache/fleece/core/Strings.java
index c9fc799..71e8820 100644
--- a/fleece-core/src/main/java/org/apache/fleece/core/Strings.java
+++ b/fleece-core/src/main/java/org/apache/fleece/core/Strings.java
@@ -21,6 +21,8 @@ package org.apache.fleece.core;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import javax.json.stream.JsonParsingException;
+
 public class Strings implements JsonChars {
     private static final BufferStrategy.BufferProvider<StringBuilder> BUILDER_CACHE =
         BufferStrategy.valueOf(System.getProperty("fleece.string-builder.strategy", "QUEUE"))
@@ -44,10 +46,18 @@ public class Strings implements JsonChars {
                 return '\n';
             case '"':
                 return '\"';
+            case '\\':
+                return '\\';  
+            case '/':
+                return '/';  
             default:
-                // no-op
+                if(Character.isHighSurrogate(current) || Character.isLowSurrogate(current)) {
+                    return current;
+                }
+                throw new JsonParsingException("Invalid escape sequence '"+current +"' (Codepoint: "+String.valueOf(current).
+                        codePointAt(0),JsonLocationImpl.UNKNOW_LOCATION);
         }
-        return current;
+
     }
 
     public static String escape(final String value) {