Merge branch '2.7'
diff --git a/.travis.yml b/.travis.yml
index d9b2ad4..75db9cc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,7 +14,7 @@
 branches:
   only:
     - master
-    - "2.5"
+    - "2.7"
     - "2.6"
 
 env:
diff --git a/pom.xml b/pom.xml
index 46c2f5e..c98317c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,13 +3,13 @@
   <parent>
     <groupId>com.fasterxml.jackson</groupId>
     <artifactId>jackson-parent</artifactId>
-    <version>2.7</version>
+    <version>2.8</version>
   </parent>
 
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
   <name>Jackson-core</name>
-  <version>2.7.8-SNAPSHOT</version>
+  <version>2.8.3-SNAPSHOT</version>
   <packaging>bundle</packaging>
   <description>Core Jackson abstractions, basic JSON streaming API implementation</description>
   <inceptionYear>2008</inceptionYear>
@@ -23,10 +23,16 @@
   </scm>
 
   <properties>
-    <!-- 02-Oct-2015, tatu: Retain Java6/JDK1.6 compatibility for streaming for Jackson 2.7 -->
+    <!-- 29-Apr-2016, tatu: Retain Java6/JDK1.6 compatibility for streaming for Jackson 2.8 -->
     <javac.src.version>1.6</javac.src.version>
     <javac.target.version>1.6</javac.target.version>
 
+    <!-- 04-May-2016, tatu: Bundle-plugin 3.x seems to require Java 7, so to
+           build for Java 6 need to downgrade here to last working 2.x version
+          (2.5.4 had some issues wrt shading)
+      -->
+    <version.plugin.bundle>2.5.3</version.plugin.bundle>
+
     <osgi.export>com.fasterxml.jackson.core;version=${project.version},
 com.fasterxml.jackson.core.*;version=${project.version}
     </osgi.export>
@@ -36,6 +42,14 @@
     <packageVersion.package>${project.groupId}.json</packageVersion.package>
   </properties>
 
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
   <build>
     <plugins>
       <plugin>
@@ -64,7 +78,6 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-site-plugin</artifactId>
-        <version>3.1</version>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
@@ -103,8 +116,7 @@
               <encoding>UTF-8</encoding>
               <maxmemory>1g</maxmemory>
               <links>
-                  <!-- JDK, other Jackson pkgs -->
-                  <link>http://docs.oracle.com/javase/6/docs/api/</link>
+                  <link>http://docs.oracle.com/javase/7/docs/api/</link>
               </links>
               <excludePackageNames>${javadoc.package.exclude}</excludePackageNames>
               <bootclasspath>${sun.boot.class.path}</bootclasspath>
diff --git a/release-notes/CREDITS b/release-notes/CREDITS
index d9d402a..4aaca26 100644
--- a/release-notes/CREDITS
+++ b/release-notes/CREDITS
@@ -78,6 +78,12 @@
 Lokesh Kumar N (LokeshN@github)
   * Contributed #209: Make use of `_allowMultipleMatches` in `FilteringParserDelegate`
    (2.7.4)
+  * Contributed fix for #117: Support for missing values (non-compliant JSON)
+   (2.8.0)
+  * Contributed implementation for #86: Allow inclusion of request body for JsonParseException
+   (2.8.0)
+  * Contributed implementation for #285: Allow inclusion of request body for JsonParseException
+   (2.8.0)
 
 Tanguy Leroux (tlrx@github)
   * Reported, contributed fix for #280: FilteringGeneratorDelegate.writeUTF8String()
@@ -93,3 +99,11 @@
   * Reportef #317: ArrayIndexOutOfBoundsException: 200 on floating point number with exactly
   200-length decimal part
    (2.7.8)
+
+Mikael Staldal (mikaelstaldal@github)
+  * Contributed fix for #265: `JsonStringEncoder` should allow passing `CharSequence`
+   (2.8.0)
+
+Kevin Gallardo (newkek@github)
+  * Reported #296: JsonParserSequence skips a token on a switched Parser
+   (2.8.0)
diff --git a/release-notes/VERSION b/release-notes/VERSION
index 27615e3..787f7d6 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -14,6 +14,42 @@
 === Releases ===
 ------------------------------------------------------------------------
 
+2.8.2 (30-Aug-2016)
+2.8.1 (20-Jul-2016)
+
+No changes since 2.8.0
+
+2.8.0 (04-Jul-2016)
+
+#86: Allow inclusion of request body for `JsonParseException`
+ (contributed by LokeshN)
+#117: Add `JsonParser.Feature.ALLOW_MISSING_VALUES` to support for missing values
+ (contributed by LokeshN)
+#136: Add `JsonpCharacterEscapes` for easier handling of potential problems
+ with JSONP and rare but technically allowed \u2028 and \u2029 linefeed characters
+#253: Add `JsonGenerator. writeEmbeddedObject()` to allow writes of opaque native types
+ (suggested by Gregoire C)
+#255: Relax ownership checks for buffers not to require increase in size
+#257: Add `writeStartObject(Object pojo)` to streamline assignment of current value
+#265: `JsonStringEncoder` should allow passing `CharSequence`
+ (contributed by Mikael S)
+#276: Add support for serializing using `java.io.DataOutput`
+#277: Add new scalar-array write methods for `int`/`long`/`double` cases
+#279: Support `DataInput` for parsing
+#280: Add `JsonParser.finishToken()` to force full, non-lazy reading of current token
+#281: Add `JsonEOFException` as sub-class of `JsonParseException`
+#282: Fail to report error for trying to write field name outside Object (root level)
+#285: Add `JsonParser.getText(Writer)`
+ (contributed by LokesN)
+#290: Add `JsonGenerator.canWriteFormattedNumbers()` for introspection
+#294: Add `JsonGenerator.writeFieldId(long)` method to support binary formats
+ with non-String keys
+#296: `JsonParserSequence` skips a token on a switched Parser
+ (reported by Kevin G)
+- Add `JsonParser.currentToken()` and `JsonParser.currentTokenId()` as replacements
+  for `getCurrentToken()` and `getCurrentTokenId()`, respectively. Existing methods
+  will likely be deprecated in 2.9.
+
 2.7.8 (not yet released)
 
 #317: ArrayIndexOutOfBoundsException: 200 on floating point number with exactly
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java
index b052507..4c975d2 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java
@@ -442,6 +442,9 @@
      * @since 2.1
      */
     public boolean canUseSchema(FormatSchema schema) {
+        if (schema == null){
+            return false;
+        }
         String ourFormat = getFormatName();
         return (ourFormat != null) && ourFormat.equals(schema.getSchemaType());
     }
@@ -875,7 +878,7 @@
     public JsonParser createParser(String content) throws IOException, JsonParseException {
         final int strLen = content.length();
         // Actually, let's use this for medium-sized content, up to 64kB chunk (32kb char)
-        if (_inputDecorator != null || strLen > 0x8000 || !canUseCharArrays()) {
+        if ((_inputDecorator != null) || (strLen > 0x8000) || !canUseCharArrays()) {
             // easier to just wrap in a Reader than extend InputDecorator; or, if content
             // is too long for us to copy it over
             return createParser(new StringReader(content));
@@ -910,6 +913,14 @@
                 false);
     }
 
+    /**
+     * @since 2.8
+     */
+    public JsonParser createParser(DataInput in) throws IOException {
+        IOContext ctxt = _createContext(in, false);
+        return _createParser(_decorate(in, ctxt), ctxt);
+    }
+
     /*
     /**********************************************************
     /* Parser factories (old ones, pre-2.2)
@@ -1148,6 +1159,28 @@
         return _createGenerator(_decorate(w, ctxt), ctxt);
     }    
 
+    /**
+     * Method for constructing generator for writing content using specified
+     * {@link DataOutput} instance.
+     * 
+     * @since 2.8
+     */
+    public JsonGenerator createGenerator(DataOutput out, JsonEncoding enc) throws IOException {
+        return createGenerator(_createDataOutputWrapper(out), enc);
+    }
+
+    /**
+     * Convenience method for constructing generator that uses default
+     * encoding of the format (UTF-8 for JSON and most other data formats).
+     *<p>
+     * Note: there are formats that use fixed encoding (like most binary data formats).
+     * 
+     * @since 2.8
+     */
+    public JsonGenerator createGenerator(DataOutput out) throws IOException {
+        return createGenerator(_createDataOutputWrapper(out), JsonEncoding.UTF8);
+    }
+
     /*
     /**********************************************************
     /* Generator factories, old (pre-2.2)
@@ -1286,6 +1319,26 @@
                 _objectCodec, _byteSymbolCanonicalizer, _rootCharSymbols, _factoryFeatures);
     }
 
+    /**
+     * @since 2.8
+     */
+    protected JsonParser _createParser(DataInput input, IOContext ctxt) throws IOException
+    {
+        // 13-May-2016, tatu: Need to take care not to accidentally create JSON parser for
+        //   non-JSON input. So, bit unclean but...
+        String format = getFormatName();
+        if (format != FORMAT_NAME_JSON) { // NOTE: only ensure override; full equality NOT needed
+            throw new UnsupportedOperationException(String.format(
+                    "InputData source not (yet?) support for this format (%s)", format));
+        }
+        // Also: while we can't do full bootstrapping (due to read-ahead limitations), should
+        // at least handle possible UTF-8 BOM
+        int firstByte = ByteSourceJsonBootstrapper.skipUTF8BOM(input);
+        ByteQuadsCanonicalizer can = _byteSymbolCanonicalizer.makeChild(_factoryFeatures);
+        return new UTF8DataInputJsonParser(ctxt, _parserFeatures, input,
+                _objectCodec, can, firstByte);
+    }
+
     /*
     /**********************************************************
     /* Factory methods used by factory for creating generator instances,
@@ -1368,7 +1421,7 @@
         }
         return in;
     }
-    
+
     /**
      * @since 2.4
      */
@@ -1383,6 +1436,19 @@
     }
 
     /**
+     * @since 2.8
+     */
+    protected final DataInput _decorate(DataInput in, IOContext ctxt) throws IOException {
+        if (_inputDecorator != null) {
+            DataInput in2 = _inputDecorator.decorate(ctxt, in);
+            if (in2 != null) {
+                return in2;
+            }
+        }
+        return in;
+    }
+    
+    /**
      * @since 2.4
      */
     protected final OutputStream _decorate(OutputStream out, IOContext ctxt) throws IOException {
@@ -1422,24 +1488,21 @@
      */
     public BufferRecycler _getBufferRecycler()
     {
-        BufferRecycler br;
-
         /* 23-Apr-2015, tatu: Let's allow disabling of buffer recycling
          *   scheme, for cases where it is considered harmful (possibly
          *   on Android, for example)
          */
         if (isEnabled(Feature.USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING)) {
             SoftReference<BufferRecycler> ref = _recyclerRef.get();
-            br = (ref == null) ? null : ref.get();
+            BufferRecycler br = (ref == null) ? null : ref.get();
     
             if (br == null) {
                 br = new BufferRecycler();
                 _recyclerRef.set(new SoftReference<BufferRecycler>(br));
             }
-        } else {
-            br = new BufferRecycler();
+            return br;
         }
-        return br;
+        return new BufferRecycler();
     }
 
     /**
@@ -1451,6 +1514,13 @@
     }
 
     /**
+     * @since 2.8
+     */
+    protected OutputStream _createDataOutputWrapper(DataOutput out) {
+        return new DataOutputAsStream(out);
+    }
+
+    /**
      * Helper methods used for constructing an optimal stream for
      * parsers to use, when input is to be read from an URL.
      * This helps when reading file content via URL.
@@ -1465,7 +1535,7 @@
              */
             String host = url.getHost();
             if (host == null || host.length() == 0) {
-                // [Issue#48]: Let's try to avoid probs with URL encoded stuff
+                // [core#48]: Let's try to avoid probs with URL encoded stuff
                 String path = url.getPath();
                 if (path.indexOf('%') < 0) {
                     return new FileInputStream(url.getPath());
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
index a30da35..92be7cd 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
@@ -290,53 +290,6 @@
 
     /*
     /**********************************************************
-    /* Forward-compatibility additions in 2.7.5: placeholders
-    /* for additions that will be in 2.8.0
-    /**********************************************************
-     */
-
-    // @since 2.7.5 (as placeholder, NOT full impl)
-    public boolean canWriteFormattedNumbers() { return false; }
-
-    // @since 2.7.5: default impl that should work fine
-    public void writeStartObject(Object forValue) throws IOException
-    {
-        writeStartObject();
-        setCurrentValue(forValue);
-    }
-
-    // @since 2.7.5: default impl that should work fine
-    public void writeArray(int[] array, int offset, int length) throws IOException
-    {
-        writeStartArray();
-        for (int i = offset, end = offset+length; i < end; ++i) {
-            writeNumber(array[i]);
-        }
-        writeEndArray();
-    }
-
-    // @since 2.7.5: default impl that should work fine
-    public void writeArray(long[] array, int offset, int length) throws IOException
-    {
-        writeStartArray();
-        for (int i = offset, end = offset+length; i < end; ++i) {
-            writeNumber(array[i]);
-        }
-        writeEndArray();
-    }
-
-    // @since 2.7.5: default impl that should work fine
-    public void writeArray(double[] array, int offset, int length) throws IOException
-    {
-        writeStartArray();
-        for (int i = offset, end = offset+length; i < end; ++i) {
-            writeNumber(array[i]);
-        }
-        writeEndArray();
-    }
-
-    /*
-    /**********************************************************
     /* Public API, Feature configuration
     /**********************************************************
      */
@@ -394,7 +347,7 @@
      *
      * @return This parser object, to allow chaining of calls
      *
-     * @deprecated Since 2.7, use {@link #overrideStdFeatures(int, int)} instead
+     * @deprecated Since 2.7, use {@link #overrideStdFeatures(int, int)} instead -- remove from 2.9
      */
     @Deprecated
     public abstract JsonGenerator setFeatureMask(int values);
@@ -745,6 +698,20 @@
      */
     public boolean canOmitFields() { return true; }
 
+    /**
+     * Introspection method to call to check whether it is possible
+     * to write numbers using {@link #writeNumber(java.lang.String)}
+     * using possible custom format, or not. Typically textual formats
+     * allow this (and JSON specifically does), whereas binary formats
+     * do not allow this (except by writing them as Strings).
+     * Usual reason for calling this method is to check whether custom
+     * formatting of numbers may be applied by higher-level code (databinding)
+     * or not.
+     *
+     * @since 2.8
+     */
+    public boolean canWriteFormattedNumbers() { return false; }
+    
     /*
     /**********************************************************
     /* Public API, write methods, structural
@@ -803,6 +770,26 @@
     public abstract void writeStartObject() throws IOException;
 
     /**
+     * Method for writing starting marker of a JSON Object value
+     * (character '{'; plus possible white space decoration
+     * if pretty-printing is enabled), to represent Java given
+     * as the argument. Argument is offered as metadata, but more
+     * importantly it should be assigned as the "current value"
+     * for the Object content that gets constructed and initialized.
+     *<p>
+     * Object values can be written in any context where values
+     * are allowed: meaning everywhere except for when
+     * a field name is expected.
+     *
+     * @since 2.8.
+     */
+    public void writeStartObject(Object forValue) throws IOException
+    {
+        writeStartObject();
+        setCurrentValue(forValue);
+    }
+
+    /**
      * Method for writing closing marker of a JSON Object value
      * (character '}'; plus possible white space decoration
      * if pretty-printing is enabled).
@@ -838,6 +825,98 @@
      */
     public abstract void writeFieldName(SerializableString name) throws IOException;
 
+    /**
+     * Alternative to {@link #writeFieldName(String)} that may be used
+     * in cases where property key is of numeric type; either where
+     * underlying format supports such notion (some binary formats do,
+     * unlike JSON), or for convenient conversion into String presentation.
+     * Default implementation will simply convert id into <code>String</code>
+     * and call {@link #writeFieldName(String)}.
+     *
+     * @since 2.8
+     */
+    public void writeFieldId(long id) throws IOException {
+        writeFieldName(Long.toString(id));
+    }
+
+    /*
+    /**********************************************************
+    /* Public API, write methods, scalar arrays (2.8)
+    /**********************************************************
+     */
+
+    /**
+     * Value write method that can be called to write a single
+     * array (sequence of {@link JsonToken#START_ARRAY}, zero or
+     * more {@link JsonToken#VALUE_NUMBER_INT}, {@link JsonToken#END_ARRAY})
+     *
+     * @since 2.8
+     *
+     * @param array Array that contains values to write
+     * @param offset Offset of the first element to write, within array
+     * @param length Number of elements in array to write, from `offset` to `offset + len - 1`
+     */
+    public void writeArray(int[] array, int offset, int length) throws IOException
+    {
+        if (array == null) {
+            throw new IllegalArgumentException("null array");
+        }
+        _verifyOffsets(array.length, offset, length);
+        writeStartArray();
+        for (int i = offset, end = offset+length; i < end; ++i) {
+            writeNumber(array[i]);
+        }
+        writeEndArray();
+    }
+
+    /**
+     * Value write method that can be called to write a single
+     * array (sequence of {@link JsonToken#START_ARRAY}, zero or
+     * more {@link JsonToken#VALUE_NUMBER_INT}, {@link JsonToken#END_ARRAY})
+     *
+     * @since 2.8
+     *
+     * @param array Array that contains values to write
+     * @param offset Offset of the first element to write, within array
+     * @param length Number of elements in array to write, from `offset` to `offset + len - 1`
+     */
+    public void writeArray(long[] array, int offset, int length) throws IOException
+    {
+        if (array == null) {
+            throw new IllegalArgumentException("null array");
+        }
+        _verifyOffsets(array.length, offset, length);
+        writeStartArray();
+        for (int i = offset, end = offset+length; i < end; ++i) {
+            writeNumber(array[i]);
+        }
+        writeEndArray();
+    }
+
+    /**
+     * Value write method that can be called to write a single
+     * array (sequence of {@link JsonToken#START_ARRAY}, zero or
+     * more {@link JsonToken#VALUE_NUMBER_FLOAT}, {@link JsonToken#END_ARRAY})
+     *
+     * @since 2.8
+     *
+     * @param array Array that contains values to write
+     * @param offset Offset of the first element to write, within array
+     * @param length Number of elements in array to write, from `offset` to `offset + len - 1`
+     */
+    public void writeArray(double[] array, int offset, int length) throws IOException
+    {
+        if (array == null) {
+            throw new IllegalArgumentException("null array");
+        }
+        _verifyOffsets(array.length, offset, length);
+        writeStartArray();
+        for (int i = offset, end = offset+length; i < end; ++i) {
+            writeNumber(array[i]);
+        }
+        writeEndArray();
+    }
+
     /*
     /**********************************************************
     /* Public API, write methods, text/String values
@@ -1109,7 +1188,7 @@
 
     /*
     /**********************************************************
-    /* Public API, write methods, other value types
+    /* Public API, write methods, numeric
     /**********************************************************
      */
 
@@ -1215,6 +1294,12 @@
      */
     public abstract void writeNumber(String encodedValue) throws IOException;
 
+    /*
+    /**********************************************************
+    /* Public API, write methods, other value types
+    /**********************************************************
+     */
+    
     /**
      * Method for outputting literal JSON boolean value (one of
      * Strings 'true' and 'false').
@@ -1234,6 +1319,17 @@
      */
     public abstract void writeNull() throws IOException;
 
+    /**
+     * Method that can be called on backends that support passing opaque datatypes of
+     * non-JSON formats
+     *
+     * @since 2.8
+     */
+    public void writeEmbeddedObject(Object object) throws IOException {
+        throw new JsonGenerationException("No native support for writing embedded objects",
+                this);
+    }
+    
     /*
     /**********************************************************
     /* Public API, write methods, Native Ids (type, object)
@@ -1283,6 +1379,73 @@
         throw new JsonGenerationException("No native support for writing Type Ids", this);
     }
 
+    // 24-May-2016, tatu: Looks like this won't quite make it in 2.8... too
+    //   many open questions on whether return value may be used and such to
+    //   really close the loop. But leaving code sample in, in case we can resolve it
+    //   it for 2.9.
+
+    /*
+     * Replacement method for {@link #writeTypeId(Object)} which is called
+     * regardless of whether format has native type ids. If it does have native
+     * type ids, those are to be used (if configuration allows this), if not,
+     * structural type id inclusion is to be used. For JSON, for example, no
+     * native type ids exist and structural inclusion is always used.
+     *<p>
+     * NOTE: from databind perspective, only "as-wrapper-array", "as-wrapper-object" and
+     * "as-property" inclusion styles call this method; the remaining "as-external-property"
+     * mechanism always uses writes type id value as simple property.
+     *
+     * @param inclStyle Kind of inclusion; {@link JsonToken#START_ARRAY} for "as-wrapper-array",
+     *     {@link JsonToken#START_OBJECT} for "as-wrapper-object" and {@link JsonToken#FIELD_NAME}
+     *     for "as-property"
+     * @param forValue Java object for which type is being written; not used by standard mechanism
+     * @param valueShape Expected shape of the value to write, as expressed by the first token (for
+     *    structural type), or any of scalar types for non-structured values (typically
+     *    just {@link JsonToken#VALUE_STRING} -- exact token not required, just the fact it's scalar)
+     * @param typeId Type id to write
+     * @param propertyName Name of property to use, in case of "as-property" inclusion style
+     *
+     * @since 2.8
+     */
+    /*
+    public Object writeTypeSuffix(JsonToken inclStyle, Object forValue, JsonToken valueShape,
+            String typeId, String propertyName) throws IOException
+    {
+        if (inclStyle == JsonToken.FIELD_NAME) { // as-property
+            if (typeId == null) { // should not include `null` type id in any form with this style
+                writeStartObject();
+            } else if (valueShape == JsonToken.START_OBJECT) {
+                if (canWriteTypeId()) {
+                    writeTypeId(typeId);
+                    writeStartObject();
+                } else {
+                    writeStartObject();
+                    writeStringField(propertyName, typeId);
+                }
+            } else if (valueShape == JsonToken.START_ARRAY) {
+                if (canWriteTypeId()) {
+                    writeTypeId(typeId);
+                    writeStartArray();
+                } else {
+                    writeStartArray();
+                    writeString(typeId);
+                }
+            } else { // any scalar
+                if (canWriteTypeId()) {
+                    writeTypeId(typeId);
+                }
+            }
+            return JsonToken.END_OBJECT;
+        }
+        if (inclStyle == JsonToken.START_ARRAY) { // as-wrapper-array
+        } else if (inclStyle == JsonToken.START_OBJECT) { // as-wrapper-object
+            
+        } else {
+            throw new JsonGenerationException("Unrecognized inclusion style: "+inclStyle, this);
+        }
+    }
+    */
+
     /*
     /**********************************************************
     /* Public API, write methods, serializing Java objects
@@ -1518,7 +1681,7 @@
      */
     public void copyCurrentEvent(JsonParser p) throws IOException
     {
-        JsonToken t = p.getCurrentToken();
+        JsonToken t = p.currentToken();
         // sanity check; what to do?
         if (t == null) {
             _reportError("No current event to copy");
@@ -1526,6 +1689,7 @@
         switch (t.id()) {
         case ID_NOT_AVAILABLE:
             _reportError("No current event to copy");
+            break; // never gets here
         case ID_START_OBJECT:
             writeStartObject();
             break;
@@ -1621,7 +1785,7 @@
      */
     public void copyCurrentStructure(JsonParser p) throws IOException
     {
-        JsonToken t = p.getCurrentToken();
+        JsonToken t = p.currentToken();
         if (t == null) {
             _reportError("No current event to copy");
         }
@@ -1730,6 +1894,18 @@
     }
 
     /**
+     * @since 2.8
+     */
+    protected final void _verifyOffsets(int arrayLength, int offset, int length)
+    {
+        if ((offset < 0) || (offset + length) > arrayLength) {
+            throw new IllegalArgumentException(String.format(
+                    "invalid argument(s) (offset=%d, length=%d) for input array of %d element",
+                    offset, length, arrayLength));
+        }
+    }
+
+    /**
      * Helper method to try to call appropriate write method for given
      * untyped Object. At this point, no structural conversions should be done,
      * only simple basic types are to be coerced as necessary.
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParseException.java b/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
index d373ad7..9176ad2 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
@@ -5,6 +5,8 @@
 
 package com.fasterxml.jackson.core;
 
+import com.fasterxml.jackson.core.util.RequestPayload;
+
 /**
  * Exception type for parsing problems, used when non-well-formed content
  * (content that does not conform to JSON syntax as per specification)
@@ -13,9 +15,19 @@
 public class JsonParseException extends JsonProcessingException {
     private static final long serialVersionUID = 2L; // 2.7
 
-    // since 2.7.4
+    // transient since 2.7.4
     protected transient JsonParser _processor;
 
+    /**
+     * Optional payload that can be assigned to pass along for error reporting
+     * or handling purposes. Core streaming parser implementations DO NOT
+     * initialize this; it is up to using applications and frameworks to
+     * populate it.
+     *
+     * @since 2.8
+     */
+    protected RequestPayload _requestPayload;
+
     @Deprecated // since 2.7
     public JsonParseException(String msg, JsonLocation loc) {
         super(msg, loc);
@@ -65,6 +77,8 @@
     /**
      * Fluent method that may be used to assign originating {@link JsonParser},
      * to be accessed using {@link #getProcessor()}.
+     *<p>
+     * NOTE: `this` instance is modified and no new instance is constructed.
      *
      * @since 2.7
      */
@@ -73,8 +87,57 @@
         return this;
     }
 
+    /**
+     * Fluent method that may be used to assign payload to this exception,
+     * to let recipient access it for diagnostics purposes.
+     *<p>
+     * NOTE: `this` instance is modified and no new instance is constructed.
+     *
+     * @since 2.8
+     */
+    public JsonParseException withRequestPayload(RequestPayload p) {
+        _requestPayload = p;
+        return this;
+    }
+    
     @Override
     public JsonParser getProcessor() {
         return _processor;
     }
+
+    /**
+     * Method that may be called to find payload that was being parsed, if
+     * one was specified for parser that threw this Exception.
+     *
+     * @return request body, if payload was specified; `null` otherwise
+     *
+     * @since 2.8
+     */
+    public RequestPayload getRequestPayload() {
+        return _requestPayload;
+    }
+
+    /**
+     * The method returns the String representation of the request payload if
+     * one was specified for parser that threw this Exception.
+     * 
+     * @return request body as String, if payload was specified; `null` otherwise
+     * 
+     * @since 2.8
+     */
+    public String getRequestPayloadAsString() {
+        return (_requestPayload != null) ? _requestPayload.toString() : null;
+    }
+    
+    /**
+     * Overriding the getMessage() to include the request body
+     */
+    @Override 
+    public String getMessage() {
+        String msg = super.getMessage();
+        if (_requestPayload != null) {
+            msg +=  "\nRequest payload : " + _requestPayload.toString();
+        }
+        return msg;
+    }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParser.java b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
index c941521..2fd0011 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
@@ -11,6 +11,7 @@
 import java.util.Iterator;
 
 import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.core.util.RequestPayload;
 
 /**
  * Base class that defines public API for reading JSON content.
@@ -208,7 +209,25 @@
           *
           * @since 2.6
           */
-         IGNORE_UNDEFINED(false)
+         IGNORE_UNDEFINED(false),
+
+         /**
+          * Feature allows the support for "missing" values in a JSON array: missing
+          * value meaning sequence of two commas, without value in-between but only
+          * optional white space.
+          * Enabling this feature will expose "missing" values as {@link JsonToken#VALUE_NULL}
+          * tokens, which typically become Java nulls in arrays and {@link java.util.Collection}
+          * in data-binding.
+          * <p>
+          * For example, enabling this feature will represent a JSON array <code>["value1",,"value3",]</code>
+          * as <code>["value1", null, "value3", null]</code> 
+          * <p>
+          * Since the JSON specification does not allow missing values this is a non-compliant JSON
+          * feature and is disabled by default.
+          * 
+          * @since 2.8
+          */
+         ALLOW_MISSING_VALUES(false)
          ;
 
         /**
@@ -260,6 +279,13 @@
      * are enabled.
      */
     protected int _features;
+    
+    /**
+     * Optional container that holds the request payload which will be displayed on JSON parsing error.
+     *
+     * @since 2.8
+     */
+    protected transient RequestPayload _requestPayload;
 
     /*
     /**********************************************************
@@ -334,12 +360,39 @@
         }
     }
 
+    /**
+     * Sets the payload to be passed if {@link JsonParseException} is thrown.
+     *
+     * @since 2.8
+     */
+    public void setRequestPayloadOnError(RequestPayload payload) {
+        _requestPayload = payload;
+    }
+    
+    /**
+     * Sets the byte[] request payload and the charset
+     *
+     * @since 2.8
+     */
+     public void setRequestPayloadOnError(byte[] payload, String charset) {
+         _requestPayload = (payload == null) ? null : new RequestPayload(payload, charset);
+     }
+
+     /**
+     * Sets the String request payload
+     *
+     * @since 2.8
+     */
+    public void setRequestPayloadOnError(String payload) {
+        _requestPayload = (payload == null) ? null : new RequestPayload(payload);
+    }
+
     /*
     /**********************************************************
     /* Format support
     /**********************************************************
      */
-    
+
     /**
      * Method to call to make this parser use specified schema. Method must
      * be called before trying to parse any content, right after parser instance
@@ -605,7 +658,7 @@
      * @return Next token from the stream, if any found, or null
      *   to indicate end-of-input
      */
-    public abstract JsonToken nextToken() throws IOException, JsonParseException;
+    public abstract JsonToken nextToken() throws IOException;
 
     /**
      * Iteration method that will advance stream enough
@@ -624,7 +677,7 @@
      *   parsers, {@link JsonToken#NOT_AVAILABLE} if no tokens were
      *   available yet)
      */
-    public abstract JsonToken nextValue() throws IOException, JsonParseException;
+    public abstract JsonToken nextValue() throws IOException;
 
     /**
      * Method that fetches next token (as if calling {@link #nextToken}) and
@@ -640,7 +693,7 @@
      * @param str Property name to compare next token to (if next token is
      *   <code>JsonToken.FIELD_NAME</code>)
      */
-    public boolean nextFieldName(SerializableString str) throws IOException, JsonParseException {
+    public boolean nextFieldName(SerializableString str) throws IOException {
         return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(getCurrentName());
     }
 
@@ -651,7 +704,7 @@
      * 
      * @since 2.5
      */
-    public String nextFieldName() throws IOException, JsonParseException {
+    public String nextFieldName() throws IOException {
         return (nextToken() == JsonToken.FIELD_NAME) ? getCurrentName() : null;
     }
 
@@ -666,7 +719,7 @@
      * but may be faster for parser to process, and can therefore be used if caller
      * expects to get a String value next from input.
      */
-    public String nextTextValue() throws IOException, JsonParseException {
+    public String nextTextValue() throws IOException {
         return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
     }
 
@@ -679,9 +732,9 @@
      *  return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
      *</pre>
      * but may be faster for parser to process, and can therefore be used if caller
-     * expects to get a String value next from input.
+     * expects to get an int value next from input.
      */
-    public int nextIntValue(int defaultValue) throws IOException, JsonParseException {
+    public int nextIntValue(int defaultValue) throws IOException {
         return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
     }
 
@@ -694,9 +747,9 @@
      *  return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
      *</pre>
      * but may be faster for parser to process, and can therefore be used if caller
-     * expects to get a String value next from input.
+     * expects to get a long value next from input.
      */
-    public long nextLongValue(long defaultValue) throws IOException, JsonParseException {
+    public long nextLongValue(long defaultValue) throws IOException {
         return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
     }
 
@@ -712,9 +765,9 @@
      *  return null;
      *</pre>
      * but may be faster for parser to process, and can therefore be used if caller
-     * expects to get a String value next from input.
+     * expects to get a Boolean value next from input.
      */
-    public Boolean nextBooleanValue() throws IOException, JsonParseException {
+    public Boolean nextBooleanValue() throws IOException {
         JsonToken t = nextToken();
         if (t == JsonToken.VALUE_TRUE) { return Boolean.TRUE; }
         if (t == JsonToken.VALUE_FALSE) { return Boolean.FALSE; }
@@ -735,8 +788,26 @@
      * will call {@link #nextToken} to point to the next
      * available token, if any.
      */
-    public abstract JsonParser skipChildren() throws IOException, JsonParseException;
-    
+    public abstract JsonParser skipChildren() throws IOException;
+
+    /**
+     * Method that may be used to force full handling of the current token
+     * so that even if lazy processing is enabled, the whole contents are
+     * read for possible retrieval. This is usually used to ensure that
+     * the token end location is available, as well as token contents
+     * (similar to what calling, say {@link #getTextCharacters()}, would
+     * achieve).
+     *<p>
+     * Note that for many dataformat implementations this method
+     * will not do anything; this is the default implementation unless
+     * overridden by sub-classes.
+     *
+     * @since 2.8
+     */
+    public void finishToken() throws IOException {
+        ; // nothing
+    }
+
     /**
      * Method that can be called to determine whether this parser
      * is closed or not. If it is closed, no new tokens can be
@@ -763,8 +834,12 @@
      *   if any: null before any tokens have been read, and
      *   after end-of-input has been encountered, as well as
      *   if the current token has been explicitly cleared.
+     *
+     * @since 2.8
      */
-    public abstract JsonToken getCurrentToken();
+    public JsonToken currentToken() {
+        return getCurrentToken();
+    }
 
     /**
      * Method similar to {@link #getCurrentToken()} but that returns an
@@ -775,10 +850,22 @@
      * Note, however, that effect may not be big enough to matter: make sure
      * to profile performance before deciding to use this method.
      * 
-     * @since 2.3
+     * @since 2.8
      * 
      * @return <code>int</code> matching one of constants from {@link JsonTokenId}.
      */
+    public int currentTokenId() {
+        return getCurrentTokenId();
+    }
+
+    /**
+     * Alias for {@link #currentToken()}, will be deprecated in Jackson 2.9
+     */
+    public abstract JsonToken getCurrentToken();
+
+    /**
+     * Alias for {@link #currentTokenId()}, will be deprecated in Jackson 2.9
+     */
     public abstract int getCurrentTokenId();
     
     /**
@@ -797,7 +884,7 @@
     /**
      * Method that is functionally equivalent to:
      *<code>
-     *  return getCurrentTokenId() == id
+     *  return currentTokenId() == id
      *</code>
      * but may be more efficiently implemented.
      *<p>
@@ -812,7 +899,7 @@
     /**
      * Method that is functionally equivalent to:
      *<code>
-     *  return getCurrentTokenId() == id
+     *  return currentToken() == t
      *</code>
      * but may be more efficiently implemented.
      *<p>
@@ -869,7 +956,7 @@
      *<p>
      * Default implementation is equivalent to:
      *<pre>
-     *   getCurrentToken() == JsonToken.START_ARRAY
+     *   currentToken() == JsonToken.START_ARRAY
      *</pre>
      * but may be overridden by custom parser implementations.
      *
@@ -877,15 +964,15 @@
      *   start-array marker (such {@link JsonToken#START_ARRAY});
      *   false if not.
      */
-    public boolean isExpectedStartArrayToken() { return getCurrentToken() == JsonToken.START_ARRAY; }
+    public boolean isExpectedStartArrayToken() { return currentToken() == JsonToken.START_ARRAY; }
 
     /**
      * Similar to {@link #isExpectedStartArrayToken()}, but checks whether stream
      * currently points to {@link JsonToken#START_OBJECT}.
-     * 
+     *
      * @since 2.5
      */
-    public boolean isExpectedStartObjectToken() { return getCurrentToken() == JsonToken.START_OBJECT; }
+    public boolean isExpectedStartObjectToken() { return currentToken() == JsonToken.START_OBJECT; }
     
     /*
     /**********************************************************
@@ -944,6 +1031,31 @@
     public abstract String getText() throws IOException;
 
     /**
+     * Method to read the textual representation of the current token in chunks and 
+     * pass it to the given Writer.
+     * Conceptually same as calling:
+     *<pre>
+     *  writer.write(parser.getText());
+     *</pre>
+     * but should typically be more efficient as longer content does need to
+     * be combined into a single <code>String</code> to return, and write
+     * can occur directly from intermediate buffers Jackson uses.
+     * 
+     * @return The number of characters written to the Writer
+     *  
+     * @since 2.8
+     */
+    public int getText(Writer writer) throws IOException, UnsupportedOperationException
+    {
+        String str = getText();
+        if (str == null) {
+            return 0;
+        }
+        writer.write(str);
+        return str.length();
+    }
+
+    /**
      * Method similar to {@link #getText}, but that will return
      * underlying (unmodifiable) character array that contains
      * textual value, instead of constructing a String object
@@ -1173,11 +1285,12 @@
      * may be thrown to indicate numeric overflow/underflow.
      */
     public boolean getBooleanValue() throws IOException {
-        JsonToken t = getCurrentToken();
+        JsonToken t = currentToken();
         if (t == JsonToken.VALUE_TRUE) return true;
         if (t == JsonToken.VALUE_FALSE) return false;
         throw new JsonParseException(this,
-                String.format("Current token (%s) not of boolean type", t));
+            String.format("Current token (%s) not of boolean type", t))
+                .withRequestPayload(_requestPayload);
     }
 
     /**
@@ -1187,9 +1300,12 @@
      *<p>
      * Note: only some specialized parser implementations support
      * embedding of objects (usually ones that are facades on top
-     * of non-streaming sources, such as object trees).
+     * of non-streaming sources, such as object trees). One exception
+     * is access to binary content (whether via base64 encoding or not)
+     * which typically is accessible using this method, as well as
+     * {@link #getBinaryValue()}.
      */
-    public abstract Object getEmbeddedObject() throws IOException;
+    public Object getEmbeddedObject() throws IOException { return null; }
 
     /*
     /**********************************************************
@@ -1583,7 +1699,8 @@
      * based on current state of the parser
      */
     protected JsonParseException _constructError(String msg) {
-        return new JsonParseException(this, msg);
+        return new JsonParseException(this, msg)
+            .withRequestPayload(_requestPayload);
     }
 
     /**
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonStreamContext.java b/src/main/java/com/fasterxml/jackson/core/JsonStreamContext.java
index 5e8ff17..ddadc92 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonStreamContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonStreamContext.java
@@ -77,7 +77,10 @@
      * Method for accessing simple type description of current context;
      * either ROOT (for root-level values), OBJECT (for field names and
      * values of JSON Objects) or ARRAY (for values of JSON Arrays)
+     *
+     * @deprecated Since 2.8 use {@link #typeDesc} instead
      */
+    @Deprecated // since 2.8
     public final String getTypeDesc() {
         switch (_type) {
         case TYPE_ROOT: return "ROOT";
@@ -88,6 +91,18 @@
     }
 
     /**
+     * @since 2.8
+     */
+    public String typeDesc() {
+        switch (_type) {
+        case TYPE_ROOT: return "root";
+        case TYPE_ARRAY: return "Array";
+        case TYPE_OBJECT: return "Object";
+        }
+        return "?";
+    }
+    
+    /**
      * @return Number of entries that are complete and started.
      */
     public final int getEntryCount() { return _index + 1; }
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonpCharacterEscapes.java b/src/main/java/com/fasterxml/jackson/core/JsonpCharacterEscapes.java
new file mode 100644
index 0000000..282bb42
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/core/JsonpCharacterEscapes.java
@@ -0,0 +1,46 @@
+package com.fasterxml.jackson.core;
+
+import com.fasterxml.jackson.core.io.CharacterEscapes;
+import com.fasterxml.jackson.core.io.SerializedString;
+
+/**
+ * Convenience {@link CharacterEscapes} implementation that escapes
+ * Unicode characters `0x2028` and `0x2029` (in addition to characters
+ * escaped otherwise), which are apparently considered linefeeds as
+ * per newer Javascript specifications, and consequently problematic
+ * when using JSONP (see https://en.wikipedia.org/wiki/JSONP).
+ *
+ * @since 2.8
+ */
+public class JsonpCharacterEscapes extends CharacterEscapes
+{
+    private static final long serialVersionUID = 1L;
+
+    private static final int[] asciiEscapes = CharacterEscapes.standardAsciiEscapesForJSON();
+    private static final SerializedString escapeFor2028 = new SerializedString("\\u2028");
+    private static final SerializedString escapeFor2029 = new SerializedString("\\u2029");
+
+    private static final JsonpCharacterEscapes sInstance = new JsonpCharacterEscapes();
+
+    public static JsonpCharacterEscapes instance() {
+        return sInstance;
+    }
+
+    @Override
+    public SerializableString getEscapeSequence(int ch)
+    {
+        switch (ch) {
+        case 0x2028:
+            return escapeFor2028;
+        case 0x2029:
+            return escapeFor2029;
+        default:
+            return null;
+        }
+    }
+
+    @Override
+    public int[] getEscapeCodesForAscii() {
+        return asciiEscapes;
+    }
+}
diff --git a/src/main/java/com/fasterxml/jackson/core/ObjectCodec.java b/src/main/java/com/fasterxml/jackson/core/ObjectCodec.java
index 649c89f..afa6aaa 100644
--- a/src/main/java/com/fasterxml/jackson/core/ObjectCodec.java
+++ b/src/main/java/com/fasterxml/jackson/core/ObjectCodec.java
@@ -26,9 +26,9 @@
 {
     protected ObjectCodec() { }
 
-    // Since 2.3: need baseline implementation to avoid backwards compatibility
+    // Since 2.3
     @Override
-    public Version version() { return Version.unknownVersion(); }
+    public abstract Version version();
     
     /*
     /**********************************************************
@@ -46,8 +46,8 @@
      * The reason is that due to type erasure, key and value types
      * can not be introspected when using this method.
      */
-    public abstract <T> T readValue(JsonParser jp, Class<T> valueType)
-        throws IOException, JsonProcessingException;
+    public abstract <T> T readValue(JsonParser p, Class<T> valueType)
+        throws IOException;
 
     /**
      * Method to deserialize JSON content into a Java type, reference
@@ -56,8 +56,8 @@
      * and specifically needs to be used if the root type is a 
      * parameterized (generic) container type.
      */
-    public abstract <T> T readValue(JsonParser jp, TypeReference<?> valueTypeRef)
-        throws IOException, JsonProcessingException;
+    public abstract <T> T readValue(JsonParser p, TypeReference<?> valueTypeRef)
+        throws IOException;
 
     /**
      * Method to deserialize JSON content into a POJO, type specified
@@ -65,30 +65,30 @@
      * including containers like {@link java.util.Collection} and
      * {@link java.util.Map}).
      */
-    public abstract <T> T readValue(JsonParser jp, ResolvedType valueType)
-        throws IOException, JsonProcessingException;
+    public abstract <T> T readValue(JsonParser p, ResolvedType valueType)
+        throws IOException;
 
     /**
      * Method for reading sequence of Objects from parser stream,
      * all with same specified value type.
      */
-    public abstract <T> Iterator<T> readValues(JsonParser jp, Class<T> valueType)
-        throws IOException, JsonProcessingException;
+    public abstract <T> Iterator<T> readValues(JsonParser p, Class<T> valueType)
+        throws IOException;
 
     /**
      * Method for reading sequence of Objects from parser stream,
      * all with same specified value type.
      */
-    public abstract <T> Iterator<T> readValues(JsonParser jp, TypeReference<?> valueTypeRef)
-        throws IOException, JsonProcessingException;
+    public abstract <T> Iterator<T> readValues(JsonParser p, TypeReference<?> valueTypeRef)
+        throws IOException;
     
     /**
      * Method for reading sequence of Objects from parser stream,
      * all with same specified value type.
      */
-    public abstract <T> Iterator<T> readValues(JsonParser jp, ResolvedType valueType)
-        throws IOException, JsonProcessingException;
-    
+    public abstract <T> Iterator<T> readValues(JsonParser p, ResolvedType valueType)
+        throws IOException;
+
     /*
     /**********************************************************
     /* API for serialization (Object-to-JSON)
@@ -99,8 +99,7 @@
      * Method to serialize given Java Object, using generator
      * provided.
      */
-    public abstract void writeValue(JsonGenerator jgen, Object value)
-        throws IOException, JsonProcessingException;
+    public abstract void writeValue(JsonGenerator gen, Object value) throws IOException;
 
     /*
     /**********************************************************
@@ -116,15 +115,13 @@
      * value event, not container). Empty or whitespace
      * documents return null.
      *
-     * @return next tree from jp, or null if empty.
+     * @return next tree from p, or null if empty.
      */
     @Override
-    public abstract <T extends TreeNode> T readTree(JsonParser jp)
-        throws IOException, JsonProcessingException;
+    public abstract <T extends TreeNode> T readTree(JsonParser p) throws IOException;
     
     @Override
-    public abstract void writeTree(JsonGenerator jg, TreeNode tree)
-        throws IOException, JsonProcessingException;
+    public abstract void writeTree(JsonGenerator gen, TreeNode tree) throws IOException;
     
     /**
      * Method for construct root level Object nodes
diff --git a/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java b/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
index 128fbcf..d2d05f2 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
@@ -6,8 +6,8 @@
 import com.fasterxml.jackson.core.*;
 import com.fasterxml.jackson.core.json.DupDetector;
 import com.fasterxml.jackson.core.json.JsonWriteContext;
+import com.fasterxml.jackson.core.json.PackageVersion;
 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
-import com.fasterxml.jackson.core.util.VersionUtil;
 
 /**
  * This base class implements part of API that a JSON generator exposes
@@ -125,7 +125,7 @@
      * a simple generated class, with information extracted from Maven project file
      * during build.
      */
-    @Override public Version version() { return VersionUtil.versionFor(getClass()); }
+    @Override public Version version() { return PackageVersion.VERSION; }
 
     @Override
     public Object getCurrentValue() {
@@ -262,9 +262,11 @@
      */
 
     /**
-     * Note: co-variant return type.
+     * Note: type was co-variant until Jackson 2.7; reverted back to
+     * base type in 2.8 to allow for overriding by subtypes that use
+     * custom context type.
      */
-    @Override public JsonWriteContext getOutputContext() { return _writeContext; }
+    @Override public JsonStreamContext getOutputContext() { return _writeContext; }
 
     /*
     /**********************************************************
@@ -277,6 +279,16 @@
     //public void writeStartObject() throws IOException
     //public void writeEndObject() throws IOException
 
+    @Override // since 2.8
+    public void writeStartObject(Object forValue) throws IOException
+    {
+        writeStartObject();
+        if ((_writeContext != null) && (forValue != null)) {
+            _writeContext.setCurrentValue(forValue);
+        }
+        setCurrentValue(forValue);
+    }
+
     /*
     /**********************************************************
     /* Public API, write methods, textual
diff --git a/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java b/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
index df5e5a0..5b3f931 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
@@ -465,9 +465,6 @@
         return false;
     }
 
-    // No embedded objects with base impl...
-    @Override public Object getEmbeddedObject() throws IOException { return null; }
-
     @SuppressWarnings("resource")
     @Override // since 2.7
     public byte[] getBinaryValue(Base64Variant variant) throws IOException
@@ -499,22 +496,10 @@
 
     /*
     /**********************************************************
-    /* Low-level reading, other
-    /**********************************************************
-     */
-
-    protected final void loadMoreGuaranteed() throws IOException {
-        if (!loadMore()) { _reportInvalidEOF(); }
-    }
-    
-    /*
-    /**********************************************************
     /* Abstract methods needed from sub-classes
     /**********************************************************
      */
 
-    protected abstract boolean loadMore() throws IOException;
-    protected abstract void _finishString() throws IOException;
     protected abstract void _closeInput() throws IOException;
     
     /*
@@ -546,7 +531,12 @@
     @Override
     protected void _handleEOF() throws JsonParseException {
         if (!_parsingContext.inRoot()) {
-            _reportInvalidEOF(": expected close marker for "+_parsingContext.getTypeDesc()+" (from "+_parsingContext.getStartLocation(_ioContext.getSourceReference())+")");
+            String marker = _parsingContext.inArray() ? "Array" : "Object";
+            _reportInvalidEOF(String.format(
+                    ": expected close marker for %s (start marker at %s)",
+                    marker,
+                    _parsingContext.getStartLocation(_ioContext.getSourceReference())),
+                    null);
         }
     }
 
@@ -566,7 +556,7 @@
     
     protected void _reportMismatchedEndMarker(int actCh, char expCh) throws JsonParseException {
         String startDesc = ""+_parsingContext.getStartLocation(_ioContext.getSourceReference());
-        _reportError("Unexpected close marker '"+((char) actCh)+"': expected '"+expCh+"' (for "+_parsingContext.getTypeDesc()+" starting at "+startDesc+")");
+        _reportError("Unexpected close marker '"+((char) actCh)+"': expected '"+expCh+"' (for "+_parsingContext.typeDesc()+" starting at "+startDesc+")");
     }
 
     /*
@@ -1038,9 +1028,8 @@
          */
     
         if ((_numTypesValid & NR_DOUBLE) != 0) {
-            /* Let's actually parse from String representation,
-             * to avoid rounding errors that non-decimal floating operations
-             * would incur
+            /* Let's actually parse from String representation, to avoid
+             * rounding errors that non-decimal floating operations could incur
              */
             _numberBigDecimal = NumberInput.parseBigDecimal(getText());
         } else if ((_numTypesValid & NR_BIGINT) != 0) {
@@ -1074,11 +1063,13 @@
     }
 
     protected void reportOverflowInt() throws IOException {
-        _reportError("Numeric value ("+getText()+") out of range of int ("+Integer.MIN_VALUE+" - "+Integer.MAX_VALUE+")");
+        _reportError(String.format("Numeric value (%s) out of range of int (%d - %s)",
+                getText(), Integer.MIN_VALUE, Integer.MAX_VALUE));
     }
     
     protected void reportOverflowLong() throws IOException {
-        _reportError("Numeric value ("+getText()+") out of range of long ("+Long.MIN_VALUE+" - "+Long.MAX_VALUE+")");
+        _reportError(String.format("Numeric value (%s) out of range of long (%d - %s)",
+                getText(), Long.MIN_VALUE, Long.MAX_VALUE));
     }    
 
     /*
@@ -1119,7 +1110,6 @@
     
     protected final int _decodeBase64Escape(Base64Variant b64variant, char ch, int index) throws IOException
     {
-        // 17-May-2011, tatu: As per [JACKSON-xxx], need to handle escaped chars
         if (ch != '\\') {
             throw reportInvalidBase64Char(b64variant, ch, index);
         }
@@ -1163,4 +1153,22 @@
         }
         return new IllegalArgumentException(base);
     }
+
+    /*
+    /**********************************************************
+    /* Stuff that was abstract and required before 2.8, but that
+    /* is not mandatory in 2.8 or above.
+    /**********************************************************
+     */
+
+    @Deprecated // since 2.8
+    protected void loadMoreGuaranteed() throws IOException {
+        if (!loadMore()) { _reportInvalidEOF(); }
+    }
+
+    @Deprecated // since 2.8
+    protected boolean loadMore() throws IOException { return false; }
+
+    // Can't declare as deprecated, for now, but shouldn't be needed
+    protected void _finishString() throws IOException { }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java b/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
index b6810a9..6448296 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
@@ -4,6 +4,7 @@
 
 import com.fasterxml.jackson.core.*;
 import com.fasterxml.jackson.core.JsonParser.Feature;
+import com.fasterxml.jackson.core.io.JsonEOFException;
 import com.fasterxml.jackson.core.io.NumberInput;
 import com.fasterxml.jackson.core.util.ByteArrayBuilder;
 import com.fasterxml.jackson.core.util.VersionUtil;
@@ -95,8 +96,14 @@
      */
 
     @Override public abstract JsonToken nextToken() throws IOException;
-    @Override public JsonToken getCurrentToken() { return _currToken; }
 
+    @Override public JsonToken currentToken() { return _currToken; }
+    @Override public int currentTokenId() {
+        final JsonToken t = _currToken;
+        return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
+    }
+    
+    @Override public JsonToken getCurrentToken() { return _currToken; }
     @Override public int getCurrentTokenId() {
         final JsonToken t = _currToken;
         return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
@@ -250,7 +257,7 @@
             case ID_NULL:
                 return false;
             case ID_EMBEDDED_OBJECT:
-                Object value = this.getEmbeddedObject();
+                Object value = getEmbeddedObject();
                 if (value instanceof Boolean) {
                     return (Boolean) value;
                 }
@@ -293,7 +300,7 @@
             case ID_NULL:
                 return 0;
             case ID_EMBEDDED_OBJECT:
-                Object value = this.getEmbeddedObject();
+                Object value = getEmbeddedObject();
                 if (value instanceof Number) {
                     return ((Number) value).intValue();
                 }
@@ -333,7 +340,7 @@
             case ID_NULL:
                 return 0L;
             case ID_EMBEDDED_OBJECT:
-                Object value = this.getEmbeddedObject();
+                Object value = getEmbeddedObject();
                 if (value instanceof Number) {
                     return ((Number) value).longValue();
                 }
@@ -409,7 +416,6 @@
      */
     protected void _decodeBase64(String str, ByteArrayBuilder builder, Base64Variant b64variant) throws IOException
     {
-        // just call helper method introduced in 2.2.3
         try {
             b64variant.decode(str, builder);
         } catch (IllegalArgumentException e) {
@@ -451,17 +457,48 @@
     }
 
     protected void _reportInvalidEOF() throws JsonParseException {
-        _reportInvalidEOF(" in "+_currToken);
+        _reportInvalidEOF(" in "+_currToken, _currToken);
     }
 
-    protected void _reportInvalidEOF(String msg) throws JsonParseException {
-        _reportError("Unexpected end-of-input"+msg);
+    /**
+     * @since 2.8
+     */
+    protected void _reportInvalidEOFInValue(JsonToken type) throws JsonParseException {
+        String msg;
+        if (type == JsonToken.VALUE_STRING) {
+            msg = " in a String value";
+        } else if ((type == JsonToken.VALUE_NUMBER_INT)
+                || (type == JsonToken.VALUE_NUMBER_FLOAT)) {
+            msg = " in a Number value";
+        } else {
+            msg = " in a value";
+        }
+        _reportInvalidEOF(msg, type);
     }
 
+    /**
+     * @since 2.8
+     */
+    protected void _reportInvalidEOF(String msg, JsonToken currToken) throws JsonParseException {
+        throw new JsonEOFException(this, currToken, "Unexpected end-of-input"+msg);
+    }
+
+    /**
+     * @deprecated Since 2.8 use {@link #_reportInvalidEOF(String, JsonToken)} instead
+     */
+    @Deprecated // since 2.8
     protected void _reportInvalidEOFInValue() throws JsonParseException {
         _reportInvalidEOF(" in a value");
     }
-
+    
+    /**
+     * @deprecated Since 2.8 use {@link #_reportInvalidEOF(String, JsonToken)} instead
+     */
+    @Deprecated // since 2.8
+    protected void _reportInvalidEOF(String msg) throws JsonParseException {
+        throw new JsonEOFException(this, null, "Unexpected end-of-input"+msg);
+    }
+    
     protected void _reportMissingRootWS(int ch) throws JsonParseException {
         _reportUnexpectedChar(ch, "Expected space separating root-level values");
     }
diff --git a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
index d395b11..8c23687 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
@@ -146,11 +146,16 @@
      */
 
     @Override public JsonToken getCurrentToken() { return _currToken; }
+    @Override public JsonToken currentToken() { return _currToken; }
 
     @Override public final int getCurrentTokenId() {
         final JsonToken t = _currToken;
         return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
     }
+    @Override public final int currentTokenId() {
+        final JsonToken t = _currToken;
+        return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
+    }
 
     @Override public boolean hasCurrentToken() { return _currToken != null; }
     @Override public boolean hasTokenId(int id) {
diff --git a/src/main/java/com/fasterxml/jackson/core/io/DataOutputAsStream.java b/src/main/java/com/fasterxml/jackson/core/io/DataOutputAsStream.java
new file mode 100644
index 0000000..5fa8cad
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/core/io/DataOutputAsStream.java
@@ -0,0 +1,44 @@
+package com.fasterxml.jackson.core.io;
+
+import java.io.*;
+
+/**
+ * Helper class to support use of {@link DataOutput} for output, directly,
+ * without caller having to provide for implementation.
+ *
+ * @since 2.8
+ */
+public class DataOutputAsStream extends OutputStream
+{
+    protected final DataOutput _output;
+
+    public DataOutputAsStream(DataOutput out) {
+        super();
+        _output = out;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        _output.write(b);
+    }
+
+    @Override
+    public void write(byte b[]) throws IOException {
+        _output.write(b, 0, b.length);
+    }
+
+    @Override
+    public void write(byte b[], int offset, int length) throws IOException {
+        _output.write(b, offset, length);
+    }
+
+    // These are no-ops, base class impl works fine
+
+    /*
+    @Override
+    public void flush() throws IOException { }
+
+    @Override
+    public void close() throws IOException { }
+    */
+}
diff --git a/src/main/java/com/fasterxml/jackson/core/io/IOContext.java b/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
index a4675be..18f50c8 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
@@ -270,12 +270,17 @@
     }
 
     protected final void _verifyRelease(byte[] toRelease, byte[] src) {
-        if ((toRelease != src) && (toRelease.length <= src.length)) { throw wrongBuf(); }
+        // 07-Mar-2016, tatu: As per [core#255], only prevent shrinking of buffer
+        if ((toRelease != src) && (toRelease.length < src.length)) { throw wrongBuf(); }
     }
 
     protected final void _verifyRelease(char[] toRelease, char[] src) {
-        if ((toRelease != src) && (toRelease.length <= src.length)) { throw wrongBuf(); }
+        // 07-Mar-2016, tatu: As per [core#255], only prevent shrinking of buffer
+        if ((toRelease != src) && (toRelease.length < src.length)) { throw wrongBuf(); }
     }
 
-    private IllegalArgumentException wrongBuf() { return new IllegalArgumentException("Trying to release buffer not owned by the context"); }
+    private IllegalArgumentException wrongBuf() {
+        // sanity check failed; trying to return different, smaller buffer.
+        return new IllegalArgumentException("Trying to release buffer smaller than original");
+    }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/io/InputDecorator.java b/src/main/java/com/fasterxml/jackson/core/io/InputDecorator.java
index cac1162..eb98a8c 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/InputDecorator.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/InputDecorator.java
@@ -49,7 +49,30 @@
      */
     public abstract InputStream decorate(IOContext ctxt, byte[] src, int offset, int length)
         throws IOException;
-    
+
+    /**
+     * Method called by {@link com.fasterxml.jackson.core.JsonFactory} instance when
+     * creating parser given an {@link DataInput}, when this decorator
+     * has been registered.
+     *<p>
+     * Default implementation simply throws {@link UnsupportedOperationException}
+     * 
+     * @param ctxt IO context in use (provides access to declared encoding).
+     *   NOTE: at this point context may not have all information initialized;
+     *   specifically auto-detected encoding is only available once parsing starts,
+     *   which may occur only after this method is called.
+     * @param input Original input source
+     * 
+     * @return InputStream to use; either 'input' as is, or decorator
+     *   version that typically delogates to 'input'
+     * 
+     * @since 2.8
+     */
+    public DataInput decorate(IOContext ctxt, DataInput input)
+        throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * Method called by {@link com.fasterxml.jackson.core.JsonFactory} instance when
      * creating parser given an {@link Reader}, when this decorator
diff --git a/src/main/java/com/fasterxml/jackson/core/io/JsonEOFException.java b/src/main/java/com/fasterxml/jackson/core/io/JsonEOFException.java
new file mode 100644
index 0000000..3660c46
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/core/io/JsonEOFException.java
@@ -0,0 +1,37 @@
+package com.fasterxml.jackson.core.io;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+
+/**
+ * Specialized {@link JsonParseException} that is thrown when end-of-input
+ * is reached unexpectedly, either within token being decoded, or during
+ * skipping of intervening white-space that is not between root-level
+ * tokens (that is, is within JSON Object or JSON Array construct).
+ *
+ * @since 2.8
+ */
+public class JsonEOFException extends JsonParseException
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Type of token that was being decoded, if parser had enough information
+     * to recognize type (such as starting double-quote for Strings)
+     */
+    protected final JsonToken _token;
+    
+    public JsonEOFException(JsonParser p, JsonToken token, String msg) {
+        super(p, msg);
+        _token = token;
+    }
+
+    /**
+     * Accessor for possibly available information about token that was being
+     * decoded while encountering end of input.
+     */
+    public JsonToken getTokenBeingDecoded() {
+        return _token;
+    }
+}
diff --git a/src/main/java/com/fasterxml/jackson/core/io/JsonStringEncoder.java b/src/main/java/com/fasterxml/jackson/core/io/JsonStringEncoder.java
index 07956eb..85521cb 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/JsonStringEncoder.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/JsonStringEncoder.java
@@ -149,6 +149,44 @@
     }
 
     /**
+     * Method that will quote text contents using JSON standard quoting,
+     * and append results to a supplied {@link StringBuilder}.
+     * Use this variant if you have e.g. a {@link StringBuilder} and want to avoid superfluous copying of it.
+     *
+     * @since 2.8
+     */
+    public void quoteAsString(CharSequence input, StringBuilder output)
+    {
+        final int[] escCodes = CharTypes.get7BitOutputEscapes();
+        final int escCodeCount = escCodes.length;
+        int inPtr = 0;
+        final int inputLen = input.length();
+
+        outer:
+        while (inPtr < inputLen) {
+            tight_loop:
+            while (true) {
+                char c = input.charAt(inPtr);
+                if (c < escCodeCount && escCodes[c] != 0) {
+                    break tight_loop;
+                }
+                output.append(c);
+                if (++inPtr >= inputLen) {
+                    break outer;
+                }
+            }
+            // something to escape; 2 or 6-char variant?
+            char d = input.charAt(inPtr++);
+            int escCode = escCodes[d];
+            int length = (escCode < 0)
+                    ? _appendNumeric(d, _qbuf)
+                    : _appendNamed(escCode, _qbuf);
+                    ;
+            output.append(_qbuf, 0, length);
+        }
+    }
+
+    /**
      * Will quote given JSON String value using standard quoting, encode
      * results as UTF-8, and return result as a byte array.
      */
diff --git a/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java b/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
index 0cdf8c7..9c3e04b 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
@@ -2,53 +2,41 @@
 
 public final class NumberOutput
 {
-    private final static char NC = (char) 0;
-
     private static int MILLION = 1000000;
     private static int BILLION = 1000000000;
-    private static long TEN_BILLION_L = 10000000000L;
-    private static long THOUSAND_L = 1000L;
+    private static long BILLION_L = 1000000000L;
 
     private static long MIN_INT_AS_LONG = (long) Integer.MIN_VALUE;
     private static long MAX_INT_AS_LONG = (long) Integer.MAX_VALUE;
 
+    final static String SMALLEST_INT = String.valueOf(Integer.MIN_VALUE);
     final static String SMALLEST_LONG = String.valueOf(Long.MIN_VALUE);
 
-    private final static char[] LEAD_3 = new char[4000];
-    private final static char[] FULL_3 = new char[4000];
+    /**
+     * Encoded representations of 3-decimal-digit indexed values, where
+     * 3 LSB are ascii characters
+     *
+     * @since 2.8.2
+     */
+    private final static int[] TRIPLET_TO_CHARS = new int[1000];
+
     static {
         /* Let's fill it with NULLs for ignorable leading digits,
          * and digit chars for others
          */
-        int ix = 0;
+        int fullIx = 0;
         for (int i1 = 0; i1 < 10; ++i1) {
-            char f1 = (char) ('0' + i1);
-            char l1 = (i1 == 0) ? NC : f1;
             for (int i2 = 0; i2 < 10; ++i2) {
-                char f2 = (char) ('0' + i2);
-                char l2 = (i1 == 0 && i2 == 0) ? NC : f2;
                 for (int i3 = 0; i3 < 10; ++i3) {
-                    // Last is never to be empty
-                    char f3 = (char) ('0' + i3);
-                    LEAD_3[ix] = l1;
-                    LEAD_3[ix+1] = l2;
-                    LEAD_3[ix+2] = f3;
-                    FULL_3[ix] = f1;
-                    FULL_3[ix+1] = f2;
-                    FULL_3[ix+2] = f3;
-                    ix += 4;
+                    int enc = ((i1 + '0') << 16)
+                            | ((i2 + '0') << 8)
+                            | (i3 + '0');
+                    TRIPLET_TO_CHARS[fullIx++] = enc;
                 }
             }
         }
     }
 
-    private final static byte[] FULL_TRIPLETS_B = new byte[4000];
-    static {
-        for (int i = 0; i < 4000; ++i) {
-            FULL_TRIPLETS_B[i] = (byte) FULL_3[i];
-        }
-    }
-    
     private final static String[] sSmallIntStrs = new String[] {
         "0","1","2","3","4","5","6","7","8","9","10"
     };
@@ -69,10 +57,9 @@
     {
         if (v < 0) {
             if (v == Integer.MIN_VALUE) {
-                /* Special case: no matching positive value within range;
-                 * let's then "upgrade" to long and output as such.
-                 */
-                return outputLong((long) v, b, off);
+                // Special case: no matching positive value within range;
+                // let's then "upgrade" to long and output as such.
+                return _outputSmallestI(b, off);
             }
             b[off++] = '-';
             v = -v;
@@ -81,16 +68,15 @@
         if (v < MILLION) { // at most 2 triplets...
             if (v < 1000) {
                 if (v < 10) {
-                    b[off++] = (char) ('0' + v);
-                } else {
-                    off = leading3(v, b, off);
+                    b[off] = (char) ('0' + v);
+                    return off+1;
                 }
-            } else {
-                int thousands = v / 1000;
-                v -= (thousands * 1000); // == value % 1000
-                off = leading3(thousands, b, off);
-                off = full3(v, b, off);
+                return _leading3(v, b, off);
             }
+            int thousands = v / 1000;
+            v -= (thousands * 1000); // == value % 1000
+            off = _leading3(thousands, b, off);
+            off = _full3(v, b, off);
             return off;
         }
 
@@ -99,8 +85,7 @@
          * handling 3 triplets. This is possible since we know we
          * can have at most '2' as billion count.
          */
-        boolean hasBillions = (v >= BILLION);
-        if (hasBillions) {
+        if (v >= BILLION) {
             v -= BILLION;
             if (v >= BILLION) {
                 v -= BILLION;
@@ -108,6 +93,7 @@
             } else {
                 b[off++] = '1';
             }
+            return _outputFullBillion(v, b, off);
         }
         int newValue = v / 1000;
         int ones = (v - (newValue * 1000)); // == value % 1000
@@ -115,22 +101,16 @@
         newValue /= 1000;
         int thousands = (v - (newValue * 1000));
         
-        // value now has millions, which have 1, 2 or 3 digits
-        if (hasBillions) {
-            off = full3(newValue, b, off);
-        } else {
-            off = leading3(newValue, b, off);
-        }
-        off = full3(thousands, b, off);
-        off = full3(ones, b, off);
-        return off;
+        off = _leading3(newValue, b, off);
+        off = _full3(thousands, b, off);
+        return _full3(ones, b, off);
     }
 
     public static int outputInt(int v, byte[] b, int off)
     {
         if (v < 0) {
             if (v == Integer.MIN_VALUE) {
-                return outputLong((long) v, b, off);
+                return _outputSmallestI(b, off);
             }
             b[off++] = '-';
             v = -v;
@@ -141,18 +121,17 @@
                 if (v < 10) {
                     b[off++] = (byte) ('0' + v);
                 } else {
-                    off = leading3(v, b, off);
+                    off = _leading3(v, b, off);
                 }
             } else {
                 int thousands = v / 1000;
                 v -= (thousands * 1000); // == value % 1000
-                off = leading3(thousands, b, off);
-                off = full3(v, b, off);
+                off = _leading3(thousands, b, off);
+                off = _full3(v, b, off);
             }
             return off;
         }
-        boolean hasB = (v >= BILLION);
-        if (hasB) {
+        if (v >= BILLION) {
             v -= BILLION;
             if (v >= BILLION) {
                 v -= BILLION;
@@ -160,23 +139,18 @@
             } else {
                 b[off++] = '1';
             }
+            return _outputFullBillion(v, b, off);
         }
         int newValue = v / 1000;
         int ones = (v - (newValue * 1000)); // == value % 1000
         v = newValue;
         newValue /= 1000;
         int thousands = (v - (newValue * 1000));
-        
-        if (hasB) {
-            off = full3(newValue, b, off);
-        } else {
-            off = leading3(newValue, b, off);
-        }
-        off = full3(thousands, b, off);
-        off = full3(ones, b, off);
-        return off;
+        off = _leading3(newValue, b, off);
+        off = _full3(thousands, b, off);
+        return _full3(ones, b, off);
     }
-    
+
     /**
      * @return Offset within buffer after outputting int
      */
@@ -184,17 +158,11 @@
     {
         // First: does it actually fit in an int?
         if (v < 0L) {
-            /* MIN_INT is actually printed as long, just because its
-             * negation is not an int but long
-             */
             if (v > MIN_INT_AS_LONG) {
                 return outputInt((int) v, b, off);
             }
             if (v == Long.MIN_VALUE) {
-                // Special case: no matching positive value within range
-                int len = SMALLEST_LONG.length();
-                SMALLEST_LONG.getChars(0, len, b, off);
-                return (off + len);
+                return _outputSmallestL(b, off);
             }
             b[off++] = '-';
             v = -v;
@@ -204,34 +172,21 @@
             }
         }
 
-        /* Ok: real long print. Need to first figure out length
-         * in characters, and then print in from end to beginning
-         */
-        int origOffset = off;
-        off += calcLongStrLength(v);
-        int ptr = off;
+        // Ok, let's separate last 9 digits (3 x full sets of 3)
+        long upper = v / BILLION_L;
+        v -= (upper * BILLION_L);
 
-        // First, with long arithmetics:
-        while (v > MAX_INT_AS_LONG) { // full triplet
-            ptr -= 3;
-            long newValue = v / THOUSAND_L;
-            int triplet = (int) (v - newValue * THOUSAND_L);
-            full3(triplet, b, ptr);
-            v = newValue;
+        // two integers?
+        if (upper < BILLION_L) {
+            off = _outputUptoBillion((int) upper, b, off);
+        } else {
+            // no, two ints and bits; hi may be about 16 or so
+            long hi = upper / BILLION_L;
+            upper -= (hi * BILLION_L);
+            off = _leading3((int) hi, b, off);
+            off = _outputFullBillion((int) upper, b, off);
         }
-        // Then with int arithmetics:
-        int ivalue = (int) v;
-        while (ivalue >= 1000) { // still full triplet
-            ptr -= 3;
-            int newValue = ivalue / 1000;
-            int triplet = ivalue - (newValue * 1000);
-            full3(triplet, b, ptr);
-            ivalue = newValue;
-        }
-        // And finally, if anything remains, partial triplet
-        leading3(ivalue, b, origOffset);
-
-        return off;
+        return _outputFullBillion((int) v, b, off);
     }
 
     public static int outputLong(long v, byte[] b, int off)
@@ -241,12 +196,7 @@
                 return outputInt((int) v, b, off);
             }
             if (v == Long.MIN_VALUE) {
-                // Special case: no matching positive value within range
-                int len = SMALLEST_LONG.length();
-                for (int i = 0; i < len; ++i) {
-                    b[off++] = (byte) SMALLEST_LONG.charAt(i);
-                }
-                return off;
+                return _outputSmallestL(b, off);
             }
             b[off++] = '-';
             v = -v;
@@ -255,41 +205,33 @@
                 return outputInt((int) v, b, off);
             }
         }
-        int origOff = off;
-        off += calcLongStrLength(v);
-        int ptr = off;
 
-        // First, with long arithmetics:
-        while (v > MAX_INT_AS_LONG) { // full triplet
-            ptr -= 3;
-            long newV = v / THOUSAND_L;
-            int t = (int) (v - newV * THOUSAND_L);
-            full3(t, b, ptr);
-            v = newV;
+        // Ok, let's separate last 9 digits (3 x full sets of 3)
+        long upper = v / BILLION_L;
+        v -= (upper * BILLION_L);
+
+        // two integers?
+        if (upper < BILLION_L) {
+            off = _outputUptoBillion((int) upper, b, off);
+        } else {
+            // no, two ints and bits; hi may be about 16 or so
+            long hi = upper / BILLION_L;
+            upper -= (hi * BILLION_L);
+            off = _leading3((int) hi, b, off);
+            off = _outputFullBillion((int) upper, b, off);
         }
-        // Then with int arithmetics:
-        int ivalue = (int) v;
-        while (ivalue >= 1000) { // still full triplet
-            ptr -= 3;
-            int newV = ivalue / 1000;
-            int t = ivalue - (newV * 1000);
-            full3(t, b, ptr);
-            ivalue = newV;
-        }
-        leading3(ivalue, b, origOff);
-        return off;
+        return _outputFullBillion((int) v, b, off);
     }
-    
+
     /*
     /**********************************************************
-    /* Secondary convenience serialization methods
+    /* Convenience serialization methods
     /**********************************************************
      */
 
     /* !!! 05-Aug-2008, tatus: Any ways to further optimize
      *   these? (or need: only called by diagnostics methods?)
      */
-
     public static String toString(int v)
     {
         // Lookup table for small values
@@ -325,78 +267,231 @@
 
     /*
     /**********************************************************
-    /* Internal methods
+    /* Internal helper methods
     /**********************************************************
      */
 
-    private static int leading3(int t, char[] b, int off)
+    private static int _outputUptoBillion(int v, char[] b, int off)
     {
-        int digitOffset = (t << 2);
-        char c = LEAD_3[digitOffset++];
-        if (c != NC) {
-            b[off++] = c;
-        }
-        c = LEAD_3[digitOffset++];
-        if (c != NC) {
-            b[off++] = c;
-        }
-        // Last is required to be non-empty
-        b[off++] = LEAD_3[digitOffset];
-        return off;
-    }
-
-    private static int leading3(int t, byte[] b, int off)
-    {
-        int digitOffset = (t << 2);
-        char c = LEAD_3[digitOffset++];
-        if (c != NC) {
-            b[off++] = (byte) c;
-        }
-        c = LEAD_3[digitOffset++];
-        if (c != NC) {
-            b[off++] = (byte) c;
-        }
-        // Last is required to be non-empty
-        b[off++] = (byte) LEAD_3[digitOffset];
-        return off;
-    }
-    
-    private static int full3(int t, char[] b, int off)
-    {
-        int digitOffset = (t << 2);
-        b[off++] = FULL_3[digitOffset++];
-        b[off++] = FULL_3[digitOffset++];
-        b[off++] = FULL_3[digitOffset];
-        return off;
-    }
-
-    private static int full3(int t, byte[] b, int off)
-    {
-        int digitOffset = (t << 2);
-        b[off++] = FULL_TRIPLETS_B[digitOffset++];
-        b[off++] = FULL_TRIPLETS_B[digitOffset++];
-        b[off++] = FULL_TRIPLETS_B[digitOffset];
-        return off;
-    }
-    
-    /**
-     *<p>
-     * Pre-conditions: <code>c</code> is positive, and larger than
-     * Integer.MAX_VALUE (about 2 billions).
-     */
-    private static int calcLongStrLength(long v)
-    {
-        int len = 10;
-        long cmp = TEN_BILLION_L;
-
-        // 19 is longest, need to worry about overflow
-        while (v >= cmp) {
-            if (len == 19) {
-                break;
+        if (v < MILLION) { // at most 2 triplets...
+            if (v < 1000) {
+                return _leading3(v, b, off);
             }
-            ++len;
-            cmp = (cmp << 3) + (cmp << 1); // 10x
+            int thousands = v / 1000;
+            int ones = v - (thousands * 1000); // == value % 1000
+            return _outputUptoMillion(b, off, thousands, ones);
         }
-        return len;
+        int thousands = v / 1000;
+        int ones = (v - (thousands * 1000)); // == value % 1000
+        int millions = thousands / 1000;
+        thousands -= (millions * 1000);
+
+        off = _leading3(millions, b, off);
+
+        int enc = TRIPLET_TO_CHARS[thousands];
+        b[off++] = (char) (enc >> 16);
+        b[off++] = (char) ((enc >> 8) & 0x7F);
+        b[off++] = (char) (enc & 0x7F);
+
+        enc = TRIPLET_TO_CHARS[ones];
+        b[off++] = (char) (enc >> 16);
+        b[off++] = (char) ((enc >> 8) & 0x7F);
+        b[off++] = (char) (enc & 0x7F);
+
+        return off;
+    }
+    
+    private static int _outputFullBillion(int v, char[] b, int off)
+    {
+        int thousands = v / 1000;
+        int ones = (v - (thousands * 1000)); // == value % 1000
+        int millions = thousands / 1000;
+
+        int enc = TRIPLET_TO_CHARS[millions];
+        b[off++] = (char) (enc >> 16);
+        b[off++] = (char) ((enc >> 8) & 0x7F);
+        b[off++] = (char) (enc & 0x7F);
+
+        thousands -= (millions * 1000);
+        enc = TRIPLET_TO_CHARS[thousands];
+        b[off++] = (char) (enc >> 16);
+        b[off++] = (char) ((enc >> 8) & 0x7F);
+        b[off++] = (char) (enc & 0x7F);
+
+        enc = TRIPLET_TO_CHARS[ones];
+        b[off++] = (char) (enc >> 16);
+        b[off++] = (char) ((enc >> 8) & 0x7F);
+        b[off++] = (char) (enc & 0x7F);
+
+        return off;
+    }
+    
+    private static int _outputUptoBillion(int v, byte[] b, int off)
+    {
+        if (v < MILLION) { // at most 2 triplets...
+            if (v < 1000) {
+                return _leading3(v, b, off);
+            }
+            int thousands = v / 1000;
+            int ones = v - (thousands * 1000); // == value % 1000
+            return _outputUptoMillion(b, off, thousands, ones);
+        }
+        int thousands = v / 1000;
+        int ones = (v - (thousands * 1000)); // == value % 1000
+        int millions = thousands / 1000;
+        thousands -= (millions * 1000);
+
+        off = _leading3(millions, b, off);
+
+        int enc = TRIPLET_TO_CHARS[thousands];
+        b[off++] = (byte) (enc >> 16);
+        b[off++] = (byte) (enc >> 8);
+        b[off++] = (byte) enc;
+
+        enc = TRIPLET_TO_CHARS[ones];
+        b[off++] = (byte) (enc >> 16);
+        b[off++] = (byte) (enc >> 8);
+        b[off++] = (byte) enc;
+
+        return off;
+    }
+
+    private static int _outputFullBillion(int v, byte[] b, int off)
+    {
+        int thousands = v / 1000;
+        int ones = (v - (thousands * 1000)); // == value % 1000
+        int millions = thousands / 1000;
+        thousands -= (millions * 1000);
+
+        int enc = TRIPLET_TO_CHARS[millions];
+        b[off++] = (byte) (enc >> 16);
+        b[off++] = (byte) (enc >> 8);
+        b[off++] = (byte) enc;
+
+        enc = TRIPLET_TO_CHARS[thousands];
+        b[off++] = (byte) (enc >> 16);
+        b[off++] = (byte) (enc >> 8);
+        b[off++] = (byte) enc;
+
+        enc = TRIPLET_TO_CHARS[ones];
+        b[off++] = (byte) (enc >> 16);
+        b[off++] = (byte) (enc >> 8);
+        b[off++] = (byte) enc;
+
+        return off;
+    }
+
+    private static int _outputUptoMillion(char[] b, int off, int thousands, int ones)
+    {
+        int enc = TRIPLET_TO_CHARS[thousands];
+        if (thousands > 9) {
+            if (thousands > 99) {
+                b[off++] = (char) (enc >> 16);
+            }
+            b[off++] = (char) ((enc >> 8) & 0x7F);
+        }
+        b[off++] = (char) (enc & 0x7F);
+        // and then full
+        enc = TRIPLET_TO_CHARS[ones];
+        b[off++] = (char) (enc >> 16);
+        b[off++] = (char) ((enc >> 8) & 0x7F);
+        b[off++] = (char) (enc & 0x7F);
+        return off;
+    }
+
+    private static int _outputUptoMillion(byte[] b, int off, int thousands, int ones)
+    {
+        int enc = TRIPLET_TO_CHARS[thousands];
+        if (thousands > 9) {
+            if (thousands > 99) {
+                b[off++] = (byte) (enc >> 16);
+            }
+            b[off++] = (byte) (enc >> 8);
+        }
+        b[off++] = (byte) enc;
+        // and then full
+        enc = TRIPLET_TO_CHARS[ones];
+        b[off++] = (byte) (enc >> 16);
+        b[off++] = (byte) (enc >> 8);
+        b[off++] = (byte) enc;
+        return off;
+    }
+    
+    private static int _leading3(int t, char[] b, int off)
+    {
+        int enc = TRIPLET_TO_CHARS[t];
+        if (t > 9) {
+            if (t > 99) {
+                b[off++] = (char) (enc >> 16);
+            }
+            b[off++] = (char) ((enc >> 8) & 0x7F);
+        }
+        b[off++] = (char) (enc & 0x7F);
+        return off;
+    }
+
+    private static int _leading3(int t, byte[] b, int off)
+    {
+        int enc = TRIPLET_TO_CHARS[t];
+        if (t > 9) {
+            if (t > 99) {
+                b[off++] = (byte) (enc >> 16);
+            }
+            b[off++] = (byte) (enc >> 8);
+        }
+        b[off++] = (byte) enc;
+        return off;
+    }
+
+    private static int _full3(int t, char[] b, int off)
+    {
+        int enc = TRIPLET_TO_CHARS[t];
+        b[off++] = (char) (enc >> 16);
+        b[off++] = (char) ((enc >> 8) & 0x7F);
+        b[off++] = (char) (enc & 0x7F);
+        return off;
+    }
+
+    private static int _full3(int t, byte[] b, int off)
+    {
+        int enc = TRIPLET_TO_CHARS[t];
+        b[off++] = (byte) (enc >> 16);
+        b[off++] = (byte) (enc >> 8);
+        b[off++] = (byte) enc;
+        return off;
+    }
+
+    // // // Special cases for where we can not flip the sign bit
+
+    private static int _outputSmallestL(char[] b, int off)
+    {
+        int len = SMALLEST_LONG.length();
+        SMALLEST_LONG.getChars(0, len, b, off);
+        return (off + len);
+    }
+
+    private static int _outputSmallestL(byte[] b, int off)
+    {
+        int len = SMALLEST_LONG.length();
+        for (int i = 0; i < len; ++i) {
+            b[off++] = (byte) SMALLEST_LONG.charAt(i);
+        }
+        return off;
+    }
+
+    private static int _outputSmallestI(char[] b, int off)
+    {
+        int len = SMALLEST_INT.length();
+        SMALLEST_INT.getChars(0, len, b, off);
+        return (off + len);
+    }
+
+    private static int _outputSmallestI(byte[] b, int off)
+    {
+        int len = SMALLEST_INT.length();
+        for (int i = 0; i < len; ++i) {
+            b[off++] = (byte) SMALLEST_INT.charAt(i);
+        }
+        return off;
     }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java b/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java
index 00b52c6..c598a1e 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java
@@ -15,7 +15,7 @@
  */
 public final class SegmentedStringWriter extends Writer
 {
-    final protected TextBuffer _buffer;
+    final private TextBuffer _buffer;
 
     public SegmentedStringWriter(BufferRecycler br) {
         super();
diff --git a/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java b/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
index 6bbe412..6ff84e9 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
@@ -28,9 +28,9 @@
     /**********************************************************
      */
 
-    protected final IOContext _context;
+    private final IOContext _context;
 
-    protected final InputStream _in;
+    private final InputStream _in;
 
     /*
     /**********************************************************
@@ -38,7 +38,7 @@
     /**********************************************************
      */
 
-    protected final byte[] _inputBuffer;
+    private final byte[] _inputBuffer;
 
     private int _inputPtr;
 
@@ -63,7 +63,7 @@
      *<p>
      * Note: includes possible BOMs, if those were part of the input.
      */
-    protected int _inputProcessed;
+//    private int _inputProcessed;
 
     /*
     /**********************************************************
@@ -71,9 +71,12 @@
     /**********************************************************
      */
 
-    protected boolean _bigEndian = true;
+    /**
+     * Whether input has been detected to be in Big-Endian encoding or not.
+     */
+    private boolean _bigEndian = true;
 
-    protected int _bytesPerChar; // 0 means "dunno yet"
+    private int _bytesPerChar; // 0 means "dunno yet"
 
     /*
     /**********************************************************
@@ -86,7 +89,7 @@
         _in = in;
         _inputBuffer = ctxt.allocReadIOBuffer();
         _inputEnd = _inputPtr = 0;
-        _inputProcessed = 0;
+//        _inputProcessed = 0;
         _bufferRecyclable = true;
     }
 
@@ -97,7 +100,7 @@
         _inputPtr = inputStart;
         _inputEnd = (inputStart + inputLen);
         // Need to offset this for correct location info
-        _inputProcessed = -inputStart;
+//        _inputProcessed = -inputStart;
         _bufferRecyclable = false;
     }
 
@@ -172,6 +175,34 @@
         return enc;
     }
 
+    /**
+     * Helper method that may be called to see if given {@link DataInput}
+     * has BOM marker, and if so, to skip it.
+     * @throws IOException 
+     *
+     * @since 2.8
+     */
+    public static int skipUTF8BOM(DataInput input) throws IOException
+    {
+        int b = input.readUnsignedByte();
+        if (b != 0xEF) {
+            return b;
+        }
+        // since this is not legal byte in JSON otherwise, except
+        // that we do get BOM; if not, report error
+        b = input.readUnsignedByte();
+        if (b != 0xBB) {
+            throw new IOException("Unexpected byte 0x"+Integer.toHexString(b)
+                +" following 0xEF; should get 0xBB as part of UTF-8 BOM");
+        }
+        b = input.readUnsignedByte();
+        if (b != 0xBF) {
+            throw new IOException("Unexpected byte 0x"+Integer.toHexString(b)
+                +" following 0xEF 0xBB; should get 0xBF as part of UTF-8 BOM");
+        }
+        return input.readUnsignedByte();
+    }
+
     /*
     /**********************************************************
     /* Constructing a Reader
@@ -215,7 +246,7 @@
         JsonEncoding enc = detectEncoding();
 
         if (enc == JsonEncoding.UTF8) {
-            /* and without canonicalization, byte-based approach is not performance; just use std UTF-8 reader
+            /* and without canonicalization, byte-based approach is not performant; just use std UTF-8 reader
              * (which is ok for larger input; not so hot for smaller; but this is not a common case)
              */
             if (JsonFactory.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(factoryFeatures)) {
@@ -393,8 +424,11 @@
             return true;
         case 0x0000FFFE: // UCS-4, in-order...
             reportWeirdUCS4("2143"); // throws exception
+            break; // never gets here
         case 0xFEFF0000: // UCS-4, in-order...
             reportWeirdUCS4("3412"); // throws exception
+            break; // never gets here
+        default:
         }
         // Ok, if not, how about 16-bit encoding BOMs?
         int msw = quad >>> 16;
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java b/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
index 1ede298..ac9e87f 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
@@ -111,6 +111,17 @@
 
     /*
     /**********************************************************
+    /* Versioned
+    /**********************************************************
+     */
+
+    @Override
+    public Version version() {
+        return VersionUtil.versionFor(getClass());
+    }
+
+    /*
+    /**********************************************************
     /* Overridden configuration methods
     /**********************************************************
      */
@@ -176,17 +187,6 @@
         _rootValueSeparator = sep;
         return this;
     }
-    
-    /*
-    /**********************************************************
-    /* Versioned
-    /**********************************************************
-     */
-
-    @Override
-    public Version version() {
-        return VersionUtil.versionFor(getClass());
-    }
 
     /*
     /**********************************************************
@@ -202,4 +202,46 @@
         writeFieldName(fieldName);
         writeString(value);
     }
+
+    /*
+    /**********************************************************
+    /* Shared helper methods
+    /**********************************************************
+     */
+
+    protected void _verifyPrettyValueWrite(String typeMsg, int status) throws IOException
+    {
+        // If we have a pretty printer, it knows what to do:
+        switch (status) {
+        case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array
+            _cfgPrettyPrinter.writeArrayValueSeparator(this);
+            break;
+        case JsonWriteContext.STATUS_OK_AFTER_COLON:
+            _cfgPrettyPrinter.writeObjectFieldValueSeparator(this);
+            break;
+        case JsonWriteContext.STATUS_OK_AFTER_SPACE:
+            _cfgPrettyPrinter.writeRootValueSeparator(this);
+            break;
+        case JsonWriteContext.STATUS_OK_AS_IS:
+            // First entry, but of which context?
+            if (_writeContext.inArray()) {
+                _cfgPrettyPrinter.beforeArrayValues(this);
+            } else if (_writeContext.inObject()) {
+                _cfgPrettyPrinter.beforeObjectEntries(this);
+            }
+            break;
+        case JsonWriteContext.STATUS_EXPECT_NAME:
+            _reportCantWriteValueExpectName(typeMsg);
+            break;
+        default:
+            _throwInternal();
+            break;
+        }
+    }
+
+    protected void _reportCantWriteValueExpectName(String typeMsg) throws IOException
+    {
+        _reportError(String.format("Can not %s, expecting field name (context: %s)",
+                typeMsg, _writeContext.typeDesc()));
+    }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java b/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java
index cf09633..e1b0479 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java
@@ -229,6 +229,7 @@
             sb.append(']');
             break;
         case TYPE_OBJECT:
+        default:
             sb.append('{');
             if (_currentName != null) {
                 sb.append('"');
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java b/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java
index dadec64..c350e22 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java
@@ -44,7 +44,7 @@
      */
 
     /**
-     * Name of the field of which value is to be parsed; only
+     * Name of the field of which value is to be written; only
      * used for OBJECT contexts
      */
     protected String _currentName;
@@ -55,8 +55,8 @@
     protected Object _currentValue;
 
     /**
-     * Marker used to indicate that we just received a name, and
-     * now expect a value
+     * Marker used to indicate that we just wrote a name, and
+     * now expect a value to write
      */
     protected boolean _gotName;
 
@@ -162,7 +162,7 @@
      * @return Index of the field entry (0-based)
      */
     public int writeFieldName(String name) throws JsonProcessingException {
-        if (_gotName) {
+        if ((_type != TYPE_OBJECT) || _gotName) {
             return STATUS_EXPECT_VALUE;
         }
         _gotName = true;
diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
index c0bad36..dc80f62 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
@@ -163,39 +163,16 @@
 
     @Override public Object getInputSource() { return _reader; }
 
-    @Override
-    protected boolean loadMore() throws IOException
-    {
-        final int bufSize = _inputEnd;
-
-        _currInputProcessed += bufSize;
-        _currInputRowStart -= bufSize;
-
-        // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
-        //   this increase to avoid "moving" name-offset, resulting most likely
-        //   in negative value, which is fine as combine value remains unchanged.
-        _nameStartOffset -= bufSize;
-
-        if (_reader != null) {
-            int count = _reader.read(_inputBuffer, 0, _inputBuffer.length);
-            if (count > 0) {
-                _inputPtr = 0;
-                _inputEnd = count;
-                return true;
-            }
-            // End of input
-            _closeInput();
-            // Should never return 0, so let's fail
-            if (count == 0) {
-                throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd);
-            }
-        }
-        return false;
-    }
-
+    @Deprecated // since 2.8
     protected char getNextChar(String eofMsg) throws IOException {
+        return getNextChar(eofMsg, null);
+    }
+    
+    protected char getNextChar(String eofMsg, JsonToken forToken) throws IOException {
         if (_inputPtr >= _inputEnd) {
-            if (!loadMore()) { _reportInvalidEOF(eofMsg); }
+            if (!_loadMore()) {
+                _reportInvalidEOF(eofMsg, forToken);
+            }
         }
         return _inputBuffer[_inputPtr++];
     }
@@ -240,6 +217,45 @@
 
     /*
     /**********************************************************
+    /* Low-level access, supporting
+    /**********************************************************
+     */
+
+    protected void _loadMoreGuaranteed() throws IOException {
+        if (!_loadMore()) { _reportInvalidEOF(); }
+    }
+    
+    protected boolean _loadMore() throws IOException
+    {
+        final int bufSize = _inputEnd;
+
+        _currInputProcessed += bufSize;
+        _currInputRowStart -= bufSize;
+
+        // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+        //   this increase to avoid "moving" name-offset, resulting most likely
+        //   in negative value, which is fine as combine value remains unchanged.
+        _nameStartOffset -= bufSize;
+
+        if (_reader != null) {
+            int count = _reader.read(_inputBuffer, 0, _inputBuffer.length);
+            if (count > 0) {
+                _inputPtr = 0;
+                _inputEnd = count;
+                return true;
+            }
+            // End of input
+            _closeInput();
+            // Should never return 0, so let's fail
+            if (count == 0) {
+                throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd);
+            }
+        }
+        return false;
+    }
+
+    /*
+    /**********************************************************
     /* Public API, data access
     /**********************************************************
      */
@@ -264,6 +280,33 @@
         return _getText2(t);
     }
 
+    @Override // since 2.8
+    public int getText(Writer writer) throws IOException
+    {
+        JsonToken t = _currToken;
+        if (t == JsonToken.VALUE_STRING) {
+            if (_tokenIncomplete) {
+                _tokenIncomplete = false;
+                _finishString(); // only strings can be incomplete
+            }
+            return _textBuffer.contentsToWriter(writer);
+        }
+        if (t == JsonToken.FIELD_NAME) {
+            String n = _parsingContext.getCurrentName();
+            writer.write(n);
+            return n.length();
+        }
+        if (t != null) {
+            if (t.isNumeric()) {
+                return _textBuffer.contentsToWriter(writer);
+            }
+            char[] ch = t.asCharArray();
+            writer.write(ch);
+            return ch.length;
+        }
+        return 0;
+    }
+    
     // // // Let's override default impls for improved performance
 
     // @since 2.1
@@ -457,7 +500,7 @@
             char ch;
             do {
                 if (_inputPtr >= _inputEnd) {
-                    loadMoreGuaranteed();
+                    _loadMoreGuaranteed();
                 }
                 ch = _inputBuffer[_inputPtr++];
             } while (ch <= INT_SPACE);
@@ -484,7 +527,7 @@
             // then second base64 char; can't get padding yet, nor ws
 
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++];
             bits = b64variant.decodeBase64Char(ch);
@@ -495,7 +538,7 @@
 
             // third base64 char; can be padding, but not ws
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++];
             bits = b64variant.decodeBase64Char(ch);
@@ -514,7 +557,7 @@
                 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
                     // Ok, must get padding
                     if (_inputPtr >= _inputEnd) {
-                        loadMoreGuaranteed();
+                        _loadMoreGuaranteed();
                     }
                     ch = _inputBuffer[_inputPtr++];
                     if (!b64variant.usesPaddingChar(ch)) {
@@ -530,7 +573,7 @@
             decodedData = (decodedData << 6) | bits;
             // fourth and last base64 char; can be padding, but not ws
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++];
             bits = b64variant.decodeBase64Char(ch);
@@ -600,9 +643,8 @@
         }
         int i = _skipWSOrEnd();
         if (i < 0) { // end-of-input
-            /* 19-Feb-2009, tatu: Should actually close/release things
-             *    like input source, symbol table and recyclable buffers now.
-             */
+            // Should actually close/release things
+            // like input source, symbol table and recyclable buffers now.
             close();
             return (_currToken = null);
         }
@@ -667,9 +709,8 @@
             }
             t = JsonToken.START_OBJECT;
             break;
-        case ']':
         case '}':
-            // Error: neither is valid at this point; valid closers have
+            // Error: } is not valid at this point; valid closers have
             // been handled earlier
             _reportUnexpectedChar(i, "expected a value");
         case 't':
@@ -734,6 +775,14 @@
         return (_currToken = t);
     }
 
+    @Override
+    public void finishToken() throws IOException {
+        if (_tokenIncomplete) {
+            _tokenIncomplete = false;
+            _finishString(); // only strings can be incomplete
+        }
+    }
+
     /*
     /**********************************************************
     /* Public API, nextXxx() overrides
@@ -1070,6 +1119,20 @@
         case '8':
         case '9':
             return (_currToken = _parsePosNumber(i));
+        /*
+         * This check proceeds only if the Feature.ALLOW_MISSING_VALUES is enabled
+         * The Check is for missing values. Incase of missing values in an array, the next token will be either ',' or ']'.
+         * This case, decrements the already incremented _inputPtr in the buffer in case of comma(,) 
+         * so that the existing flow goes back to checking the next token which will be comma again and
+         * it continues the parsing.
+         * Also the case returns NULL as current token in case of ',' or ']'.    
+         */
+        case ',':
+        case ']':
+        	if(isEnabled(Feature.ALLOW_MISSING_VALUES)) {
+        		_inputPtr--;
+        		return (_currToken = JsonToken.VALUE_NULL);  
+        	}    
         }
         return (_currToken = _handleOddValue(i));
     }
@@ -1384,7 +1447,8 @@
 
         // This is the place to do leading-zero check(s) too:
         int intLen = 0;
-        char c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : getNextChar("No digit following minus sign");
+        char c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++]
+                : getNextChar("No digit following minus sign", JsonToken.VALUE_NUMBER_INT);
         if (c == '0') {
             c = _verifyNoLeadingZeroes();
         }
@@ -1399,7 +1463,7 @@
                 outPtr = 0;
             }
             outBuf[outPtr++] = c;
-            if (_inputPtr >= _inputEnd && !loadMore()) {
+            if (_inputPtr >= _inputEnd && !_loadMore()) {
                 // EOF is legal for main level int values
                 c = CHAR_NULL;
                 eof = true;
@@ -1423,7 +1487,7 @@
 
             fract_loop:
             while (true) {
-                if (_inputPtr >= _inputEnd && !loadMore()) {
+                if (_inputPtr >= _inputEnd && !_loadMore()) {
                     eof = true;
                     break fract_loop;
                 }
@@ -1474,7 +1538,7 @@
                     outPtr = 0;
                 }
                 outBuf[outPtr++] = c;
-                if (_inputPtr >= _inputEnd && !loadMore()) {
+                if (_inputPtr >= _inputEnd && !_loadMore()) {
                     eof = true;
                     break exp_loop;
                 }
@@ -1518,7 +1582,7 @@
 
     private char _verifyNLZ2() throws IOException
     {
-        if (_inputPtr >= _inputEnd && !loadMore()) {
+        if (_inputPtr >= _inputEnd && !_loadMore()) {
             return '0';
         }
         char ch = _inputBuffer[_inputPtr];
@@ -1531,7 +1595,7 @@
         // if so, just need to skip either all zeroes (if followed by number); or all but one (if non-number)
         ++_inputPtr; // Leading zero to be skipped
         if (ch == INT_0) {
-            while (_inputPtr < _inputEnd || loadMore()) {
+            while (_inputPtr < _inputEnd || _loadMore()) {
                 ch = _inputBuffer[_inputPtr];
                 if (ch < '0' || ch > '9') { // followed by non-number; retain one zero
                     return '0';
@@ -1553,7 +1617,9 @@
     {
         if (ch == 'I') {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) { _reportInvalidEOFInValue(); }
+                if (!_loadMore()) {
+                    _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_INT);
+                }
             }
             ch = _inputBuffer[_inputPtr++];
             if (ch == 'N') {
@@ -1646,8 +1712,8 @@
 
         while (true) {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOF(": was expecting closing '"+((char) endChar)+"' for name");
+                if (!_loadMore()) {
+                    _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
                 }
             }
             char c = _inputBuffer[_inputPtr++];
@@ -1786,10 +1852,8 @@
         // Most likely an error, unless we are to allow single-quote-strings
         switch (i) {
         case '\'':
-            /* [JACKSON-173]: allow single quotes. Unlike with regular
-             * Strings, we'll eagerly parse contents; this so that there's
-             * no need to store information on quote char used.
-             *
+            /* Allow single quotes? Unlike with regular Strings, we'll eagerly parse
+             * contents; this so that there'sno need to store information on quote char used.
              * Also, no separation to fast/slow parsing; we'll just do
              * one regular (~= slowish) parsing, to keep code simple
              */
@@ -1797,6 +1861,21 @@
                 return _handleApos();
             }
             break;
+        case ']':
+            /* 28-Mar-2016: [core#116]: If Feature.ALLOW_MISSING_VALUES is enabled
+             *   we may allow "missing values", that is, encountering a trailing
+             *   comma or closing marker where value would be expected
+             */
+            if (!_parsingContext.inArray()) {
+                break;
+            }
+            // fall through
+        case ',':
+            if (isEnabled(Feature.ALLOW_MISSING_VALUES)) {
+                --_inputPtr;
+                return JsonToken.VALUE_NULL;
+            }
+            break;
         case 'N':
             _matchToken("NaN", 1);
             if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
@@ -1813,8 +1892,8 @@
             break;
         case '+': // note: '-' is taken as number
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOFInValue();
+                if (!_loadMore()) {
+                    _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_INT);
                 }
             }
             return _handleInvalidNumberStart(_inputBuffer[_inputPtr++], false);
@@ -1835,8 +1914,9 @@
 
         while (true) {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOF(": was expecting closing quote for a string value");
+                if (!_loadMore()) {
+                    _reportInvalidEOF(": was expecting closing quote for a string value",
+                            JsonToken.VALUE_STRING);
                 }
             }
             char c = _inputBuffer[_inputPtr++];
@@ -1878,7 +1958,7 @@
 
         while (true) {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) { // acceptable for now (will error out later)
+                if (!_loadMore()) { // acceptable for now (will error out later)
                     break;
                 }
             }
@@ -1959,8 +2039,9 @@
 
         while (true) {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOF(": was expecting closing quote for a string value");
+                if (!_loadMore()) {
+                    _reportInvalidEOF(": was expecting closing quote for a string value",
+                            JsonToken.VALUE_STRING);
                 }
             }
             char c = _inputBuffer[_inputPtr++];
@@ -2005,8 +2086,9 @@
         while (true) {
             if (inPtr >= inLen) {
                 _inputPtr = inPtr;
-                if (!loadMore()) {
-                    _reportInvalidEOF(": was expecting closing quote for a string value");
+                if (!_loadMore()) {
+                    _reportInvalidEOF(": was expecting closing quote for a string value",
+                            JsonToken.VALUE_STRING);
                 }
                 inPtr = _inputPtr;
                 inLen = _inputEnd;
@@ -2046,7 +2128,7 @@
      * (to see if we have \n following \r).
      */
     protected final void _skipCR() throws IOException {
-        if (_inputPtr < _inputEnd || loadMore()) {
+        if (_inputPtr < _inputEnd || _loadMore()) {
             if (_inputBuffer[_inputPtr] == '\n') {
                 ++_inputPtr;
             }
@@ -2111,10 +2193,7 @@
 
     private final int _skipColon2(boolean gotColon) throws IOException
     {
-        while (true) {
-            if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
-            }
+        while (_inputPtr < _inputEnd || _loadMore()) {
             int i = (int) _inputBuffer[_inputPtr++];
             if (i > INT_SPACE) {
                 if (i == INT_SLASH) {
@@ -2146,6 +2225,9 @@
                 }
             }
         }
+        _reportInvalidEOF(" within/between "+_parsingContext.typeDesc()+" entries",
+                null);
+        return -1;
     }
 
     // Variant called when we know there's at least 4 more bytes available
@@ -2200,7 +2282,7 @@
     private final int _skipComma(int i) throws IOException
     {
         if (i != INT_COMMA) {
-            _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
+            _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
         }
         while (_inputPtr < _inputEnd) {
             i = (int) _inputBuffer[_inputPtr++];
@@ -2227,7 +2309,7 @@
 
     private final int _skipAfterComma2() throws IOException
     {
-        while (_inputPtr < _inputEnd || loadMore()) {
+        while (_inputPtr < _inputEnd || _loadMore()) {
             int i = (int) _inputBuffer[_inputPtr++];
             if (i > INT_SPACE) {
                 if (i == INT_SLASH) {
@@ -2252,7 +2334,7 @@
                 }
             }
         }
-        throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries");
+        throw _constructError("Unexpected end-of-input within/between "+_parsingContext.typeDesc()+" entries");
     }
 
     private final int _skipWSOrEnd() throws IOException
@@ -2260,7 +2342,7 @@
         // Let's handle first character separately since it is likely that
         // it is either non-whitespace; or we have longer run of white space
         if (_inputPtr >= _inputEnd) {
-            if (!loadMore()) {
+            if (!_loadMore()) {
                 return _eofAsNextChar();
             }
         }
@@ -2310,7 +2392,7 @@
     {
         while (true) {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) { // We ran out of input...
+                if (!_loadMore()) { // We ran out of input...
                     return _eofAsNextChar();
                 }
             }
@@ -2345,8 +2427,8 @@
             _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)");
         }
         // First: check which comment (if either) it is:
-        if (_inputPtr >= _inputEnd && !loadMore()) {
-            _reportInvalidEOF(" in a comment");
+        if (_inputPtr >= _inputEnd && !_loadMore()) {
+            _reportInvalidEOF(" in a comment", null);
         }
         char c = _inputBuffer[_inputPtr++];
         if (c == '/') {
@@ -2361,11 +2443,11 @@
     private void _skipCComment() throws IOException
     {
         // Ok: need the matching '*/'
-        while ((_inputPtr < _inputEnd) || loadMore()) {
+        while ((_inputPtr < _inputEnd) || _loadMore()) {
             int i = (int) _inputBuffer[_inputPtr++];
             if (i <= '*') {
                 if (i == '*') { // end?
-                    if ((_inputPtr >= _inputEnd) && !loadMore()) {
+                    if ((_inputPtr >= _inputEnd) && !_loadMore()) {
                         break;
                     }
                     if (_inputBuffer[_inputPtr] == INT_SLASH) {
@@ -2386,7 +2468,7 @@
                 }
             }
         }
-        _reportInvalidEOF(" in a comment");
+        _reportInvalidEOF(" in a comment", null);
     }
 
     private boolean _skipYAMLComment() throws IOException
@@ -2401,7 +2483,7 @@
     private void _skipLine() throws IOException
     {
         // Ok: need to find EOF or linefeed
-        while ((_inputPtr < _inputEnd) || loadMore()) {
+        while ((_inputPtr < _inputEnd) || _loadMore()) {
             int i = (int) _inputBuffer[_inputPtr++];
             if (i < INT_SPACE) {
                 if (i == INT_LF) {
@@ -2422,8 +2504,8 @@
     protected char _decodeEscaped() throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            if (!loadMore()) {
-                _reportInvalidEOF(" in character escape sequence");
+            if (!_loadMore()) {
+                _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
             }
         }
         char c = _inputBuffer[_inputPtr++];
@@ -2458,8 +2540,8 @@
         int value = 0;
         for (int i = 0; i < 4; ++i) {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOF(" in character escape sequence");
+                if (!_loadMore()) {
+                    _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
                 }
             }
             int ch = (int) _inputBuffer[_inputPtr++];
@@ -2529,7 +2611,7 @@
 
         do {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
+                if (!_loadMore()) {
                     _reportInvalidToken(matchStr.substring(0, i));
                 }
             }
@@ -2541,7 +2623,7 @@
 
         // but let's also ensure we either get EOF, or non-alphanum char...
         if (_inputPtr >= _inputEnd) {
-            if (!loadMore()) {
+            if (!_loadMore()) {
                 return;
             }
         }
@@ -2577,7 +2659,7 @@
             char ch;
             do {
                 if (_inputPtr >= _inputEnd) {
-                    loadMoreGuaranteed();
+                    _loadMoreGuaranteed();
                 }
                 ch = _inputBuffer[_inputPtr++];
             } while (ch <= INT_SPACE);
@@ -2596,7 +2678,7 @@
             // then second base64 char; can't get padding yet, nor ws
 
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++];
             bits = b64variant.decodeBase64Char(ch);
@@ -2607,7 +2689,7 @@
 
             // third base64 char; can be padding, but not ws
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++];
             bits = b64variant.decodeBase64Char(ch);
@@ -2626,7 +2708,7 @@
                 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
                     // Ok, must get more padding chars, then
                     if (_inputPtr >= _inputEnd) {
-                        loadMoreGuaranteed();
+                        _loadMoreGuaranteed();
                     }
                     ch = _inputBuffer[_inputPtr++];
                     if (!b64variant.usesPaddingChar(ch)) {
@@ -2643,7 +2725,7 @@
             decodedData = (decodedData << 6) | bits;
             // fourth and last base64 char; can be padding, but not ws
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++];
             bits = b64variant.decodeBase64Char(ch);
@@ -2739,7 +2821,7 @@
          */
         while (true) {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
+                if (!_loadMore()) {
                     break;
                 }
             }
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java
new file mode 100644
index 0000000..8bc3789
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java
@@ -0,0 +1,2797 @@
+package com.fasterxml.jackson.core.json;
+
+import java.io.*;
+import java.util.Arrays;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.base.ParserBase;
+import com.fasterxml.jackson.core.io.CharTypes;
+import com.fasterxml.jackson.core.io.IOContext;
+import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
+import com.fasterxml.jackson.core.util.*;
+
+import static com.fasterxml.jackson.core.JsonTokenId.*;
+
+/**
+ * This is a concrete implementation of {@link JsonParser}, which is
+ * based on a {@link java.io.DataInput} as the input source.
+ *<p>
+ * Due to limitations in look-ahead (basically there's none), as well
+ * as overhead of reading content mostly byte-by-byte,
+ * there are some
+ * minor differences from regular streaming parsing. Specifically:
+ *<ul>
+ * <li>Input location is not being tracked, as offsets would need to
+ *   be updated for each read from all over the place; if caller wants
+ *   this information, it has to track this with {@link DataInput}.
+ *  </li>
+ * <li>As a consequence linefeed handling is removed so all white-space is
+ *    equal; and checks are simplified NOT to check for control characters
+ *  </li>
+ * </ul>
+ *
+ * @since 2.8
+ */
+public class UTF8DataInputJsonParser
+    extends ParserBase
+{
+    final static byte BYTE_LF = (byte) '\n';
+
+    // This is the main input-code lookup table, fetched eagerly
+    private final static int[] _icUTF8 = CharTypes.getInputCodeUtf8();
+
+    // Latin1 encoding is not supported, but we do use 8-bit subset for
+    // pre-processing task, to simplify first pass, keep it fast.
+    protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
+
+    /*
+    /**********************************************************
+    /* Configuration
+    /**********************************************************
+     */
+
+    /**
+     * Codec used for data binding when (if) requested; typically full
+     * <code>ObjectMapper</code>, but that abstract is not part of core
+     * package.
+     */
+    protected ObjectCodec _objectCodec;
+
+    /**
+     * Symbol table that contains field names encountered so far
+     */
+    final protected ByteQuadsCanonicalizer _symbols;
+
+    /*
+    /**********************************************************
+    /* Parsing state
+    /**********************************************************
+     */
+
+    /**
+     * Temporary buffer used for name parsing.
+     */
+    protected int[] _quadBuffer = new int[16];
+
+    /**
+     * Flag that indicates that the current token has not yet
+     * been fully processed, and needs to be finished for
+     * some access (or skipped to obtain the next token)
+     */
+    protected boolean _tokenIncomplete;
+
+    /**
+     * Temporary storage for partially parsed name bytes.
+     */
+    private int _quad1;
+
+    /*
+    /**********************************************************
+    /* Current input data
+    /**********************************************************
+     */
+
+    protected DataInput _inputData;
+
+    /**
+     * Sometimes we need buffering for just a single byte we read but
+     * have to "push back"
+     */
+    protected int _nextByte = -1;
+
+    /*
+    /**********************************************************
+    /* Life-cycle
+    /**********************************************************
+     */
+
+    public UTF8DataInputJsonParser(IOContext ctxt, int features, DataInput inputData,
+            ObjectCodec codec, ByteQuadsCanonicalizer sym,
+            int firstByte)
+    {
+        super(ctxt, features);
+        _objectCodec = codec;
+        _symbols = sym;
+        _inputData = inputData;
+        _nextByte = firstByte;
+    }
+
+    @Override
+    public ObjectCodec getCodec() {
+        return _objectCodec;
+    }
+
+    @Override
+    public void setCodec(ObjectCodec c) {
+        _objectCodec = c;
+    }
+
+    /*
+    /**********************************************************
+    /* Overrides for life-cycle
+    /**********************************************************
+     */
+
+    @Override
+    public int releaseBuffered(OutputStream out) throws IOException {
+        return 0;
+    }
+
+    @Override
+    public Object getInputSource() {
+        return _inputData;
+    }
+
+    /*
+    /**********************************************************
+    /* Overrides, low-level reading
+    /**********************************************************
+     */
+
+    @Override
+    protected void _closeInput() throws IOException { }
+
+    /**
+     * Method called to release internal buffers owned by the base
+     * reader. This may be called along with {@link #_closeInput} (for
+     * example, when explicitly closing this reader instance), or
+     * separately (if need be).
+     */
+    @Override
+    protected void _releaseBuffers() throws IOException
+    {
+        super._releaseBuffers();
+        // Merge found symbols, if any:
+        _symbols.release();
+    }
+
+    /*
+    /**********************************************************
+    /* Public API, data access
+    /**********************************************************
+     */
+
+    @Override
+    public String getText() throws IOException
+    {
+        if (_currToken == JsonToken.VALUE_STRING) {
+            if (_tokenIncomplete) {
+                _tokenIncomplete = false;
+                return _finishAndReturnString(); // only strings can be incomplete
+            }
+            return _textBuffer.contentsAsString();
+        }
+        return _getText2(_currToken);
+    }
+
+    @Override
+    public int getText(Writer writer) throws IOException
+    {
+        JsonToken t = _currToken;
+        if (t == JsonToken.VALUE_STRING) {
+            if (_tokenIncomplete) {
+                _tokenIncomplete = false;
+                _finishString(); // only strings can be incomplete
+            }
+            return _textBuffer.contentsToWriter(writer);
+        }
+        if (t == JsonToken.FIELD_NAME) {
+            String n = _parsingContext.getCurrentName();
+            writer.write(n);
+            return n.length();
+        }
+        if (t != null) {
+            if (t.isNumeric()) {
+                return _textBuffer.contentsToWriter(writer);
+            }
+            char[] ch = t.asCharArray();
+            writer.write(ch);
+            return ch.length;
+        }
+        return 0;
+    }
+
+    // // // Let's override default impls for improved performance
+    @Override
+    public String getValueAsString() throws IOException
+    {
+        if (_currToken == JsonToken.VALUE_STRING) {
+            if (_tokenIncomplete) {
+                _tokenIncomplete = false;
+                return _finishAndReturnString(); // only strings can be incomplete
+            }
+            return _textBuffer.contentsAsString();
+        }
+        if (_currToken == JsonToken.FIELD_NAME) {
+            return getCurrentName();
+        }
+        return super.getValueAsString(null);
+    }
+
+    @Override
+    public String getValueAsString(String defValue) throws IOException
+    {
+        if (_currToken == JsonToken.VALUE_STRING) {
+            if (_tokenIncomplete) {
+                _tokenIncomplete = false;
+                return _finishAndReturnString(); // only strings can be incomplete
+            }
+            return _textBuffer.contentsAsString();
+        }
+        if (_currToken == JsonToken.FIELD_NAME) {
+            return getCurrentName();
+        }
+        return super.getValueAsString(defValue);
+    }
+
+    @Override
+    public int getValueAsInt() throws IOException
+    {
+        JsonToken t = _currToken;
+        if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
+            // inlined 'getIntValue()'
+            if ((_numTypesValid & NR_INT) == 0) {
+                if (_numTypesValid == NR_UNKNOWN) {
+                    return _parseIntValue();
+                }
+                if ((_numTypesValid & NR_INT) == 0) {
+                    convertNumberToInt();
+                }
+            }
+            return _numberInt;
+        }
+        return super.getValueAsInt(0);
+    }
+
+    @Override
+    public int getValueAsInt(int defValue) throws IOException
+    {
+        JsonToken t = _currToken;
+        if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
+            // inlined 'getIntValue()'
+            if ((_numTypesValid & NR_INT) == 0) {
+                if (_numTypesValid == NR_UNKNOWN) {
+                    return _parseIntValue();
+                }
+                if ((_numTypesValid & NR_INT) == 0) {
+                    convertNumberToInt();
+                }
+            }
+            return _numberInt;
+        }
+        return super.getValueAsInt(defValue);
+    }
+    
+    protected final String _getText2(JsonToken t)
+    {
+        if (t == null) {
+            return null;
+        }
+        switch (t.id()) {
+        case ID_FIELD_NAME:
+            return _parsingContext.getCurrentName();
+
+        case ID_STRING:
+            // fall through
+        case ID_NUMBER_INT:
+        case ID_NUMBER_FLOAT:
+            return _textBuffer.contentsAsString();
+        default:
+        	return t.asString();
+        }
+    }
+
+    @Override
+    public char[] getTextCharacters() throws IOException
+    {
+        if (_currToken != null) { // null only before/after document
+            switch (_currToken.id()) {
+                
+            case ID_FIELD_NAME:
+                if (!_nameCopied) {
+                    String name = _parsingContext.getCurrentName();
+                    int nameLen = name.length();
+                    if (_nameCopyBuffer == null) {
+                        _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen);
+                    } else if (_nameCopyBuffer.length < nameLen) {
+                        _nameCopyBuffer = new char[nameLen];
+                    }
+                    name.getChars(0, nameLen, _nameCopyBuffer, 0);
+                    _nameCopied = true;
+                }
+                return _nameCopyBuffer;
+    
+            case ID_STRING:
+                if (_tokenIncomplete) {
+                    _tokenIncomplete = false;
+                    _finishString(); // only strings can be incomplete
+                }
+                // fall through
+            case ID_NUMBER_INT:
+            case ID_NUMBER_FLOAT:
+                return _textBuffer.getTextBuffer();
+                
+            default:
+                return _currToken.asCharArray();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public int getTextLength() throws IOException
+    {
+        if (_currToken == JsonToken.VALUE_STRING) {
+            if (_tokenIncomplete) {
+                _tokenIncomplete = false;
+                _finishString(); // only strings can be incomplete
+            }
+            return _textBuffer.size();
+        }
+        if (_currToken == JsonToken.FIELD_NAME) {
+            return _parsingContext.getCurrentName().length();
+        }
+        if (_currToken != null) { // null only before/after document
+            if (_currToken.isNumeric()) {
+                return _textBuffer.size();
+            }
+            return _currToken.asCharArray().length;
+        }
+        return 0;
+    }
+
+    @Override
+    public int getTextOffset() throws IOException
+    {
+        // Most have offset of 0, only some may have other values:
+        if (_currToken != null) {
+            switch (_currToken.id()) {
+            case ID_FIELD_NAME:
+                return 0;
+            case ID_STRING:
+                if (_tokenIncomplete) {
+                    _tokenIncomplete = false;
+                    _finishString(); // only strings can be incomplete
+                }
+                // fall through
+            case ID_NUMBER_INT:
+            case ID_NUMBER_FLOAT:
+                return _textBuffer.getTextOffset();
+            default:
+            }
+        }
+        return 0;
+    }
+    
+    @Override
+    public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
+    {
+        if (_currToken != JsonToken.VALUE_STRING &&
+                (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) {
+            _reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
+        }
+        /* To ensure that we won't see inconsistent data, better clear up
+         * state...
+         */
+        if (_tokenIncomplete) {
+            try {
+                _binaryValue = _decodeBase64(b64variant);
+            } catch (IllegalArgumentException iae) {
+                throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage());
+            }
+            /* let's clear incomplete only now; allows for accessing other
+             * textual content in error cases
+             */
+            _tokenIncomplete = false;
+        } else { // may actually require conversion...
+            if (_binaryValue == null) {
+                @SuppressWarnings("resource")
+                ByteArrayBuilder builder = _getByteArrayBuilder();
+                _decodeBase64(getText(), builder, b64variant);
+                _binaryValue = builder.toByteArray();
+            }
+        }
+        return _binaryValue;
+    }
+
+    @Override
+    public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
+    {
+        // if we have already read the token, just use whatever we may have
+        if (!_tokenIncomplete || _currToken != JsonToken.VALUE_STRING) {
+            byte[] b = getBinaryValue(b64variant);
+            out.write(b);
+            return b.length;
+        }
+        // otherwise do "real" incremental parsing...
+        byte[] buf = _ioContext.allocBase64Buffer();
+        try {
+            return _readBinary(b64variant, out, buf);
+        } finally {
+            _ioContext.releaseBase64Buffer(buf);
+        }
+    }
+
+    protected int _readBinary(Base64Variant b64variant, OutputStream out,
+                              byte[] buffer) throws IOException
+    {
+        int outputPtr = 0;
+        final int outputEnd = buffer.length - 3;
+        int outputCount = 0;
+
+        while (true) {
+            // first, we'll skip preceding white space, if any
+            int ch;
+            do {
+                ch = _inputData.readUnsignedByte();
+            } while (ch <= INT_SPACE);
+            int bits = b64variant.decodeBase64Char(ch);
+            if (bits < 0) { // reached the end, fair and square?
+                if (ch == INT_QUOTE) {
+                    break;
+                }
+                bits = _decodeBase64Escape(b64variant, ch, 0);
+                if (bits < 0) { // white space to skip
+                    continue;
+                }
+            }
+
+            // enough room? If not, flush
+            if (outputPtr > outputEnd) {
+                outputCount += outputPtr;
+                out.write(buffer, 0, outputPtr);
+                outputPtr = 0;
+            }
+
+            int decodedData = bits;
+
+            // then second base64 char; can't get padding yet, nor ws
+            ch = _inputData.readUnsignedByte();
+            bits = b64variant.decodeBase64Char(ch);
+            if (bits < 0) {
+                bits = _decodeBase64Escape(b64variant, ch, 1);
+            }
+            decodedData = (decodedData << 6) | bits;
+
+            // third base64 char; can be padding, but not ws
+            ch = _inputData.readUnsignedByte();
+            bits = b64variant.decodeBase64Char(ch);
+
+            // First branch: can get padding (-> 1 byte)
+            if (bits < 0) {
+                if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+                    // could also just be 'missing'  padding
+                    if (ch == '"' && !b64variant.usesPadding()) {
+                        decodedData >>= 4;
+                        buffer[outputPtr++] = (byte) decodedData;
+                        break;
+                    }
+                    bits = _decodeBase64Escape(b64variant, ch, 2);
+                }
+                if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+                    // Ok, must get padding
+                    ch = _inputData.readUnsignedByte();
+                    if (!b64variant.usesPaddingChar(ch)) {
+                        throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
+                    }
+                    // Got 12 bits, only need 8, need to shift
+                    decodedData >>= 4;
+                    buffer[outputPtr++] = (byte) decodedData;
+                    continue;
+                }
+            }
+            // Nope, 2 or 3 bytes
+            decodedData = (decodedData << 6) | bits;
+            // fourth and last base64 char; can be padding, but not ws
+            ch = _inputData.readUnsignedByte();
+            bits = b64variant.decodeBase64Char(ch);
+            if (bits < 0) {
+                if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+                    // could also just be 'missing'  padding
+                    if (ch == '"' && !b64variant.usesPadding()) {
+                        decodedData >>= 2;
+                        buffer[outputPtr++] = (byte) (decodedData >> 8);
+                        buffer[outputPtr++] = (byte) decodedData;
+                        break;
+                    }
+                    bits = _decodeBase64Escape(b64variant, ch, 3);
+                }
+                if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+                    /* With padding we only get 2 bytes; but we have
+                     * to shift it a bit so it is identical to triplet
+                     * case with partial output.
+                     * 3 chars gives 3x6 == 18 bits, of which 2 are
+                     * dummies, need to discard:
+                     */
+                    decodedData >>= 2;
+                    buffer[outputPtr++] = (byte) (decodedData >> 8);
+                    buffer[outputPtr++] = (byte) decodedData;
+                    continue;
+                }
+            }
+            // otherwise, our triplet is now complete
+            decodedData = (decodedData << 6) | bits;
+            buffer[outputPtr++] = (byte) (decodedData >> 16);
+            buffer[outputPtr++] = (byte) (decodedData >> 8);
+            buffer[outputPtr++] = (byte) decodedData;
+        }
+        _tokenIncomplete = false;
+        if (outputPtr > 0) {
+            outputCount += outputPtr;
+            out.write(buffer, 0, outputPtr);
+        }
+        return outputCount;
+    }
+
+    /*
+    /**********************************************************
+    /* Public API, traversal, basic
+    /**********************************************************
+     */
+
+    /**
+     * @return Next token from the stream, if any found, or null
+     *   to indicate end-of-input
+     */
+    @Override
+    public JsonToken nextToken() throws IOException
+    {
+        /* First: field names are special -- we will always tokenize
+         * (part of) value along with field name to simplify
+         * state handling. If so, can and need to use secondary token:
+         */
+        if (_currToken == JsonToken.FIELD_NAME) {
+            return _nextAfterName();
+        }
+        // But if we didn't already have a name, and (partially?) decode number,
+        // need to ensure no numeric information is leaked
+        _numTypesValid = NR_UNKNOWN;
+        if (_tokenIncomplete) {
+            _skipString(); // only strings can be partial
+        }
+        int i = _skipWS();
+        // clear any data retained so far
+        _binaryValue = null;
+        _tokenInputRow = _currInputRow;
+
+        // Closing scope?
+        if (i == INT_RBRACKET) {
+            if (!_parsingContext.inArray()) {
+                _reportMismatchedEndMarker(i, '}');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            return (_currToken = JsonToken.END_ARRAY);
+        }
+        if (i == INT_RCURLY) {
+            if (!_parsingContext.inObject()) {
+                _reportMismatchedEndMarker(i, ']');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            return (_currToken = JsonToken.END_OBJECT);
+        }
+
+        // Nope: do we then expect a comma?
+        if (_parsingContext.expectComma()) {
+            if (i != INT_COMMA) {
+                _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
+            }
+            i = _skipWS();
+        }
+
+        /* And should we now have a name? Always true for
+         * Object contexts, since the intermediate 'expect-value'
+         * state is never retained.
+         */
+        if (!_parsingContext.inObject()) {
+            return _nextTokenNotInObject(i);
+        }
+        // So first parse the field name itself:
+        String n = _parseName(i);
+        _parsingContext.setCurrentName(n);
+        _currToken = JsonToken.FIELD_NAME;
+
+        i = _skipColon();
+
+        // Ok: we must have a value... what is it? Strings are very common, check first:
+        if (i == INT_QUOTE) {
+            _tokenIncomplete = true;
+            _nextToken = JsonToken.VALUE_STRING;
+            return _currToken;
+        }        
+        JsonToken t;
+
+        switch (i) {
+        case '-':
+            t = _parseNegNumber();
+            break;
+
+            /* Should we have separate handling for plus? Although
+             * it is not allowed per se, it may be erroneously used,
+             * and could be indicate by a more specific error message.
+             */
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            t = _parsePosNumber(i);
+            break;
+        case 'f':
+            _matchToken("false", 1);
+             t = JsonToken.VALUE_FALSE;
+            break;
+        case 'n':
+            _matchToken("null", 1);
+            t = JsonToken.VALUE_NULL;
+            break;
+        case 't':
+            _matchToken("true", 1);
+            t = JsonToken.VALUE_TRUE;
+            break;
+        case '[':
+            t = JsonToken.START_ARRAY;
+            break;
+        case '{':
+            t = JsonToken.START_OBJECT;
+            break;
+
+        default:
+            t = _handleUnexpectedValue(i);
+        }
+        _nextToken = t;
+        return _currToken;
+    }
+
+    private final JsonToken _nextTokenNotInObject(int i) throws IOException
+    {
+        if (i == INT_QUOTE) {
+            _tokenIncomplete = true;
+            return (_currToken = JsonToken.VALUE_STRING);
+        }
+        switch (i) {
+        case '[':
+            _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+            return (_currToken = JsonToken.START_ARRAY);
+        case '{':
+            _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+            return (_currToken = JsonToken.START_OBJECT);
+        case 't':
+            _matchToken("true", 1);
+            return (_currToken = JsonToken.VALUE_TRUE);
+        case 'f':
+            _matchToken("false", 1);
+            return (_currToken = JsonToken.VALUE_FALSE);
+        case 'n':
+            _matchToken("null", 1);
+            return (_currToken = JsonToken.VALUE_NULL);
+        case '-':
+            return (_currToken = _parseNegNumber());
+            /* Should we have separate handling for plus? Although
+             * it is not allowed per se, it may be erroneously used,
+             * and could be indicated by a more specific error message.
+             */
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            return (_currToken = _parsePosNumber(i));
+        }
+        return (_currToken = _handleUnexpectedValue(i));
+    }
+    
+    private final JsonToken _nextAfterName()
+    {
+        _nameCopied = false; // need to invalidate if it was copied
+        JsonToken t = _nextToken;
+        _nextToken = null;
+        
+        // Also: may need to start new context?
+        if (t == JsonToken.START_ARRAY) {
+            _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+        } else if (t == JsonToken.START_OBJECT) {
+            _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+        }
+        return (_currToken = t);
+    }
+
+    @Override
+    public void finishToken() throws IOException {
+        if (_tokenIncomplete) {
+            _tokenIncomplete = false;
+            _finishString(); // only strings can be incomplete
+        }
+    }
+
+    /*
+    /**********************************************************
+    /* Public API, traversal, nextXxxValue/nextFieldName
+    /**********************************************************
+     */
+
+    // Can not implement without look-ahead...
+//    public boolean nextFieldName(SerializableString str) throws IOException
+
+    @Override
+    public String nextFieldName() throws IOException
+    {
+        // // // Note: this is almost a verbatim copy of nextToken()
+
+        _numTypesValid = NR_UNKNOWN;
+        if (_currToken == JsonToken.FIELD_NAME) {
+            _nextAfterName();
+            return null;
+        }
+        if (_tokenIncomplete) {
+            _skipString();
+        }
+        int i = _skipWS();
+        _binaryValue = null;
+        _tokenInputRow = _currInputRow;
+
+        if (i == INT_RBRACKET) {
+            if (!_parsingContext.inArray()) {
+                _reportMismatchedEndMarker(i, '}');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            _currToken = JsonToken.END_ARRAY;
+            return null;
+        }
+        if (i == INT_RCURLY) {
+            if (!_parsingContext.inObject()) {
+                _reportMismatchedEndMarker(i, ']');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            _currToken = JsonToken.END_OBJECT;
+            return null;
+        }
+
+        // Nope: do we then expect a comma?
+        if (_parsingContext.expectComma()) {
+            if (i != INT_COMMA) {
+                _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
+            }
+            i = _skipWS();
+        }
+        if (!_parsingContext.inObject()) {
+            _nextTokenNotInObject(i);
+            return null;
+        }
+
+        final String nameStr = _parseName(i);
+        _parsingContext.setCurrentName(nameStr);
+        _currToken = JsonToken.FIELD_NAME;
+
+        i = _skipColon();
+        if (i == INT_QUOTE) {
+            _tokenIncomplete = true;
+            _nextToken = JsonToken.VALUE_STRING;
+            return nameStr;
+        }
+        JsonToken t;
+        switch (i) {
+        case '-':
+            t = _parseNegNumber();
+            break;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            t = _parsePosNumber(i);
+            break;
+        case 'f':
+            _matchToken("false", 1);
+             t = JsonToken.VALUE_FALSE;
+            break;
+        case 'n':
+            _matchToken("null", 1);
+            t = JsonToken.VALUE_NULL;
+            break;
+        case 't':
+            _matchToken("true", 1);
+            t = JsonToken.VALUE_TRUE;
+            break;
+        case '[':
+            t = JsonToken.START_ARRAY;
+            break;
+        case '{':
+            t = JsonToken.START_OBJECT;
+            break;
+
+        default:
+            t = _handleUnexpectedValue(i);
+        }
+        _nextToken = t;
+        return nameStr;
+    }
+
+    @Override
+    public String nextTextValue() throws IOException
+    {
+        // two distinct cases; either got name and we know next type, or 'other'
+        if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+            _nameCopied = false;
+            JsonToken t = _nextToken;
+            _nextToken = null;
+            _currToken = t;
+            if (t == JsonToken.VALUE_STRING) {
+                if (_tokenIncomplete) {
+                    _tokenIncomplete = false;
+                    return _finishAndReturnString();
+                }
+                return _textBuffer.contentsAsString();
+            }
+            if (t == JsonToken.START_ARRAY) {
+                _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+            } else if (t == JsonToken.START_OBJECT) {
+                _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+            }
+            return null;
+        }
+        return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
+    }
+
+    @Override
+    public int nextIntValue(int defaultValue) throws IOException
+    {
+        // two distinct cases; either got name and we know next type, or 'other'
+        if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+            _nameCopied = false;
+            JsonToken t = _nextToken;
+            _nextToken = null;
+            _currToken = t;
+            if (t == JsonToken.VALUE_NUMBER_INT) {
+                return getIntValue();
+            }
+            if (t == JsonToken.START_ARRAY) {
+                _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+            } else if (t == JsonToken.START_OBJECT) {
+                _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+            }
+            return defaultValue;
+        }
+        return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
+    }
+
+    @Override
+    public long nextLongValue(long defaultValue) throws IOException
+    {
+        // two distinct cases; either got name and we know next type, or 'other'
+        if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+            _nameCopied = false;
+            JsonToken t = _nextToken;
+            _nextToken = null;
+            _currToken = t;
+            if (t == JsonToken.VALUE_NUMBER_INT) {
+                return getLongValue();
+            }
+            if (t == JsonToken.START_ARRAY) {
+                _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+            } else if (t == JsonToken.START_OBJECT) {
+                _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+            }
+            return defaultValue;
+        }
+        return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
+    }
+
+    @Override
+    public Boolean nextBooleanValue() throws IOException
+    {
+        // two distinct cases; either got name and we know next type, or 'other'
+        if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+            _nameCopied = false;
+            JsonToken t = _nextToken;
+            _nextToken = null;
+            _currToken = t;
+            if (t == JsonToken.VALUE_TRUE) {
+                return Boolean.TRUE;
+            }
+            if (t == JsonToken.VALUE_FALSE) {
+                return Boolean.FALSE;
+            }
+            if (t == JsonToken.START_ARRAY) {
+                _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+            } else if (t == JsonToken.START_OBJECT) {
+                _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+            }
+            return null;
+        }
+
+        JsonToken t = nextToken();
+        if (t == JsonToken.VALUE_TRUE) {
+            return Boolean.TRUE;
+        }
+        if (t == JsonToken.VALUE_FALSE) {
+            return Boolean.FALSE;
+        }
+        return null;
+    }
+
+    /*
+    /**********************************************************
+    /* Internal methods, number parsing
+    /**********************************************************
+     */
+
+    /**
+     * Initial parsing method for number values. It needs to be able
+     * to parse enough input to be able to determine whether the
+     * value is to be considered a simple integer value, or a more
+     * generic decimal value: latter of which needs to be expressed
+     * as a floating point number. The basic rule is that if the number
+     * has no fractional or exponential part, it is an integer; otherwise
+     * a floating point number.
+     *<p>
+     * Because much of input has to be processed in any case, no partial
+     * parsing is done: all input text will be stored for further
+     * processing. However, actual numeric value conversion will be
+     * deferred, since it is usually the most complicated and costliest
+     * part of processing.
+     */
+    protected JsonToken _parsePosNumber(int c) throws IOException
+    {
+        char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+        int outPtr;
+
+        // One special case: if first char is 0, must not be followed by a digit.
+        // Gets bit tricky as we only want to retain 0 if it's the full value
+        if (c == INT_0) {
+            c = _handleLeadingZeroes();
+            if (c <= INT_9 && c >= INT_0) { // skip if followed by digit
+                outPtr = 0;
+            } else {
+                outBuf[0] = '0';
+                outPtr = 1;
+            }
+        } else {
+            outBuf[0] = (char) c;
+            c = _inputData.readUnsignedByte();
+            outPtr = 1;
+        }
+        int intLen = outPtr;
+
+        // With this, we have a nice and tight loop:
+        while (c <= INT_9 && c >= INT_0) {
+            ++intLen;
+            outBuf[outPtr++] = (char) c;
+            c = _inputData.readUnsignedByte();
+        }
+        if (c == '.' || c == 'e' || c == 'E') {
+            return _parseFloat(outBuf, outPtr, c, false, intLen);
+        }
+        _textBuffer.setCurrentLength(outPtr);
+        // As per [core#105], need separating space between root values; check here
+        if (_parsingContext.inRoot()) {
+            _verifyRootSpace();
+        } else {
+            _nextByte = c;
+        }
+        // And there we have it!
+        return resetInt(false, intLen);
+    }
+    
+    protected JsonToken _parseNegNumber() throws IOException
+    {
+        char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+        int outPtr = 0;
+
+        // Need to prepend sign?
+        outBuf[outPtr++] = '-';
+        int c = _inputData.readUnsignedByte();
+        outBuf[outPtr++] = (char) c;
+        // Note: must be followed by a digit
+        if (c <= INT_0) {
+            // One special case: if first char is 0 need to check no leading zeroes
+            if (c == INT_0) {
+                c = _handleLeadingZeroes();
+            } else {
+                return _handleInvalidNumberStart(c, true);
+            }
+        } else {
+            if (c > INT_9) {
+                return _handleInvalidNumberStart(c, true);
+            }
+            c = _inputData.readUnsignedByte();
+        }
+        // Ok: we can first just add digit we saw first:
+        int intLen = 1;
+
+        // With this, we have a nice and tight loop:
+        while (c <= INT_9 && c >= INT_0) {
+            ++intLen;
+            outBuf[outPtr++] = (char) c;
+            c = _inputData.readUnsignedByte();
+        }
+        if (c == '.' || c == 'e' || c == 'E') {
+            return _parseFloat(outBuf, outPtr, c, true, intLen);
+        }
+        _textBuffer.setCurrentLength(outPtr);
+        // As per [core#105], need separating space between root values; check here
+        _nextByte = c;
+        if (_parsingContext.inRoot()) {
+            _verifyRootSpace();
+        }
+        // And there we have it!
+        return resetInt(true, intLen);
+    }
+
+    /**
+     * Method called when we have seen one zero, and want to ensure
+     * it is not followed by another, or, if leading zeroes allowed,
+     * skipped redundant ones.
+     *
+     * @return Character immediately following zeroes
+     */
+    private final int _handleLeadingZeroes() throws IOException
+    {
+        int ch = _inputData.readUnsignedByte();
+        // if not followed by a number (probably '.'); return zero as is, to be included
+        if (ch < INT_0 || ch > INT_9) {
+            return ch;
+        }
+        // we may want to allow leading zeroes them, after all...
+        if (!isEnabled(Feature.ALLOW_NUMERIC_LEADING_ZEROS)) {
+            reportInvalidNumber("Leading zeroes not allowed");
+        }
+        // if so, just need to skip either all zeroes (if followed by number); or all but one (if non-number)
+        while (ch == INT_0) {
+            ch = _inputData.readUnsignedByte();
+        }
+        return ch;
+    }
+
+    private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
+            boolean negative, int integerPartLength) throws IOException
+    {
+        int fractLen = 0;
+
+        // And then see if we get other parts
+        if (c == INT_PERIOD) { // yes, fraction
+            outBuf[outPtr++] = (char) c;
+
+            fract_loop:
+            while (true) {
+                c = _inputData.readUnsignedByte();
+                if (c < INT_0 || c > INT_9) {
+                    break fract_loop;
+                }
+                ++fractLen;
+                if (outPtr >= outBuf.length) {
+                    outBuf = _textBuffer.finishCurrentSegment();
+                    outPtr = 0;
+                }
+                outBuf[outPtr++] = (char) c;
+            }
+            // must be followed by sequence of ints, one minimum
+            if (fractLen == 0) {
+                reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
+            }
+        }
+
+        int expLen = 0;
+        if (c == INT_e || c == INT_E) { // exponent?
+            if (outPtr >= outBuf.length) {
+                outBuf = _textBuffer.finishCurrentSegment();
+                outPtr = 0;
+            }
+            outBuf[outPtr++] = (char) c;
+            c = _inputData.readUnsignedByte();
+            // Sign indicator?
+            if (c == '-' || c == '+') {
+                if (outPtr >= outBuf.length) {
+                    outBuf = _textBuffer.finishCurrentSegment();
+                    outPtr = 0;
+                }
+                outBuf[outPtr++] = (char) c;
+                c = _inputData.readUnsignedByte();
+            }
+            while (c <= INT_9 && c >= INT_0) {
+                ++expLen;
+                if (outPtr >= outBuf.length) {
+                    outBuf = _textBuffer.finishCurrentSegment();
+                    outPtr = 0;
+                }
+                outBuf[outPtr++] = (char) c;
+                c = _inputData.readUnsignedByte();
+            }
+            // must be followed by sequence of ints, one minimum
+            if (expLen == 0) {
+                reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit");
+            }
+        }
+
+        // Ok; unless we hit end-of-input, need to push last char read back
+        // As per #105, need separating space between root values; check here
+        _nextByte = c;
+        if (_parsingContext.inRoot()) {
+            _verifyRootSpace();
+        }
+        _textBuffer.setCurrentLength(outPtr);
+
+        // And there we have it!
+        return resetFloat(negative, integerPartLength, fractLen, expLen);
+    }
+
+    /**
+     * Method called to ensure that a root-value is followed by a space token,
+     * if possible.
+     *<p>
+     * NOTE: with {@link DataInput} source, not really feasible, up-front.
+     * If we did want, we could rearrange things to require space before
+     * next read, but initially let's just do nothing.
+     */
+    private final void _verifyRootSpace() throws IOException
+    {
+        int ch = _nextByte;
+        if (ch <= INT_SPACE) {
+            _nextByte = -1;
+            if (ch == INT_CR || ch == INT_LF) {
+                ++_currInputRow;
+            }
+            return;
+        }
+        _reportMissingRootWS(ch);
+    }
+
+    /*
+    /**********************************************************
+    /* Internal methods, secondary parsing
+    /**********************************************************
+     */
+    
+    protected final String _parseName(int i) throws IOException
+    {
+        if (i != INT_QUOTE) {
+            return _handleOddName(i);
+        }
+        // If so, can also unroll loops nicely
+        /* 25-Nov-2008, tatu: This may seem weird, but here we do
+         *   NOT want to worry about UTF-8 decoding. Rather, we'll
+         *   assume that part is ok (if not it will get caught
+         *   later on), and just handle quotes and backslashes here.
+         */
+        final int[] codes = _icLatin1;
+
+        int q = _inputData.readUnsignedByte();
+
+        if (codes[q] == 0) {
+            i = _inputData.readUnsignedByte();
+            if (codes[i] == 0) {
+                q = (q << 8) | i;
+                i = _inputData.readUnsignedByte();
+                if (codes[i] == 0) {
+                    q = (q << 8) | i;
+                    i = _inputData.readUnsignedByte();
+                    if (codes[i] == 0) {
+                        q = (q << 8) | i;
+                        i = _inputData.readUnsignedByte();
+                        if (codes[i] == 0) {
+                            _quad1 = q;
+                            return _parseMediumName(i);
+                        }
+                        if (i == INT_QUOTE) { // 4 byte/char case or broken
+                            return findName(q, 4);
+                        }
+                        return parseName(q, i, 4);
+                    }
+                    if (i == INT_QUOTE) { // 3 byte/char case or broken
+                        return findName(q, 3);
+                    }
+                    return parseName(q, i, 3);
+                }                
+                if (i == INT_QUOTE) { // 2 byte/char case or broken
+                    return findName(q, 2);
+                }
+                return parseName(q, i, 2);
+            }
+            if (i == INT_QUOTE) { // one byte/char case or broken
+                return findName(q, 1);
+            }
+            return parseName(q, i, 1);
+        }     
+        if (q == INT_QUOTE) { // special case, ""
+            return "";
+        }
+        return parseName(0, q, 0); // quoting or invalid char
+    }
+
+    private final String _parseMediumName(int q2) throws IOException
+    {
+        final int[] codes = _icLatin1;
+
+        // Ok, got 5 name bytes so far
+        int i = _inputData.readUnsignedByte();
+        if (codes[i] != 0) {
+            if (i == INT_QUOTE) { // 5 bytes
+                return findName(_quad1, q2, 1);
+            }
+            return parseName(_quad1, q2, i, 1); // quoting or invalid char
+        }
+        q2 = (q2 << 8) | i;
+        i = _inputData.readUnsignedByte();
+        if (codes[i] != 0) {
+            if (i == INT_QUOTE) { // 6 bytes
+                return findName(_quad1, q2, 2);
+            }
+            return parseName(_quad1, q2, i, 2);
+        }
+        q2 = (q2 << 8) | i;
+        i = _inputData.readUnsignedByte();
+        if (codes[i] != 0) {
+            if (i == INT_QUOTE) { // 7 bytes
+                return findName(_quad1, q2, 3);
+            }
+            return parseName(_quad1, q2, i, 3);
+        }
+        q2 = (q2 << 8) | i;
+        i = _inputData.readUnsignedByte();
+        if (codes[i] != 0) {
+            if (i == INT_QUOTE) { // 8 bytes
+                return findName(_quad1, q2, 4);
+            }
+            return parseName(_quad1, q2, i, 4);
+        }
+        return _parseMediumName2(i, q2);
+    }
+
+    private final String _parseMediumName2(int q3, final int q2) throws IOException
+    {
+        final int[] codes = _icLatin1;
+
+        // Got 9 name bytes so far
+        int i = _inputData.readUnsignedByte();
+        if (codes[i] != 0) {
+            if (i == INT_QUOTE) { // 9 bytes
+                return findName(_quad1, q2, q3, 1);
+            }
+            return parseName(_quad1, q2, q3, i, 1);
+        }
+        q3 = (q3 << 8) | i;
+        i = _inputData.readUnsignedByte();
+        if (codes[i] != 0) {
+            if (i == INT_QUOTE) { // 10 bytes
+                return findName(_quad1, q2, q3, 2);
+            }
+            return parseName(_quad1, q2, q3, i, 2);
+        }
+        q3 = (q3 << 8) | i;
+        i = _inputData.readUnsignedByte();
+        if (codes[i] != 0) {
+            if (i == INT_QUOTE) { // 11 bytes
+                return findName(_quad1, q2, q3, 3);
+            }
+            return parseName(_quad1, q2, q3, i, 3);
+        }
+        q3 = (q3 << 8) | i;
+        i = _inputData.readUnsignedByte();
+        if (codes[i] != 0) {
+            if (i == INT_QUOTE) { // 12 bytes
+                return findName(_quad1, q2, q3, 4);
+            }
+            return parseName(_quad1, q2, q3, i, 4);
+        }
+        return _parseLongName(i, q2, q3);
+    }
+    
+    private final String _parseLongName(int q, final int q2, int q3) throws IOException
+    {
+        _quadBuffer[0] = _quad1;
+        _quadBuffer[1] = q2;
+        _quadBuffer[2] = q3;
+
+        // As explained above, will ignore UTF-8 encoding at this point
+        final int[] codes = _icLatin1;
+        int qlen = 3;
+
+        while (true) {
+            int i = _inputData.readUnsignedByte();
+            if (codes[i] != 0) {
+                if (i == INT_QUOTE) {
+                    return findName(_quadBuffer, qlen, q, 1);
+                }
+                return parseEscapedName(_quadBuffer, qlen, q, i, 1);
+            }
+
+            q = (q << 8) | i;
+            i = _inputData.readUnsignedByte();
+            if (codes[i] != 0) {
+                if (i == INT_QUOTE) {
+                    return findName(_quadBuffer, qlen, q, 2);
+                }
+                return parseEscapedName(_quadBuffer, qlen, q, i, 2);
+            }
+
+            q = (q << 8) | i;
+            i = _inputData.readUnsignedByte();
+            if (codes[i] != 0) {
+                if (i == INT_QUOTE) {
+                    return findName(_quadBuffer, qlen, q, 3);
+                }
+                return parseEscapedName(_quadBuffer, qlen, q, i, 3);
+            }
+
+            q = (q << 8) | i;
+            i = _inputData.readUnsignedByte();
+            if (codes[i] != 0) {
+                if (i == INT_QUOTE) {
+                    return findName(_quadBuffer, qlen, q, 4);
+                }
+                return parseEscapedName(_quadBuffer, qlen, q, i, 4);
+            }
+
+            // Nope, no end in sight. Need to grow quad array etc
+            if (qlen >= _quadBuffer.length) {
+                _quadBuffer = _growArrayBy(_quadBuffer, qlen);
+            }
+            _quadBuffer[qlen++] = q;
+            q = i;
+        }
+    }
+
+    private final String parseName(int q1, int ch, int lastQuadBytes) throws IOException {
+        return parseEscapedName(_quadBuffer, 0, q1, ch, lastQuadBytes);
+    }
+
+    private final String parseName(int q1, int q2, int ch, int lastQuadBytes) throws IOException {
+        _quadBuffer[0] = q1;
+        return parseEscapedName(_quadBuffer, 1, q2, ch, lastQuadBytes);
+    }
+
+    private final String parseName(int q1, int q2, int q3, int ch, int lastQuadBytes) throws IOException {
+        _quadBuffer[0] = q1;
+        _quadBuffer[1] = q2;
+        return parseEscapedName(_quadBuffer, 2, q3, ch, lastQuadBytes);
+    }
+    
+    /**
+     * Slower parsing method which is generally branched to when
+     * an escape sequence is detected (or alternatively for long
+     * names, one crossing input buffer boundary).
+     * Needs to be able to handle more exceptional cases, gets slower,
+     * and hance is offlined to a separate method.
+     */
+    protected final String parseEscapedName(int[] quads, int qlen, int currQuad, int ch,
+            int currQuadBytes) throws IOException
+    {
+        /* 25-Nov-2008, tatu: This may seem weird, but here we do not want to worry about
+         *   UTF-8 decoding yet. Rather, we'll assume that part is ok (if not it will get
+         *   caught later on), and just handle quotes and backslashes here.
+         */
+        final int[] codes = _icLatin1;
+
+        while (true) {
+            if (codes[ch] != 0) {
+                if (ch == INT_QUOTE) { // we are done
+                    break;
+                }
+                // Unquoted white space?
+                if (ch != INT_BACKSLASH) {
+                    // As per [JACKSON-208], call can now return:
+                    _throwUnquotedSpace(ch, "name");
+                } else {
+                    // Nope, escape sequence
+                    ch = _decodeEscaped();
+                }
+                /* Oh crap. May need to UTF-8 (re-)encode it, if it's
+                 * beyond 7-bit ascii. Gets pretty messy.
+                 * If this happens often, may want to use different name
+                 * canonicalization to avoid these hits.
+                 */
+                if (ch > 127) {
+                    // Ok, we'll need room for first byte right away
+                    if (currQuadBytes >= 4) {
+                        if (qlen >= quads.length) {
+                            _quadBuffer = quads = _growArrayBy(quads, quads.length);
+                        }
+                        quads[qlen++] = currQuad;
+                        currQuad = 0;
+                        currQuadBytes = 0;
+                    }
+                    if (ch < 0x800) { // 2-byte
+                        currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
+                        ++currQuadBytes;
+                        // Second byte gets output below:
+                    } else { // 3 bytes; no need to worry about surrogates here
+                        currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
+                        ++currQuadBytes;
+                        // need room for middle byte?
+                        if (currQuadBytes >= 4) {
+                            if (qlen >= quads.length) {
+                                _quadBuffer = quads = _growArrayBy(quads, quads.length);
+                            }
+                            quads[qlen++] = currQuad;
+                            currQuad = 0;
+                            currQuadBytes = 0;
+                        }
+                        currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
+                        ++currQuadBytes;
+                    }
+                    // And same last byte in both cases, gets output below:
+                    ch = 0x80 | (ch & 0x3f);
+                }
+            }
+            // Ok, we have one more byte to add at any rate:
+            if (currQuadBytes < 4) {
+                ++currQuadBytes;
+                currQuad = (currQuad << 8) | ch;
+            } else {
+                if (qlen >= quads.length) {
+                    _quadBuffer = quads = _growArrayBy(quads, quads.length);
+                }
+                quads[qlen++] = currQuad;
+                currQuad = ch;
+                currQuadBytes = 1;
+            }
+            ch = _inputData.readUnsignedByte();
+        }
+
+        if (currQuadBytes > 0) {
+            if (qlen >= quads.length) {
+                _quadBuffer = quads = _growArrayBy(quads, quads.length);
+            }
+            quads[qlen++] = pad(currQuad, currQuadBytes);
+        }
+        String name = _symbols.findName(quads, qlen);
+        if (name == null) {
+            name = addName(quads, qlen, currQuadBytes);
+        }
+        return name;
+    }
+
+    /**
+     * Method called when we see non-white space character other
+     * than double quote, when expecting a field name.
+     * In standard mode will just throw an exception; but
+     * in non-standard modes may be able to parse name.
+     */
+    protected String _handleOddName(int ch) throws IOException
+    {
+        if (ch == '\'' && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
+            return _parseAposName();
+        }
+        if (!isEnabled(Feature.ALLOW_UNQUOTED_FIELD_NAMES)) {
+            char c = (char) _decodeCharForError(ch);
+            _reportUnexpectedChar(c, "was expecting double-quote to start field name");
+        }
+        /* Also: note that although we use a different table here,
+         * it does NOT handle UTF-8 decoding. It'll just pass those
+         * high-bit codes as acceptable for later decoding.
+         */
+        final int[] codes = CharTypes.getInputCodeUtf8JsNames();
+        // Also: must start with a valid character...
+        if (codes[ch] != 0) {
+            _reportUnexpectedChar(ch, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name");
+        }
+
+        /* Ok, now; instead of ultra-optimizing parsing here (as with
+         * regular JSON names), let's just use the generic "slow"
+         * variant. Can measure its impact later on if need be
+         */
+        int[] quads = _quadBuffer;
+        int qlen = 0;
+        int currQuad = 0;
+        int currQuadBytes = 0;
+
+        while (true) {
+            // Ok, we have one more byte to add at any rate:
+            if (currQuadBytes < 4) {
+                ++currQuadBytes;
+                currQuad = (currQuad << 8) | ch;
+            } else {
+                if (qlen >= quads.length) {
+                    _quadBuffer = quads = _growArrayBy(quads, quads.length);
+                }
+                quads[qlen++] = currQuad;
+                currQuad = ch;
+                currQuadBytes = 1;
+            }
+            ch = _inputData.readUnsignedByte();
+            if (codes[ch] != 0) {
+                break;
+            }
+        }
+        // Note: we must "push back" character read here for future consumption
+        _nextByte = ch;
+        if (currQuadBytes > 0) {
+            if (qlen >= quads.length) {
+                _quadBuffer = quads = _growArrayBy(quads, quads.length);
+            }
+            quads[qlen++] = currQuad;
+        }
+        String name = _symbols.findName(quads, qlen);
+        if (name == null) {
+            name = addName(quads, qlen, currQuadBytes);
+        }
+        return name;
+    }
+
+    /* Parsing to allow optional use of non-standard single quotes.
+     * Plenty of duplicated code;
+     * main reason being to try to avoid slowing down fast path
+     * for valid JSON -- more alternatives, more code, generally
+     * bit slower execution.
+     */
+    protected String _parseAposName() throws IOException
+    {
+        int ch = _inputData.readUnsignedByte();
+        if (ch == '\'') { // special case, ''
+            return "";
+        }
+        int[] quads = _quadBuffer;
+        int qlen = 0;
+        int currQuad = 0;
+        int currQuadBytes = 0;
+
+        // Copied from parseEscapedFieldName, with minor mods:
+
+        final int[] codes = _icLatin1;
+
+        while (true) {
+            if (ch == '\'') {
+                break;
+            }
+            // additional check to skip handling of double-quotes
+            if (ch != '"' && codes[ch] != 0) {
+                if (ch != '\\') {
+                    // Unquoted white space?
+                    // As per [JACKSON-208], call can now return:
+                    _throwUnquotedSpace(ch, "name");
+                } else {
+                    // Nope, escape sequence
+                    ch = _decodeEscaped();
+                }
+                /* Oh crap. May need to UTF-8 (re-)encode it, if it's  beyond
+                 * 7-bit ASCII. Gets pretty messy. If this happens often, may want
+                 * to use different name canonicalization to avoid these hits.
+                 */
+                if (ch > 127) {
+                    // Ok, we'll need room for first byte right away
+                    if (currQuadBytes >= 4) {
+                        if (qlen >= quads.length) {
+                            _quadBuffer = quads = _growArrayBy(quads, quads.length);
+                        }
+                        quads[qlen++] = currQuad;
+                        currQuad = 0;
+                        currQuadBytes = 0;
+                    }
+                    if (ch < 0x800) { // 2-byte
+                        currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
+                        ++currQuadBytes;
+                        // Second byte gets output below:
+                    } else { // 3 bytes; no need to worry about surrogates here
+                        currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
+                        ++currQuadBytes;
+                        // need room for middle byte?
+                        if (currQuadBytes >= 4) {
+                            if (qlen >= quads.length) {
+                                _quadBuffer = quads = _growArrayBy(quads, quads.length);
+                            }
+                            quads[qlen++] = currQuad;
+                            currQuad = 0;
+                            currQuadBytes = 0;
+                        }
+                        currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
+                        ++currQuadBytes;
+                    }
+                    // And same last byte in both cases, gets output below:
+                    ch = 0x80 | (ch & 0x3f);
+                }
+            }
+            // Ok, we have one more byte to add at any rate:
+            if (currQuadBytes < 4) {
+                ++currQuadBytes;
+                currQuad = (currQuad << 8) | ch;
+            } else {
+                if (qlen >= quads.length) {
+                    _quadBuffer = quads = _growArrayBy(quads, quads.length);
+                }
+                quads[qlen++] = currQuad;
+                currQuad = ch;
+                currQuadBytes = 1;
+            }
+            ch = _inputData.readUnsignedByte();
+        }
+
+        if (currQuadBytes > 0) {
+            if (qlen >= quads.length) {
+                _quadBuffer = quads = _growArrayBy(quads, quads.length);
+            }
+            quads[qlen++] = pad(currQuad, currQuadBytes);
+        }
+        String name = _symbols.findName(quads, qlen);
+        if (name == null) {
+            name = addName(quads, qlen, currQuadBytes);
+        }
+        return name;
+    }
+
+    /*
+    /**********************************************************
+    /* Internal methods, symbol (name) handling
+    /**********************************************************
+     */
+
+    private final String findName(int q1, int lastQuadBytes) throws JsonParseException
+    {
+        q1 = pad(q1, lastQuadBytes);
+        // Usually we'll find it from the canonical symbol table already
+        String name = _symbols.findName(q1);
+        if (name != null) {
+            return name;
+        }
+        // If not, more work. We'll need add stuff to buffer
+        _quadBuffer[0] = q1;
+        return addName(_quadBuffer, 1, lastQuadBytes);
+    }
+
+    private final String findName(int q1, int q2, int lastQuadBytes) throws JsonParseException
+    {
+        q2 = pad(q2, lastQuadBytes);
+        // Usually we'll find it from the canonical symbol table already
+        String name = _symbols.findName(q1, q2);
+        if (name != null) {
+            return name;
+        }
+        // If not, more work. We'll need add stuff to buffer
+        _quadBuffer[0] = q1;
+        _quadBuffer[1] = q2;
+        return addName(_quadBuffer, 2, lastQuadBytes);
+    }
+
+    private final String findName(int q1, int q2, int q3, int lastQuadBytes) throws JsonParseException
+    {
+        q3 = pad(q3, lastQuadBytes);
+        String name = _symbols.findName(q1, q2, q3);
+        if (name != null) {
+            return name;
+        }
+        int[] quads = _quadBuffer;
+        quads[0] = q1;
+        quads[1] = q2;
+        quads[2] = pad(q3, lastQuadBytes);
+        return addName(quads, 3, lastQuadBytes);
+    }
+    
+    private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes) throws JsonParseException
+    {
+        if (qlen >= quads.length) {
+            _quadBuffer = quads = _growArrayBy(quads, quads.length);
+        }
+        quads[qlen++] = pad(lastQuad, lastQuadBytes);
+        String name = _symbols.findName(quads, qlen);
+        if (name == null) {
+            return addName(quads, qlen, lastQuadBytes);
+        }
+        return name;
+    }
+
+    /**
+     * This is the main workhorse method used when we take a symbol
+     * table miss. It needs to demultiplex individual bytes, decode
+     * multi-byte chars (if any), and then construct Name instance
+     * and add it to the symbol table.
+     */
+    private final String addName(int[] quads, int qlen, int lastQuadBytes) throws JsonParseException
+    {
+        /* Ok: must decode UTF-8 chars. No other validation is
+         * needed, since unescaping has been done earlier as necessary
+         * (as well as error reporting for unescaped control chars)
+         */
+        // 4 bytes per quad, except last one maybe less
+        int byteLen = (qlen << 2) - 4 + lastQuadBytes;
+
+        /* And last one is not correctly aligned (leading zero bytes instead
+         * need to shift a bit, instead of trailing). Only need to shift it
+         * for UTF-8 decoding; need revert for storage (since key will not
+         * be aligned, to optimize lookup speed)
+         */
+        int lastQuad;
+
+        if (lastQuadBytes < 4) {
+            lastQuad = quads[qlen-1];
+            // 8/16/24 bit left shift
+            quads[qlen-1] = (lastQuad << ((4 - lastQuadBytes) << 3));
+        } else {
+            lastQuad = 0;
+        }
+
+        // Need some working space, TextBuffer works well:
+        char[] cbuf = _textBuffer.emptyAndGetCurrentSegment();
+        int cix = 0;
+
+        for (int ix = 0; ix < byteLen; ) {
+            int ch = quads[ix >> 2]; // current quad, need to shift+mask
+            int byteIx = (ix & 3);
+            ch = (ch >> ((3 - byteIx) << 3)) & 0xFF;
+            ++ix;
+
+            if (ch > 127) { // multi-byte
+                int needed;
+                if ((ch & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF)
+                    ch &= 0x1F;
+                    needed = 1;
+                } else if ((ch & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF)
+                    ch &= 0x0F;
+                    needed = 2;
+                } else if ((ch & 0xF8) == 0xF0) { // 4 bytes; double-char with surrogates and all...
+                    ch &= 0x07;
+                    needed = 3;
+                } else { // 5- and 6-byte chars not valid xml chars
+                    _reportInvalidInitial(ch);
+                    needed = ch = 1; // never really gets this far
+                }
+                if ((ix + needed) > byteLen) {
+                    _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
+                }
+                
+                // Ok, always need at least one more:
+                int ch2 = quads[ix >> 2]; // current quad, need to shift+mask
+                byteIx = (ix & 3);
+                ch2 = (ch2 >> ((3 - byteIx) << 3));
+                ++ix;
+                
+                if ((ch2 & 0xC0) != 0x080) {
+                    _reportInvalidOther(ch2);
+                }
+                ch = (ch << 6) | (ch2 & 0x3F);
+                if (needed > 1) {
+                    ch2 = quads[ix >> 2];
+                    byteIx = (ix & 3);
+                    ch2 = (ch2 >> ((3 - byteIx) << 3));
+                    ++ix;
+                    
+                    if ((ch2 & 0xC0) != 0x080) {
+                        _reportInvalidOther(ch2);
+                    }
+                    ch = (ch << 6) | (ch2 & 0x3F);
+                    if (needed > 2) { // 4 bytes? (need surrogates on output)
+                        ch2 = quads[ix >> 2];
+                        byteIx = (ix & 3);
+                        ch2 = (ch2 >> ((3 - byteIx) << 3));
+                        ++ix;
+                        if ((ch2 & 0xC0) != 0x080) {
+                            _reportInvalidOther(ch2 & 0xFF);
+                        }
+                        ch = (ch << 6) | (ch2 & 0x3F);
+                    }
+                }
+                if (needed > 2) { // surrogate pair? once again, let's output one here, one later on
+                    ch -= 0x10000; // to normalize it starting with 0x0
+                    if (cix >= cbuf.length) {
+                        cbuf = _textBuffer.expandCurrentSegment();
+                    }
+                    cbuf[cix++] = (char) (0xD800 + (ch >> 10));
+                    ch = 0xDC00 | (ch & 0x03FF);
+                }
+            }
+            if (cix >= cbuf.length) {
+                cbuf = _textBuffer.expandCurrentSegment();
+            }
+            cbuf[cix++] = (char) ch;
+        }
+
+        // Ok. Now we have the character array, and can construct the String
+        String baseName = new String(cbuf, 0, cix);
+        // And finally, un-align if necessary
+        if (lastQuadBytes < 4) {
+            quads[qlen-1] = lastQuad;
+        }
+        return _symbols.addName(baseName, quads, qlen);
+    }
+
+    /*
+    /**********************************************************
+    /* Internal methods, String value parsing
+    /**********************************************************
+     */
+
+    @Override
+    protected void _finishString() throws IOException
+    {
+        int outPtr = 0;
+        char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+        final int[] codes = _icUTF8;
+        final int outEnd = outBuf.length;
+
+        do {
+            int c = _inputData.readUnsignedByte();
+            if (codes[c] != 0) {
+                if (c == INT_QUOTE) {
+                    _textBuffer.setCurrentLength(outPtr);
+                    return;
+                }
+                _finishString2(outBuf, outPtr, c);
+                return;
+            }
+            outBuf[outPtr++] = (char) c;
+        } while (outPtr < outEnd);
+        _finishString2(outBuf, outPtr, _inputData.readUnsignedByte());
+    }
+
+    private String _finishAndReturnString() throws IOException
+    {
+        int outPtr = 0;
+        char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+        final int[] codes = _icUTF8;
+        final int outEnd = outBuf.length;
+
+        do {
+            int c = _inputData.readUnsignedByte();
+            if (codes[c] != 0) {
+                if (c == INT_QUOTE) {
+                    return _textBuffer.setCurrentAndReturn(outPtr);
+                }
+                _finishString2(outBuf, outPtr, c);
+                return _textBuffer.contentsAsString();
+            }
+            outBuf[outPtr++] = (char) c;
+        } while (outPtr < outEnd);
+        _finishString2(outBuf, outPtr, _inputData.readUnsignedByte());
+        return _textBuffer.contentsAsString();
+    }
+    
+    private final void _finishString2(char[] outBuf, int outPtr, int c)
+        throws IOException
+    {
+        // Here we do want to do full decoding, hence:
+        final int[] codes = _icUTF8;
+        int outEnd = outBuf.length;
+
+        main_loop:
+        for (;; c = _inputData.readUnsignedByte()) {
+            // Then the tight ASCII non-funny-char loop:
+            while (codes[c] == 0) {
+                if (outPtr >= outEnd) {
+                    outBuf = _textBuffer.finishCurrentSegment();
+                    outPtr = 0;
+                    outEnd = outBuf.length;
+                }
+                outBuf[outPtr++] = (char) c;
+                c = _inputData.readUnsignedByte();
+            }
+            // Ok: end marker, escape or multi-byte?
+            if (c == INT_QUOTE) {
+                break main_loop;
+            }
+            switch (codes[c]) {
+            case 1: // backslash
+                c = _decodeEscaped();
+                break;
+            case 2: // 2-byte UTF
+                c = _decodeUtf8_2(c);
+                break;
+            case 3: // 3-byte UTF
+                c = _decodeUtf8_3(c);
+                break;
+            case 4: // 4-byte UTF
+                c = _decodeUtf8_4(c);
+                // Let's add first part right away:
+                outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
+                if (outPtr >= outBuf.length) {
+                    outBuf = _textBuffer.finishCurrentSegment();
+                    outPtr = 0;
+                    outEnd = outBuf.length;
+                }
+                c = 0xDC00 | (c & 0x3FF);
+                // And let the other char output down below
+                break;
+            default:
+                if (c < INT_SPACE) {
+                    _throwUnquotedSpace(c, "string value");
+                } else {
+                    // Is this good enough error message?
+                    _reportInvalidChar(c);
+                }
+            }
+            // Need more room?
+            if (outPtr >= outBuf.length) {
+                outBuf = _textBuffer.finishCurrentSegment();
+                outPtr = 0;
+                outEnd = outBuf.length;
+            }
+            // Ok, let's add char to output:
+            outBuf[outPtr++] = (char) c;
+        }
+        _textBuffer.setCurrentLength(outPtr);
+    }
+
+    /**
+     * Method called to skim through rest of unparsed String value,
+     * if it is not needed. This can be done bit faster if contents
+     * need not be stored for future access.
+     */
+    protected void _skipString() throws IOException
+    {
+        _tokenIncomplete = false;
+
+        // Need to be fully UTF-8 aware here:
+        final int[] codes = _icUTF8;
+
+        main_loop:
+        while (true) {
+            int c;
+
+            ascii_loop:
+            while (true) {
+                c = _inputData.readUnsignedByte();
+                if (codes[c] != 0) {
+                    break ascii_loop;
+                }
+            }
+            // Ok: end marker, escape or multi-byte?
+            if (c == INT_QUOTE) {
+                break main_loop;
+            }
+            
+            switch (codes[c]) {
+            case 1: // backslash
+                _decodeEscaped();
+                break;
+            case 2: // 2-byte UTF
+                _skipUtf8_2();
+                break;
+            case 3: // 3-byte UTF
+                _skipUtf8_3();
+                break;
+            case 4: // 4-byte UTF
+                _skipUtf8_4();
+                break;
+            default:
+                if (c < INT_SPACE) {
+                    _throwUnquotedSpace(c, "string value");
+                } else {
+                    // Is this good enough error message?
+                    _reportInvalidChar(c);
+                }
+            }
+        }
+    }
+
+    /**
+     * Method for handling cases where first non-space character
+     * of an expected value token is not legal for standard JSON content.
+     */
+    protected JsonToken _handleUnexpectedValue(int c)
+        throws IOException
+    {
+        // Most likely an error, unless we are to allow single-quote-strings
+        switch (c) {
+        case ']':
+            if (!_parsingContext.inArray()) {
+                break;
+            }
+            // fall through
+        case ',':
+            /* !!! TODO: 08-May-2016, tatu: To support `Feature.ALLOW_MISSING_VALUES` would
+             *    need handling here...
+             */
+            if (isEnabled(Feature.ALLOW_MISSING_VALUES)) {
+//               _inputPtr--;
+                _nextByte = c;
+               return JsonToken.VALUE_NULL;
+            }
+            // fall through
+        case '}':
+            // Error: neither is valid at this point; valid closers have
+            // been handled earlier
+            _reportUnexpectedChar(c, "expected a value");
+        case '\'':
+            if (isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
+                return _handleApos();
+            }
+            break;
+        case 'N':
+            _matchToken("NaN", 1);
+            if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+                return resetAsNaN("NaN", Double.NaN);
+            }
+            _reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+            break;
+        case 'I':
+            _matchToken("Infinity", 1);
+            if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+                return resetAsNaN("Infinity", Double.POSITIVE_INFINITY);
+            }
+            _reportError("Non-standard token 'Infinity': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+            break;
+        case '+': // note: '-' is taken as number
+            return _handleInvalidNumberStart(_inputData.readUnsignedByte(), false);
+        }
+        // [core#77] Try to decode most likely token
+        if (Character.isJavaIdentifierStart(c)) {
+            _reportInvalidToken(c, ""+((char) c), "('true', 'false' or 'null')");
+        }
+        // but if it doesn't look like a token:
+        _reportUnexpectedChar(c, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')");
+        return null;
+    }
+
+    protected JsonToken _handleApos() throws IOException
+    {
+        int c = 0;
+        // Otherwise almost verbatim copy of _finishString()
+        int outPtr = 0;
+        char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+
+        // Here we do want to do full decoding, hence:
+        final int[] codes = _icUTF8;
+
+        main_loop:
+        while (true) {
+            // Then the tight ascii non-funny-char loop:
+            ascii_loop:
+            while (true) {
+                int outEnd = outBuf.length;
+                if (outPtr >= outBuf.length) {
+                    outBuf = _textBuffer.finishCurrentSegment();
+                    outPtr = 0;
+                    outEnd = outBuf.length;
+                }
+                do {
+                    c = _inputData.readUnsignedByte();
+                    if (c == '\'') {
+                        break main_loop;
+                    }
+                    if (codes[c] != 0) {
+                        break ascii_loop;
+                    }
+                    outBuf[outPtr++] = (char) c;
+                } while (outPtr < outEnd);
+            }
+            switch (codes[c]) {
+            case 1: // backslash
+                c = _decodeEscaped();
+                break;
+            case 2: // 2-byte UTF
+                c = _decodeUtf8_2(c);
+                break;
+            case 3: // 3-byte UTF
+                c = _decodeUtf8_3(c);
+                break;
+            case 4: // 4-byte UTF
+                c = _decodeUtf8_4(c);
+                // Let's add first part right away:
+                outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
+                if (outPtr >= outBuf.length) {
+                    outBuf = _textBuffer.finishCurrentSegment();
+                    outPtr = 0;
+                }
+                c = 0xDC00 | (c & 0x3FF);
+                // And let the other char output down below
+                break;
+            default:
+                if (c < INT_SPACE) {
+                    _throwUnquotedSpace(c, "string value");
+                }
+                // Is this good enough error message?
+                _reportInvalidChar(c);
+            }
+            // Need more room?
+            if (outPtr >= outBuf.length) {
+                outBuf = _textBuffer.finishCurrentSegment();
+                outPtr = 0;
+            }
+            // Ok, let's add char to output:
+            outBuf[outPtr++] = (char) c;
+        }
+        _textBuffer.setCurrentLength(outPtr);
+
+        return JsonToken.VALUE_STRING;
+    }
+    
+    /**
+     * Method called if expected numeric value (due to leading sign) does not
+     * look like a number
+     */
+    protected JsonToken _handleInvalidNumberStart(int ch, boolean neg)
+        throws IOException
+    {
+        while (ch == 'I') {
+            ch = _inputData.readUnsignedByte();
+            String match;
+            if (ch == 'N') {
+                match = neg ? "-INF" :"+INF";
+            } else if (ch == 'n') {
+                match = neg ? "-Infinity" :"+Infinity";
+            } else {
+                break;
+            }
+            _matchToken(match, 3);
+            if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+                return resetAsNaN(match, neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
+            }
+            _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+        }
+        reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value");
+        return null;
+    }
+
+    protected final void _matchToken(String matchStr, int i) throws IOException
+    {
+        final int len = matchStr.length();
+        do {
+            int ch = _inputData.readUnsignedByte();
+            if (ch != matchStr.charAt(i)) {
+                _reportInvalidToken(ch, matchStr.substring(0, i));
+            }
+        } while (++i < len);
+
+        int ch = _inputData.readUnsignedByte();
+        if (ch >= '0' && ch != ']' && ch != '}') { // expected/allowed chars
+            _checkMatchEnd(matchStr, i, ch);
+        }
+        _nextByte = ch;
+    }
+
+    private final void _checkMatchEnd(String matchStr, int i, int ch) throws IOException {
+        // but actually only alphanums are problematic
+        char c = (char) _decodeCharForError(ch);
+        if (Character.isJavaIdentifierPart(c)) {
+            _reportInvalidToken(c, matchStr.substring(0, i));
+        }
+    }
+
+    /*
+    /**********************************************************
+    /* Internal methods, ws skipping, escape/unescape
+    /**********************************************************
+     */
+
+    private final int _skipWS() throws IOException
+    {
+        int i = _nextByte;
+        if (i < 0) {
+            i = _inputData.readUnsignedByte();
+        } else {
+            _nextByte = -1;
+        }
+        while (true) {
+            if (i > INT_SPACE) {
+                if (i == INT_SLASH || i == INT_HASH) {
+                    return _skipWSComment(i);
+                }
+                return i;
+            } else {
+                // 06-May-2016, tatu: Could verify validity of WS, but for now why bother.
+                //   ... but line number is useful thingy
+                if (i == INT_CR || i == INT_LF) {
+                    ++_currInputRow;
+                }
+            }
+            i = _inputData.readUnsignedByte();
+        }
+    }
+
+    private final int _skipWSComment(int i) throws IOException
+    {
+        while (true) {
+            if (i > INT_SPACE) {
+                if (i == INT_SLASH) {
+                    _skipComment();
+                } else if (i == INT_HASH) {
+                    if (!_skipYAMLComment()) {
+                        return i;
+                    }
+                } else {
+                    return i;
+                }
+            } else {
+                // 06-May-2016, tatu: Could verify validity of WS, but for now why bother.
+                //   ... but line number is useful thingy
+                if (i == INT_CR || i == INT_LF) {
+                    ++_currInputRow;
+                }
+                /*
+                if ((i != INT_SPACE) && (i != INT_LF) && (i != INT_CR)) {
+                    _throwInvalidSpace(i);
+                }
+                */
+            }
+            i = _inputData.readUnsignedByte();
+        }        
+    }
+
+    private final int _skipColon() throws IOException
+    {
+        int i = _nextByte;
+        if (i < 0) {
+            i = _inputData.readUnsignedByte();
+        } else {
+            _nextByte = -1;
+        }
+        // Fast path: colon with optional single-space/tab before and/or after:
+        if (i == INT_COLON) { // common case, no leading space
+            i = _inputData.readUnsignedByte();
+            if (i > INT_SPACE) { // nor trailing
+                if (i == INT_SLASH || i == INT_HASH) {
+                    return _skipColon2(i, true);
+                }
+                return i;
+            }
+            if (i == INT_SPACE || i == INT_TAB) {
+                i = _inputData.readUnsignedByte();
+                if (i > INT_SPACE) {
+                    if (i == INT_SLASH || i == INT_HASH) {
+                        return _skipColon2(i, true);
+                    }
+                    return i;
+                }
+            }
+            return _skipColon2(i, true); // true -> skipped colon
+        }
+        if (i == INT_SPACE || i == INT_TAB) {
+            i = _inputData.readUnsignedByte();
+        }
+        if (i == INT_COLON) {
+            i = _inputData.readUnsignedByte();
+            if (i > INT_SPACE) {
+                if (i == INT_SLASH || i == INT_HASH) {
+                    return _skipColon2(i, true);
+                }
+                return i;
+            }
+            if (i == INT_SPACE || i == INT_TAB) {
+                i = _inputData.readUnsignedByte();
+                if (i > INT_SPACE) {
+                    if (i == INT_SLASH || i == INT_HASH) {
+                        return _skipColon2(i, true);
+                    }
+                    return i;
+                }
+            }
+            return _skipColon2(i, true);
+        }
+        return _skipColon2(i, false);
+    }
+
+    private final int _skipColon2(int i, boolean gotColon) throws IOException
+    {
+        for (;; i = _inputData.readUnsignedByte()) {
+            if (i > INT_SPACE) {
+                if (i == INT_SLASH) {
+                    _skipComment();
+                    continue;
+                }
+                if (i == INT_HASH) {
+                    if (_skipYAMLComment()) {
+                        continue;
+                    }
+                }
+                if (gotColon) {
+                    return i;
+                }
+                if (i != INT_COLON) {
+                    _reportUnexpectedChar(i, "was expecting a colon to separate field name and value");
+                }
+                gotColon = true;
+            } else {
+                // 06-May-2016, tatu: Could verify validity of WS, but for now why bother.
+                //   ... but line number is useful thingy
+                if (i == INT_CR || i == INT_LF) {
+                    ++_currInputRow;
+                }
+            }
+        }
+    }
+
+    private final void _skipComment() throws IOException
+    {
+        if (!isEnabled(Feature.ALLOW_COMMENTS)) {
+            _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)");
+        }
+        int c = _inputData.readUnsignedByte();
+        if (c == '/') {
+            _skipLine();
+        } else if (c == '*') {
+            _skipCComment();
+        } else {
+            _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment");
+        }
+    }
+
+    private final void _skipCComment() throws IOException
+    {
+        // Need to be UTF-8 aware here to decode content (for skipping)
+        final int[] codes = CharTypes.getInputCodeComment();
+        int i = _inputData.readUnsignedByte();
+
+        // Ok: need the matching '*/'
+        main_loop:
+        while (true) {
+            int code = codes[i];
+            if (code != 0) {
+                switch (code) {
+                case '*':
+                    i = _inputData.readUnsignedByte();
+                    if (i == INT_SLASH) {
+                        return;
+                    }
+                    continue main_loop;
+                case INT_LF:
+                case INT_CR:
+                    ++_currInputRow;
+                    break;
+                case 2: // 2-byte UTF
+                    _skipUtf8_2();
+                    break;
+                case 3: // 3-byte UTF
+                    _skipUtf8_3();
+                    break;
+                case 4: // 4-byte UTF
+                    _skipUtf8_4();
+                    break;
+                default: // e.g. -1
+                    // Is this good enough error message?
+                    _reportInvalidChar(i);
+                }
+            }
+            i = _inputData.readUnsignedByte();
+        }
+    }
+
+    private final boolean _skipYAMLComment() throws IOException
+    {
+        if (!isEnabled(Feature.ALLOW_YAML_COMMENTS)) {
+            return false;
+        }
+        _skipLine();
+        return true;
+    }
+
+    /**
+     * Method for skipping contents of an input line; usually for CPP
+     * and YAML style comments.
+     */
+    private final void _skipLine() throws IOException
+    {
+        // Ok: need to find EOF or linefeed
+        final int[] codes = CharTypes.getInputCodeComment();
+        while (true) {
+            int i = _inputData.readUnsignedByte();
+            int code = codes[i];
+            if (code != 0) {
+                switch (code) {
+                case INT_LF:
+                case INT_CR:
+                    ++_currInputRow;
+                    return;
+                case '*': // nop for these comments
+                    break;
+                case 2: // 2-byte UTF
+                    _skipUtf8_2();
+                    break;
+                case 3: // 3-byte UTF
+                    _skipUtf8_3();
+                    break;
+                case 4: // 4-byte UTF
+                    _skipUtf8_4();
+                    break;
+                default: // e.g. -1
+                    if (code < 0) {
+                        // Is this good enough error message?
+                        _reportInvalidChar(i);
+                    }
+                }
+            }
+        }
+    }
+    
+    @Override
+    protected char _decodeEscaped() throws IOException
+    {
+        int c = _inputData.readUnsignedByte();
+
+        switch (c) {
+            // First, ones that are mapped
+        case 'b':
+            return '\b';
+        case 't':
+            return '\t';
+        case 'n':
+            return '\n';
+        case 'f':
+            return '\f';
+        case 'r':
+            return '\r';
+
+            // And these are to be returned as they are
+        case '"':
+        case '/':
+        case '\\':
+            return (char) c;
+
+        case 'u': // and finally hex-escaped
+            break;
+
+        default:
+            return _handleUnrecognizedCharacterEscape((char) _decodeCharForError(c));
+        }
+
+        // Ok, a hex escape. Need 4 characters
+        int value = 0;
+        for (int i = 0; i < 4; ++i) {
+            int ch = _inputData.readUnsignedByte();
+            int digit = CharTypes.charToHex(ch);
+            if (digit < 0) {
+                _reportUnexpectedChar(ch, "expected a hex-digit for character escape sequence");
+            }
+            value = (value << 4) | digit;
+        }
+        return (char) value;
+    }
+
+    protected int _decodeCharForError(int firstByte) throws IOException
+    {
+        int c = firstByte & 0xFF;
+        if (c > 0x7F) { // if >= 0, is ascii and fine as is
+            int needed;
+            
+            // Ok; if we end here, we got multi-byte combination
+            if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF)
+                c &= 0x1F;
+                needed = 1;
+            } else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF)
+                c &= 0x0F;
+                needed = 2;
+            } else if ((c & 0xF8) == 0xF0) {
+                // 4 bytes; double-char with surrogates and all...
+                c &= 0x07;
+                needed = 3;
+            } else {
+                _reportInvalidInitial(c & 0xFF);
+                needed = 1; // never gets here
+            }
+
+            int d = _inputData.readUnsignedByte();
+            if ((d & 0xC0) != 0x080) {
+                _reportInvalidOther(d & 0xFF);
+            }
+            c = (c << 6) | (d & 0x3F);
+            
+            if (needed > 1) { // needed == 1 means 2 bytes total
+                d = _inputData.readUnsignedByte(); // 3rd byte
+                if ((d & 0xC0) != 0x080) {
+                    _reportInvalidOther(d & 0xFF);
+                }
+                c = (c << 6) | (d & 0x3F);
+                if (needed > 2) { // 4 bytes? (need surrogates)
+                    d = _inputData.readUnsignedByte();
+                    if ((d & 0xC0) != 0x080) {
+                        _reportInvalidOther(d & 0xFF);
+                    }
+                    c = (c << 6) | (d & 0x3F);
+                }
+            }
+        }
+        return c;
+    }
+
+    /*
+    /**********************************************************
+    /* Internal methods,UTF8 decoding
+    /**********************************************************
+     */
+
+    private final int _decodeUtf8_2(int c) throws IOException
+    {
+        int d = _inputData.readUnsignedByte();
+        if ((d & 0xC0) != 0x080) {
+            _reportInvalidOther(d & 0xFF);
+        }
+        return ((c & 0x1F) << 6) | (d & 0x3F);
+    }
+
+    private final int _decodeUtf8_3(int c1) throws IOException
+    {
+        c1 &= 0x0F;
+        int d = _inputData.readUnsignedByte();
+        if ((d & 0xC0) != 0x080) {
+            _reportInvalidOther(d & 0xFF);
+        }
+        int c = (c1 << 6) | (d & 0x3F);
+        d = _inputData.readUnsignedByte();
+        if ((d & 0xC0) != 0x080) {
+            _reportInvalidOther(d & 0xFF);
+        }
+        c = (c << 6) | (d & 0x3F);
+        return c;
+    }
+
+    /**
+     * @return Character value <b>minus 0x10000</c>; this so that caller
+     *    can readily expand it to actual surrogates
+     */
+    private final int _decodeUtf8_4(int c) throws IOException
+    {
+        int d = _inputData.readUnsignedByte();
+        if ((d & 0xC0) != 0x080) {
+            _reportInvalidOther(d & 0xFF);
+        }
+        c = ((c & 0x07) << 6) | (d & 0x3F);
+        d = _inputData.readUnsignedByte();
+        if ((d & 0xC0) != 0x080) {
+            _reportInvalidOther(d & 0xFF);
+        }
+        c = (c << 6) | (d & 0x3F);
+        d = _inputData.readUnsignedByte();
+        if ((d & 0xC0) != 0x080) {
+            _reportInvalidOther(d & 0xFF);
+        }
+
+        /* note: won't change it to negative here, since caller
+         * already knows it'll need a surrogate
+         */
+        return ((c << 6) | (d & 0x3F)) - 0x10000;
+    }
+
+    private final void _skipUtf8_2() throws IOException
+    {
+        int c = _inputData.readUnsignedByte();
+        if ((c & 0xC0) != 0x080) {
+            _reportInvalidOther(c & 0xFF);
+        }
+    }
+
+    /* Alas, can't heavily optimize skipping, since we still have to
+     * do validity checks...
+     */
+    private final void _skipUtf8_3() throws IOException
+    {
+        //c &= 0x0F;
+        int c = _inputData.readUnsignedByte();
+        if ((c & 0xC0) != 0x080) {
+            _reportInvalidOther(c & 0xFF);
+        }
+        c = _inputData.readUnsignedByte();
+        if ((c & 0xC0) != 0x080) {
+            _reportInvalidOther(c & 0xFF);
+        }
+    }
+
+    private final void _skipUtf8_4() throws IOException
+    {
+        int d = _inputData.readUnsignedByte();
+        if ((d & 0xC0) != 0x080) {
+            _reportInvalidOther(d & 0xFF);
+        }
+        d = _inputData.readUnsignedByte();
+        if ((d & 0xC0) != 0x080) {
+            _reportInvalidOther(d & 0xFF);
+        }
+        d = _inputData.readUnsignedByte();
+        if ((d & 0xC0) != 0x080) {
+            _reportInvalidOther(d & 0xFF);
+        }
+    }
+
+    /*
+    /**********************************************************
+    /* Internal methods, error reporting
+    /**********************************************************
+     */
+
+    protected void _reportInvalidToken(int ch, String matchedPart) throws IOException
+     {
+         _reportInvalidToken(ch, matchedPart, "'null', 'true', 'false' or NaN");
+     }
+
+    protected void _reportInvalidToken(int ch, String matchedPart, String msg)
+        throws IOException
+     {
+         StringBuilder sb = new StringBuilder(matchedPart);
+
+         /* Let's just try to find what appears to be the token, using
+          * regular Java identifier character rules. It's just a heuristic,
+          * nothing fancy here (nor fast).
+          */
+         while (true) {
+             char c = (char) _decodeCharForError(ch);
+             if (!Character.isJavaIdentifierPart(c)) {
+                 break;
+             }
+             sb.append(c);
+             ch = _inputData.readUnsignedByte();
+         }
+         _reportError("Unrecognized token '"+sb.toString()+"': was expecting "+msg);
+     }
+        
+    protected void _reportInvalidChar(int c)
+        throws JsonParseException
+    {
+        // Either invalid WS or illegal UTF-8 start char
+        if (c < INT_SPACE) {
+            _throwInvalidSpace(c);
+        }
+        _reportInvalidInitial(c);
+    }
+
+    protected void _reportInvalidInitial(int mask)
+        throws JsonParseException
+    {
+        _reportError("Invalid UTF-8 start byte 0x"+Integer.toHexString(mask));
+    }
+
+    private void _reportInvalidOther(int mask)
+        throws JsonParseException
+    {
+        _reportError("Invalid UTF-8 middle byte 0x"+Integer.toHexString(mask));
+    }
+
+    private static int[] _growArrayBy(int[] arr, int more)
+    {
+        if (arr == null) {
+            return new int[more];
+        }
+        return Arrays.copyOf(arr, arr.length + more);
+    }
+
+    /*
+    /**********************************************************
+    /* Internal methods, binary access
+    /**********************************************************
+     */
+
+    /**
+     * Efficient handling for incremental parsing of base64-encoded
+     * textual content.
+     */
+    @SuppressWarnings("resource")
+    protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOException
+    {
+        ByteArrayBuilder builder = _getByteArrayBuilder();
+
+        //main_loop:
+        while (true) {
+            // first, we'll skip preceding white space, if any
+            int ch;
+            do {
+                ch = _inputData.readUnsignedByte();
+            } while (ch <= INT_SPACE);
+            int bits = b64variant.decodeBase64Char(ch);
+            if (bits < 0) { // reached the end, fair and square?
+                if (ch == INT_QUOTE) {
+                    return builder.toByteArray();
+                }
+                bits = _decodeBase64Escape(b64variant, ch, 0);
+                if (bits < 0) { // white space to skip
+                    continue;
+                }
+            }
+            int decodedData = bits;
+            
+            // then second base64 char; can't get padding yet, nor ws
+            ch = _inputData.readUnsignedByte();
+            bits = b64variant.decodeBase64Char(ch);
+            if (bits < 0) {
+                bits = _decodeBase64Escape(b64variant, ch, 1);
+            }
+            decodedData = (decodedData << 6) | bits;
+            // third base64 char; can be padding, but not ws
+            ch = _inputData.readUnsignedByte();
+            bits = b64variant.decodeBase64Char(ch);
+
+            // First branch: can get padding (-> 1 byte)
+            if (bits < 0) {
+                if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+                    // could also just be 'missing'  padding
+                    if (ch == '"' && !b64variant.usesPadding()) {
+                        decodedData >>= 4;
+                        builder.append(decodedData);
+                        return builder.toByteArray();
+                    }
+                    bits = _decodeBase64Escape(b64variant, ch, 2);
+                }
+                if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+                    ch = _inputData.readUnsignedByte();
+                    if (!b64variant.usesPaddingChar(ch)) {
+                        throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
+                    }
+                    // Got 12 bits, only need 8, need to shift
+                    decodedData >>= 4;
+                    builder.append(decodedData);
+                    continue;
+                }
+            }
+            // Nope, 2 or 3 bytes
+            decodedData = (decodedData << 6) | bits;
+            // fourth and last base64 char; can be padding, but not ws
+            ch = _inputData.readUnsignedByte();
+            bits = b64variant.decodeBase64Char(ch);
+            if (bits < 0) {
+                if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+                    // could also just be 'missing'  padding
+                    if (ch == '"' && !b64variant.usesPadding()) {
+                        decodedData >>= 2;
+                        builder.appendTwoBytes(decodedData);
+                        return builder.toByteArray();
+                    }
+                    bits = _decodeBase64Escape(b64variant, ch, 3);
+                }
+                if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+                    /* With padding we only get 2 bytes; but we have
+                     * to shift it a bit so it is identical to triplet
+                     * case with partial output.
+                     * 3 chars gives 3x6 == 18 bits, of which 2 are
+                     * dummies, need to discard:
+                     */
+                    decodedData >>= 2;
+                    builder.appendTwoBytes(decodedData);
+                    continue;
+                }
+            }
+            // otherwise, our triplet is now complete
+            decodedData = (decodedData << 6) | bits;
+            builder.appendThreeBytes(decodedData);
+        }
+    }
+
+    /*
+    /**********************************************************
+    /* Improved location updating (refactored in 2.7)
+    /**********************************************************
+     */
+
+    @Override
+    public JsonLocation getTokenLocation() {
+        final Object src = _ioContext.getSourceReference();
+        return new JsonLocation(src,
+                -1L, -1L, _tokenInputRow, -1);
+    }
+
+    @Override
+    public JsonLocation getCurrentLocation() {
+        final Object src = _ioContext.getSourceReference();
+        return new JsonLocation(src,
+                -1L, -1L, _currInputRow, -1);
+    }
+
+    /*
+    /**********************************************************
+    /* Internal methods, other
+    /**********************************************************
+     */
+
+    /**
+     * Helper method needed to fix [Issue#148], masking of 0x00 character
+     */
+    private final static int pad(int q, int bytes) {
+        return (bytes == 4) ? q : (q | (-1 << (bytes << 3)));
+    }
+}
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
index 5524691..80559d4 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
@@ -22,7 +22,6 @@
     private final static byte BYTE_BACKSLASH = (byte) '\\';
     private final static byte BYTE_COMMA = (byte) ',';
     private final static byte BYTE_COLON = (byte) ':';
-    private final static byte BYTE_QUOTE = (byte) '"';
 
     // intermediate copies only made up to certain length...
     private final static int MAX_BYTES_TO_BUFFER = 512;
@@ -35,7 +34,7 @@
 
     /*
     /**********************************************************
-    /* Output buffering
+    /* Configuration
     /**********************************************************
      */
 
@@ -45,6 +44,20 @@
     final protected OutputStream _outputStream;
 
     /**
+     * Character used for quoting JSON Object property names
+     * and String values.
+     *
+     * @since 2.8
+     */
+    protected byte _quoteChar = '"'; // TODO: make configurable
+    
+    /*
+    /**********************************************************
+    /* Output buffering
+    /**********************************************************
+     */
+
+    /**
      * Intermediate buffer in which contents are buffered before
      * being written using {@link #_outputStream}.
      */
@@ -193,7 +206,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         // But as one segment, or multiple?
         if (len <= _outputMaxContiguous) {
             if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
@@ -207,7 +220,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
     
     @Override
@@ -234,7 +247,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         int len = name.appendQuotedUTF8(_outputBuffer, _outputTail);
         if (len < 0) { // couldn't append, bit longer processing
             _writeBytes(name.asQuotedUTF8());
@@ -244,7 +257,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }    
 
     private final void _writeUnq(SerializableString name) throws IOException {
@@ -281,7 +294,7 @@
     public final void writeEndArray() throws IOException
     {
         if (!_writeContext.inArray()) {
-            _reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc());
+            _reportError("Current context not Array but "+_writeContext.typeDesc());
         }
         if (_cfgPrettyPrinter != null) {
             _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount());
@@ -309,11 +322,30 @@
         }
     }
 
+    @Override // since 2.8
+    public void writeStartObject(Object forValue) throws IOException
+    {
+        _verifyValueWrite("start an object");
+        JsonWriteContext ctxt = _writeContext.createChildObjectContext();
+        _writeContext = ctxt;
+        if (forValue != null) {
+            ctxt.setCurrentValue(forValue);
+        }
+        if (_cfgPrettyPrinter != null) {
+            _cfgPrettyPrinter.writeStartObject(this);
+        } else {
+            if (_outputTail >= _outputEnd) {
+                _flushBuffer();
+            }
+            _outputBuffer[_outputTail++] = '{';
+        }
+    }
+    
     @Override
     public final void writeEndObject() throws IOException
     {
         if (!_writeContext.inObject()) {
-            _reportError("Current context not an object but "+_writeContext.getTypeDesc());
+            _reportError("Current context not Object but "+_writeContext.typeDesc());
         }
         if (_cfgPrettyPrinter != null) {
             _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
@@ -353,7 +385,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         name.getChars(0, len, _charBuffer, 0);
         // But as one segment, or multiple?
         if (len <= _outputMaxContiguous) {
@@ -367,7 +399,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     protected final void _writePPFieldName(SerializableString name) throws IOException
@@ -387,14 +419,14 @@
             if (_outputTail >= _outputEnd) {
                 _flushBuffer();
             }
-            _outputBuffer[_outputTail++] = BYTE_QUOTE;
+            _outputBuffer[_outputTail++] = _quoteChar;
         }
         _writeBytes(name.asQuotedUTF8());
         if (addQuotes) {
             if (_outputTail >= _outputEnd) {
                 _flushBuffer();
             }
-            _outputBuffer[_outputTail++] = BYTE_QUOTE;
+            _outputBuffer[_outputTail++] = _quoteChar;
         }
     }
     
@@ -421,12 +453,12 @@
         if ((_outputTail + len) >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         _writeStringSegment(text, 0, len); // we checked space already above
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     @Override
@@ -436,7 +468,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         // One or multiple segments?
         if (len <= _outputMaxContiguous) {
             if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
@@ -450,7 +482,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     @Override
@@ -460,7 +492,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         int len = text.appendQuotedUTF8(_outputBuffer, _outputTail);
         if (len < 0) {
             _writeBytes(text.asQuotedUTF8());
@@ -470,7 +502,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
     
     @Override
@@ -480,12 +512,12 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         _writeBytes(text, offset, length);
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     @Override
@@ -495,7 +527,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         // One or multiple segments?
         if (len <= _outputMaxContiguous) {
             _writeUTF8Segment(text, offset, len);
@@ -505,7 +537,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     /*
@@ -733,13 +765,13 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         _writeBinary(b64variant, data, offset, offset+len);
         // and closing quotes
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     @Override
@@ -752,7 +784,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         byte[] encodingBuffer = _ioContext.allocBase64Buffer();
         int bytes;
         try {
@@ -772,7 +804,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         return bytes;
     }
     
@@ -801,9 +833,9 @@
         if ((_outputTail + 8) >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     } 
     
     @Override
@@ -826,9 +858,9 @@
         if ((_outputTail + 13) >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }    
 
     @Override
@@ -851,9 +883,9 @@
         if ((_outputTail + 23) >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     @Override
@@ -929,12 +961,12 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
         writeRaw(value);
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = BYTE_QUOTE;
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
     
     @Override
@@ -966,67 +998,39 @@
     @Override
     protected final void _verifyValueWrite(String typeMsg) throws IOException
     {
-        int status = _writeContext.writeValue();
-        if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
-            _reportError("Can not "+typeMsg+", expecting field name");
-        }
-        if (_cfgPrettyPrinter == null) {
-            byte b;
-            switch (status) {
-            case JsonWriteContext.STATUS_OK_AFTER_COMMA:
-                b = BYTE_COMMA;
-                break;
-            case JsonWriteContext.STATUS_OK_AFTER_COLON:
-                b = BYTE_COLON;
-                break;
-            case JsonWriteContext.STATUS_OK_AFTER_SPACE: // root-value separator
-                if (_rootValueSeparator != null) {
-                    byte[] raw = _rootValueSeparator.asUnquotedUTF8();
-                    if (raw.length > 0) {
-                        _writeBytes(raw);
-                    }
-                }
-                return;
-            case JsonWriteContext.STATUS_OK_AS_IS:
-            default:
-                return;
-            }
-            if (_outputTail >= _outputEnd) {
-                _flushBuffer();
-            }
-            _outputBuffer[_outputTail] = b;
-            ++_outputTail;
+        final int status = _writeContext.writeValue();
+        if (_cfgPrettyPrinter != null) {
+            // Otherwise, pretty printer knows what to do...
+            _verifyPrettyValueWrite(typeMsg, status);
             return;
         }
-        // Otherwise, pretty printer knows what to do...
-        _verifyPrettyValueWrite(typeMsg, status);
-    }
-
-    protected final void _verifyPrettyValueWrite(String typeMsg, int status) throws IOException
-    {
-        // If we have a pretty printer, it knows what to do:
+        byte b;
         switch (status) {
-        case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array
-            _cfgPrettyPrinter.writeArrayValueSeparator(this);
+        case JsonWriteContext.STATUS_OK_AS_IS:
+        default:
+            return;
+        case JsonWriteContext.STATUS_OK_AFTER_COMMA:
+            b = BYTE_COMMA;
             break;
         case JsonWriteContext.STATUS_OK_AFTER_COLON:
-            _cfgPrettyPrinter.writeObjectFieldValueSeparator(this);
+            b = BYTE_COLON;
             break;
-        case JsonWriteContext.STATUS_OK_AFTER_SPACE:
-            _cfgPrettyPrinter.writeRootValueSeparator(this);
-            break;
-        case JsonWriteContext.STATUS_OK_AS_IS:
-            // First entry, but of which context?
-            if (_writeContext.inArray()) {
-                _cfgPrettyPrinter.beforeArrayValues(this);
-            } else if (_writeContext.inObject()) {
-                _cfgPrettyPrinter.beforeObjectEntries(this);
+        case JsonWriteContext.STATUS_OK_AFTER_SPACE: // root-value separator
+            if (_rootValueSeparator != null) {
+                byte[] raw = _rootValueSeparator.asUnquotedUTF8();
+                if (raw.length > 0) {
+                    _writeBytes(raw);
+                }
             }
-            break;
-        default:
-            _throwInternal();
-            break;
+            return;
+        case JsonWriteContext.STATUS_EXPECT_NAME:
+            _reportCantWriteValueExpectName(typeMsg);
+            return;
         }
+        if (_outputTail >= _outputEnd) {
+            _flushBuffer();
+        }
+        _outputBuffer[_outputTail++] = b;
     }
 
     /*
@@ -1158,7 +1162,7 @@
             if (_outputTail >= _outputEnd) {
                 _flushBuffer();
             }
-            _outputBuffer[_outputTail++] = BYTE_QUOTE;        
+            _outputBuffer[_outputTail++] = _quoteChar;        
         }
 
         int left = text.length();
@@ -1178,7 +1182,7 @@
             if (_outputTail >= _outputEnd) {
                 _flushBuffer();
             }
-            _outputBuffer[_outputTail++] = BYTE_QUOTE;
+            _outputBuffer[_outputTail++] = _quoteChar;
         }
     }
 
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
index 9296543..5a0dcda 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
@@ -15,8 +15,6 @@
 /**
  * This is a concrete implementation of {@link JsonParser}, which is
  * based on a {@link java.io.InputStream} as the input source.
- *<p>
- * Note: non-final since version 2.3.
  */
 public class UTF8StreamJsonParser
     extends ParserBase
@@ -185,8 +183,7 @@
     /**********************************************************
      */
 
-    @Override
-    protected final boolean loadMore() throws IOException
+    protected final boolean _loadMore() throws IOException
     {
         final int bufSize = _inputEnd;
 
@@ -322,6 +319,33 @@
         return _getText2(_currToken);
     }
 
+    @Override // since 2.8
+    public int getText(Writer writer) throws IOException
+    {
+        JsonToken t = _currToken;
+        if (t == JsonToken.VALUE_STRING) {
+            if (_tokenIncomplete) {
+                _tokenIncomplete = false;
+                _finishString(); // only strings can be incomplete
+            }
+            return _textBuffer.contentsToWriter(writer);
+        }
+        if (t == JsonToken.FIELD_NAME) {
+            String n = _parsingContext.getCurrentName();
+            writer.write(n);
+            return n.length();
+        }
+        if (t != null) {
+            if (t.isNumeric()) {
+                return _textBuffer.contentsToWriter(writer);
+            }
+            char[] ch = t.asCharArray();
+            writer.write(ch);
+            return ch.length;
+        }
+        return 0;
+    }
+
     // // // Let's override default impls for improved performance
     
     // @since 2.1
@@ -563,7 +587,7 @@
             int ch;
             do {
                 if (_inputPtr >= _inputEnd) {
-                    loadMoreGuaranteed();
+                    _loadMoreGuaranteed();
                 }
                 ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
             } while (ch <= INT_SPACE);
@@ -590,7 +614,7 @@
             // then second base64 char; can't get padding yet, nor ws
 
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++] & 0xFF;
             bits = b64variant.decodeBase64Char(ch);
@@ -601,7 +625,7 @@
 
             // third base64 char; can be padding, but not ws
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++] & 0xFF;
             bits = b64variant.decodeBase64Char(ch);
@@ -620,7 +644,7 @@
                 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
                     // Ok, must get padding
                     if (_inputPtr >= _inputEnd) {
-                        loadMoreGuaranteed();
+                        _loadMoreGuaranteed();
                     }
                     ch = _inputBuffer[_inputPtr++] & 0xFF;
                     if (!b64variant.usesPaddingChar(ch)) {
@@ -636,7 +660,7 @@
             decodedData = (decodedData << 6) | bits;
             // fourth and last base64 char; can be padding, but not ws
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++] & 0xFF;
             bits = b64variant.decodeBase64Char(ch);
@@ -734,7 +758,7 @@
         // Nope: do we then expect a comma?
         if (_parsingContext.expectComma()) {
             if (i != INT_COMMA) {
-                _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
+                _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
             }
             i = _skipWS();
         }
@@ -870,7 +894,15 @@
         }
         return (_currToken = t);
     }
-    
+
+    @Override
+    public void finishToken() throws IOException {
+        if (_tokenIncomplete) {
+            _tokenIncomplete = false;
+            _finishString(); // only strings can be incomplete
+        }
+    }
+
     /*
     /**********************************************************
     /* Public API, traversal, nextXxxValue/nextFieldName
@@ -920,7 +952,7 @@
         // Nope: do we then expect a comma?
         if (_parsingContext.expectComma()) {
             if (i != INT_COMMA) {
-                _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
+                _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
             }
             i = _skipWS();
         }
@@ -1007,7 +1039,7 @@
         // Nope: do we then expect a comma?
         if (_parsingContext.expectComma()) {
             if (i != INT_COMMA) {
-                _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
+                _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
             }
             i = _skipWS();
         }
@@ -1406,7 +1438,7 @@
         outBuf[outPtr++] = '-';
         // Must have something after sign too
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
         // Note: must be followed by a digit
@@ -1467,7 +1499,7 @@
     {
         // Ok, parse the rest
         while (true) {
-            if (_inputPtr >= _inputEnd && !loadMore()) {
+            if (_inputPtr >= _inputEnd && !_loadMore()) {
                 _textBuffer.setCurrentLength(outPtr);
                 return resetInt(negative, intPartLength);
             }
@@ -1504,7 +1536,7 @@
     private final int _verifyNoLeadingZeroes() throws IOException
     {
         // Ok to have plain "0"
-        if (_inputPtr >= _inputEnd && !loadMore()) {
+        if (_inputPtr >= _inputEnd && !_loadMore()) {
             return INT_0;
         }
         int ch = _inputBuffer[_inputPtr] & 0xFF;
@@ -1519,7 +1551,7 @@
         // if so, just need to skip either all zeroes (if followed by number); or all but one (if non-number)
         ++_inputPtr; // Leading zero to be skipped
         if (ch == INT_0) {
-            while (_inputPtr < _inputEnd || loadMore()) {
+            while (_inputPtr < _inputEnd || _loadMore()) {
                 ch = _inputBuffer[_inputPtr] & 0xFF;
                 if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
                     return INT_0;
@@ -1549,7 +1581,7 @@
 
             fract_loop:
             while (true) {
-                if (_inputPtr >= _inputEnd && !loadMore()) {
+                if (_inputPtr >= _inputEnd && !_loadMore()) {
                     eof = true;
                     break fract_loop;
                 }
@@ -1579,7 +1611,7 @@
             outBuf[outPtr++] = (char) c;
             // Not optional, can require that we get one more char
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             c = (int) _inputBuffer[_inputPtr++] & 0xFF;
             // Sign indicator?
@@ -1591,7 +1623,7 @@
                 outBuf[outPtr++] = (char) c;
                 // Likewise, non optional:
                 if (_inputPtr >= _inputEnd) {
-                    loadMoreGuaranteed();
+                    _loadMoreGuaranteed();
                 }
                 c = (int) _inputBuffer[_inputPtr++] & 0xFF;
             }
@@ -1604,7 +1636,7 @@
                     outPtr = 0;
                 }
                 outBuf[outPtr++] = (char) c;
-                if (_inputPtr >= _inputEnd && !loadMore()) {
+                if (_inputPtr >= _inputEnd && !_loadMore()) {
                     eof = true;
                     break exp_loop;
                 }
@@ -1878,8 +1910,8 @@
     protected String slowParseName() throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            if (!loadMore()) {
-                _reportInvalidEOF(": was expecting closing '\"' for name");
+            if (!_loadMore()) {
+                _reportInvalidEOF(": was expecting closing '\"' for name", JsonToken.FIELD_NAME);
             }
         }
         int i = _inputBuffer[_inputPtr++] & 0xFF;
@@ -1909,7 +1941,7 @@
      * an escape sequence is detected (or alternatively for long
      * names, one crossing input buffer boundary).
      * Needs to be able to handle more exceptional cases, gets slower,
-     * and hance is offlined to a separate method.
+     * and hence is offlined to a separate method.
      */
     protected final String parseEscapedName(int[] quads, int qlen, int currQuad, int ch,
             int currQuadBytes) throws IOException
@@ -1934,7 +1966,7 @@
                     ch = _decodeEscaped();
                 }
                 /* Oh crap. May need to UTF-8 (re-)encode it, if it's
-                 * beyond 7-bit ascii. Gets pretty messy.
+                 * beyond 7-bit ASCII. Gets pretty messy.
                  * If this happens often, may want to use different name
                  * canonicalization to avoid these hits.
                  */
@@ -1984,8 +2016,8 @@
                 currQuadBytes = 1;
             }
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOF(" in field name");
+                if (!_loadMore()) {
+                    _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
                 }
             }
             ch = _inputBuffer[_inputPtr++] & 0xFF;
@@ -2054,8 +2086,8 @@
                 currQuadBytes = 1;
             }
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOF(" in field name");
+                if (!_loadMore()) {
+                    _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
                 }
             }
             ch = _inputBuffer[_inputPtr] & 0xFF;
@@ -2086,8 +2118,8 @@
     protected String _parseAposName() throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            if (!loadMore()) {
-                _reportInvalidEOF(": was expecting closing '\'' for name");
+            if (!_loadMore()) {
+                _reportInvalidEOF(": was expecting closing '\'' for field name", JsonToken.FIELD_NAME);
             }
         }
         int ch = _inputBuffer[_inputPtr++] & 0xFF;
@@ -2168,8 +2200,8 @@
                 currQuadBytes = 1;
             }
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOF(" in field name");
+                if (!_loadMore()) {
+                    _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
                 }
             }
             ch = _inputBuffer[_inputPtr++] & 0xFF;
@@ -2304,7 +2336,7 @@
                     needed = ch = 1; // never really gets this far
                 }
                 if ((ix + needed) > byteLen) {
-                    _reportInvalidEOF(" in field name");
+                    _reportInvalidEOF(" in field name", JsonToken.FIELD_NAME);
                 }
                 
                 // Ok, always need at least one more:
@@ -2368,13 +2400,17 @@
     /**********************************************************
      */
 
+    protected void _loadMoreGuaranteed() throws IOException {
+        if (!_loadMore()) { _reportInvalidEOF(); }
+    }
+    
     @Override
     protected void _finishString() throws IOException
     {
         // First, single tight loop for ASCII content, not split across input buffer boundary:        
         int ptr = _inputPtr;
         if (ptr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
             ptr = _inputPtr;
         }
         int outPtr = 0;
@@ -2408,7 +2444,7 @@
         // First, single tight loop for ASCII content, not split across input buffer boundary:        
         int ptr = _inputPtr;
         if (ptr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
             ptr = _inputPtr;
         }
         int outPtr = 0;
@@ -2450,7 +2486,7 @@
             while (true) {
                 int ptr = _inputPtr;
                 if (ptr >= _inputEnd) {
-                    loadMoreGuaranteed();
+                    _loadMoreGuaranteed();
                     ptr = _inputPtr;
                 }
                 if (outPtr >= outBuf.length) {
@@ -2540,7 +2576,7 @@
                 int ptr = _inputPtr;
                 int max = _inputEnd;
                 if (ptr >= max) {
-                    loadMoreGuaranteed();
+                    _loadMoreGuaranteed();
                     ptr = _inputPtr;
                     max = _inputEnd;
                 }
@@ -2591,7 +2627,29 @@
     {
         // Most likely an error, unless we are to allow single-quote-strings
         switch (c) {
+        /*
+         * This check proceeds only if the Feature.ALLOW_MISSING_VALUES is enabled
+         * The Check is for missing values. Incase of missing values in an array, the next token will be either ',' or ']'.
+         * This case, decrements the already incremented _inputPtr in the buffer in case of comma(,) 
+         * so that the existing flow goes back to checking the next token which will be comma again and
+         * it continues the parsing.
+         * Also the case returns NULL as current token in case of ',' or ']'.    
+         */
         case ']':
+            if (!_parsingContext.inArray()) {
+                break;
+            }
+            // fall through
+        case ',':
+            /* 28-Mar-2016: [core#116]: If Feature.ALLOW_MISSING_VALUES is enabled
+             *   we may allow "missing values", that is, encountering a trailing
+             *   comma or closing marker where value would be expected
+             */
+            if (isEnabled(Feature.ALLOW_MISSING_VALUES)) {
+               _inputPtr--;
+               return JsonToken.VALUE_NULL;
+            }
+            // fall through
         case '}':
             // Error: neither is valid at this point; valid closers have
             // been handled earlier
@@ -2617,13 +2675,13 @@
             break;
         case '+': // note: '-' is taken as number
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOFInValue();
+                if (!_loadMore()) {
+                    _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_INT);
                 }
             }
             return _handleInvalidNumberStart(_inputBuffer[_inputPtr++] & 0xFF, false);
         }
-        // [Issue#77] Try to decode most likely token
+        // [core#77] Try to decode most likely token
         if (Character.isJavaIdentifierStart(c)) {
             _reportInvalidToken(""+((char) c), "('true', 'false' or 'null')");
         }
@@ -2650,7 +2708,7 @@
             ascii_loop:
             while (true) {
                 if (_inputPtr >= _inputEnd) {
-                    loadMoreGuaranteed();
+                    _loadMoreGuaranteed();
                 }
                 if (outPtr >= outBuf.length) {
                     outBuf = _textBuffer.finishCurrentSegment();
@@ -2731,8 +2789,8 @@
     {
         while (ch == 'I') {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOFInValue();
+                if (!_loadMore()) {
+                    _reportInvalidEOFInValue(JsonToken.VALUE_NUMBER_FLOAT); // possibly?
                 }
             }
             ch = _inputBuffer[_inputPtr++];
@@ -2778,7 +2836,7 @@
     {
         final int len = matchStr.length();
         do {
-            if (((_inputPtr >= _inputEnd) && !loadMore())
+            if (((_inputPtr >= _inputEnd) && !_loadMore())
                 ||  (_inputBuffer[_inputPtr] != matchStr.charAt(i))) {
                 _reportInvalidToken(matchStr.substring(0, i));
             }
@@ -2786,7 +2844,7 @@
         } while (++i < len);
     
         // but let's also ensure we either get EOF, or non-alphanum char...
-        if (_inputPtr >= _inputEnd && !loadMore()) {
+        if (_inputPtr >= _inputEnd && !_loadMore()) {
             return;
         }
         int ch = _inputBuffer[_inputPtr] & 0xFF;
@@ -2836,7 +2894,7 @@
 
     private final int _skipWS2() throws IOException
     {
-        while (_inputPtr < _inputEnd || loadMore()) {
+        while (_inputPtr < _inputEnd || _loadMore()) {
             int i = _inputBuffer[_inputPtr++] & 0xFF;
             if (i > INT_SPACE) {
                 if (i == INT_SLASH) {
@@ -2861,7 +2919,7 @@
                 }
             }
         }        
-        throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries");
+        throw _constructError("Unexpected end-of-input within/between "+_parsingContext.typeDesc()+" entries");
     }
     
     private final int _skipWSOrEnd() throws IOException
@@ -2869,7 +2927,7 @@
         // Let's handle first character separately since it is likely that
         // it is either non-whitespace; or we have longer run of white space
         if (_inputPtr >= _inputEnd) {
-            if (!loadMore()) {
+            if (!_loadMore()) {
                 return _eofAsNextChar();
             }
         }
@@ -2917,7 +2975,7 @@
 
     private final int _skipWSOrEnd2() throws IOException
     {
-        while ((_inputPtr < _inputEnd) || loadMore()) {
+        while ((_inputPtr < _inputEnd) || _loadMore()) {
             int i = _inputBuffer[_inputPtr++] & 0xFF;
             if (i > INT_SPACE) {
                 if (i == INT_SLASH) {
@@ -3002,7 +3060,7 @@
 
     private final int _skipColon2(boolean gotColon) throws IOException
     {
-        while (_inputPtr < _inputEnd || loadMore()) {
+        while (_inputPtr < _inputEnd || _loadMore()) {
             int i = _inputBuffer[_inputPtr++] & 0xFF;
 
             if (i > INT_SPACE) {
@@ -3033,7 +3091,9 @@
                 }
             }
         }
-        throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries");
+        _reportInvalidEOF(" within/between "+_parsingContext.typeDesc()+" entries",
+                null);
+        return -1;
     }
 
     private final void _skipComment() throws IOException
@@ -3042,8 +3102,8 @@
             _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)");
         }
         // First: check which comment (if either) it is:
-        if (_inputPtr >= _inputEnd && !loadMore()) {
-            _reportInvalidEOF(" in a comment");
+        if (_inputPtr >= _inputEnd && !_loadMore()) {
+            _reportInvalidEOF(" in a comment", null);
         }
         int c = _inputBuffer[_inputPtr++] & 0xFF;
         if (c == '/') {
@@ -3062,13 +3122,13 @@
 
         // Ok: need the matching '*/'
         main_loop:
-        while ((_inputPtr < _inputEnd) || loadMore()) {
+        while ((_inputPtr < _inputEnd) || _loadMore()) {
             int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
             int code = codes[i];
             if (code != 0) {
                 switch (code) {
                 case '*':
-                    if (_inputPtr >= _inputEnd && !loadMore()) {
+                    if (_inputPtr >= _inputEnd && !_loadMore()) {
                         break main_loop;
                     }
                     if (_inputBuffer[_inputPtr] == INT_SLASH) {
@@ -3098,7 +3158,7 @@
                 }
             }
         }
-        _reportInvalidEOF(" in a comment");
+        _reportInvalidEOF(" in a comment", null);
     }
 
     private final boolean _skipYAMLComment() throws IOException
@@ -3118,7 +3178,7 @@
     {
         // Ok: need to find EOF or linefeed
         final int[] codes = CharTypes.getInputCodeComment();
-        while ((_inputPtr < _inputEnd) || loadMore()) {
+        while ((_inputPtr < _inputEnd) || _loadMore()) {
             int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
             int code = codes[i];
             if (code != 0) {
@@ -3155,8 +3215,8 @@
     protected char _decodeEscaped() throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            if (!loadMore()) {
-                _reportInvalidEOF(" in character escape sequence");
+            if (!_loadMore()) {
+                _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
             }
         }
         int c = (int) _inputBuffer[_inputPtr++];
@@ -3191,8 +3251,8 @@
         int value = 0;
         for (int i = 0; i < 4; ++i) {
             if (_inputPtr >= _inputEnd) {
-                if (!loadMore()) {
-                    _reportInvalidEOF(" in character escape sequence");
+                if (!_loadMore()) {
+                    _reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
                 }
             }
             int ch = (int) _inputBuffer[_inputPtr++];
@@ -3260,7 +3320,7 @@
     private final int _decodeUtf8_2(int c) throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         int d = (int) _inputBuffer[_inputPtr++];
         if ((d & 0xC0) != 0x080) {
@@ -3272,7 +3332,7 @@
     private final int _decodeUtf8_3(int c1) throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         c1 &= 0x0F;
         int d = (int) _inputBuffer[_inputPtr++];
@@ -3281,7 +3341,7 @@
         }
         int c = (c1 << 6) | (d & 0x3F);
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         d = (int) _inputBuffer[_inputPtr++];
         if ((d & 0xC0) != 0x080) {
@@ -3314,7 +3374,7 @@
     private final int _decodeUtf8_4(int c) throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         int d = (int) _inputBuffer[_inputPtr++];
         if ((d & 0xC0) != 0x080) {
@@ -3323,7 +3383,7 @@
         c = ((c & 0x07) << 6) | (d & 0x3F);
 
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         d = (int) _inputBuffer[_inputPtr++];
         if ((d & 0xC0) != 0x080) {
@@ -3331,7 +3391,7 @@
         }
         c = (c << 6) | (d & 0x3F);
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         d = (int) _inputBuffer[_inputPtr++];
         if ((d & 0xC0) != 0x080) {
@@ -3347,7 +3407,7 @@
     private final void _skipUtf8_2() throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         int c = (int) _inputBuffer[_inputPtr++];
         if ((c & 0xC0) != 0x080) {
@@ -3361,7 +3421,7 @@
     private final void _skipUtf8_3() throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         //c &= 0x0F;
         int c = (int) _inputBuffer[_inputPtr++];
@@ -3369,7 +3429,7 @@
             _reportInvalidOther(c & 0xFF, _inputPtr);
         }
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         c = (int) _inputBuffer[_inputPtr++];
         if ((c & 0xC0) != 0x080) {
@@ -3380,21 +3440,21 @@
     private final void _skipUtf8_4(int c) throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         int d = (int) _inputBuffer[_inputPtr++];
         if ((d & 0xC0) != 0x080) {
             _reportInvalidOther(d & 0xFF, _inputPtr);
         }
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         d = (int) _inputBuffer[_inputPtr++];
         if ((d & 0xC0) != 0x080) {
             _reportInvalidOther(d & 0xFF, _inputPtr);
         }
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         d = (int) _inputBuffer[_inputPtr++];
         if ((d & 0xC0) != 0x080) {
@@ -3414,7 +3474,7 @@
      */
     protected final void _skipCR() throws IOException
     {
-        if (_inputPtr < _inputEnd || loadMore()) {
+        if (_inputPtr < _inputEnd || _loadMore()) {
             if (_inputBuffer[_inputPtr] == BYTE_LF) {
                 ++_inputPtr;
             }
@@ -3426,7 +3486,7 @@
         private int nextByte() throws IOException
     {
         if (_inputPtr >= _inputEnd) {
-            loadMoreGuaranteed();
+            _loadMoreGuaranteed();
         }
         return _inputBuffer[_inputPtr++] & 0xFF;
     }
@@ -3451,7 +3511,7 @@
           * nothing fancy here (nor fast).
           */
          while (true) {
-             if (_inputPtr >= _inputEnd && !loadMore()) {
+             if (_inputPtr >= _inputEnd && !_loadMore()) {
                  break;
              }
              int i = (int) _inputBuffer[_inputPtr++];
@@ -3522,7 +3582,7 @@
             int ch;
             do {
                 if (_inputPtr >= _inputEnd) {
-                    loadMoreGuaranteed();
+                    _loadMoreGuaranteed();
                 }
                 ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
             } while (ch <= INT_SPACE);
@@ -3541,7 +3601,7 @@
             // then second base64 char; can't get padding yet, nor ws
             
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++] & 0xFF;
             bits = b64variant.decodeBase64Char(ch);
@@ -3552,7 +3612,7 @@
             
             // third base64 char; can be padding, but not ws
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++] & 0xFF;
             bits = b64variant.decodeBase64Char(ch);
@@ -3571,7 +3631,7 @@
                 if (bits == Base64Variant.BASE64_VALUE_PADDING) {
                     // Ok, must get padding
                     if (_inputPtr >= _inputEnd) {
-                        loadMoreGuaranteed();
+                        _loadMoreGuaranteed();
                     }
                     ch = _inputBuffer[_inputPtr++] & 0xFF;
                     if (!b64variant.usesPaddingChar(ch)) {
@@ -3587,7 +3647,7 @@
             decodedData = (decodedData << 6) | bits;
             // fourth and last base64 char; can be padding, but not ws
             if (_inputPtr >= _inputEnd) {
-                loadMoreGuaranteed();
+                _loadMoreGuaranteed();
             }
             ch = _inputBuffer[_inputPtr++] & 0xFF;
             bits = b64variant.decodeBase64Char(ch);
diff --git a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
index 2340ea2..180497a 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
@@ -20,13 +20,27 @@
 
     /*
     /**********************************************************
-    /* Output buffering
+    /* Configuration
     /**********************************************************
      */
 
     final protected Writer _writer;
 
     /**
+     * Character used for quoting JSON Object property names
+     * and String values.
+     *
+     * @since 2.8
+     */
+    protected char _quoteChar = '"'; // TODO: make configurable
+
+    /*
+    /**********************************************************
+    /* Output buffering
+    /**********************************************************
+     */
+    
+    /**
      * Intermediate buffer in which contents are buffered before
      * being written using {@link #_writer}.
      */
@@ -60,8 +74,7 @@
      * internally to hold a reference to currently used escape
      */
     protected SerializableString _currentEscape;
-    
-    
+
     /*
     /**********************************************************
     /* Life-cycle
@@ -79,7 +92,7 @@
     
     /*
     /**********************************************************
-    /* Overridden configuration methods
+    /* Overridden configuration, introspection methods
     /**********************************************************
      */
     
@@ -95,6 +108,10 @@
         return Math.max(0, len);
     }
 
+    // json does allow this so
+    @Override
+    public boolean canWriteFormattedNumbers() { return true; }
+
     /*
     /**********************************************************
     /* Overridden methods
@@ -141,16 +158,16 @@
             return;
         }
         // we know there's room for at least one more char
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         // The beef:
         _writeString(name);
         // and closing quotes; need room for one more char:
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
-    
+
     protected void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException
     {
         if (_cfgPrettyPrinter != null) {
@@ -171,7 +188,7 @@
             return;
         }
         // we know there's room for at least one more char
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         // The beef:
         final int qlen = quoted.length;
         if ((_outputTail + qlen + 1) >= _outputEnd) {
@@ -180,11 +197,11 @@
             if (_outputTail >= _outputEnd) {
                 _flushBuffer();
             }
-            _outputBuffer[_outputTail++] = '"';
+            _outputBuffer[_outputTail++] = _quoteChar;
         } else {
             System.arraycopy(quoted, 0, _outputBuffer, _outputTail, qlen);
             _outputTail += qlen;
-            _outputBuffer[_outputTail++] = '"';
+            _outputBuffer[_outputTail++] = _quoteChar;
         }
     }
     
@@ -195,7 +212,7 @@
      */
 
     @Override
-    public void writeStartArray() throws IOException, JsonGenerationException
+    public void writeStartArray() throws IOException
     {
         _verifyValueWrite("start an array");
         _writeContext = _writeContext.createChildArrayContext();
@@ -210,10 +227,10 @@
     }
 
     @Override
-    public void writeEndArray() throws IOException, JsonGenerationException
+    public void writeEndArray() throws IOException
     {
         if (!_writeContext.inArray()) {
-            _reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc());
+            _reportError("Current context not Array but "+_writeContext.typeDesc());
         }
         if (_cfgPrettyPrinter != null) {
             _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount());
@@ -226,8 +243,27 @@
         _writeContext = _writeContext.clearAndGetParent();
     }
 
+    @Override // since 2.8
+    public void writeStartObject(Object forValue) throws IOException
+    {
+        _verifyValueWrite("start an object");
+        JsonWriteContext ctxt = _writeContext.createChildObjectContext();
+        _writeContext = ctxt;
+        if (forValue != null) {
+            ctxt.setCurrentValue(forValue);
+        }
+        if (_cfgPrettyPrinter != null) {
+            _cfgPrettyPrinter.writeStartObject(this);
+        } else {
+            if (_outputTail >= _outputEnd) {
+                _flushBuffer();
+            }
+            _outputBuffer[_outputTail++] = '{';
+        }
+    }
+    
     @Override
-    public void writeStartObject() throws IOException, JsonGenerationException
+    public void writeStartObject() throws IOException
     {
         _verifyValueWrite("start an object");
         _writeContext = _writeContext.createChildObjectContext();
@@ -242,10 +278,10 @@
     }
 
     @Override
-    public void writeEndObject() throws IOException, JsonGenerationException
+    public void writeEndObject() throws IOException
     {
         if (!_writeContext.inObject()) {
-            _reportError("Current context not an object but "+_writeContext.getTypeDesc());
+            _reportError("Current context not Object but "+_writeContext.typeDesc());
         }
         if (_cfgPrettyPrinter != null) {
             _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
@@ -276,12 +312,12 @@
             if (_outputTail >= _outputEnd) {
                 _flushBuffer();
             }
-            _outputBuffer[_outputTail++] = '"';
+            _outputBuffer[_outputTail++] = _quoteChar;
             _writeString(name);
             if (_outputTail >= _outputEnd) {
                 _flushBuffer();
             }
-            _outputBuffer[_outputTail++] = '"';
+            _outputBuffer[_outputTail++] = _quoteChar;
         }
     }
 
@@ -300,12 +336,12 @@
             if (_outputTail >= _outputEnd) {
                 _flushBuffer();
             }
-            _outputBuffer[_outputTail++] = '"';
+            _outputBuffer[_outputTail++] = _quoteChar;
             writeRaw(quoted, 0, quoted.length);
             if (_outputTail >= _outputEnd) {
                 _flushBuffer();
             }
-            _outputBuffer[_outputTail++] = '"';
+            _outputBuffer[_outputTail++] = _quoteChar;
         }
     }
 
@@ -326,13 +362,13 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         _writeString(text);
         // And finally, closing quotes
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     @Override
@@ -342,13 +378,13 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         _writeString(text, offset, len);
         // And finally, closing quotes
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     @Override
@@ -358,7 +394,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         // Note: copied from writeRaw:
         char[] text = sstr.asQuotedChars();
         final int len = text.length;
@@ -378,7 +414,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     @Override
@@ -511,13 +547,13 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         _writeBinary(b64variant, data, offset, offset+len);
         // and closing quotes
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     @Override
@@ -530,7 +566,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         byte[] encodingBuffer = _ioContext.allocBase64Buffer();
         int bytes;
         try {
@@ -550,7 +586,7 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         return bytes;
     }
     
@@ -579,9 +615,9 @@
         if ((_outputTail + 8) >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
     }    
 
     @Override
@@ -603,9 +639,9 @@
         if ((_outputTail + 13) >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
     }    
 
     @Override
@@ -627,9 +663,9 @@
         if ((_outputTail + 23) >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
 
     // !!! 05-Aug-2008, tatus: Any ways to optimize these?
@@ -706,14 +742,14 @@
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
         writeRaw(value);
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail++] = '"';
+        _outputBuffer[_outputTail++] = _quoteChar;
     }
-    
+
     @Override
     public void writeBoolean(boolean state) throws IOException
     {
@@ -753,17 +789,17 @@
     @Override
     protected void _verifyValueWrite(String typeMsg) throws IOException
     {
+        final int status = _writeContext.writeValue();
         if (_cfgPrettyPrinter != null) {
             // Otherwise, pretty printer knows what to do...
-            _verifyPrettyValueWrite(typeMsg);
+            _verifyPrettyValueWrite(typeMsg, status);
             return;
         }
         char c;
-        final int status = _writeContext.writeValue();
-        if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
-            _reportError("Can not "+typeMsg+", expecting field name");
-        }
         switch (status) {
+        case JsonWriteContext.STATUS_OK_AS_IS:
+        default:
+            return;
         case JsonWriteContext.STATUS_OK_AFTER_COMMA:
             c = ',';
             break;
@@ -775,47 +811,14 @@
                 writeRaw(_rootValueSeparator.getValue());
             }
             return;
-        case JsonWriteContext.STATUS_OK_AS_IS:
-        default:
+        case JsonWriteContext.STATUS_EXPECT_NAME:
+            _reportCantWriteValueExpectName(typeMsg);
             return;
         }
         if (_outputTail >= _outputEnd) {
             _flushBuffer();
         }
-        _outputBuffer[_outputTail] = c;
-        ++_outputTail;
-    }
-
-    protected void _verifyPrettyValueWrite(String typeMsg) throws IOException
-    {
-        final int status = _writeContext.writeValue();
-        if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
-            _reportError("Can not "+typeMsg+", expecting field name");
-        }
-
-        // If we have a pretty printer, it knows what to do:
-        switch (status) {
-        case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array
-            _cfgPrettyPrinter.writeArrayValueSeparator(this);
-            break;
-        case JsonWriteContext.STATUS_OK_AFTER_COLON:
-            _cfgPrettyPrinter.writeObjectFieldValueSeparator(this);
-            break;
-        case JsonWriteContext.STATUS_OK_AFTER_SPACE:
-            _cfgPrettyPrinter.writeRootValueSeparator(this);
-            break;
-        case JsonWriteContext.STATUS_OK_AS_IS:
-            // First entry, but of which context?
-            if (_writeContext.inArray()) {
-                _cfgPrettyPrinter.beforeArrayValues(this);
-            } else if (_writeContext.inObject()) {
-                _cfgPrettyPrinter.beforeObjectEntries(this);
-            }
-            break;
-        default:
-            _throwInternal();
-            break;
-        }
+        _outputBuffer[_outputTail++] = c;
     }
 
     /*
diff --git a/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java b/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java
index 3532b7e..b3d3ffb 100644
--- a/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java
+++ b/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java
@@ -36,7 +36,7 @@
     /**
      * No point in trying to construct tiny tables, just need to resize soon.
      */
-    final static int MIN_HASH_SIZE = 16;
+    private final static int MIN_HASH_SIZE = 16;
     
     /**
      * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 8k;
@@ -56,7 +56,7 @@
      * Reference to the root symbol table, for child tables, so
      * that they can merge table information back as necessary.
      */
-    final protected ByteQuadsCanonicalizer _parent;
+    final private ByteQuadsCanonicalizer _parent;
 
     /**
      * Member that is only used by the root table instance: root
@@ -64,7 +64,7 @@
      * may return new state if they add entries to the table.
      * Child tables do NOT use the reference.
      */
-    final protected AtomicReference<TableInfo> _tableInfo;
+    final private AtomicReference<TableInfo> _tableInfo;
     
     /**
      * Seed value we use as the base to make hash codes non-static between
@@ -88,7 +88,7 @@
      * NOTE: non-final to allow disabling intern()ing in case of excessive
      * collisions.
      */
-    protected boolean _intern;
+    private boolean _intern;
 
     /**
      * Flag that indicates whether we should throw an exception if enough 
@@ -96,7 +96,7 @@
      * 
      * @since 2.4
      */
-    protected final boolean _failOnDoS;
+    private final boolean _failOnDoS;
     
     /*
     /**********************************************************
@@ -110,7 +110,7 @@
      * structure (details of which may be tweaked depending on expected rates
      * of collisions).
      */
-    protected int[] _hashArea;
+    private int[] _hashArea;
 
     /**
      * Number of slots for primary entries within {@link #_hashArea}; which is
@@ -118,17 +118,17 @@
      * primary covers only half of the area; plus, additional area for longer
      * symbols after hash area).
      */
-    protected int _hashSize;
+    private int _hashSize;
 
     /**
      * Offset within {@link #_hashArea} where secondary entries start
      */
-    protected int _secondaryStart;
+    private int _secondaryStart;
 
     /**
      * Offset within {@link #_hashArea} where tertiary entries start
      */
-    protected int _tertiaryStart;
+    private int _tertiaryStart;
     
     /**
      * Constant that determines size of buckets for tertiary entries:
@@ -139,12 +139,12 @@
      * Default value is 2, for buckets of 4 slots; grows bigger with
      * bigger table sizes.
      */
-    protected int _tertiaryShift;
+    private int _tertiaryShift;
 
     /**
      * Total number of Strings in the symbol table; only used for child tables.
      */
-    protected int _count;
+    private int _count;
 
     /**
      * Array that contains <code>String</code> instances matching
@@ -152,7 +152,7 @@
      * Contains nulls for unused entries. Note that this size is twice
      * that of {@link #_hashArea}
      */
-    protected String[] _names;
+    private String[] _names;
 
     /*
     /**********************************************************
@@ -165,7 +165,7 @@
      * for more spilled over entries (if any).
      * Spill over area is within fixed-size portion of {@link #_hashArea}.
      */
-    protected int _spilloverEnd;
+    private int _spilloverEnd;
 
     /**
      * Offset within {@link #_hashArea} that follows main slots and contains
@@ -175,7 +175,7 @@
      * Note that long name area follows immediately after the fixed-size
      * main hash area ({@link #_hashArea}).
      */
-    protected int _longNameOffset;
+    private int _longNameOffset;
 
     /**
      * This flag is set if, after adding a new entry, it is deemed
diff --git a/src/main/java/com/fasterxml/jackson/core/sym/CharsToNameCanonicalizer.java b/src/main/java/com/fasterxml/jackson/core/sym/CharsToNameCanonicalizer.java
index a668f2e..1d50226 100644
--- a/src/main/java/com/fasterxml/jackson/core/sym/CharsToNameCanonicalizer.java
+++ b/src/main/java/com/fasterxml/jackson/core/sym/CharsToNameCanonicalizer.java
@@ -58,21 +58,21 @@
      * reuse factories it doesn't matter either way; but when
      * recreating factories often, initial overhead may dominate.
      */
-    protected static final int DEFAULT_T_SIZE = 64;
+    private static final int DEFAULT_T_SIZE = 64;
 
     /**
      * Let's not expand symbol tables past some maximum size;
      * this should protected against OOMEs caused by large documents
      * with unique (~= random) names.
      */
-    protected static final int MAX_T_SIZE = 0x10000; // 64k entries == 256k mem
+    private static final int MAX_T_SIZE = 0x10000; // 64k entries == 256k mem
 
     /**
      * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 16k;
      * this corresponds to 64k main hash index. This should allow for enough distinct
      * names for almost any case.
      */
-    final static int MAX_ENTRIES_FOR_REUSE = 12000;
+    static final int MAX_ENTRIES_FOR_REUSE = 12000;
 
     /**
      * Also: to thwart attacks based on hash collisions (which may or may not
@@ -88,8 +88,8 @@
      * 
      * @since 2.1
      */
-    final static int MAX_COLL_CHAIN_LENGTH = 100;
-    
+    static final int MAX_COLL_CHAIN_LENGTH = 100;
+
     final static CharsToNameCanonicalizer sBootstrapSymbolTable = new CharsToNameCanonicalizer();
 
     /*
@@ -104,7 +104,7 @@
      * defined, and child instance is released (call to <code>release</code>),
      * parent's shared tables may be updated from the child instance.
      */
-    protected CharsToNameCanonicalizer _parent;
+    private CharsToNameCanonicalizer _parent;
 
     /**
      * Seed value we use as the base to make hash codes non-static between
@@ -117,13 +117,13 @@
      */
     final private int _hashSeed;
 
-    final protected int _flags;
+    final private int _flags;
     
     /**
      * Whether any canonicalization should be attempted (whether using
      * intern or not)
      */
-    protected boolean _canonicalize;
+    private boolean _canonicalize;
     
     /*
     /**********************************************************
@@ -135,7 +135,7 @@
      * Primary matching symbols; it's expected most match occur from
      * here.
      */
-    protected String[] _symbols;
+    private String[] _symbols;
 
     /**
      * Overflow buckets; if primary doesn't match, lookup is done
@@ -144,27 +144,27 @@
      * Note: Number of buckets is half of number of symbol entries, on
      * assumption there's less need for buckets.
      */
-    protected Bucket[] _buckets;
+    private Bucket[] _buckets;
 
     /**
      * Current size (number of entries); needed to know if and when
      * rehash.
      */
-    protected int _size;
+    private int _size;
 
     /**
      * Limit that indicates maximum size this instance can hold before
      * it needs to be expanded and rehashed. Calculated using fill
      * factor passed in to constructor.
      */
-    protected int _sizeThreshold;
+    private int _sizeThreshold;
 
     /**
      * Mask used to get index from hash values; equal to
      * <code>_buckets.length - 1</code>, when _buckets.length is
      * a power of two.
      */
-    protected int _indexMask;
+    private int _indexMask;
 
     /**
      * We need to keep track of the longest collision list; this is needed
@@ -173,8 +173,8 @@
      * 
      * @since 2.1
      */
-    protected int _longestCollisionList;
-    
+    private int _longestCollisionList;
+
     /*
     /**********************************************************
     /* State regarding shared arrays
@@ -187,7 +187,7 @@
      * (first) change is made, and potentially if updated bucket list
      * is to be resync'ed back to master instance.
      */
-    protected boolean _dirty;
+    private boolean _dirty;
 
     /*
     /**********************************************************
@@ -203,8 +203,8 @@
      * 
      * @since 2.4
      */
-    protected BitSet _overflows;
-    
+    private BitSet _overflows;
+
     /*
     /**********************************************************
     /* Life-cycle
diff --git a/src/main/java/com/fasterxml/jackson/core/util/ByteArrayBuilder.java b/src/main/java/com/fasterxml/jackson/core/util/ByteArrayBuilder.java
index 30a2622..cfbe77a 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/ByteArrayBuilder.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/ByteArrayBuilder.java
@@ -42,7 +42,7 @@
     private int _pastLen;
     private byte[] _currBlock;
     private int _currBlockPtr;
-    
+
     public ByteArrayBuilder() { this(null); }
     public ByteArrayBuilder(BufferRecycler br) { this(br, INITIAL_BLOCK_SIZE); }
     public ByteArrayBuilder(int firstBlockSize) { this(null, firstBlockSize); }
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java b/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
index f8c31ca..6641151 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
@@ -200,16 +200,43 @@
 
     @Override
     public void writeStartObject() throws IOException { delegate.writeStartObject(); }
-    
+
+    @Override
+    public void writeStartObject(Object forValue) throws IOException { delegate.writeStartObject(forValue); }
+
     @Override
     public void writeEndObject() throws IOException { delegate.writeEndObject(); }
 
     @Override
-    public void writeFieldName(String name) throws IOException { delegate.writeFieldName(name); }
+    public void writeFieldName(String name) throws IOException {
+        delegate.writeFieldName(name);
+    }
 
     @Override
-    public void writeFieldName(SerializableString name) throws IOException { delegate.writeFieldName(name); }
-    
+    public void writeFieldName(SerializableString name) throws IOException {
+        delegate.writeFieldName(name);
+    }
+
+    @Override
+    public void writeFieldId(long id) throws IOException {
+        delegate.writeFieldId(id);
+    }
+
+    @Override
+    public void writeArray(int[] array, int offset, int length) throws IOException {
+        delegate.writeArray(array, offset, length);
+    }
+
+    @Override
+    public void writeArray(long[] array, int offset, int length) throws IOException {
+        delegate.writeArray(array, offset, length);
+    }
+
+    @Override
+    public void writeArray(double[] array, int offset, int length) throws IOException {
+        delegate.writeArray(array, offset, length);
+    }
+
     /*
     /**********************************************************
     /* Public API, write methods, text/String values
@@ -326,6 +353,9 @@
     
     @Override
     public void writeTypeId(Object id) throws IOException { delegate.writeTypeId(id); }
+
+    @Override
+    public void writeEmbeddedObject(Object object) throws IOException { delegate.writeEmbeddedObject(object); }
     
     /*
     /**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java b/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
index c96d239..9ec93fb 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
@@ -2,6 +2,7 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.Writer;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 
@@ -106,7 +107,10 @@
     /* Public API, token accessors
     /**********************************************************
      */
- 
+
+    @Override public JsonToken currentToken() { return delegate.currentToken(); }
+    @Override public int currentTokenId() { return delegate.currentTokenId(); }
+    
     @Override public JsonToken getCurrentToken() { return delegate.getCurrentToken(); }
     @Override public int getCurrentTokenId() { return delegate.getCurrentTokenId(); }
     @Override public boolean hasCurrentToken() { return delegate.hasCurrentToken(); }
@@ -140,6 +144,7 @@
     @Override public char[] getTextCharacters() throws IOException { return delegate.getTextCharacters(); }
     @Override public int getTextLength() throws IOException { return delegate.getTextLength(); }
     @Override public int getTextOffset() throws IOException { return delegate.getTextOffset(); }
+    @Override public int getText(Writer writer) throws IOException, UnsupportedOperationException { return delegate.getText(writer);  }
 
     /*
     /**********************************************************
@@ -209,6 +214,8 @@
     @Override public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
     @Override public JsonToken nextToken() throws IOException { return delegate.nextToken(); }
     @Override public JsonToken nextValue() throws IOException { return delegate.nextValue(); }
+
+    @Override public void finishToken() throws IOException { delegate.finishToken(); }
     
     @Override
     public JsonParser skipChildren() throws IOException {
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java b/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java
index 1100d61..5b75047 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java
@@ -20,23 +20,56 @@
      * as delegate)
      */
     protected final JsonParser[] _parsers;
-    
+
+    /**
+     * Configuration that determines whether state of parsers is first verified
+     * to see if parser already points to a token (that is,
+     * {@link JsonParser#hasCurrentToken()} returns <code>true</code>), and if so
+     * that token is first return before {@link JsonParser#nextToken} is called.
+     * If enabled, this check is made; if disabled, no check is made and
+     * {@link JsonParser#nextToken} is always called for all parsers.
+     *<p>
+     * Default setting is <code>false</code> (for backwards-compatibility)
+     * so that possible existing token is not considered for parsers.
+     * 
+     * @since 2.8
+     */
+    protected final boolean _checkForExistingToken;
+
     /**
      * Index of the next parser in {@link #_parsers}.
      */
-    protected int _nextParser;
-    
+    protected int _nextParserIndex;
+
+    /**
+     * Flag used to indicate that `JsonParser.nextToken()` should not be called,
+     * due to parser already pointing to a token.
+     *
+     * @since 2.8
+     */
+    protected boolean _hasToken;
+
     /*
      *******************************************************
      * Construction
      *******************************************************
      */
 
-    protected JsonParserSequence(JsonParser[] parsers)
+    @Deprecated // since 2.8
+    protected JsonParserSequence(JsonParser[] parsers) {
+        this(false, parsers);
+    }
+
+    /**
+     * @since 2.8
+     */
+    protected JsonParserSequence(boolean checkForExistingToken, JsonParser[] parsers)
     {
         super(parsers[0]);
+        _checkForExistingToken = checkForExistingToken;
+        _hasToken = checkForExistingToken && delegate.hasCurrentToken();
         _parsers = parsers;
-        _nextParser = 1;
+        _nextParserIndex = 1;
     }
 
     /**
@@ -48,11 +81,12 @@
      * within sequences. This is done to minimize delegation depth,
      * ideally only having just a single level of delegation.
      */
-    public static JsonParserSequence createFlattened(JsonParser first, JsonParser second)
+    public static JsonParserSequence createFlattened(boolean checkForExistingToken,
+            JsonParser first, JsonParser second)
     {
         if (!(first instanceof JsonParserSequence || second instanceof JsonParserSequence)) {
-            // simple:
-            return new JsonParserSequence(new JsonParser[] { first, second });
+            return new JsonParserSequence(checkForExistingToken,
+                    new JsonParser[] { first, second });
         }
         ArrayList<JsonParser> p = new ArrayList<JsonParser>();
         if (first instanceof JsonParserSequence) {
@@ -65,44 +99,59 @@
         } else {
             p.add(second);
         }
-        return new JsonParserSequence(p.toArray(new JsonParser[p.size()]));
+        return new JsonParserSequence(checkForExistingToken,
+                p.toArray(new JsonParser[p.size()]));
     }
 
+    /**
+     * @deprecated Since 2.8 use {@link #createFlattened(boolean, JsonParser, JsonParser)}
+     *    instead
+     */
+    @Deprecated // since 2.8
+    public static JsonParserSequence createFlattened(JsonParser first, JsonParser second) {
+        return createFlattened(false, first, second);
+    }
+    
     @SuppressWarnings("resource")
-    protected void addFlattenedActiveParsers(List<JsonParser> result)
+    protected void addFlattenedActiveParsers(List<JsonParser> listToAddIn)
     {
-        for (int i = _nextParser-1, len = _parsers.length; i < len; ++i) {
+        for (int i = _nextParserIndex-1, len = _parsers.length; i < len; ++i) {
             JsonParser p = _parsers[i];
             if (p instanceof JsonParserSequence) {
-                ((JsonParserSequence) p).addFlattenedActiveParsers(result);
+                ((JsonParserSequence) p).addFlattenedActiveParsers(listToAddIn);
             } else {
-                result.add(p);
+                listToAddIn.add(p);
             }
         }
     }
-    
+
     /*
-     *******************************************************
-     * Overridden methods, needed: cases where default
-     * delegation does not work
-     *******************************************************
+    /*******************************************************
+    /* Overridden methods, needed: cases where default
+    /* delegation does not work
+    /*******************************************************
      */
-    
+
     @Override
     public void close() throws IOException {
         do { delegate.close(); } while (switchToNext());
     }
 
     @Override
-    public JsonToken nextToken() throws IOException, JsonParseException
+    public JsonToken nextToken() throws IOException
     {
-        JsonToken t = delegate.nextToken();
-        if (t != null) return t;
-        while (switchToNext()) {
-            t = delegate.nextToken();
-            if (t != null) return t;
+        if (delegate == null) {
+            return null;
         }
-        return null;
+        if (_hasToken) {
+            _hasToken = false;
+           return delegate.currentToken();
+        }
+        JsonToken t = delegate.nextToken();
+        if (t == null) {
+            return switchAndReturnNext();
+        }
+        return t;
     }
 
     /*
@@ -119,7 +168,7 @@
     public int containedParsersCount() {
         return _parsers.length;
     }
-    
+
     /*
     /*******************************************************
     /* Helper methods
@@ -127,19 +176,35 @@
      */
 
     /**
-     * Method that will switch active parser from the current one
-     * to next parser in sequence, if there is another parser left,
-     * making this the new delegate. Old delegate is returned if
-     * switch succeeds.
+     * Method that will switch active delegate parser from the current one
+     * to the next parser in sequence, if there is another parser left:
+     * if so, the next parser will become the active delegate parser.
      * 
      * @return True if switch succeeded; false otherwise
+     *
+     * @since 2.8
      */
     protected boolean switchToNext()
     {
-        if (_nextParser >= _parsers.length) {
-            return false;
+        if (_nextParserIndex < _parsers.length) {
+            delegate = _parsers[_nextParserIndex++];
+            return true;
         }
-        delegate = _parsers[_nextParser++];
-        return true;
+        return false;
+    }
+
+    protected JsonToken switchAndReturnNext() throws IOException
+    {
+        while (_nextParserIndex < _parsers.length) {
+            delegate = _parsers[_nextParserIndex++];
+            if (_checkForExistingToken && delegate.hasCurrentToken()) {
+                return delegate.getCurrentToken();
+            }
+            JsonToken t = delegate.nextToken();
+            if (t != null) {
+                return t;
+            }
+        }
+        return null;
     }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/util/RequestPayload.java b/src/main/java/com/fasterxml/jackson/core/util/RequestPayload.java
new file mode 100644
index 0000000..a7e7e85
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/core/util/RequestPayload.java
@@ -0,0 +1,67 @@
+package com.fasterxml.jackson.core.util;
+
+import java.io.IOException;
+
+/**
+ * Container object used to contain optional information on content
+ * being parsed, passed to {@link com.fasterxml.jackson.core.JsonParseException} in case of
+ * exception being thrown; this may be useful for caller to display
+ * information on failure.
+ *
+ * @since 2.8
+ */
+public class RequestPayload
+    implements java.io.Serializable // just in case, even though likely included as transient
+{
+    private static final long serialVersionUID = 1L;
+
+    // request payload as byte[]
+    protected byte[] _payloadAsBytes;
+
+    // request payload as String
+    protected CharSequence _payloadAsText;
+
+    // Charset if the request payload is set in bytes
+    protected String _charset;
+
+    public RequestPayload(byte[] bytes, String charset) {
+        if (bytes == null) {
+            throw new IllegalArgumentException();
+        }
+        _payloadAsBytes = bytes;
+        _charset = (charset == null || charset.isEmpty()) ? "UTF-8" : charset;
+    }
+
+    public RequestPayload(CharSequence str) {
+        if (str == null) {
+            throw new IllegalArgumentException();
+        }
+        _payloadAsText = str;
+    }
+
+    /**
+     * Returns the raw request payload object i.e, either byte[] or String
+     * 
+     * @return Object which is a raw request payload i.e, either byte[] or
+     *         String
+     */
+    public Object getRawPayload() {
+        if (_payloadAsBytes != null) {
+            return _payloadAsBytes;
+        }
+
+        return _payloadAsText;
+    }
+
+    @Override
+    public String toString() {
+        if (_payloadAsBytes != null) {
+            try {
+                return new String(_payloadAsBytes, _charset);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return _payloadAsText.toString();
+    }
+}
diff --git a/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java b/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
index 85250b1..c32ebf3 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
@@ -1,8 +1,8 @@
 package com.fasterxml.jackson.core.util;
 
+import java.io.*;
 import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.*;
 
 import com.fasterxml.jackson.core.io.NumberInput;
 
@@ -399,6 +399,45 @@
         return NumberInput.parseDouble(contentsAsString());
     }
 
+    /**
+     * @since 2.8
+     */
+    public int contentsToWriter(Writer w) throws IOException
+    {
+        if (_resultArray != null) {
+            w.write(_resultArray);
+            return _resultArray.length;
+        }
+        if (_resultString != null) { // Can take a shortcut...
+            w.write(_resultString);
+            return _resultString.length();
+        }
+        // Do we use shared array?
+        if (_inputStart >= 0) {
+            final int len = _inputLen;
+            if (len > 0) {
+                w.write(_inputBuffer, _inputStart, len);
+            }
+            return len;
+        }
+        // nope, not shared
+        int total = 0;
+        if (_segments != null) {
+            for (int i = 0, end = _segments.size(); i < end; ++i) {
+                char[] curr = _segments.get(i);
+                int currLen = curr.length;
+                w.write(curr, 0, currLen);
+                total += currLen;
+            }
+        }
+        int len = _currentSize;
+        if (len > 0) {
+            w.write(_currentSegment, 0, len);
+            total += len;
+        }
+        return total;
+    }
+
     /*
     /**********************************************************
     /* Public mutators:
diff --git a/src/test/java/com/fasterxml/jackson/core/BaseTest.java b/src/test/java/com/fasterxml/jackson/core/BaseTest.java
index 5184162..ca8ce4f 100644
--- a/src/test/java/com/fasterxml/jackson/core/BaseTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/BaseTest.java
@@ -3,12 +3,45 @@
 import java.io.*;
 import java.util.Arrays;
 
+import com.fasterxml.jackson.core.testsupport.MockDataInput;
+import com.fasterxml.jackson.core.testsupport.ThrottledInputStream;
+
 import junit.framework.TestCase;
 
+@SuppressWarnings("resource")
 public abstract class BaseTest
     extends TestCase
 {
     protected final static String FIELD_BASENAME = "f";
+
+    protected final static int MODE_INPUT_STREAM = 0;
+    protected final static int MODE_INPUT_STREAM_THROTTLED = 1;
+    protected final static int MODE_READER = 2;
+    protected final static int MODE_DATA_INPUT = 3;
+
+    protected final static int[] ALL_MODES = new int[] {
+        MODE_INPUT_STREAM,
+        MODE_INPUT_STREAM_THROTTLED,
+        MODE_READER,
+        MODE_DATA_INPUT
+    };
+
+    protected final static int[] ALL_BINARY_MODES = new int[] {
+        MODE_INPUT_STREAM,
+        MODE_INPUT_STREAM_THROTTLED,
+        MODE_DATA_INPUT
+    };
+
+    protected final static int[] ALL_TEXT_MODES = new int[] {
+        MODE_READER
+    };
+
+    // DataInput not streaming
+    protected final static int[] ALL_STREAMING_MODES = new int[] {
+        MODE_INPUT_STREAM,
+        MODE_INPUT_STREAM_THROTTLED,
+        MODE_READER
+    };
     
     /*
     /**********************************************************
@@ -125,116 +158,118 @@
             return true;
         }
     }
-    
+
+    protected final JsonFactory JSON_FACTORY = new JsonFactory();
+
     /*
     /**********************************************************
     /* High-level helpers
     /**********************************************************
      */
 
-    protected void verifyJsonSpecSampleDoc(JsonParser jp, boolean verifyContents)
+    protected void verifyJsonSpecSampleDoc(JsonParser p, boolean verifyContents)
         throws IOException
     {
-        verifyJsonSpecSampleDoc(jp, verifyContents, true);
+        verifyJsonSpecSampleDoc(p, verifyContents, true);
     }
 
-    protected void verifyJsonSpecSampleDoc(JsonParser jp, boolean verifyContents,
+    protected void verifyJsonSpecSampleDoc(JsonParser p, boolean verifyContents,
             boolean requireNumbers)
         throws IOException
     {
-        if (!jp.hasCurrentToken()) {
-            jp.nextToken();
+        if (!p.hasCurrentToken()) {
+            p.nextToken();
         }
-        assertToken(JsonToken.START_OBJECT, jp.getCurrentToken()); // main object
+        assertToken(JsonToken.START_OBJECT, p.currentToken()); // main object
 
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Image'
+        assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Image'
         if (verifyContents) {
-            verifyFieldName(jp, "Image");
+            verifyFieldName(p, "Image");
         }
 
-        assertToken(JsonToken.START_OBJECT, jp.nextToken()); // 'image' object
+        assertToken(JsonToken.START_OBJECT, p.nextToken()); // 'image' object
 
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Width'
+        assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Width'
         if (verifyContents) {
-            verifyFieldName(jp, "Width");
+            verifyFieldName(p, "Width");
         }
 
-        verifyIntToken(jp.nextToken(), requireNumbers);
+        verifyIntToken(p.nextToken(), requireNumbers);
         if (verifyContents) {
-            verifyIntValue(jp, SAMPLE_SPEC_VALUE_WIDTH);
+            verifyIntValue(p, SAMPLE_SPEC_VALUE_WIDTH);
         }
 
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Height'
+        assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Height'
         if (verifyContents) {
-            verifyFieldName(jp, "Height");
+            verifyFieldName(p, "Height");
         }
 
-        verifyIntToken(jp.nextToken(), requireNumbers);
+        verifyIntToken(p.nextToken(), requireNumbers);
         if (verifyContents) {
-            verifyIntValue(jp, SAMPLE_SPEC_VALUE_HEIGHT);
+            verifyIntValue(p, SAMPLE_SPEC_VALUE_HEIGHT);
         }
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Title'
+        assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Title'
         if (verifyContents) {
-            verifyFieldName(jp, "Title");
+            verifyFieldName(p, "Title");
         }
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals(SAMPLE_SPEC_VALUE_TITLE, getAndVerifyText(jp));
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Thumbnail'
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(SAMPLE_SPEC_VALUE_TITLE, getAndVerifyText(p));
+        assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Thumbnail'
         if (verifyContents) {
-            verifyFieldName(jp, "Thumbnail");
+            verifyFieldName(p, "Thumbnail");
         }
 
-        assertToken(JsonToken.START_OBJECT, jp.nextToken()); // 'thumbnail' object
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Url'
+        assertToken(JsonToken.START_OBJECT, p.nextToken()); // 'thumbnail' object
+        assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Url'
         if (verifyContents) {
-            verifyFieldName(jp, "Url");
+            verifyFieldName(p, "Url");
         }
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
         if (verifyContents) {
-            assertEquals(SAMPLE_SPEC_VALUE_TN_URL, getAndVerifyText(jp));
+            assertEquals(SAMPLE_SPEC_VALUE_TN_URL, getAndVerifyText(p));
         }
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Height'
+        assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Height'
         if (verifyContents) {
-            verifyFieldName(jp, "Height");
+            verifyFieldName(p, "Height");
         }
-        verifyIntToken(jp.nextToken(), requireNumbers);
+        verifyIntToken(p.nextToken(), requireNumbers);
         if (verifyContents) {
-            verifyIntValue(jp, SAMPLE_SPEC_VALUE_TN_HEIGHT);
+            verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_HEIGHT);
         }
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Width'
+        assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Width'
         if (verifyContents) {
-            verifyFieldName(jp, "Width");
+            verifyFieldName(p, "Width");
         }
         // Width value is actually a String in the example
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
         if (verifyContents) {
-            assertEquals(SAMPLE_SPEC_VALUE_TN_WIDTH, getAndVerifyText(jp));
+            assertEquals(SAMPLE_SPEC_VALUE_TN_WIDTH, getAndVerifyText(p));
         }
 
-        assertToken(JsonToken.END_OBJECT, jp.nextToken()); // 'thumbnail' object
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'IDs'
-        assertToken(JsonToken.START_ARRAY, jp.nextToken()); // 'ids' array
-        verifyIntToken(jp.nextToken(), requireNumbers); // ids[0]
+        assertToken(JsonToken.END_OBJECT, p.nextToken()); // 'thumbnail' object
+        assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'IDs'
+        assertToken(JsonToken.START_ARRAY, p.nextToken()); // 'ids' array
+        verifyIntToken(p.nextToken(), requireNumbers); // ids[0]
         if (verifyContents) {
-            verifyIntValue(jp, SAMPLE_SPEC_VALUE_TN_ID1);
+            verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID1);
         }
-        verifyIntToken(jp.nextToken(), requireNumbers); // ids[1]
+        verifyIntToken(p.nextToken(), requireNumbers); // ids[1]
         if (verifyContents) {
-            verifyIntValue(jp, SAMPLE_SPEC_VALUE_TN_ID2);
+            verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID2);
         }
-        verifyIntToken(jp.nextToken(), requireNumbers); // ids[2]
+        verifyIntToken(p.nextToken(), requireNumbers); // ids[2]
         if (verifyContents) {
-            verifyIntValue(jp, SAMPLE_SPEC_VALUE_TN_ID3);
+            verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID3);
         }
-        verifyIntToken(jp.nextToken(), requireNumbers); // ids[3]
+        verifyIntToken(p.nextToken(), requireNumbers); // ids[3]
         if (verifyContents) {
-            verifyIntValue(jp, SAMPLE_SPEC_VALUE_TN_ID4);
+            verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID4);
         }
-        assertToken(JsonToken.END_ARRAY, jp.nextToken()); // 'ids' array
+        assertToken(JsonToken.END_ARRAY, p.nextToken()); // 'ids' array
 
-        assertToken(JsonToken.END_OBJECT, jp.nextToken()); // 'image' object
+        assertToken(JsonToken.END_OBJECT, p.nextToken()); // 'image' object
 
-        assertToken(JsonToken.END_OBJECT, jp.nextToken()); // main object
+        assertToken(JsonToken.END_OBJECT, p.nextToken()); // main object
     }
 
     private void verifyIntToken(JsonToken t, boolean requireNumbers)
@@ -251,18 +286,18 @@
         }
     }
     
-    protected void verifyFieldName(JsonParser jp, String expName)
+    protected void verifyFieldName(JsonParser p, String expName)
         throws IOException
     {
-        assertEquals(expName, jp.getText());
-        assertEquals(expName, jp.getCurrentName());
+        assertEquals(expName, p.getText());
+        assertEquals(expName, p.getCurrentName());
     }
 
-    protected void verifyIntValue(JsonParser jp, long expValue)
+    protected void verifyIntValue(JsonParser p, long expValue)
         throws IOException
     {
         // First, via textual
-        assertEquals(String.valueOf(expValue), jp.getText());
+        assertEquals(String.valueOf(expValue), p.getText());
     }
     
     /*
@@ -271,27 +306,72 @@
     /**********************************************************
      */
 
-    protected JsonParser createParserUsingReader(String input)
-        throws IOException, JsonParseException
+    protected JsonParser createParser(int mode, String doc) throws IOException {
+        return createParser(JSON_FACTORY, mode, doc);
+    }
+
+    protected JsonParser createParser(int mode, byte[] doc) throws IOException {
+        return createParser(JSON_FACTORY, mode, doc);
+    }
+
+    protected JsonParser createParser(JsonFactory f, int mode, String doc) throws IOException
+    {
+        switch (mode) {
+        case MODE_INPUT_STREAM:
+            return createParserUsingStream(f, doc, "UTF-8");
+        case MODE_INPUT_STREAM_THROTTLED:
+            {
+                InputStream in = new ThrottledInputStream(doc.getBytes("UTF-8"), 1);
+                return f.createParser(in);
+            }
+        case MODE_READER:
+            return createParserUsingReader(f, doc);
+        case MODE_DATA_INPUT:
+            return createParserForDataInput(f, new MockDataInput(doc));
+        default:
+        }
+        throw new RuntimeException("internal error");
+    }
+
+    protected JsonParser createParser(JsonFactory f, int mode, byte[] doc) throws IOException
+    {
+        switch (mode) {
+        case MODE_INPUT_STREAM:
+            return f.createParser(new ByteArrayInputStream(doc));
+        case MODE_INPUT_STREAM_THROTTLED:
+            {
+                InputStream in = new ThrottledInputStream(doc, 1);
+                return f.createParser(in);
+            }
+        case MODE_READER:
+            return f.createParser(new StringReader(new String(doc, "UTF-8")));
+        case MODE_DATA_INPUT:
+            return createParserForDataInput(f, new MockDataInput(doc));
+        default:
+        }
+        throw new RuntimeException("internal error");
+    }
+    
+    protected JsonParser createParserUsingReader(String input) throws IOException
     {
         return createParserUsingReader(new JsonFactory(), input);
     }
 
     protected JsonParser createParserUsingReader(JsonFactory f, String input)
-        throws IOException, JsonParseException
+        throws IOException
     {
         return f.createParser(new StringReader(input));
     }
 
     protected JsonParser createParserUsingStream(String input, String encoding)
-        throws IOException, JsonParseException
+        throws IOException
     {
         return createParserUsingStream(new JsonFactory(), input, encoding);
     }
 
     protected JsonParser createParserUsingStream(JsonFactory f,
-                                                 String input, String encoding)
-        throws IOException, JsonParseException
+            String input, String encoding)
+        throws IOException
     {
 
         /* 23-Apr-2008, tatus: UTF-32 is not supported by JDK, have to
@@ -309,6 +389,13 @@
         return f.createParser(is);
     }
 
+    protected JsonParser createParserForDataInput(JsonFactory f,
+            DataInput input)
+        throws IOException
+    {
+        return f.createParser(input);
+    }
+
     /*
     /**********************************************************
     /* Helper read/write methods
@@ -361,9 +448,9 @@
         }
     }
 
-    protected void assertToken(JsonToken expToken, JsonParser jp)
+    protected void assertToken(JsonToken expToken, JsonParser p)
     {
-        assertToken(expToken, jp.getCurrentToken());
+        assertToken(expToken, p.currentToken());
     }
 
     protected void assertType(Object ob, Class<?> expType)
@@ -395,16 +482,16 @@
      * available methods, and ensures results are consistent, before
      * returning them
      */
-    protected String getAndVerifyText(JsonParser jp) throws IOException
+    protected String getAndVerifyText(JsonParser p) throws IOException
     {
         // Ok, let's verify other accessors
-        int actLen = jp.getTextLength();
-        char[] ch = jp.getTextCharacters();
-        String str2 = new String(ch, jp.getTextOffset(), actLen);
-        String str = jp.getText();
+        int actLen = p.getTextLength();
+        char[] ch = p.getTextCharacters();
+        String str2 = new String(ch, p.getTextOffset(), actLen);
+        String str = p.getText();
 
         if (str.length() !=  actLen) {
-            fail("Internal problem (jp.token == "+jp.getCurrentToken()+"): jp.getText().length() ['"+str+"'] == "+str.length()+"; jp.getTextLength() == "+actLen);
+            fail("Internal problem (p.token == "+p.currentToken()+"): p.getText().length() ['"+str+"'] == "+str.length()+"; p.getTextLength() == "+actLen);
         }
         assertEquals("String access via getText(), getTextXxx() must be the same", str, str2);
 
diff --git a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java b/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
index d5a2ae0..0301b19 100644
--- a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
+++ b/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
@@ -2,6 +2,8 @@
 
 import java.io.StringWriter;
 
+import com.fasterxml.jackson.core.io.JsonEOFException;
+
 public class TestExceptions extends BaseTest
 {
     private final JsonFactory JSON_F = new JsonFactory();
@@ -42,4 +44,65 @@
         assertEquals("Test!", e.getOriginalMessage());
         g.close();
     }
+
+    // [core#281]: new eof exception
+    public void testEofExceptionsBytes() throws Exception {
+        _testEofExceptions(MODE_INPUT_STREAM);
+    }
+
+    // [core#281]: new eof exception
+    public void testEofExceptionsChars() throws Exception {
+        _testEofExceptions(MODE_READER);
+    }
+
+    private void _testEofExceptions(int mode) throws Exception
+    {
+        JsonParser p = createParser(mode, "[ ");
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Should get exception");
+        } catch (JsonEOFException e) {
+            verifyException(e, "close marker for Array");
+        }
+        p.close();
+
+        p = createParser(mode, "{ \"foo\" : [ ] ");
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Should get exception");
+        } catch (JsonEOFException e) {
+            verifyException(e, "close marker for Object");
+        }
+        p.close();
+
+        p = createParser(mode, "{ \"fo");
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Should get exception");
+        } catch (JsonEOFException e) {
+            
+            verifyException(e, "in field name");
+            assertEquals(JsonToken.FIELD_NAME, e.getTokenBeingDecoded());
+        }
+        p.close();
+
+        p = createParser(mode, "{ \"field\" : ");
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Should get exception");
+        } catch (JsonEOFException e) {
+            verifyException(e, "unexpected end-of-input");
+            verifyException(e, "Object entries");
+        }
+        p.close();
+
+        // any other cases we'd like to test?
+    }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/TestJDKSerializability.java b/src/test/java/com/fasterxml/jackson/core/TestJDKSerializability.java
index ced0384..c03458f 100644
--- a/src/test/java/com/fasterxml/jackson/core/TestJDKSerializability.java
+++ b/src/test/java/com/fasterxml/jackson/core/TestJDKSerializability.java
@@ -11,7 +11,7 @@
 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
 
 /**
- * Unit tests for [Issue#31] (https://github.com/FasterXML/jackson-core/issues/31)
+ * Unit tests for [core#31] (https://github.com/FasterXML/jackson-core/issues/31)
  */
 public class TestJDKSerializability extends BaseTest
 {
@@ -128,7 +128,7 @@
             objIn.close();
         }
     }
-    
+
     @SuppressWarnings("resource")
     protected String _copyJson(JsonFactory f, String json, boolean useBytes) throws IOException
     {
@@ -144,13 +144,13 @@
         return sw.toString();
     }
         
-    protected void _copyJson(JsonFactory f, String json, JsonGenerator jg) throws IOException
+    protected void _copyJson(JsonFactory f, String json, JsonGenerator g) throws IOException
     {
-        JsonParser jp = f.createParser(json);
-        while (jp.nextToken() != null) {
-            jg.copyCurrentEvent(jp);
+        JsonParser p = f.createParser(json);
+        while (p.nextToken() != null) {
+            g.copyCurrentEvent(p);
         }
-        jp.close();
-        jg.close();
+        p.close();
+        g.close();
     }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/TestBase64Generation.java b/src/test/java/com/fasterxml/jackson/core/base64/TestBase64Generation.java
index e947b71..ef3c673 100644
--- a/src/test/java/com/fasterxml/jackson/core/base64/TestBase64Generation.java
+++ b/src/test/java/com/fasterxml/jackson/core/base64/TestBase64Generation.java
@@ -3,37 +3,13 @@
 import java.io.*;
 
 import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.testsupport.ThrottledInputStream;
 
 public class TestBase64Generation
     extends com.fasterxml.jackson.core.BaseTest
 {
-    static class ThrottledInputStream extends FilterInputStream
-    {
-        protected final int _maxBytes;
-
-        public ThrottledInputStream(byte[] data, int maxBytes)
-        {
-            this(new ByteArrayInputStream(data), maxBytes);
-        }
-        
-        public ThrottledInputStream(InputStream in, int maxBytes)
-        {
-            super(in);
-            _maxBytes = maxBytes;
-        }
-
-        @Override
-        public int read(byte[] buf) throws IOException {
-            return read(buf, 0, buf.length);
-        }
-        
-        @Override
-        public int read(byte[] buf, int offset, int len) throws IOException {
-            return in.read(buf, offset, Math.min(_maxBytes, len));
-        }
-        
-    }
     
+
     /*
     /**********************************************************
     /* Test methods
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/TestJsonParserBinary.java b/src/test/java/com/fasterxml/jackson/core/base64/TestJsonParserBinary.java
deleted file mode 100644
index 23dacc1..0000000
--- a/src/test/java/com/fasterxml/jackson/core/base64/TestJsonParserBinary.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.fasterxml.jackson.core.base64;
-
-import java.io.*;
-
-import com.fasterxml.jackson.core.*;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests for verifying that accessing base64 encoded content works ok.
- */
-public class TestJsonParserBinary
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    /*
-    /**********************************************************************
-    /* Unit tests
-    /**********************************************************************
-     */
-
-    public void testSimple()
-        throws IOException
-    {
-        // let's test reader (char) based first, then stream (byte)
-        _testSimple(false);
-        _testSimple(true);
-    }
-
-    public void testInArray()
-        throws IOException
-    {
-        // let's test reader (char) based first, then stream (byte)
-        _testInArray(false);
-        _testInArray(true);
-    }
-
-    public void testWithEscaped() throws IOException
-    {
-        // let's test reader (char) based first, then stream (byte)
-        _testEscaped(false);
-        _testEscaped(true);
-    }
-    
-    /*
-    /**********************************************************************
-    /* Actual test methods
-    /**********************************************************************
-     */
-
-    private void _testSimple(boolean useStream)
-        throws IOException
-    {
-        /* The usual sample input string, from Thomas Hobbes's "Leviathan"
-         * (via Wikipedia)
-         */
-        final String RESULT = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";
-        final byte[] RESULT_BYTES = RESULT.getBytes("US-ASCII");
-
-        // And here's what should produce it...
-        final String INPUT_STR = 
- "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz"
-+"IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg"
-+"dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu"
-+"dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo"
-+"ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="
-            ;
-
-        final String DOC = "\""+INPUT_STR+"\"";
-        JsonParser jp = _getParser(DOC, useStream);
-
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        byte[] data = jp.getBinaryValue();
-        assertNotNull(data);
-        assertArrayEquals(RESULT_BYTES, data);
-        jp.close();
-    }
-
-    private void _testInArray(boolean useStream)
-        throws IOException
-    {
-        JsonFactory jf = new JsonFactory();
-
-        final int entryCount = 7;
-
-        StringWriter sw = new StringWriter();
-        JsonGenerator jg = jf.createGenerator(sw);
-        jg.writeStartArray();
-
-        byte[][] entries = new byte[entryCount][];
-        for (int i = 0; i < entryCount; ++i) {
-            byte[] b = new byte[200 + i * 100];
-            for (int x = 0; x < b.length; ++x) {
-                b[x] = (byte) (i + x);
-            }
-            entries[i] = b;
-            jg.writeBinary(b);
-        }
-
-        jg.writeEndArray();
-        jg.close();
-
-        JsonParser jp = _getParser(sw.toString(), useStream);
-
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-
-        for (int i = 0; i < entryCount; ++i) {
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            byte[] b = jp.getBinaryValue();
-            assertArrayEquals(entries[i], b);
-        }
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        jp.close();
-    }
-
-    private void _testEscaped(boolean useStream) throws IOException
-    {
-        // Input: "Test!" -> "VGVzdCE="
-
-        // First, try with embedded linefeed half-way through:
-
-        String DOC = quote("VGVz\\ndCE="); // note: must double-quote to get linefeed
-        JsonParser jp = _getParser(DOC, useStream);
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        byte[] b = jp.getBinaryValue();
-        assertEquals("Test!", new String(b, "US-ASCII"));
-        assertNull(jp.nextToken());
-        jp.close();
-
-        // and then with escaped chars
-//        DOC = quote("V\\u0047V\\u007AdCE="); // note: must escape backslash...
-        DOC = quote("V\\u0047V\\u007AdCE="); // note: must escape backslash...
-        jp = _getParser(DOC, useStream);
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        b = jp.getBinaryValue();
-        assertEquals("Test!", new String(b, "US-ASCII"));
-        assertNull(jp.nextToken());
-        jp.close();
-    }
-    
-    /*
-    /**********************************************************************
-    /* Other helper methods
-    /**********************************************************************
-     */
-    
-    private JsonParser _getParser(String doc, boolean useStream)
-        throws IOException
-    {
-        JsonFactory jf = new JsonFactory();
-        if (useStream) {
-            return jf.createParser(doc.getBytes("UTF-8"));
-        }
-        return jf.createParser(new StringReader(doc));
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/TestIOContext.java b/src/test/java/com/fasterxml/jackson/core/io/TestIOContext.java
index 3bad591..475abb5 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/TestIOContext.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/TestIOContext.java
@@ -24,7 +24,7 @@
         try {
             ctxt.releaseReadIOBuffer(new byte[1]);
         } catch (IllegalArgumentException e) {
-            verifyException(e, "not owned");
+            verifyException(e, "smaller than original");
         }
         // but call with null is a NOP for convenience
         ctxt.releaseReadIOBuffer(null);
@@ -40,7 +40,7 @@
         try {
             ctxt.releaseWriteEncodingBuffer(new byte[1]);
         } catch (IllegalArgumentException e) {
-            verifyException(e, "not owned");
+            verifyException(e, "smaller than original");
         }
         ctxt.releaseWriteEncodingBuffer(null);
 
@@ -55,7 +55,7 @@
         try {
             ctxt.releaseTokenBuffer(new char[1]);
         } catch (IllegalArgumentException e) {
-            verifyException(e, "not owned");
+            verifyException(e, "smaller than original");
         }
         ctxt.releaseTokenBuffer(null);
 
@@ -70,7 +70,7 @@
         try {
             ctxt.releaseConcatBuffer(new char[1]);
         } catch (IllegalArgumentException e) {
-            verifyException(e, "not owned");
+            verifyException(e, "smaller than original");
         }
         ctxt.releaseConcatBuffer(null);
 
@@ -85,7 +85,7 @@
         try {
             ctxt.releaseNameCopyBuffer(new char[1]);
         } catch (IllegalArgumentException e) {
-            verifyException(e, "not owned");
+            verifyException(e, "smaller than original");
         }
         ctxt.releaseNameCopyBuffer(null);
     }
diff --git a/src/test/java/com/fasterxml/jackson/core/io/TestJDKSerializable.java b/src/test/java/com/fasterxml/jackson/core/io/TestJDKSerializable.java
deleted file mode 100644
index 214344c..0000000
--- a/src/test/java/com/fasterxml/jackson/core/io/TestJDKSerializable.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.fasterxml.jackson.core.io;
-
-import java.io.*;
-
-import com.fasterxml.jackson.core.*;
-
-public class TestJDKSerializable
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    public void testLocationSerializability() throws Exception
-    {
-        JsonFactory jf = new JsonFactory();
-        JsonParser jp = jf.createParser("  { }");
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        JsonLocation loc = jp.getCurrentLocation();
-
-        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-        ObjectOutputStream out = new ObjectOutputStream(bytes);
-        out.writeObject(loc);
-        out.close();
-        byte[] stuff = bytes.toByteArray();
-        
-        ObjectInputStream obIn = new ObjectInputStream(new ByteArrayInputStream(stuff));
-        JsonLocation loc2 = (JsonLocation) obIn.readObject();
-        assertNotNull(loc2);
-        
-        assertEquals(loc.getLineNr(), loc2.getLineNr());
-        assertEquals(loc.getColumnNr(), loc2.getColumnNr());
-        jp.close();
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/TestJsonStringEncoder.java b/src/test/java/com/fasterxml/jackson/core/io/TestJsonStringEncoder.java
index 9c982a4..ec03582 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/TestJsonStringEncoder.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/TestJsonStringEncoder.java
@@ -6,7 +6,6 @@
 import static org.junit.Assert.*;
 
 import com.fasterxml.jackson.core.*;
-import com.fasterxml.jackson.core.io.JsonStringEncoder;
 
 public class TestJsonStringEncoder
     extends com.fasterxml.jackson.core.BaseTest
@@ -20,6 +19,21 @@
         assertArrayEquals("\\\"x\\\"".toCharArray(), result);
     }
 
+    public void testQuoteCharSequenceAsString() throws Exception
+    {
+        JsonStringEncoder encoder = new JsonStringEncoder();
+        StringBuilder output = new StringBuilder();
+        StringBuilder builder = new StringBuilder();
+        builder.append("foobar");
+        encoder.quoteAsString(builder, output);
+        assertEquals("foobar", output.toString());
+        builder.setLength(0);
+        output.setLength(0);
+        builder.append("\"x\"");
+        encoder.quoteAsString(builder, output);
+        assertEquals("\\\"x\\\"", output.toString());
+    }
+
     // For [JACKSON-853]
     public void testQuoteLongAsString() throws Exception
     {
@@ -37,7 +51,24 @@
         assertEquals(exp, new String(result));
         
     }
-    
+
+    public void testQuoteLongCharSequenceAsString() throws Exception
+    {
+        JsonStringEncoder encoder = new JsonStringEncoder();
+        StringBuilder output = new StringBuilder();
+        StringBuilder input = new StringBuilder();
+        StringBuilder sb2 = new StringBuilder();
+        for (int i = 0; i < 1111; ++i) {
+            input.append('"');
+            sb2.append("\\\"");
+        }
+        String exp = sb2.toString();
+        encoder.quoteAsString(input, output);
+        assertEquals(2*input.length(), output.length());
+        assertEquals(exp, output.toString());
+
+    }
+
     public void testQuoteAsUTF8() throws Exception
     {
         // In this case, let's actually use existing JsonGenerator to produce expected values
@@ -82,7 +113,18 @@
         char[] quoted = JsonStringEncoder.getInstance().quoteAsString(new String(input));
         assertEquals("\\u0000\\u0001\\u0002\\u0003\\u0004", new String(quoted));
     }
-    
+
+    // [JACKSON-884]
+    public void testCharSequenceWithCtrlChars() throws Exception
+    {
+        char[] input = new char[] { 0, 1, 2, 3, 4 };
+        StringBuilder builder = new StringBuilder();
+        builder.append(input);
+        StringBuilder output = new StringBuilder();
+        JsonStringEncoder.getInstance().quoteAsString(builder, output);
+        assertEquals("\\u0000\\u0001\\u0002\\u0003\\u0004", output.toString());
+    }
+
     /*
     /**********************************************************
     /* Helper methods
diff --git a/src/test/java/com/fasterxml/jackson/core/json/ArrayGenerationTest.java b/src/test/java/com/fasterxml/jackson/core/json/ArrayGenerationTest.java
index 80483bf..dd490b3 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/ArrayGenerationTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/ArrayGenerationTest.java
@@ -6,7 +6,7 @@
 import com.fasterxml.jackson.core.*;
 
 /**
- * Basic testing for scalar-array write methods added in 2.8
+ * Basic testing for scalar-array write methods added in 2.8.
  */
 public class ArrayGenerationTest extends BaseTest
 {
diff --git a/src/test/java/com/fasterxml/jackson/core/json/GeneratorBasicTest.java b/src/test/java/com/fasterxml/jackson/core/json/GeneratorBasicTest.java
index 7b159a9..a490d5f 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/GeneratorBasicTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/GeneratorBasicTest.java
@@ -55,14 +55,22 @@
 
     public void testIntValueWrite() throws Exception
     {
-        doTestIntValueWrite(false);
-        doTestIntValueWrite(true);
+        // char[]
+        doTestIntValueWrite(false, false);
+        doTestIntValueWrite(true, false);
+        // byte[]
+        doTestIntValueWrite(false, true);
+        doTestIntValueWrite(true, true);
     }
 
     public void testLongValueWrite() throws Exception
     {
-        doTestLongValueWrite(false);
-        doTestLongValueWrite(true);
+        // char[]
+        doTestLongValueWrite(false, false);
+        doTestLongValueWrite(true, false);
+        // byte[]
+        doTestLongValueWrite(false, true);
+        doTestLongValueWrite(true, true);
     }
 
     public void testBooleanWrite() throws Exception
@@ -129,14 +137,18 @@
 
          String docStr = sw.toString();
 
-         JsonParser jp = createParserUsingReader(docStr);
-         assertEquals(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-         assertEquals(1, jp.getIntValue());
-         assertEquals(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-         assertEquals(2, jp.getIntValue());
-         assertEquals(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-         assertEquals(-13, jp.getIntValue());
-         jp.close();
+         try {
+             JsonParser jp = createParserUsingReader(docStr);
+             assertEquals(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+             assertEquals(1, jp.getIntValue());
+             assertEquals(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+             assertEquals(2, jp.getIntValue());
+             assertEquals(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+             assertEquals(-13, jp.getIntValue());
+             jp.close();
+         } catch (IOException e) {
+             fail("Problem with document ["+docStr+"]: "+e.getMessage());
+         }
      }
     
     // Convenience methods
@@ -273,63 +285,114 @@
     /**********************************************************
      */
 
-    private void doTestIntValueWrite(boolean pad) throws Exception
+    private void doTestIntValueWrite(boolean pad, boolean useBytes) throws Exception
     {
         int[] VALUES = new int[] {
             0, 1, -9, 32, -32, 57, 189, 2017, -9999, 13240, 123456,
-            1111111, 22222222, 123456789, Integer.MAX_VALUE, Integer.MAX_VALUE
+            1111111, 22222222, 123456789,
+            7300999, -7300999,
+            99300999, -99300999,
+            999300999, -999300999,
+            1000300999, 2000500126, -1000300999, -2000500126,
+            Integer.MIN_VALUE, Integer.MAX_VALUE
         };
         for (int i = 0; i < VALUES.length; ++i) {
             int VALUE = VALUES[i];
-            StringWriter sw = new StringWriter();
-            JsonGenerator gen = JSON_F.createGenerator(sw);
-            gen.writeNumber(VALUE);
-            if (pad) {
-                gen.writeRaw(" ");
+            String docStr;
+            JsonParser p;
+
+            if (useBytes) {
+                ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+                JsonGenerator gen = JSON_F.createGenerator(bytes);
+                gen.writeNumber(VALUE);
+                if (pad) {
+                    gen.writeRaw(" ");
+                }
+                gen.close();
+                docStr = bytes.toString("UTF-8");
+                p = JSON_F.createParser(bytes.toByteArray());
+            } else {
+                StringWriter sw = new StringWriter();
+                JsonGenerator gen = JSON_F.createGenerator(sw);
+                gen.writeNumber(VALUE);
+                if (pad) {
+                    gen.writeRaw(" ");
+                }
+                gen.close();
+                docStr = sw.toString();
+                p = JSON_F.createParser(docStr);
             }
-            gen.close();
-            String docStr = sw.toString();
-            JsonParser jp = createParserUsingReader(docStr);
-            JsonToken t = jp.nextToken();
+            JsonToken t = null;
+            try {
+                t = p.nextToken();
+            } catch (IOException e) {
+                fail("Problem with value "+VALUE+", document ["+docStr+"]: "+e.getMessage());
+            }
             assertNotNull("Document \""+docStr+"\" yielded no tokens", t);
             // Number are always available as lexical representation too
             String exp = ""+VALUE;
-            if (!exp.equals(jp.getText())) {
-                fail("Expected '"+exp+"', got '"+jp.getText());
+            if (!exp.equals(p.getText())) {
+                fail("Expected '"+exp+"', got '"+p.getText());
             }
             assertEquals(JsonToken.VALUE_NUMBER_INT, t);
-            assertEquals(VALUE, jp.getIntValue());
-            assertEquals(null, jp.nextToken());
-            jp.close();
+            assertEquals(VALUE, p.getIntValue());
+            assertEquals(null, p.nextToken());
+            p.close();
         }
     }
 
-    private void doTestLongValueWrite(boolean pad) throws Exception
+    private void doTestLongValueWrite(boolean pad, boolean useBytes) throws Exception
     {
         long[] VALUES = new long[] {
-            0L, 1L, -1L, -12005002294L, Long.MIN_VALUE, Long.MAX_VALUE
+            0L, 1L, -1L, 2000100345, -12005002294L,
+            5111222333L, -5111222333L,
+            65111222333L, -65111222333L,
+            123456789012L, -123456789012L,
+            123456789012345L, -123456789012345L,
+            123456789012345789L, -123456789012345789L,
+            Long.MIN_VALUE, Long.MAX_VALUE
         };
         for (int i = 0; i < VALUES.length; ++i) {
             long VALUE = VALUES[i];
-            StringWriter sw = new StringWriter();
-            JsonGenerator gen = JSON_F.createGenerator(sw);
-            gen.writeNumber(VALUE);
-            if (pad) {
-                gen.writeRaw(" ");
+            String docStr;
+            JsonParser p;
+
+            if (useBytes) {
+                ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+                JsonGenerator gen = JSON_F.createGenerator(bytes);
+                gen.writeNumber(VALUE);
+                if (pad) {
+                    gen.writeRaw(" ");
+                }
+                gen.close();
+                docStr = bytes.toString("UTF-8");
+                p = JSON_F.createParser(bytes.toByteArray());
+            } else {
+                StringWriter sw = new StringWriter();
+                JsonGenerator gen = JSON_F.createGenerator(sw);
+                gen.writeNumber(VALUE);
+                if (pad) {
+                    gen.writeRaw(" ");
+                }
+                gen.close();
+                docStr = sw.toString();
+                p = JSON_F.createParser(docStr);
             }
-            gen.close();
-            String docStr = sw.toString();
-            JsonParser jp = createParserUsingReader(docStr);
-            JsonToken t = jp.nextToken();
+            JsonToken t = null;
+            try {
+                t = p.nextToken();
+            } catch (IOException e) {
+                fail("Problem with number "+VALUE+", document ["+docStr+"]: "+e.getMessage());
+            }
             assertNotNull("Document \""+docStr+"\" yielded no tokens", t);
             String exp = ""+VALUE;
-            if (!exp.equals(jp.getText())) {
-                fail("Expected '"+exp+"', got '"+jp.getText());
+            if (!exp.equals(p.getText())) {
+                fail("Expected '"+exp+"', got '"+p.getText());
             }
             assertEquals(JsonToken.VALUE_NUMBER_INT, t);
-            assertEquals(VALUE, jp.getLongValue());
-            assertEquals(null, jp.nextToken());
-            jp.close();
+            assertEquals(VALUE, p.getLongValue());
+            assertEquals(null, p.nextToken());
+            p.close();
         }
     }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailTest.java b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailTest.java
index 7b4368b..67ebb25 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailTest.java
@@ -32,6 +32,12 @@
         _testFailOnWritingStringNotFieldName(F, true);        
     }
 
+    // for [core#282]
+    public void testFailOnWritingFieldNameInRoot() throws Exception {
+        _testFailOnWritingFieldNameInRoot(F, false);
+        _testFailOnWritingFieldNameInRoot(F, true);
+    }
+    
     /*
     /**********************************************************
     /* Internal methods
@@ -83,5 +89,24 @@
         gen.close();
     }
 
-
+    // for [core#282]
+    private void _testFailOnWritingFieldNameInRoot(JsonFactory f, boolean useReader) throws Exception
+    {
+        JsonGenerator gen;
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        if (useReader) {
+            gen = f.createGenerator(new OutputStreamWriter(bout, "UTF-8"));
+        } else {
+            gen = f.createGenerator(bout, JsonEncoding.UTF8);
+        }
+        try {
+            gen.writeFieldName("a");
+            gen.flush();
+            String json = bout.toString("UTF-8");
+            fail("Should not have let "+gen.getClass().getName()+".writeFieldName() be used in root context: output = "+json);
+        } catch (JsonProcessingException e) {
+            verifyException(e, "can not write a field name");
+        }
+        gen.close();
+    }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/GeneratorFeaturesTest.java b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFeaturesTest.java
new file mode 100644
index 0000000..20bdff4
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFeaturesTest.java
@@ -0,0 +1,323 @@
+package com.fasterxml.jackson.core.json;
+
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Set of basic unit tests for verifying that the basic generator
+ * functionality works as expected.
+ */
+public class GeneratorFeaturesTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    private final JsonFactory JSON_F = new JsonFactory();
+
+    public void testConfigDefaults() throws IOException
+    {
+        JsonGenerator g = JSON_F.createGenerator(new StringWriter());
+        assertFalse(g.isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS));
+        assertFalse(g.isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN));
+
+        assertTrue(g.canOmitFields());
+        assertFalse(g.canWriteBinaryNatively());
+        assertTrue(g.canWriteFormattedNumbers());
+        assertFalse(g.canWriteObjectId());
+        assertFalse(g.canWriteTypeId());
+        
+        g.close();
+    }
+
+    @SuppressWarnings("deprecation")
+    public void testConfigOverrides() throws IOException
+    {
+        // but also allow overide
+        JsonGenerator g = JSON_F.createGenerator(new StringWriter());
+        int mask = JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS.getMask()
+                | JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN.getMask();
+        g.overrideStdFeatures(mask, mask);
+        assertTrue(g.isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS));
+        assertTrue(g.isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN));
+
+        // and for now, also test straight override
+        g.setFeatureMask(0);
+        assertFalse(g.isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS));
+        assertFalse(g.isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN));
+        g.close();
+    }
+
+    public void testFieldNameQuoting() throws IOException
+    {
+        JsonFactory f = new JsonFactory();
+        // by default, quoting should be enabled
+        _testFieldNameQuoting(f, true);
+        // can disable it
+        f.disable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
+        _testFieldNameQuoting(f, false);
+        // and (re)enable:
+        f.enable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
+        _testFieldNameQuoting(f, true);
+    }
+
+    public void testNonNumericQuoting() throws IOException
+    {
+        JsonFactory f = new JsonFactory();
+        // by default, quoting should be enabled
+        _testNonNumericQuoting(f, true);
+        // can disable it
+        f.disable(JsonGenerator.Feature.QUOTE_NON_NUMERIC_NUMBERS);
+        _testNonNumericQuoting(f, false);
+        // and (re)enable:
+        f.enable(JsonGenerator.Feature.QUOTE_NON_NUMERIC_NUMBERS);
+        _testNonNumericQuoting(f, true);
+    }
+
+    /**
+     * Testing for [JACKSON-176], ability to force serializing numbers
+     * as JSON Strings.
+     */
+    public void testNumbersAsJSONStrings() throws IOException
+    {
+        JsonFactory f = new JsonFactory();
+        // by default should output numbers as-is:
+        assertEquals("[1,2,1.25,2.25,3001,0.5,-1]", _writeNumbers(f));        
+
+        // but if overridden, quotes as Strings
+        f.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
+        assertEquals("[\"1\",\"2\",\"1.25\",\"2.25\",\"3001\",\"0.5\",\"-1\"]",
+                     _writeNumbers(f));
+
+        
+    }
+
+    public void testBigDecimalAsPlain() throws IOException
+    {
+        JsonFactory f = new JsonFactory();
+        BigDecimal ENG = new BigDecimal("1E+2");
+
+        StringWriter sw = new StringWriter();
+        JsonGenerator g = f.createGenerator(sw);
+        g.writeNumber(ENG);
+        g.close();
+        assertEquals("1E+2", sw.toString());
+
+        f.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
+        sw = new StringWriter();
+        g = f.createGenerator(sw);
+        g.writeNumber(ENG);
+        g.close();
+        assertEquals("100", sw.toString());
+    }
+
+    public void testBigDecimalAsPlainString() throws Exception
+    {
+        JsonFactory f = new JsonFactory();
+        BigDecimal ENG = new BigDecimal("1E+2");
+        f.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
+        f.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
+
+        StringWriter sw = new StringWriter();
+        JsonGenerator g = f.createGenerator(sw);
+        g.writeNumber(ENG);
+        g.close();
+        assertEquals(quote("100"), sw.toString());
+
+        // also, as bytes
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        g = f.createGenerator(bos);
+        g.writeNumber(ENG);
+        g.close();
+        assertEquals(quote("100"), bos.toString("UTF-8"));
+    }
+
+    // [core#315]
+    public void testTooBigBigDecimal() throws Exception
+    {
+        JsonFactory f = new JsonFactory();
+        f.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
+
+        // 24-Aug-2016, tatu: Initial check limits scale to [-9999,+9999]
+        BigDecimal BIG = new BigDecimal("1E+9999");
+        BigDecimal TOO_BIG = new BigDecimal("1E+10000");
+        BigDecimal SMALL = new BigDecimal("1E-9999");
+        BigDecimal TOO_SMALL = new BigDecimal("1E-10000");
+
+        for (boolean useBytes : new boolean[] { false, true } ) {
+            for (boolean asString : new boolean[] { false, true } ) {
+                JsonGenerator g;
+                
+                if (useBytes) {
+                    g = f.createGenerator(new ByteArrayOutputStream());
+                } else {
+                    g = f.createGenerator(new StringWriter());
+                }
+                if (asString) {
+                    g.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
+                }
+
+                // first, ok cases:
+                g.writeStartArray();
+                g.writeNumber(BIG);
+                g.writeNumber(SMALL);
+                g.writeEndArray();
+                g.close();
+
+                // then invalid
+                for (BigDecimal input : new BigDecimal[] { TOO_BIG, TOO_SMALL }) {
+                    if (useBytes) {
+                        g = f.createGenerator(new ByteArrayOutputStream());
+                    } else {
+                        g = f.createGenerator(new StringWriter());
+                    }
+                    if (asString) {
+                        g.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
+                    }
+                    try {
+                        g.writeNumber(input);
+                        fail("Should not have written without exception: "+input);
+                    } catch (JsonGenerationException e) {
+                        verifyException(e, "Attempt to write plain `java.math.BigDecimal`");
+                        verifyException(e, "illegal scale");
+                    }
+                    g.close();
+                }
+            }
+        }
+    }
+
+    private String _writeNumbers(JsonFactory f) throws IOException
+    {
+        StringWriter sw = new StringWriter();
+        JsonGenerator g = f.createGenerator(sw);
+    
+        g.writeStartArray();
+        g.writeNumber(1);
+        g.writeNumber(2L);
+        g.writeNumber(1.25);
+        g.writeNumber(2.25f);
+        g.writeNumber(BigInteger.valueOf(3001));
+        g.writeNumber(BigDecimal.valueOf(0.5));
+        g.writeNumber("-1");
+        g.writeEndArray();
+        g.close();
+
+        return sw.toString();
+    }
+
+    // for [core#246]
+    public void testFieldNameQuotingEnabled() throws IOException
+    {
+        // // First, test with default factory, with quoting enabled by default
+        
+        // First, default, with quotes
+        _testFieldNameQuotingEnabled(JSON_F, true, true, "{\"foo\":1}");
+        _testFieldNameQuotingEnabled(JSON_F, false, true, "{\"foo\":1}");
+
+        // then without quotes
+        _testFieldNameQuotingEnabled(JSON_F, true, false, "{foo:1}");
+        _testFieldNameQuotingEnabled(JSON_F, false, false, "{foo:1}");
+
+        // // Then with alternatively configured factory
+
+        JsonFactory f2 = new JsonFactory();
+        f2.disable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
+
+        _testFieldNameQuotingEnabled(f2, true, true, "{\"foo\":1}");
+        _testFieldNameQuotingEnabled(f2, false, true, "{\"foo\":1}");
+
+        // then without quotes
+        _testFieldNameQuotingEnabled(f2, true, false, "{foo:1}");
+        _testFieldNameQuotingEnabled(f2, false, false, "{foo:1}");
+    }
+
+    private void _testFieldNameQuotingEnabled(JsonFactory f, boolean useBytes,
+            boolean useQuotes, String exp) throws IOException
+    {
+        ByteArrayOutputStream bytes = useBytes ? new ByteArrayOutputStream() : null;
+        StringWriter sw = useBytes ? null : new StringWriter();
+        JsonGenerator gen = useBytes ? f.createGenerator(bytes) : f.createGenerator(sw);
+        if (useQuotes) {
+            gen.enable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
+        } else {
+            gen.disable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
+        }
+
+        gen.writeStartObject();
+        gen.writeFieldName("foo");
+        gen.writeNumber(1);
+        gen.writeEndObject();
+        gen.close();
+
+        String json = useBytes ? bytes.toString("UTF-8") : sw.toString();
+        assertEquals(exp, json);
+    }
+
+    public void testChangeOnGenerator() throws IOException
+    {
+        StringWriter w = new StringWriter();
+
+        JsonGenerator g = JSON_F.createGenerator(w);
+        g.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
+        g.writeNumber(123);
+        g.close();
+        assertEquals(quote("123"), w.toString());
+
+        // but also the opposite
+        w = new StringWriter();
+        g = JSON_F.createGenerator(w);
+        g.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
+        g.disable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
+        g.writeNumber(123);
+        g.close();
+        assertEquals("123", w.toString());
+    }
+
+    /*
+    /**********************************************************
+    /* Helper methods
+    /**********************************************************
+     */
+
+    private void _testFieldNameQuoting(JsonFactory f, boolean quoted)
+        throws IOException
+    {
+        StringWriter sw = new StringWriter();
+        JsonGenerator g = f.createGenerator(sw);
+        g.writeStartObject();
+        g.writeFieldName("foo");
+        g.writeNumber(1);
+        g.writeEndObject();
+        g.close();
+
+        String result = sw.toString();
+        if (quoted) {
+            assertEquals("{\"foo\":1}", result);
+        } else {
+            assertEquals("{foo:1}", result);
+        }
+    }
+    private void _testNonNumericQuoting(JsonFactory f, boolean quoted)
+        throws IOException
+    {
+        StringWriter sw = new StringWriter();
+        JsonGenerator g = f.createGenerator(sw);
+        g.writeStartObject();
+        g.writeFieldName("double");
+        g.writeNumber(Double.NaN);
+        g.writeEndObject();
+        g.writeStartObject();
+        g.writeFieldName("float");
+        g.writeNumber(Float.NaN);
+        g.writeEndObject();
+        g.close();
+	
+        String result = sw.toString();
+        if (quoted) {
+            assertEquals("{\"double\":\"NaN\"} {\"float\":\"NaN\"}", result);
+        } else {
+            assertEquals("{\"double\":NaN} {\"float\":NaN}", result);
+        }
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java b/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java
index 6b3f4c9..85363f4 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java
@@ -3,16 +3,15 @@
 import com.fasterxml.jackson.core.*;
 import com.fasterxml.jackson.core.util.JsonParserSequence;
 
+@SuppressWarnings("resource")
 public class ParserSequenceTest
     extends com.fasterxml.jackson.core.BaseTest
 {
-    private final JsonFactory JSON_FACTORY = new JsonFactory();
-
     public void testSimple() throws Exception
     {
         JsonParser p1 = JSON_FACTORY.createParser("[ 1 ]");
         JsonParser p2 = JSON_FACTORY.createParser("[ 2 ]");
-        JsonParserSequence seq = JsonParserSequence.createFlattened(p1, p2);
+        JsonParserSequence seq = JsonParserSequence.createFlattened(false, p1, p2);
         assertEquals(2, seq.containedParsersCount());
 
         assertFalse(p1.isClosed());
@@ -45,8 +44,52 @@
         assertTrue(seq.isClosed());
 
         seq.close();
-        // redundant, but call to remove IDE warnings
-        p1.close();
-        p2.close();
+    }
+
+    // for [jackson-core#296]
+    public void testInitializationDisabled() throws Exception
+    {
+        // // First, with old legacy settings
+
+        JsonParser p1 = JSON_FACTORY.createParser("1 2");
+        JsonParser p2 = JSON_FACTORY.createParser("3 true");
+        assertToken(JsonToken.VALUE_NUMBER_INT, p1.nextToken());
+        assertEquals(1, p1.getIntValue());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p2.nextToken());
+        assertEquals(3, p2.getIntValue());
+
+        // with legacy settings, will see neither '1' nor '3'
+        
+        JsonParserSequence seq = JsonParserSequence.createFlattened(false, p1, p2);
+        assertToken(JsonToken.VALUE_NUMBER_INT, seq.nextToken());
+        assertEquals(2, seq.getIntValue());
+        assertToken(JsonToken.VALUE_TRUE, seq.nextToken());
+        assertNull(seq.nextToken());
+        seq.close();
+    }
+
+    // for [jackson-core#296]
+    public void testInitializationEnabled() throws Exception
+    {
+        // // and then with new "check for current":
+        JsonParser p1 = JSON_FACTORY.createParser("1 2");
+        JsonParser p2 = JSON_FACTORY.createParser("3 true");
+        assertToken(JsonToken.VALUE_NUMBER_INT, p1.nextToken());
+        assertEquals(1, p1.getIntValue());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p2.nextToken());
+        assertEquals(3, p2.getIntValue());
+
+        // with new settings, both '1' and '3' will be visible
+        
+        JsonParserSequence seq = JsonParserSequence.createFlattened(true, p1, p2);
+        assertToken(JsonToken.VALUE_NUMBER_INT, seq.nextToken());
+        assertEquals(1, seq.getIntValue());
+        assertToken(JsonToken.VALUE_NUMBER_INT, seq.nextToken());
+        assertEquals(2, seq.getIntValue());
+        assertToken(JsonToken.VALUE_NUMBER_INT, seq.nextToken());
+        assertEquals(3, seq.getIntValue());
+        assertToken(JsonToken.VALUE_TRUE, seq.nextToken());
+        assertNull(seq.nextToken());
+        seq.close();
     }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/RequestPayloadOnExceptionTest.java b/src/test/java/com/fasterxml/jackson/core/json/RequestPayloadOnExceptionTest.java
new file mode 100644
index 0000000..7fbc717
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/json/RequestPayloadOnExceptionTest.java
@@ -0,0 +1,144 @@
+package com.fasterxml.jackson.core.json;
+
+import com.fasterxml.jackson.core.*;
+
+public class RequestPayloadOnExceptionTest extends BaseTest
+{
+    /**
+     * Tests for Request payload data (bytes) on parsing error
+     */
+    public void testRequestPayloadAsBytesOnParseException() throws Exception {
+        testRequestPayloadAsBytesOnParseExceptionInternal(true, "nul");
+        testRequestPayloadAsBytesOnParseExceptionInternal(false, "nul");
+    }
+
+    /**
+     * Tests for Request payload data (String) on parsing error
+     */
+    public void testRequestPayloadAsStringOnParseException() throws Exception {
+        testRequestPayloadAsStringOnParseExceptionInternal(true, "nul");
+        testRequestPayloadAsStringOnParseExceptionInternal(false, "nul");
+    }
+
+    /**
+     * Tests for Raw Request payload data on parsing error
+     */
+    public void testRawRequestPayloadOnParseException() throws Exception {
+        testRawRequestPayloadOnParseExceptionInternal(true, "nul");
+        testRawRequestPayloadOnParseExceptionInternal(false, "nul");
+    }
+
+    /**
+     * Tests for no Request payload data on parsing error
+     */
+    public void testNoRequestPayloadOnParseException() throws Exception {
+        testNoRequestPayloadOnParseExceptionInternal(true, "nul");
+        testNoRequestPayloadOnParseExceptionInternal(false, "nul");
+    }
+
+    /**
+     * Tests for Request payload data which is null
+     */
+    public void testNullRequestPayloadOnParseException() throws Exception {
+        testNullRequestPayloadOnParseExceptionInternal(true, "nul");
+        testNullRequestPayloadOnParseExceptionInternal(false, "nul");
+    }
+
+    /**
+     * Tests for null Charset in Request payload data
+     */
+    public void testNullCharsetOnParseException() throws Exception {
+        testNullCharsetOnParseExceptionInternal(true, "nul");
+        testNullCharsetOnParseExceptionInternal(false, "nul");
+    }
+
+    /*
+     * *******************Private Methods*************************
+     */
+    private void testRequestPayloadAsBytesOnParseExceptionInternal(boolean isStream, String value) throws Exception {
+        final String doc = "{ \"key1\" : " + value + " }";
+        JsonParser jp = isStream ? createParserUsingStream(doc, "UTF-8") : createParserUsingReader(doc);
+        jp.setRequestPayloadOnError(doc.getBytes(), "UTF-8");
+        assertToken(JsonToken.START_OBJECT, jp.nextToken());
+        try {
+            jp.nextToken();
+            fail("Expecting parsing exception");
+        } catch (JsonParseException ex) {
+            assertEquals("Request payload data should match", doc, ex.getRequestPayloadAsString());
+            assertTrue("Message contains request body", ex.getMessage().contains("Request payload : " + doc));
+        }
+        jp.close();
+    }
+
+    private void testRequestPayloadAsStringOnParseExceptionInternal(boolean isStream, String value) throws Exception {
+        final String doc = "{ \"key1\" : " + value + " }";
+        JsonParser jp = isStream ? createParserUsingStream(doc, "UTF-8") : createParserUsingReader(doc);
+        jp.setRequestPayloadOnError(doc);
+        assertToken(JsonToken.START_OBJECT, jp.nextToken());
+        try {
+            jp.nextToken();
+            fail("Expecting parsing exception");
+        } catch (JsonParseException ex) {
+            assertEquals("Request payload data should match", doc, ex.getRequestPayloadAsString());
+            assertTrue("Message contains request body", ex.getMessage().contains("Request payload : " + doc));
+        }
+        jp.close();
+    }
+
+    private void testRawRequestPayloadOnParseExceptionInternal(boolean isStream, String value) throws Exception {
+        final String doc = "{ \"key1\" : " + value + " }";
+        JsonParser jp = isStream ? createParserUsingStream(doc, "UTF-8") : createParserUsingReader(doc);
+        jp.setRequestPayloadOnError(doc.getBytes(), "UTF-8");
+        assertToken(JsonToken.START_OBJECT, jp.nextToken());
+        try {
+            jp.nextToken();
+            fail("Expecting parsing exception");
+        } catch (JsonParseException ex) {
+            assertTrue(((byte[]) ex.getRequestPayload().getRawPayload()).length > 0);
+            assertTrue("Message contains request body", ex.getMessage().contains("Request payload : " + doc));
+        }
+        jp.close();
+    }
+
+    private void testNoRequestPayloadOnParseExceptionInternal(boolean isStream, String value) throws Exception {
+        final String doc = "{ \"key1\" : " + value + " }";
+        JsonParser jp = isStream ? createParserUsingStream(doc, "UTF-8") : createParserUsingReader(doc);
+        assertToken(JsonToken.START_OBJECT, jp.nextToken());
+        try {
+            jp.nextToken();
+            fail("Expecting parsing exception");
+        } catch (JsonParseException ex) {
+            assertEquals("Request payload data should be null", null, ex.getRequestPayload());
+        }
+        jp.close();
+    }
+
+    private void testNullRequestPayloadOnParseExceptionInternal(boolean isStream, String value) throws Exception {
+        final String doc = "{ \"key1\" : " + value + " }";
+        JsonParser jp = isStream ? createParserUsingStream(doc, "UTF-8") : createParserUsingReader(doc);
+        jp.setRequestPayloadOnError(null, "UTF-8");
+        assertToken(JsonToken.START_OBJECT, jp.nextToken());
+        try {
+            jp.nextToken();
+            fail("Expecting parsing exception");
+        } catch (JsonParseException ex) {
+            assertEquals("Request payload data should be null", null, ex.getRequestPayload());
+        }
+        jp.close();
+    }
+
+    private void testNullCharsetOnParseExceptionInternal(boolean isStream, String value) throws Exception {
+        final String doc = "{ \"key1\" : " + value + " }";
+        JsonParser jp = isStream ? createParserUsingStream(doc, "UTF-8") : createParserUsingReader(doc);
+        jp.setRequestPayloadOnError(doc.getBytes(), "UTF-8");
+        assertToken(JsonToken.START_OBJECT, jp.nextToken());
+        try {
+            jp.nextToken();
+            fail("Expecting parsing exception");
+        } catch (JsonParseException ex) {
+            assertEquals("Request payload data should match", doc, ex.getRequestPayloadAsString());
+            assertTrue("Message contains request body", ex.getMessage().contains("Request payload : " + doc));
+        }
+        jp.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/StringGenerationTest.java b/src/test/java/com/fasterxml/jackson/core/json/StringGenerationTest.java
index b36cbe6..4fd67c1 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/StringGenerationTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/StringGenerationTest.java
@@ -20,7 +20,7 @@
         "\"\"\"", "\\r)'\"",
         "Longer text & other stuff:\twith some\r\n\r\n random linefeeds etc added in to cause some \"special\" handling \\\\ to occur...\n"
     };
- 
+
     private final JsonFactory FACTORY = new JsonFactory();
     
     public void testBasicEscaping() throws Exception
@@ -32,21 +32,21 @@
     // for [core#194]
     public void testMediumStringsBytes() throws Exception
     {
-        _testMediumStrings(true, 1100);
-        _testMediumStrings(true, 2300);
-        _testMediumStrings(true, 3800);
-        _testMediumStrings(true, 7500);
-        _testMediumStrings(true, 19000);
+        for (int mode : ALL_BINARY_MODES) {
+            for (int size : new int[] { 1100, 2300, 3800, 7500, 19000 }) {
+                _testMediumStrings(mode, size);
+            }
+        }
     }
 
     // for [core#194]
     public void testMediumStringsChars() throws Exception
     {
-        _testMediumStrings(false, 1100);
-        _testMediumStrings(false, 2300);
-        _testMediumStrings(false, 3800);
-        _testMediumStrings(false, 7500);
-        _testMediumStrings(false, 19000);
+        for (int mode : ALL_TEXT_MODES) {
+            for (int size : new int[] { 1100, 2300, 3800, 7500, 19000 }) {
+                _testMediumStrings(mode, size);
+            }
+        }
     }
 
     public void testLongerRandomSingleChunk() throws Exception
@@ -54,10 +54,12 @@
         /* Let's first generate 100k of pseudo-random characters, favoring
          * 7-bit ascii range
          */
-        for (int round = 0; round < 80; ++round) {
-            String content = generateRandom(75000+round);
-            doTestLongerRandom(content, false);
-            doTestLongerRandom(content, true);
+        for (int mode : ALL_TEXT_MODES) {
+            for (int round = 0; round < 80; ++round) {
+                String content = generateRandom(75000+round);
+                _testLongerRandom(mode, content, false);
+                _testLongerRandom(mode, content, true);
+            }
         }
     }
 
@@ -66,10 +68,12 @@
         /* Let's first generate 100k of pseudo-random characters, favoring
          * 7-bit ascii range
          */
-        for (int round = 0; round < 70; ++round) {
-            String content = generateRandom(73000+round);
-            doTestLongerRandomMulti(content, false, round);
-            doTestLongerRandomMulti(content, true, round);
+        for (int mode : ALL_TEXT_MODES) {
+            for (int round = 0; round < 70; ++round) {
+                String content = generateRandom(73000+round);
+                _testLongerRandomMulti(mode, content, false, round);
+                _testLongerRandomMulti(mode, content, true, round);
+            }
         }
     }
 
@@ -126,27 +130,25 @@
         return sb.toString();
     }
 
-    private void _testMediumStrings(boolean useBinary, int length) throws Exception
+    private void _testMediumStrings(int readMode, int length) throws Exception
     {
         String text = _generareMediumText(length);
         StringWriter sw = new StringWriter();
         ByteArrayOutputStream bytes = new ByteArrayOutputStream();
 
-        JsonGenerator gen = useBinary ? FACTORY.createGenerator(bytes)
+        JsonGenerator gen = (readMode != MODE_READER) ? FACTORY.createGenerator(bytes)
                 : FACTORY.createGenerator(sw);
         gen.writeStartArray();
         gen.writeString(text);
         gen.writeEndArray();
         gen.close();
 
-        String json;
-        if (useBinary) {
-            json = bytes.toString("UTF-8");
+        JsonParser p;
+        if (readMode == MODE_READER) {
+            p = FACTORY.createParser(sw.toString());
         } else {
-            json = sw.toString();
+            p = createParser(FACTORY, readMode, bytes.toByteArray());
         }
-
-        JsonParser p = FACTORY.createParser(json);
         assertToken(JsonToken.START_ARRAY, p.nextToken());
         assertToken(JsonToken.VALUE_STRING, p.nextToken());
         assertEquals(text, p.getText());
@@ -154,8 +156,7 @@
         p.close();
     }
     
-    private void doTestBasicEscaping(boolean charArray)
-        throws Exception
+    private void doTestBasicEscaping(boolean charArray) throws Exception
     {
         for (int i = 0; i < SAMPLES.length; ++i) {
             String VALUE = SAMPLES[i];
@@ -172,18 +173,18 @@
             gen.writeEndArray();
             gen.close();
             String docStr = sw.toString();
-            JsonParser jp = createParserUsingReader(docStr);
-            assertEquals(JsonToken.START_ARRAY, jp.nextToken());
-            JsonToken t = jp.nextToken();
+            JsonParser p = createParserUsingReader(docStr);
+            assertEquals(JsonToken.START_ARRAY, p.nextToken());
+            JsonToken t = p.nextToken();
             assertEquals(JsonToken.VALUE_STRING, t);
-            assertEquals(VALUE, jp.getText());
-            assertEquals(JsonToken.END_ARRAY, jp.nextToken());
-            assertEquals(null, jp.nextToken());
-            jp.close();
+            assertEquals(VALUE, p.getText());
+            assertEquals(JsonToken.END_ARRAY, p.nextToken());
+            assertEquals(null, p.nextToken());
+            p.close();
         }
     }
 
-    private void doTestLongerRandom(String text, boolean charArray)
+    private void _testLongerRandom(int readMode, String text, boolean charArray)
         throws Exception
     {
         ByteArrayOutputStream bow = new ByteArrayOutputStream(text.length());
@@ -200,11 +201,11 @@
         gen.writeEndArray();
         gen.close();
         byte[] docData = bow.toByteArray();
-        JsonParser jp = FACTORY.createParser(new ByteArrayInputStream(docData));
-        assertEquals(JsonToken.START_ARRAY, jp.nextToken());
-        JsonToken t = jp.nextToken();
+        JsonParser p = createParser(FACTORY, readMode, docData);
+        assertEquals(JsonToken.START_ARRAY, p.nextToken());
+        JsonToken t = p.nextToken();
         assertEquals(JsonToken.VALUE_STRING, t);
-        String act = jp.getText();
+        String act = p.getText();
         if (!text.equals(act)) {
             if (text.length() != act.length()) {
                 fail("Expected string length "+text.length()+", actual "+act.length());
@@ -217,12 +218,11 @@
             }
             fail("Strings differ at position #"+i+" (len "+text.length()+"): expected char 0x"+Integer.toHexString(text.charAt(i))+", actual 0x"+Integer.toHexString(act.charAt(i)));
         }
-        assertEquals(JsonToken.END_ARRAY, jp.nextToken());
-        assertEquals(null, jp.nextToken());
-        jp.close();
+        assertEquals(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
     }
 
-    private void doTestLongerRandomMulti(String text, boolean charArray, int round)
+    private void _testLongerRandomMulti(int readMode, String text, boolean charArray, int round)
         throws Exception
     {
         ByteArrayOutputStream bow = new ByteArrayOutputStream(text.length());
@@ -265,13 +265,13 @@
         gen.writeEndArray();
         gen.close();
         byte[] docData = bow.toByteArray();
-        JsonParser jp = FACTORY.createParser(new ByteArrayInputStream(docData));
-        assertEquals(JsonToken.START_ARRAY, jp.nextToken());
+        JsonParser p = createParser(FACTORY, readMode, docData);
+        assertEquals(JsonToken.START_ARRAY, p.nextToken());
 
         offset = 0;
-        while (jp.nextToken() == JsonToken.VALUE_STRING) {
+        while (p.nextToken() == JsonToken.VALUE_STRING) {
             // Let's verify, piece by piece
-            String act = jp.getText();
+            String act = p.getText();
             String exp = text.substring(offset, offset+act.length());
             if (act.length() != exp.length()) {
                 fail("String segment ["+offset+" - "+(offset+act.length())+"[ differs; exp length "+exp+", actual "+act);                
@@ -287,7 +287,7 @@
             }
             offset += act.length();
         }
-        assertEquals(JsonToken.END_ARRAY, jp.getCurrentToken());
-        jp.close();
+        assertEquals(JsonToken.END_ARRAY, p.currentToken());
+        p.close();
     }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestComments.java b/src/test/java/com/fasterxml/jackson/core/json/TestComments.java
deleted file mode 100644
index 9840909..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestComments.java
+++ /dev/null
@@ -1,274 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-import java.io.*;
-
-import com.fasterxml.jackson.core.*;
-
-/**
- * Unit tests for verifying that support for (non-standard) comments
- * works as expected.
- */
-public class TestComments
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    final static String DOC_WITH_SLASHSTAR_COMMENT =
-        "[ /* comment:\n ends here */ 1 /* one more ok to have \"unquoted\"  */ ]"
-        ;
-
-    final static String DOC_WITH_SLASHSLASH_COMMENT =
-        "[ // comment...\n 1 \r  // one more, not array: []   \n ]"
-        ;
-
-    /*
-    /**********************************************************
-    /* Test method wrappers
-    /**********************************************************
-     */
-    
-    /**
-     * Unit test for verifying that by default comments are not
-     * recognized.
-     */
-    public void testDefaultSettings()
-        throws Exception
-    {
-        JsonFactory jf = new JsonFactory();
-        assertFalse(jf.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
-        JsonParser jp = jf.createParser(new StringReader("[ 1 ]"));
-        assertFalse(jp.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
-        jp.close();
-    }
-
-    public void testCommentsDisabled()
-        throws Exception
-    {
-        _testDisabled(DOC_WITH_SLASHSTAR_COMMENT, false);
-        _testDisabled(DOC_WITH_SLASHSLASH_COMMENT, false);
-        _testDisabled(DOC_WITH_SLASHSTAR_COMMENT, true);
-        _testDisabled(DOC_WITH_SLASHSLASH_COMMENT, true);
-    }
-
-    public void testCommentsEnabled()
-        throws Exception
-    {
-        _testEnabled(DOC_WITH_SLASHSTAR_COMMENT, false);
-        _testEnabled(DOC_WITH_SLASHSLASH_COMMENT, false);
-        _testEnabled(DOC_WITH_SLASHSTAR_COMMENT, true);
-        _testEnabled(DOC_WITH_SLASHSLASH_COMMENT, true);
-    }
-
-    // for [JACKSON-779]
-    public void testCommentsWithUTF8() throws Exception
-    {
-        final String JSON = "/* \u00a9 2099 Yoyodyne Inc. */\n [ \"bar? \u00a9\" ]\n";
-        _testWithUTF8Chars(JSON, false);
-        _testWithUTF8Chars(JSON, true);
-    }
-
-    public void testYAMLCommentsBytes() throws Exception {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true);
-        _testYAMLComments(f, true);
-        _testCommentsBeforePropValue(f, true, "# foo\n");
-    }
-
-    public void testYAMLCommentsChars() throws Exception {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true);
-        _testYAMLComments(f, false);
-        final String COMMENT = "# foo\n";
-        _testCommentsBeforePropValue(f, false, COMMENT);
-        _testCommentsBetweenArrayValues(f, false, COMMENT);
-    }
-
-    public void testCCommentsBytes() throws Exception {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
-        final String COMMENT = "/* foo */\n";
-        _testCommentsBeforePropValue(f, true, COMMENT);
-    }
-
-    public void testCCommentsChars() throws Exception {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
-        final String COMMENT = "/* foo */\n";
-        _testCommentsBeforePropValue(f, false, COMMENT);
-    }
-
-    public void testCppCommentsBytes() throws Exception {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
-        final String COMMENT = "// foo\n";
-        _testCommentsBeforePropValue(f, true, COMMENT);
-    }
-
-    public void testCppCommentsChars() throws Exception {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
-        final String COMMENT = "// foo \n";
-        _testCommentsBeforePropValue(f, false, COMMENT);
-    }
-
-    @SuppressWarnings("resource")
-    private void _testCommentsBeforePropValue(JsonFactory f, boolean useStream, String comment) throws Exception
-    {
-        for (String arg : new String[] {
-                ":%s123",
-                " :%s123",
-                "\t:%s123",
-                ": %s123",
-                ":\t%s123",
-        }) {
-            String commented = String.format(arg, comment);
-            
-            final String DOC = "{\"abc\"" + commented + "}";
-            JsonParser jp = useStream ?
-                    f.createParser(DOC.getBytes("UTF-8"))
-                    : f.createParser(DOC);
-            assertEquals(JsonToken.START_OBJECT, jp.nextToken());
-            JsonToken t = null;
-            try {
-                t = jp.nextToken();
-            } catch (Exception e) {
-                throw new RuntimeException("Failed on '"+DOC+"' due to "+e, e);
-            }
-            assertEquals(JsonToken.FIELD_NAME, t);
-
-            try {
-                t = jp.nextToken();
-            } catch (Exception e) {
-                throw new RuntimeException("Failed on '"+DOC+"' due to "+e, e);
-            }
-            assertEquals(JsonToken.VALUE_NUMBER_INT, t);
-            assertEquals(123, jp.getIntValue());
-            assertEquals(JsonToken.END_OBJECT, jp.nextToken());
-            jp.close();
-        }
-        
-    }
-
-    @SuppressWarnings("resource")
-    private void _testCommentsBetweenArrayValues(JsonFactory f, boolean useStream, String comment) throws Exception
-    {
-        for (String tmpl : new String[] {
-                "%s,",
-                " %s,",
-                "\t%s,",
-                "%s ,",
-                "%s\t,",
-                " %s ,",
-                "\t%s\t,",
-                "\n%s,",
-                "%s\n,",
-        }) {
-            String commented = String.format(tmpl, comment);
-            
-            final String DOC = "[1"+commented+"2]";
-            JsonParser jp = useStream ?
-                    f.createParser(DOC.getBytes("UTF-8"))
-                    : f.createParser(DOC);
-            assertEquals(JsonToken.START_ARRAY, jp.nextToken());
-            JsonToken t = null;
-            try {
-                t = jp.nextToken();
-            } catch (Exception e) {
-                throw new RuntimeException("Failed on '"+DOC+"' due to "+e, e);
-            }
-            assertEquals(JsonToken.VALUE_NUMBER_INT, t);
-            assertEquals(1, jp.getIntValue());
-
-            try {
-                t = jp.nextToken();
-            } catch (Exception e) {
-                throw new RuntimeException("Failed on '"+DOC+"' due to "+e, e);
-            }
-            assertEquals(JsonToken.VALUE_NUMBER_INT, t);
-            assertEquals(2, jp.getIntValue());
-            assertEquals(JsonToken.END_ARRAY, jp.nextToken());
-            jp.close();
-        }
-        
-    }
-    
-    private void _testYAMLComments(JsonFactory f, boolean useStream) throws Exception
-    {
-        final String DOC = "# foo\n"
-                +" {\"a\" # xyz\n"
-                +" : # foo\n"
-                +" 1, # more\n"
-                +"\"b\": [ \n"
-                +" #all!\n"
-                +" 3 #yay!\n"
-                +"] # foobar\n"
-                +"} # x"
-                ;
-        JsonParser jp = useStream ?
-                f.createParser(DOC.getBytes("UTF-8"))
-                : f.createParser(DOC);
-        assertEquals(JsonToken.START_OBJECT, jp.nextToken());
-        assertEquals(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("a", jp.getCurrentName());
-        assertEquals(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(1, jp.getIntValue());
-        assertEquals(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("b", jp.getCurrentName());
-        assertEquals(JsonToken.START_ARRAY, jp.nextToken());
-        assertEquals(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(3, jp.getIntValue());
-        assertEquals(JsonToken.END_ARRAY, jp.nextToken());
-        assertEquals(JsonToken.END_OBJECT, jp.nextToken());
-        assertNull(jp.nextToken());
-        jp.close();
-    }
-
-    /*
-    /**********************************************************
-    /* Helper methods
-    /**********************************************************
-     */
-
-    private void _testWithUTF8Chars(String doc, boolean useStream) throws IOException
-    {
-        // should basically just stream through
-        JsonParser jp = _createParser(doc, useStream, true);
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        assertNull(jp.nextToken());
-        jp.close();
-    }
-    
-    private void _testDisabled(String doc, boolean useStream) throws IOException
-    {
-        JsonParser jp = _createParser(doc, useStream, false);
-        try {
-            jp.nextToken();
-            fail("Expected exception for unrecognized comment");
-        } catch (JsonParseException je) {
-            // Should have something denoting that user may want to enable 'ALLOW_COMMENTS'
-            verifyException(je, "ALLOW_COMMENTS");
-        }
-        jp.close();
-    }
-
-    private void _testEnabled(String doc, boolean useStream)
-        throws IOException
-    {
-        JsonParser jp = _createParser(doc, useStream, true);
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(1, jp.getIntValue());
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        jp.close();
-    }
-
-    private JsonParser _createParser(String doc, boolean useStream, boolean enabled)
-        throws IOException
-    {
-        JsonFactory jf = new JsonFactory();
-        jf.configure(JsonParser.Feature.ALLOW_COMMENTS, enabled);
-        JsonParser jp = useStream ?
-            jf.createParser(doc.getBytes("UTF-8"))
-            : jf.createParser(doc);
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        return jp;
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestCustomEscaping.java b/src/test/java/com/fasterxml/jackson/core/json/TestCustomEscaping.java
index ae7a841..7188be7 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestCustomEscaping.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestCustomEscaping.java
@@ -78,7 +78,7 @@
     }
 
     // // // Tests for [JACKSON-106]
-    
+
     public void testEscapeCustomWithReader() throws Exception
     {
         _testEscapeCustom(false); // reader
@@ -88,7 +88,40 @@
     {
         _testEscapeCustom(true); // stream (utf-8)
     }
-    
+
+    public void testJsonpEscapes() throws Exception {
+        _testJsonpEscapes(false);
+        _testJsonpEscapes(true);
+    }
+
+    @SuppressWarnings("resource")
+    private void _testJsonpEscapes(boolean useStream) throws Exception
+    {
+        JsonFactory f = new JsonFactory();
+        f.setCharacterEscapes(JsonpCharacterEscapes.instance());
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        JsonGenerator g;
+
+        // First: output normally; should not add escaping
+        if (useStream) {
+            g = f.createGenerator(bytes, JsonEncoding.UTF8);
+        } else {
+            g = f.createGenerator(new OutputStreamWriter(bytes, "UTF-8"));
+        }
+        final String VALUE_TEMPLATE = "String with JS 'linefeeds': %s and %s...";
+        final String INPUT_VALUE = String.format(VALUE_TEMPLATE, "\u2028", "\u2029");
+
+        g.writeStartArray();
+        g.writeString(INPUT_VALUE);
+        g.writeEndArray();
+        g.close();
+
+        String json = bytes.toString("UTF-8");
+        assertEquals(String.format("[%s]",
+                quote(String.format(VALUE_TEMPLATE, "\\u2028", "\\u2029"))),
+                json);
+    }
+
     /*
     /********************************************************
     /* Secondary test methods
@@ -102,18 +135,18 @@
         final String VALUE = "chars: [\u00A0]/[\u1234]";
         final String KEY = "fun:\u0088:\u3456";
         ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-        JsonGenerator jgen;
+        JsonGenerator g;
 
         // First: output normally; should not add escaping
         if (useStream) {
-            jgen = f.createGenerator(bytes, JsonEncoding.UTF8);
+            g = f.createGenerator(bytes, JsonEncoding.UTF8);
         } else {
-            jgen = f.createGenerator(new OutputStreamWriter(bytes, "UTF-8"));
+            g = f.createGenerator(new OutputStreamWriter(bytes, "UTF-8"));
         }
-        jgen.writeStartArray();
-        jgen.writeString(VALUE);
-        jgen.writeEndArray();
-        jgen.close();
+        g.writeStartArray();
+        g.writeString(VALUE);
+        g.writeEndArray();
+        g.close();
         String json = bytes.toString("UTF-8");
         
         assertEquals("["+quote(VALUE)+"]", json);
@@ -122,31 +155,31 @@
 
         bytes = new ByteArrayOutputStream();
         if (useStream) {
-            jgen = f.createGenerator(bytes, JsonEncoding.UTF8);
+            g = f.createGenerator(bytes, JsonEncoding.UTF8);
         } else {
-            jgen = f.createGenerator(new OutputStreamWriter(bytes, "UTF-8"));
+            g = f.createGenerator(new OutputStreamWriter(bytes, "UTF-8"));
         }
-        jgen.enable(JsonGenerator.Feature.ESCAPE_NON_ASCII);
-        jgen.writeStartArray();
-        jgen.writeString(VALUE);
-        jgen.writeEndArray();
-        jgen.close();
+        g.enable(JsonGenerator.Feature.ESCAPE_NON_ASCII);
+        g.writeStartArray();
+        g.writeString(VALUE);
+        g.writeEndArray();
+        g.close();
         json = bytes.toString("UTF-8");
         assertEquals("["+quote("chars: [\\u00A0]/[\\u1234]")+"]", json);
 
         // and then keys
         bytes = new ByteArrayOutputStream();
         if (useStream) {
-            jgen = f.createGenerator(bytes, JsonEncoding.UTF8);
+            g = f.createGenerator(bytes, JsonEncoding.UTF8);
         } else {
-            jgen = f.createGenerator(new OutputStreamWriter(bytes, "UTF-8"));
+            g = f.createGenerator(new OutputStreamWriter(bytes, "UTF-8"));
         }
-        jgen.enable(JsonGenerator.Feature.ESCAPE_NON_ASCII);
-        jgen.writeStartObject();
-        jgen.writeFieldName(KEY);
-        jgen.writeBoolean(true);
-        jgen.writeEndObject();
-        jgen.close();
+        g.enable(JsonGenerator.Feature.ESCAPE_NON_ASCII);
+        g.writeStartObject();
+        g.writeFieldName(KEY);
+        g.writeBoolean(true);
+        g.writeEndObject();
+        g.close();
         json = bytes.toString("UTF-8");
         assertEquals("{"+quote("fun:\\u0088:\\u3456")+":true}", json);
     }
@@ -158,18 +191,18 @@
         final String STR_IN = "[abcd/"+((char) TWO_BYTE_ESCAPED)+"/"+((char) THREE_BYTE_ESCAPED)+"]";
         final String STR_OUT = "[\\A\\u0062c[D]/"+TWO_BYTE_ESCAPED_STRING+"/"+THREE_BYTE_ESCAPED_STRING+"]";
         ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-        JsonGenerator jgen;
+        JsonGenerator g;
         
         // First: output normally; should not add escaping
         if (useStream) {
-            jgen = f.createGenerator(bytes, JsonEncoding.UTF8);
+            g = f.createGenerator(bytes, JsonEncoding.UTF8);
         } else {
-            jgen = f.createGenerator(new OutputStreamWriter(bytes, "UTF-8"));
+            g = f.createGenerator(new OutputStreamWriter(bytes, "UTF-8"));
         }
-        jgen.writeStartObject();
-        jgen.writeStringField(STR_IN, STR_IN);
-        jgen.writeEndObject();
-        jgen.close();
+        g.writeStartObject();
+        g.writeStringField(STR_IN, STR_IN);
+        g.writeEndObject();
+        g.close();
         String json = bytes.toString("UTF-8");
         assertEquals("{"+quote(STR_OUT)+":"+quote(STR_OUT)+"}", json);
     }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestJsonGeneratorFeatures.java b/src/test/java/com/fasterxml/jackson/core/json/TestJsonGeneratorFeatures.java
deleted file mode 100644
index d2f6c28..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestJsonGeneratorFeatures.java
+++ /dev/null
@@ -1,278 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-import java.io.*;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
-import com.fasterxml.jackson.core.*;
-
-/**
- * Set of basic unit tests for verifying that the basic generator
- * functionality works as expected.
- */
-public class TestJsonGeneratorFeatures
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    private final JsonFactory JSON_F = new JsonFactory();
-
-    public void testConfigDefaults() throws IOException
-    {
-        JsonGenerator g = JSON_F.createGenerator(new StringWriter());
-        assertFalse(g.isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS));
-        assertFalse(g.isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN));
-        g.close();
-    }
-
-    public void testFieldNameQuoting() throws IOException
-    {
-        JsonFactory jf = new JsonFactory();
-        // by default, quoting should be enabled
-        _testFieldNameQuoting(jf, true);
-        // can disable it
-        jf.disable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
-        _testFieldNameQuoting(jf, false);
-        // and (re)enable:
-        jf.enable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
-        _testFieldNameQuoting(jf, true);
-    }
-
-    public void testNonNumericQuoting() throws IOException
-    {
-        JsonFactory jf = new JsonFactory();
-        // by default, quoting should be enabled
-        _testNonNumericQuoting(jf, true);
-        // can disable it
-        jf.disable(JsonGenerator.Feature.QUOTE_NON_NUMERIC_NUMBERS);
-        _testNonNumericQuoting(jf, false);
-        // and (re)enable:
-        jf.enable(JsonGenerator.Feature.QUOTE_NON_NUMERIC_NUMBERS);
-        _testNonNumericQuoting(jf, true);
-    }
-
-    /**
-     * Testing for [JACKSON-176], ability to force serializing numbers
-     * as JSON Strings.
-     */
-    public void testNumbersAsJSONStrings() throws IOException
-    {
-        JsonFactory jf = new JsonFactory();
-        // by default should output numbers as-is:
-        assertEquals("[1,2,1.25,2.25,3001,0.5,-1]", _writeNumbers(jf));        
-
-        // but if overridden, quotes as Strings
-        jf.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
-        assertEquals("[\"1\",\"2\",\"1.25\",\"2.25\",\"3001\",\"0.5\",\"-1\"]",
-                     _writeNumbers(jf));
-    }
-
-    // [core#85]
-    public void testBigDecimalAsPlain() throws IOException
-    {
-        JsonFactory jf = new JsonFactory();
-        BigDecimal ENG = new BigDecimal("1E+2");
-
-        StringWriter sw = new StringWriter();
-        JsonGenerator jg = jf.createGenerator(sw);
-        jg.writeNumber(ENG);
-        jg.close();
-        assertEquals("1E+2", sw.toString());
-
-        jf.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
-        sw = new StringWriter();
-        jg = jf.createGenerator(sw);
-        jg.writeNumber(ENG);
-        jg.close();
-        assertEquals("100", sw.toString());
-    }
-
-    // [core#184]
-    public void testBigDecimalAsPlainString() throws Exception
-    {
-        JsonFactory jf = new JsonFactory();
-        BigDecimal ENG = new BigDecimal("1E+2");
-        jf.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
-        jf.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
-
-        StringWriter sw = new StringWriter();
-        JsonGenerator jg = jf.createGenerator(sw);
-        jg.writeNumber(ENG);
-        jg.close();
-        assertEquals(quote("100"), sw.toString());
-
-        // also, as bytes
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        jg = jf.createGenerator(bos);
-        jg.writeNumber(ENG);
-        jg.close();
-        assertEquals(quote("100"), bos.toString("UTF-8"));
-    }
-
-    // [core#315]
-    public void testTooBigBigDecimal() throws Exception
-    {
-        JsonFactory f = new JsonFactory();
-        f.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
-
-        // 24-Aug-2016, tatu: Initial check limits scale to [-9999,+9999]
-        BigDecimal BIG = new BigDecimal("1E+9999");
-        BigDecimal TOO_BIG = new BigDecimal("1E+10000");
-        BigDecimal SMALL = new BigDecimal("1E-9999");
-        BigDecimal TOO_SMALL = new BigDecimal("1E-10000");
-
-        for (boolean useBytes : new boolean[] { false, true } ) {
-            for (boolean asString : new boolean[] { false, true } ) {
-                JsonGenerator g;
-                
-                if (useBytes) {
-                    g = f.createGenerator(new ByteArrayOutputStream());
-                } else {
-                    g = f.createGenerator(new StringWriter());
-                }
-                if (asString) {
-                    g.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
-                }
-
-                // first, ok cases:
-                g.writeStartArray();
-                g.writeNumber(BIG);
-                g.writeNumber(SMALL);
-                g.writeEndArray();
-                g.close();
-
-                // then invalid
-                for (BigDecimal input : new BigDecimal[] { TOO_BIG, TOO_SMALL }) {
-                    if (useBytes) {
-                        g = f.createGenerator(new ByteArrayOutputStream());
-                    } else {
-                        g = f.createGenerator(new StringWriter());
-                    }
-                    if (asString) {
-                        g.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
-                    }
-                    try {
-                        g.writeNumber(input);
-                        fail("Should not have written without exception: "+input);
-                    } catch (JsonGenerationException e) {
-                        verifyException(e, "Attempt to write plain `java.math.BigDecimal`");
-                        verifyException(e, "illegal scale");
-                    }
-                    g.close();
-                }
-            }
-        }
-    }
-    
-    private String _writeNumbers(JsonFactory jf) throws IOException
-    {
-        StringWriter sw = new StringWriter();
-        JsonGenerator jg = jf.createGenerator(sw);
-    
-        jg.writeStartArray();
-        jg.writeNumber(1);
-        jg.writeNumber(2L);
-        jg.writeNumber(1.25);
-        jg.writeNumber(2.25f);
-        jg.writeNumber(BigInteger.valueOf(3001));
-        jg.writeNumber(BigDecimal.valueOf(0.5));
-        jg.writeNumber("-1");
-        jg.writeEndArray();
-        jg.close();
-
-        return sw.toString();
-    }
-
-    // for [core#246]
-    public void testFieldNameQuotingEnabled() throws IOException
-    {
-        // // First, test with default factory, with quoting enabled by default
-        
-        // First, default, with quotes
-        _testFieldNameQuotingEnabled(JSON_F, true, true, "{\"foo\":1}");
-        _testFieldNameQuotingEnabled(JSON_F, false, true, "{\"foo\":1}");
-
-        // then without quotes
-        _testFieldNameQuotingEnabled(JSON_F, true, false, "{foo:1}");
-        _testFieldNameQuotingEnabled(JSON_F, false, false, "{foo:1}");
-
-        // // Then with alternatively configured factory
-
-        JsonFactory JF2 = new JsonFactory();
-        JF2.disable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
-
-        _testFieldNameQuotingEnabled(JF2, true, true, "{\"foo\":1}");
-        _testFieldNameQuotingEnabled(JF2, false, true, "{\"foo\":1}");
-
-        // then without quotes
-        _testFieldNameQuotingEnabled(JF2, true, false, "{foo:1}");
-        _testFieldNameQuotingEnabled(JF2, false, false, "{foo:1}");
-    }
-
-    private void _testFieldNameQuotingEnabled(JsonFactory jf, boolean useBytes,
-            boolean useQuotes, String exp) throws IOException
-    {
-        ByteArrayOutputStream bytes = useBytes ? new ByteArrayOutputStream() : null;
-        StringWriter sw = useBytes ? null : new StringWriter();
-        JsonGenerator gen = useBytes ? jf.createGenerator(bytes) : jf.createGenerator(sw);
-        if (useQuotes) {
-            gen.enable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
-        } else {
-            gen.disable(JsonGenerator.Feature.QUOTE_FIELD_NAMES);
-        }
-
-        gen.writeStartObject();
-        gen.writeFieldName("foo");
-        gen.writeNumber(1);
-        gen.writeEndObject();
-        gen.close();
-
-        String json = useBytes ? bytes.toString("UTF-8") : sw.toString();
-        assertEquals(exp, json);
-    }
-    
-    /*
-    /**********************************************************
-    /* Helper methods
-    /**********************************************************
-     */
-
-    private void _testFieldNameQuoting(JsonFactory jf, boolean quoted)
-        throws IOException
-    {
-        StringWriter sw = new StringWriter();
-        JsonGenerator jg = jf.createGenerator(sw);
-        jg.writeStartObject();
-        jg.writeFieldName("foo");
-        jg.writeNumber(1);
-        jg.writeEndObject();
-        jg.close();
-
-        String result = sw.toString();
-        if (quoted) {
-            assertEquals("{\"foo\":1}", result);
-        } else {
-            assertEquals("{foo:1}", result);
-        }
-    }
-    private void _testNonNumericQuoting(JsonFactory jf, boolean quoted)
-        throws IOException
-    {
-        StringWriter sw = new StringWriter();
-        JsonGenerator jg = jf.createGenerator(sw);
-        jg.writeStartObject();
-        jg.writeFieldName("double");
-        jg.writeNumber(Double.NaN);
-        jg.writeEndObject();
-        jg.writeStartObject();
-        jg.writeFieldName("float");
-        jg.writeNumber(Float.NaN);
-        jg.writeEndObject();
-        jg.close();
-	
-        String result = sw.toString();
-        if (quoted) {
-            assertEquals("{\"double\":\"NaN\"} {\"float\":\"NaN\"}", result);
-        } else {
-            assertEquals("{\"double\":NaN} {\"float\":NaN}", result);
-        }
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestJsonParser.java b/src/test/java/com/fasterxml/jackson/core/json/TestJsonParser.java
deleted file mode 100644
index d4dead5..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestJsonParser.java
+++ /dev/null
@@ -1,609 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-import com.fasterxml.jackson.core.*;
-import com.fasterxml.jackson.core.util.JsonParserDelegate;
-
-import java.io.*;
-import java.net.URL;
-import java.util.*;
-
-/**
- * Set of basic unit tests for verifying that the basic parser
- * functionality works as expected.
- */
-public class TestJsonParser
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    private final JsonFactory JSON_FACTORY = new JsonFactory();
-
-    public void testConfig() throws Exception
-    {
-        JsonParser jp = createParserUsingReader("[ ]");
-        jp.enable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
-        assertTrue(jp.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
-        jp.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
-        assertFalse(jp.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
-
-        jp.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
-        assertTrue(jp.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
-        jp.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
-        assertFalse(jp.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
-        jp.close();
-    }
-
-    public void testInterningWithStreams() throws Exception
-    {
-        _testIntern(true, true, "a");
-        _testIntern(true, false, "b");
-    }
-
-    public void testInterningWithReaders() throws Exception
-    {
-        _testIntern(false, true, "c");
-        _testIntern(false, false, "d");
-    }
-    
-    private void _testIntern(boolean useStream, boolean enableIntern, String expName) throws IOException
-    {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonFactory.Feature.INTERN_FIELD_NAMES, enableIntern);
-        assertEquals(enableIntern, f.isEnabled(JsonFactory.Feature.INTERN_FIELD_NAMES));
-        final String JSON = "{ \""+expName+"\" : 1}";
-        JsonParser jp = useStream ?
-            createParserUsingStream(f, JSON, "UTF-8") : createParserUsingReader(f, JSON);
-            
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        // needs to be same of cours
-        String actName = jp.getCurrentName();
-        assertEquals(expName, actName);
-        if (enableIntern) {
-            assertSame(expName, actName);
-        } else {
-            assertNotSame(expName, actName);
-        }
-        jp.close();
-    }
-
-    /**
-     * This basic unit test verifies that example given in the Json
-     * specification (RFC-4627 or later) is properly parsed at
-     * high-level, without verifying values.
-     */
-    public void testSpecExampleSkipping()
-        throws Exception
-    {
-        doTestSpec(false);
-    }
-
-    /**
-     * Unit test that verifies that the spec example JSON is completely
-     * parsed, and proper values are given for contents of all
-     * events/tokens.
-     */
-    public void testSpecExampleFully()
-        throws Exception
-    {
-        doTestSpec(true);
-    }
-
-    /**
-     * Unit test that verifies that 3 basic keywords (null, true, false)
-     * are properly parsed in various contexts.
-     */
-    public void testKeywords()
-        throws Exception
-    {
-        final String DOC = "{\n"
-            +"\"key1\" : null,\n"
-            +"\"key2\" : true,\n"
-            +"\"key3\" : false,\n"
-            +"\"key4\" : [ false, null, true ]\n"
-            +"}"
-            ;
-
-        JsonParser jp = createParserUsingStream(DOC, "UTF-8");
-
-        JsonStreamContext ctxt = jp.getParsingContext();
-        assertTrue(ctxt.inRoot());
-        assertFalse(ctxt.inArray());
-        assertFalse(ctxt.inObject());
-        assertEquals(0, ctxt.getEntryCount());
-        assertEquals(0, ctxt.getCurrentIndex());
-
-        /* Before advancing to content, we should have following
-         * default state...
-         */
-        assertFalse(jp.hasCurrentToken());
-        assertNull(jp.getText());
-        assertNull(jp.getTextCharacters());
-        assertEquals(0, jp.getTextLength());
-        // not sure if this is defined but:
-        assertEquals(0, jp.getTextOffset());
-
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-
-        assertTrue(jp.hasCurrentToken());
-        JsonLocation loc = jp.getTokenLocation();
-        assertNotNull(loc);
-        assertEquals(1, loc.getLineNr());
-        assertEquals(1, loc.getColumnNr());
-
-        ctxt = jp.getParsingContext();
-        assertFalse(ctxt.inRoot());
-        assertFalse(ctxt.inArray());
-        assertTrue(ctxt.inObject());
-        assertEquals(0, ctxt.getEntryCount());
-        assertEquals(0, ctxt.getCurrentIndex());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        verifyFieldName(jp, "key1");
-        assertEquals(2, jp.getTokenLocation().getLineNr());
-
-        ctxt = jp.getParsingContext();
-        assertFalse(ctxt.inRoot());
-        assertFalse(ctxt.inArray());
-        assertTrue(ctxt.inObject());
-        assertEquals(1, ctxt.getEntryCount());
-        assertEquals(0, ctxt.getCurrentIndex());
-        assertEquals("key1", ctxt.getCurrentName());
-
-        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
-        assertEquals("key1", ctxt.getCurrentName());
-
-        ctxt = jp.getParsingContext();
-        assertEquals(1, ctxt.getEntryCount());
-        assertEquals(0, ctxt.getCurrentIndex());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        verifyFieldName(jp, "key2");
-        ctxt = jp.getParsingContext();
-        assertEquals(2, ctxt.getEntryCount());
-        assertEquals(1, ctxt.getCurrentIndex());
-        assertEquals("key2", ctxt.getCurrentName());
-
-        assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-        assertEquals("key2", ctxt.getCurrentName());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        verifyFieldName(jp, "key3");
-        assertToken(JsonToken.VALUE_FALSE, jp.nextToken());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        verifyFieldName(jp, "key4");
-
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        ctxt = jp.getParsingContext();
-        assertTrue(ctxt.inArray());
-        assertNull(ctxt.getCurrentName());
-        assertEquals("key4", ctxt.getParent().getCurrentName());
-        
-        assertToken(JsonToken.VALUE_FALSE, jp.nextToken());
-        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
-        assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-
-        ctxt = jp.getParsingContext();
-        assertTrue(ctxt.inObject());
-
-        assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        ctxt = jp.getParsingContext();
-        assertTrue(ctxt.inRoot());
-        assertNull(ctxt.getCurrentName());
-
-        jp.close();
-    }
-
-    public void testSkipping() throws Exception
-    {
-        String DOC =
-            "[ 1, 3, [ true, null ], 3, { \"a\":\"b\" }, [ [ ] ], { } ]";
-            ;
-        JsonParser jp = createParserUsingStream(DOC, "UTF-8");
-
-        // First, skipping of the whole thing
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        jp.skipChildren();
-        assertEquals(JsonToken.END_ARRAY, jp.getCurrentToken());
-        JsonToken t = jp.nextToken();
-        if (t != null) {
-            fail("Expected null at end of doc, got "+t);
-        }
-        jp.close();
-
-        // Then individual ones
-        jp = createParserUsingStream(DOC, "UTF-8");
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        jp.skipChildren();
-        // shouldn't move
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.getCurrentToken());
-        assertEquals(1, jp.getIntValue());
-
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        // then skip array
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        jp.skipChildren();
-        assertToken(JsonToken.END_ARRAY, jp.getCurrentToken());
-
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        jp.skipChildren();
-        assertToken(JsonToken.END_OBJECT, jp.getCurrentToken());
-
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        jp.skipChildren();
-        assertToken(JsonToken.END_ARRAY, jp.getCurrentToken());
-
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        jp.skipChildren();
-        assertToken(JsonToken.END_OBJECT, jp.getCurrentToken());
-
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-
-        jp.close();
-    }
-
-    public void testNameEscaping() throws IOException
-    {
-        _testNameEscaping(false);
-        _testNameEscaping(true);
-    }
-
-    private void _testNameEscaping(boolean useStream) throws IOException
-    {
-        final Map<String,String> NAME_MAP = new LinkedHashMap<String,String>();
-        NAME_MAP.put("", "");
-        NAME_MAP.put("\\\"funny\\\"", "\"funny\"");
-        NAME_MAP.put("\\\\", "\\");
-        NAME_MAP.put("\\r", "\r");
-        NAME_MAP.put("\\n", "\n");
-        NAME_MAP.put("\\t", "\t");
-        NAME_MAP.put("\\r\\n", "\r\n");
-        NAME_MAP.put("\\\"\\\"", "\"\"");
-        NAME_MAP.put("Line\\nfeed", "Line\nfeed");
-        NAME_MAP.put("Yet even longer \\\"name\\\"!", "Yet even longer \"name\"!");
-
-        int entry = 0;
-        for (Map.Entry<String,String> en : NAME_MAP.entrySet()) {
-            ++entry;
-            String input = en.getKey();
-            String expResult = en.getValue();
-            final String DOC = "{ \""+input+"\":null}";
-            JsonParser jp = useStream ?
-                    JSON_FACTORY.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-                : JSON_FACTORY.createParser(new StringReader(DOC));
-
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-            assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-            // first, sanity check (field name == getText()
-            String act = jp.getCurrentName();
-            assertEquals(act, getAndVerifyText(jp));
-            if (!expResult.equals(act)) {
-                String msg = "Failed for name #"+entry+"/"+NAME_MAP.size();
-                if (expResult.length() != act.length()) {
-                    fail(msg+": exp length "+expResult.length()+", actual "+act.length());
-                }
-                assertEquals(msg, expResult, act);
-            }
-            assertToken(JsonToken.VALUE_NULL, jp.nextToken());
-            assertToken(JsonToken.END_OBJECT, jp.nextToken());
-            jp.close();
-        }
-    }
-    
-    /**
-     * Unit test that verifies that long text segments are handled
-     * correctly; mostly to stress-test underlying segment-based
-     * text buffer(s).
-     */
-    public void testLongText() throws Exception
-    {
-        // lengths chosen to tease out problems with buffer allocation...
-        _testLongText(7700);
-        _testLongText(49000);
-        _testLongText(96000);
-    }
-
-    @SuppressWarnings("resource")
-    private void _testLongText(int LEN) throws Exception
-    {
-        StringBuilder sb = new StringBuilder(LEN + 100);
-        Random r = new Random(99);
-        while (sb.length() < LEN) {
-            sb.append(r.nextInt());
-            sb.append(" xyz foo");
-            if (r.nextBoolean()) {
-                sb.append(" and \"bar\"");
-            } else if (r.nextBoolean()) {
-                sb.append(" [whatever].... ");
-            } else {
-                // Let's try some more 'exotic' chars
-                sb.append(" UTF-8-fu: try this {\u00E2/\u0BF8/\uA123!} (look funny?)");
-            }
-            if (r.nextBoolean()) {
-                if (r.nextBoolean()) {
-                    sb.append('\n');
-                } else if (r.nextBoolean()) {
-                    sb.append('\r');
-                } else {
-                    sb.append("\r\n");
-                }
-            }
-        }
-        final String VALUE = sb.toString();
-        
-        // Let's use real generator to get JSON done right
-        StringWriter sw = new StringWriter(LEN + (LEN >> 2));
-        JsonGenerator jg = JSON_FACTORY.createGenerator(sw);
-        jg.writeStartObject();
-        jg.writeFieldName("doc");
-        jg.writeString(VALUE);
-        jg.writeEndObject();
-        jg.close();
-        
-        final String DOC = sw.toString();
-
-        for (int type = 0; type < 3; ++type) {
-            JsonParser jp;
-
-            switch (type) {
-            default:
-                jp = JSON_FACTORY.createParser(DOC.getBytes("UTF-8"));
-                break;
-            case 1:
-                jp = JSON_FACTORY.createParser(DOC);
-                break;
-            case 2: // NEW: let's also exercise UTF-32...
-                jp = JSON_FACTORY.createParser(encodeInUTF32BE(DOC));
-                break;
-            }
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-            assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-            assertEquals("doc", jp.getCurrentName());
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            
-            String act = getAndVerifyText(jp);
-            if (act.length() != VALUE.length()) {
-                fail("Expected length "+VALUE.length()+", got "+act.length());
-            }
-            if (!act.equals(VALUE)) {
-                fail("Long text differs");
-            }
-
-            // should still know the field name
-            assertEquals("doc", jp.getCurrentName());
-            assertToken(JsonToken.END_OBJECT, jp.nextToken());
-            assertNull(jp.nextToken());
-            jp.close();
-        }
-    }
-
-    /**
-     * Simple unit test that verifies that passing in a byte array
-     * as source works as expected.
-     */
-    public void testBytesAsSource() throws Exception
-    {
-        String JSON = "[ 1, 2, 3, 4 ]";
-        byte[] b = JSON.getBytes("UTF-8");
-        int offset = 50;
-        int len = b.length;
-        byte[] src = new byte[offset + len + offset];
-
-        System.arraycopy(b, 0, src, offset, len);
-
-        JsonParser jp = JSON_FACTORY.createParser(src, offset, len);
-
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(1, jp.getIntValue());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(2, jp.getIntValue());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(3, jp.getIntValue());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(4, jp.getIntValue());
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        assertNull(jp.nextToken());
-
-        jp.close();
-    }
-
-    // [JACKSON-632]
-    public void testUtf8BOMHandling() throws Exception
-    {
-        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-        // first, write BOM:
-        bytes.write(0xEF);
-        bytes.write(0xBB);
-        bytes.write(0xBF);
-        bytes.write("[ 1 ]".getBytes("UTF-8"));
-        JsonParser jp = JSON_FACTORY.createParser(bytes.toByteArray());
-        assertEquals(JsonToken.START_ARRAY, jp.nextToken());
-        // should also have skipped first 3 bytes of BOM; but do we have offset available?
-        /* 08-Oct-2013, tatu: Alas, due to [Issue#111], we have to omit BOM in calculations
-         *   as we do not know what the offset is due to -- may need to revisit, if this
-         *   discrepancy becomes an issue. For now it just means that BOM is considered
-         *   "out of stream" (not part of input).
-         */
-        JsonLocation loc = jp.getTokenLocation();
-        // so if BOM was consider in-stream (part of input), this should expect 3:
-        assertEquals(0, loc.getByteOffset());
-        assertEquals(-1, loc.getCharOffset());
-        jp.close();
-    }
-
-    // [Issue#48]
-    public void testSpacesInURL() throws Exception
-    {
-        File f = File.createTempFile("pre fix&stuff", ".txt");
-        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "UTF-8"));
-        w.write("{ }");
-        w.close();
-        URL url = f.toURI().toURL();
-
-        JsonParser jp = JSON_FACTORY.createParser(url);
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        jp.close();
-    }
-
-    // [#142]
-    public void testHandlingOfInvalidSpaceBytes() throws Exception {
-        _testHandlingOfInvalidSpace(true);
-        _testHandlingOfInvalidSpaceFromResource(true);
-    }
-    
-    // [#142]
-    public void testHandlingOfInvalidSpaceChars() throws Exception {
-        _testHandlingOfInvalidSpace(false);
-        _testHandlingOfInvalidSpaceFromResource(false);
-    }
-
-    private void _testHandlingOfInvalidSpace(boolean useStream) throws Exception
-    {
-        final String JSON = "{ \u00A0 \"a\":1}";
-        JsonParser jp = useStream
-                ? createParserUsingStream(JSON_FACTORY, JSON, "UTF-8")
-                : createParserUsingReader(JSON_FACTORY, JSON);
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        try {
-            jp.nextToken();
-            fail("Should have failed");
-        } catch (JsonParseException e) {
-            verifyException(e, "unexpected character");
-            // and correct error code
-            verifyException(e, "code 160");
-        }
-        jp.close();
-    }
-
-    private void _testHandlingOfInvalidSpaceFromResource(boolean useStream) throws Exception
-    {
-        InputStream in = getClass().getResourceAsStream("/test_0xA0.json");
-        @SuppressWarnings("resource")
-        JsonParser jp = useStream
-                ? JSON_FACTORY.createParser(in)
-                : JSON_FACTORY.createParser(new InputStreamReader(in, "UTF-8"));
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        try {
-            assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-            assertEquals("request", jp.getCurrentName());
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-            assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-            assertEquals("mac", jp.getCurrentName());
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertNotNull(jp.getText());
-            assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-            assertEquals("data", jp.getCurrentName());
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-
-            // ... and from there on, just loop
-            
-            while (jp.nextToken()  != null) { }
-            fail("Should have failed");
-        } catch (JsonParseException e) {
-            verifyException(e, "unexpected character");
-            // and correct error code
-            verifyException(e, "code 160");
-        }
-        jp.close();
-    }
-
-    public void testGetValueAsTextBytes() throws Exception
-    {
-        JsonFactory f = new JsonFactory();
-        _testGetValueAsText(f, true, false);
-        _testGetValueAsText(f, true, true);
-    }
-
-    public void testGetValueAsTextChars() throws Exception
-    {
-        JsonFactory f = new JsonFactory();
-        _testGetValueAsText(f, false, false);
-        _testGetValueAsText(f, false, true);
-    }
-    
-    @SuppressWarnings("resource")
-    private void _testGetValueAsText(JsonFactory f,
-            boolean useBytes, boolean delegate) throws Exception
-    {
-        String JSON = "{\"a\":1,\"b\":true,\"c\":null,\"d\":\"foo\"}";
-        JsonParser p = useBytes ? f.createParser(JSON.getBytes("UTF-8"))
-                : f.createParser(JSON);
-
-        if (delegate) {
-            p = new JsonParserDelegate(p);
-        }
-        
-        assertToken(JsonToken.START_OBJECT, p.nextToken());
-        assertNull(p.getValueAsString());
-
-        assertToken(JsonToken.FIELD_NAME, p.nextToken());
-        assertEquals("a", p.getText());
-        assertEquals("a", p.getValueAsString());
-        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
-        assertEquals("1", p.getValueAsString());
-
-        assertToken(JsonToken.FIELD_NAME, p.nextToken());
-        assertEquals("b", p.getValueAsString());
-        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
-        assertEquals("true", p.getValueAsString());
-
-        assertToken(JsonToken.FIELD_NAME, p.nextToken());
-        assertEquals("c", p.getValueAsString());
-        assertToken(JsonToken.VALUE_NULL, p.nextToken());
-        // null token returned as Java null, as per javadoc
-        assertNull(p.getValueAsString());
-
-        assertToken(JsonToken.FIELD_NAME, p.nextToken());
-        assertEquals("d", p.getValueAsString());
-        assertToken(JsonToken.VALUE_STRING, p.nextToken());
-        assertEquals("foo", p.getValueAsString());
-
-        assertToken(JsonToken.END_OBJECT, p.nextToken());
-        assertNull(p.getValueAsString());
-
-        assertNull(p.nextToken());
-        p.close();
-    }
-
-    /*
-    /**********************************************************
-    /* Helper methods
-    /**********************************************************
-     */
-
-    private void doTestSpec(boolean verify) throws IOException
-    {
-        // First, using a StringReader:
-        doTestSpecIndividual(null, verify);
-
-        // Then with streams using supported encodings:
-        doTestSpecIndividual("UTF-8", verify);
-        doTestSpecIndividual("UTF-16BE", verify);
-        doTestSpecIndividual("UTF-16LE", verify);
-
-        /* Hmmh. UTF-32 is harder only because JDK doesn't come with
-         * a codec for it. Can't test it yet using this method
-         */
-        doTestSpecIndividual("UTF-32", verify);
-    }
-
-    private void doTestSpecIndividual(String enc, boolean verify) throws IOException
-    {
-        String doc = SAMPLE_DOC_JSON_SPEC;
-        JsonParser jp;
-
-        if (enc == null) {
-            jp = createParserUsingReader(doc);
-        } else {
-            jp = createParserUsingStream(doc, enc);
-        }
-        verifyJsonSpecSampleDoc(jp, verify);
-        jp.close();
-    }
-}
-
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java b/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java
deleted file mode 100644
index 2aaeeb1..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java
+++ /dev/null
@@ -1,526 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-import java.io.ByteArrayInputStream;
-import java.io.StringReader;
-import java.util.Random;
-
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonToken;
-import com.fasterxml.jackson.core.SerializableString;
-import com.fasterxml.jackson.core.io.SerializedString;
-
-public class TestNextXxx
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    /*
-    /********************************************************
-    /* Wrappers to test InputStream vs Reader
-    /********************************************************
-     */
-
-    private final JsonFactory JSON_F = new JsonFactory();
-
-    public void testIsNextTokenName() throws Exception
-    {
-        _testIsNextTokenName1(false);
-        _testIsNextTokenName1(true);
-    }
-
-    public void testIsNextTokenName2() throws Exception {
-        _testIsNextTokenName2(false);
-        _testIsNextTokenName2(true);
-    }        
-    
-    public void testIsNextTokenName3() throws Exception {
-        _testIsNextTokenName3(false);
-        _testIsNextTokenName3(true);
-    }
-
-    public void testIsNextTokenName4() throws Exception {
-        _testIsNextTokenName4(false);
-        _testIsNextTokenName4(true);
-    }
-    
-    // [jackson-core#34]
-    public void testIssue34() throws Exception
-    {
-        _testIssue34(false);
-        _testIssue34(true);
-    }
-
-    // [jackson-core#38] with nextFieldName
-    public void testIssue38() throws Exception
-    {
-        _testIssue38(false);
-        _testIssue38(true);
-    }
-
-    public void testNextNameWithLongContent() throws Exception
-    {
-        _testNextNameWithLong(false);
-        _testNextNameWithLong(true);
-    }
-
-    // for [core#220]: problem with `nextFieldName(str)`, indented content
-    public void testNextNameWithIndentation() throws Exception
-    {
-        _testNextFieldNameIndent(false);
-        _testNextFieldNameIndent(true);
-    }
-    
-    public void testNextTextValue() throws Exception
-    {
-        _textNextText(false);
-        _textNextText(true);
-    }
-
-    public void testNextIntValue() throws Exception
-    {
-        _textNextInt(false);
-        _textNextInt(true);
-    }
-
-    public void testNextLongValue() throws Exception
-    {
-        _textNextLong(false);
-        _textNextLong(true);
-    }
-
-    public void testNextBooleanValue() throws Exception
-    {
-        _textNextBoolean(false);
-        _textNextBoolean(true);
-    }
-    
-    /*
-    /********************************************************
-    /* Actual test code
-    /********************************************************
-     */
-
-    private void _testIsNextTokenName1(boolean useStream) throws Exception
-    {
-        final String DOC = "{\"name\":123,\"name2\":14,\"x\":\"name\"}";
-        JsonFactory jf = new JsonFactory();
-        JsonParser jp = useStream ?
-            jf.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : jf.createParser(new StringReader(DOC));
-        final SerializedString NAME = new SerializedString("name");
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.START_OBJECT, jp.getCurrentToken());
-        assertTrue(jp.nextFieldName(NAME));
-        assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
-        assertEquals(NAME.getValue(), jp.getCurrentName());
-        assertEquals(NAME.getValue(), jp.getText());
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.getCurrentToken());
-        assertEquals(123, jp.getIntValue());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
-        assertEquals("name2", jp.getCurrentName());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        // do NOT check number value, to enforce skipping
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
-        assertEquals("x", jp.getCurrentName());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.VALUE_STRING, jp.getCurrentToken());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.END_OBJECT, jp.getCurrentToken());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertNull(jp.getCurrentToken());
-
-        jp.close();
-
-        // Actually, try again with slightly different sequence...
-        jp = useStream ? jf.createParser(DOC.getBytes("UTF-8"))
-                : jf.createParser(DOC);
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        assertFalse(jp.nextFieldName(new SerializedString("Nam")));
-        assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
-        assertEquals(NAME.getValue(), jp.getCurrentName());
-        assertEquals(NAME.getValue(), jp.getText());
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.getCurrentToken());
-        assertEquals(123, jp.getIntValue());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
-        assertEquals("name2", jp.getCurrentName());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
-        assertEquals("x", jp.getCurrentName());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.VALUE_STRING, jp.getCurrentToken());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.END_OBJECT, jp.getCurrentToken());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertNull(jp.getCurrentToken());
-
-        jp.close();
-    }
-
-    private void _testIsNextTokenName2(boolean useStream) throws Exception
-    {
-        final String DOC = "{\"name\":123,\"name2\":14,\"x\":\"name\"}";
-        JsonParser jp = useStream ?
-                JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : JSON_F.createParser(new StringReader(DOC));
-        SerializableString NAME = new SerializedString("name");
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.START_OBJECT, jp.getCurrentToken());
-        assertTrue(jp.nextFieldName(NAME));
-        assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
-        assertEquals(NAME.getValue(), jp.getCurrentName());
-        assertEquals(NAME.getValue(), jp.getText());
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.getCurrentToken());
-        assertEquals(123, jp.getIntValue());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
-        assertEquals("name2", jp.getCurrentName());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
-        assertEquals("x", jp.getCurrentName());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.VALUE_STRING, jp.getCurrentToken());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertToken(JsonToken.END_OBJECT, jp.getCurrentToken());
-
-        assertFalse(jp.nextFieldName(NAME));
-        assertNull(jp.getCurrentToken());
-
-        jp.close();
-    }
-
-    private void _testIsNextTokenName3(boolean useStream) throws Exception
-    {
-        final String DOC = "{\"name\":123,\"name2\":14,\"x\":\"name\"}";
-        JsonParser p = useStream ?
-                JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : JSON_F.createParser(new StringReader(DOC));
-        assertNull(p.nextFieldName());
-        assertToken(JsonToken.START_OBJECT, p.getCurrentToken());
-        assertEquals("name", p.nextFieldName());
-        assertToken(JsonToken.FIELD_NAME, p.getCurrentToken());
-        assertEquals("name", p.getCurrentName());
-        assertEquals("name", p.getText());
-        assertNull(p.nextFieldName());
-        assertToken(JsonToken.VALUE_NUMBER_INT, p.getCurrentToken());
-        assertEquals(123, p.getIntValue());
-
-        assertEquals("name2", p.nextFieldName());
-        assertToken(JsonToken.FIELD_NAME, p.getCurrentToken());
-        assertEquals("name2", p.getCurrentName());
-        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
-
-        assertEquals("x", p.nextFieldName());
-        assertToken(JsonToken.FIELD_NAME, p.getCurrentToken());
-        assertEquals("x", p.getCurrentName());
-
-        assertNull(p.nextFieldName());
-        assertToken(JsonToken.VALUE_STRING, p.getCurrentToken());
-
-        assertNull(p.nextFieldName());
-        assertToken(JsonToken.END_OBJECT, p.getCurrentToken());
-
-        assertNull(p.nextFieldName());
-        assertNull(p.getCurrentToken());
-
-        p.close();
-    }
-
-    private void _testIsNextTokenName4(boolean useStream) throws Exception
-    {
-        final String DOC = "{\"name\":-123,\"name2\":99}";
-        JsonParser jp = useStream ?
-                JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : JSON_F.createParser(new StringReader(DOC));
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-
-        assertTrue(jp.nextFieldName(new SerializedString("name")));
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(-123, jp.getIntValue());
-
-        assertTrue(jp.nextFieldName(new SerializedString("name2")));
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(99, jp.getIntValue());
-        assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        assertNull(jp.nextToken());
-
-        jp.close();
-    }
-
-    private void _testNextFieldNameIndent(boolean useStream) throws Exception
-    {
-        final String DOC = "{\n  \"name\" : \n  [\n  ]\n   }";
-        JsonParser p = useStream ?
-                JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : JSON_F.createParser(new StringReader(DOC));
-        assertToken(JsonToken.START_OBJECT, p.nextToken());
-        assertTrue(p.nextFieldName(new SerializedString("name")));
-
-        assertToken(JsonToken.START_ARRAY, p.nextToken());
-        assertToken(JsonToken.END_ARRAY, p.nextToken());
-        assertToken(JsonToken.END_OBJECT, p.nextToken());
-
-        assertNull(p.nextToken());
-
-        p.close();
-    }
-
-    private void _textNextText(boolean useStream) throws Exception
-    {
-        final String DOC = aposToQuotes("{'a':'123','b':5,'c':[false,'foo']}");
-        JsonParser p = useStream ?
-            JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : JSON_F.createParser(new StringReader(DOC));
-        assertNull(p.nextTextValue());
-        assertToken(JsonToken.START_OBJECT, p.getCurrentToken());
-        assertNull(p.nextTextValue());
-        assertToken(JsonToken.FIELD_NAME, p.getCurrentToken());
-        assertEquals("a", p.getCurrentName());
-
-        assertEquals("123", p.nextTextValue());
-        assertToken(JsonToken.FIELD_NAME, p.nextToken());
-        assertEquals("b", p.getCurrentName());
-        assertNull(p.nextFieldName());
-        assertToken(JsonToken.VALUE_NUMBER_INT, p.getCurrentToken());
-
-        assertEquals("c", p.nextFieldName());
-        
-        assertNull(p.nextTextValue());
-        assertToken(JsonToken.START_ARRAY, p.getCurrentToken());
-        assertNull(p.nextTextValue());
-        assertToken(JsonToken.VALUE_FALSE, p.getCurrentToken());
-        assertEquals("foo", p.nextTextValue());
-        
-        assertNull(p.nextTextValue());
-        assertToken(JsonToken.END_ARRAY, p.getCurrentToken());
-        assertNull(p.nextTextValue());
-        assertToken(JsonToken.END_OBJECT, p.getCurrentToken());
-        assertNull(p.nextTextValue());
-        assertNull(p.getCurrentToken());
-
-        p.close();
-    }
-
-    private void _textNextInt(boolean useStream) throws Exception
-    {
-        final String DOC = aposToQuotes("{'a':'123','b':5,'c':[false,456]}");
-        JsonParser p = useStream ?
-            JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : JSON_F.createParser(new StringReader(DOC));
-        assertEquals(0, p.nextIntValue(0));
-        assertToken(JsonToken.START_OBJECT, p.getCurrentToken());
-        assertEquals(0, p.nextIntValue(0));
-        assertToken(JsonToken.FIELD_NAME, p.getCurrentToken());
-        assertEquals("a", p.getCurrentName());
-
-        assertEquals(0, p.nextIntValue(0));
-        assertToken(JsonToken.VALUE_STRING, p.getCurrentToken());
-        assertEquals("123", p.getText());
-        assertToken(JsonToken.FIELD_NAME, p.nextToken());
-        assertEquals("b", p.getCurrentName());
-        assertEquals(5, p.nextIntValue(0));
-
-        assertEquals("c", p.nextFieldName());
-        
-        assertEquals(0, p.nextIntValue(0));
-        assertToken(JsonToken.START_ARRAY, p.getCurrentToken());
-        assertEquals(0, p.nextIntValue(0));
-        assertToken(JsonToken.VALUE_FALSE, p.getCurrentToken());
-        assertEquals(456, p.nextIntValue(0));
-        
-        assertEquals(0, p.nextIntValue(0));
-        assertToken(JsonToken.END_ARRAY, p.getCurrentToken());
-        assertEquals(0, p.nextIntValue(0));
-        assertToken(JsonToken.END_OBJECT, p.getCurrentToken());
-        assertEquals(0, p.nextIntValue(0));
-        assertNull(p.getCurrentToken());
-
-        p.close();
-    }
-
-    private void _textNextLong(boolean useStream) throws Exception
-    {
-        final String DOC = aposToQuotes("{'a':'xyz','b':-59,'c':[false,-1]}");
-        JsonParser p = useStream ?
-            JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : JSON_F.createParser(new StringReader(DOC));
-        assertEquals(0L, p.nextLongValue(0L));
-        assertToken(JsonToken.START_OBJECT, p.getCurrentToken());
-        assertEquals(0L, p.nextLongValue(0L));
-        assertToken(JsonToken.FIELD_NAME, p.getCurrentToken());
-        assertEquals("a", p.getCurrentName());
-
-        assertEquals(0L, p.nextLongValue(0L));
-        assertToken(JsonToken.VALUE_STRING, p.getCurrentToken());
-        assertEquals("xyz", p.getText());
-        assertToken(JsonToken.FIELD_NAME, p.nextToken());
-        assertEquals("b", p.getCurrentName());
-        assertEquals(-59L, p.nextLongValue(0L));
-
-        assertEquals("c", p.nextFieldName());
-        
-        assertEquals(0L, p.nextLongValue(0L));
-        assertToken(JsonToken.START_ARRAY, p.getCurrentToken());
-        assertEquals(0L, p.nextLongValue(0L));
-        assertToken(JsonToken.VALUE_FALSE, p.getCurrentToken());
-        assertEquals(-1L, p.nextLongValue(0L));
-        
-        assertEquals(0L, p.nextLongValue(0L));
-        assertToken(JsonToken.END_ARRAY, p.getCurrentToken());
-        assertEquals(0L, p.nextLongValue(0L));
-        assertToken(JsonToken.END_OBJECT, p.getCurrentToken());
-        assertEquals(0L, p.nextLongValue(0L));
-        assertNull(p.getCurrentToken());
-
-        p.close();
-    }
-
-    private void _textNextBoolean(boolean useStream) throws Exception
-    {
-        final String DOC = aposToQuotes("{'a':'xyz','b':true,'c':[false,0]}");
-        JsonParser p = useStream ?
-            JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : JSON_F.createParser(new StringReader(DOC));
-        assertNull(p.nextBooleanValue());
-        assertToken(JsonToken.START_OBJECT, p.getCurrentToken());
-        assertNull(p.nextBooleanValue());
-        assertToken(JsonToken.FIELD_NAME, p.getCurrentToken());
-        assertEquals("a", p.getCurrentName());
-
-        assertNull(p.nextBooleanValue());
-        assertToken(JsonToken.VALUE_STRING, p.getCurrentToken());
-        assertEquals("xyz", p.getText());
-        assertToken(JsonToken.FIELD_NAME, p.nextToken());
-        assertEquals("b", p.getCurrentName());
-        assertEquals(Boolean.TRUE, p.nextBooleanValue());
-
-        assertEquals("c", p.nextFieldName());
-        
-        assertNull(p.nextBooleanValue());
-        assertToken(JsonToken.START_ARRAY, p.getCurrentToken());
-        assertEquals(Boolean.FALSE, p.nextBooleanValue());
-        assertNull(p.nextBooleanValue());
-        assertToken(JsonToken.VALUE_NUMBER_INT, p.getCurrentToken());
-        assertEquals(0, p.getIntValue());
-        
-        assertNull(p.nextBooleanValue());
-        assertToken(JsonToken.END_ARRAY, p.getCurrentToken());
-        assertNull(p.nextBooleanValue());
-        assertToken(JsonToken.END_OBJECT, p.getCurrentToken());
-        assertNull(p.nextBooleanValue());
-        assertNull(p.getCurrentToken());
-
-        p.close();
-    }
-    
-    private void _testIssue34(boolean useStream) throws Exception
-    {
-        final int TESTROUNDS = 223;
-        final String DOC_PART = "{ \"fieldName\": 1 }";
-
-        // build the big document to trigger issue
-        StringBuilder sb = new StringBuilder(2000);
-        for (int i = 0; i < TESTROUNDS; ++i) {
-            sb.append(DOC_PART);
-        }
-        final String DOC = sb.toString();
-
-        SerializableString fieldName = new SerializedString("fieldName");
-        JsonFactory jf = new JsonFactory();
-        JsonParser parser = useStream ?
-            jf.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : jf.createParser(new StringReader(DOC));
-
-        for (int i = 0; i < TESTROUNDS - 1; i++) {
-            assertEquals(JsonToken.START_OBJECT, parser.nextToken());
-
-            // These will succeed
-            assertTrue(parser.nextFieldName(fieldName));
-
-            parser.nextLongValue(-1);
-            assertEquals(JsonToken.END_OBJECT, parser.nextToken());
-        }
-
-        assertEquals(JsonToken.START_OBJECT, parser.nextToken());
-
-        // This will fail
-        assertTrue(parser.nextFieldName(fieldName));
-        parser.close();
-    }
-
-    private void _testIssue38(boolean useStream) throws Exception
-    {
-        final String DOC = "{\"field\" :\"value\"}";
-        SerializableString fieldName = new SerializedString("field");
-        JsonFactory jf = new JsonFactory();
-        JsonParser parser = useStream ?
-            jf.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-            : jf.createParser(new StringReader(DOC));
-        assertEquals(JsonToken.START_OBJECT, parser.nextToken());
-        assertTrue(parser.nextFieldName(fieldName));
-        assertEquals(JsonToken.VALUE_STRING, parser.nextToken());
-        assertEquals("value", parser.getText());
-        assertEquals(JsonToken.END_OBJECT, parser.nextToken());
-        assertNull(parser.nextToken());
-        parser.close();
-    }
-
-    private void _testNextNameWithLong(boolean useStream) throws Exception
-    {
-        // do 5 meg thingy
-        final int SIZE = 5 * 1024 * 1024;
-        StringBuilder sb = new StringBuilder(SIZE + 20);
-
-        sb.append("{");
-        Random rnd = new Random(1);
-        int count = 0;
-        while (sb.length() < SIZE) {
-            ++count;
-            if (sb.length() > 1) {
-                sb.append(", ");
-            }
-            int val = rnd.nextInt();
-            sb.append('"');
-            sb.append("f"+val);
-            sb.append("\":");
-            sb.append(String.valueOf(val % 1000));
-        }
-        sb.append("}");
-        final String DOC = sb.toString();
-    
-        JsonParser parser = useStream ?
-                JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
-                : JSON_F.createParser(new StringReader(DOC));
-        assertToken(JsonToken.START_OBJECT, parser.nextToken());
-        rnd = new Random(1);
-        for (int i = 0; i < count; ++i) {
-            int exp = rnd.nextInt();
-            SerializableString expName = new SerializedString("f"+exp);
-            assertTrue(parser.nextFieldName(expName));
-            assertToken(JsonToken.VALUE_NUMBER_INT, parser.nextToken());
-            assertEquals(exp % 1000, parser.getIntValue());
-        }
-        assertToken(JsonToken.END_OBJECT, parser.nextToken());
-        parser.close();
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java b/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java
deleted file mode 100644
index af61f1e..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java
+++ /dev/null
@@ -1,598 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.StringReader;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
-import com.fasterxml.jackson.core.*;
-
-/**
- * Set of basic unit tests for verifying that the basic parser
- * functionality works as expected.
- */
-@SuppressWarnings("resource")
-public class TestNumericValues
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    private final JsonFactory FACTORY = new JsonFactory();
-    
-    public void testSimpleBoolean() throws Exception
-    {
-        JsonParser jp = FACTORY.createParser("[ true ]");
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-        assertEquals(true, jp.getBooleanValue());
-        jp.close();
-    }
-    
-    public void testSimpleInt() throws Exception
-    {
-        for (int EXP_I : new int[] { 1234, -999, 0, 1, -2 }) {
-            _testSimpleInt(EXP_I, false);
-            _testSimpleInt(EXP_I, true);
-        }
-    }
-
-    private void _testSimpleInt(int EXP_I, boolean useStream) throws Exception
-    {
-        String DOC = "[ "+EXP_I+" ]";
-        JsonParser jp = useStream
-                ? FACTORY.createParser(DOC)
-                : FACTORY.createParser(DOC.getBytes("UTF-8"));
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(JsonParser.NumberType.INT, jp.getNumberType());
-        assertEquals(""+EXP_I, jp.getText());
-
-        assertEquals(EXP_I, jp.getIntValue());
-        assertEquals((long) EXP_I, jp.getLongValue());
-        assertEquals((double) EXP_I, jp.getDoubleValue());
-        assertEquals(BigDecimal.valueOf((long) EXP_I), jp.getDecimalValue());
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        assertNull(jp.nextToken());
-        jp.close();
-
-        DOC = String.valueOf(EXP_I);
-        jp = useStream
-                ? FACTORY.createParser(DOC)
-                : FACTORY.createParser(DOC.getBytes("UTF-8"));
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(DOC, jp.getText());
-
-        int i = 0;
-        
-        try {
-            i = jp.getIntValue();
-        } catch (Exception e) {
-            throw new Exception("Failed to parse input '"+DOC+"' (parser of type "+jp.getClass().getSimpleName()+")", e);
-        }
-        
-        assertEquals(EXP_I, i);
-
-        assertEquals((long) EXP_I, jp.getLongValue());
-        assertEquals((double) EXP_I, jp.getDoubleValue());
-        assertEquals(BigDecimal.valueOf((long) EXP_I), jp.getDecimalValue());
-        assertNull(jp.nextToken());
-        jp.close();
-    }
-
-    public void testIntRange() throws Exception
-    {
-        // let's test with readers and streams, separate code paths:
-        for (int i = 0; i < 2; ++i) {
-            String input = "[ "+Integer.MAX_VALUE+","+Integer.MIN_VALUE+" ]";
-            JsonParser jp;
-            if (i == 0) {
-                jp = FACTORY.createParser(input);                
-            } else {
-                jp = createParserUsingStream(input, "UTF-8");
-            }
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(JsonParser.NumberType.INT, jp.getNumberType());
-            assertEquals(Integer.MAX_VALUE, jp.getIntValue());
-    
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(JsonParser.NumberType.INT, jp.getNumberType());
-            assertEquals(Integer.MIN_VALUE, jp.getIntValue());
-            jp.close();
-        }
-    }
-
-    public void testSimpleLong() throws Exception
-    {
-        long EXP_L = 12345678907L;
-
-        JsonParser jp = FACTORY.createParser("[ "+EXP_L+" ]");
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        // beyond int, should be long
-        assertEquals(JsonParser.NumberType.LONG, jp.getNumberType());
-        assertEquals(""+EXP_L, jp.getText());
-
-        assertEquals(EXP_L, jp.getLongValue());
-        // Should get an exception if trying to convert to int 
-        try {
-            jp.getIntValue();
-        } catch (JsonParseException jpe) {
-            verifyException(jpe, "out of range");
-        }
-        assertEquals((double) EXP_L, jp.getDoubleValue());
-        assertEquals(BigDecimal.valueOf((long) EXP_L), jp.getDecimalValue());
-        jp.close();
-    }
-
-    public void testLongRange() throws Exception
-    {
-        for (int i = 0; i < 2; ++i) {
-            long belowMinInt = -1L + Integer.MIN_VALUE;
-            long aboveMaxInt = 1L + Integer.MAX_VALUE;
-            String input = "[ "+Long.MAX_VALUE+","+Long.MIN_VALUE+","+aboveMaxInt+", "+belowMinInt+" ]";
-            JsonParser jp;
-            if (i == 0) {
-                jp = FACTORY.createParser(input);                
-            } else {
-                jp = this.createParserUsingStream(input, "UTF-8");
-            }
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(JsonParser.NumberType.LONG, jp.getNumberType());
-            assertEquals(Long.MAX_VALUE, jp.getLongValue());
-        
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(JsonParser.NumberType.LONG, jp.getNumberType());
-            assertEquals(Long.MIN_VALUE, jp.getLongValue());
-
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(JsonParser.NumberType.LONG, jp.getNumberType());
-            assertEquals(aboveMaxInt, jp.getLongValue());
-
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(JsonParser.NumberType.LONG, jp.getNumberType());
-            assertEquals(belowMinInt, jp.getLongValue());
-
-            
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());        
-            jp.close();
-        }
-    }
-
-    public void testBigDecimalRange()
-        throws Exception
-    {
-        for (int i = 0; i < 2; ++i) {
-            // let's test first values outside of Long range
-            BigInteger small = new BigDecimal(Long.MIN_VALUE).toBigInteger();
-            small = small.subtract(BigInteger.ONE);
-            BigInteger big = new BigDecimal(Long.MAX_VALUE).toBigInteger();
-            big = big.add(BigInteger.ONE);
-            String input = "[ "+small+"  ,  "+big+"]";
-            JsonParser jp;
-            if (i == 0) {
-                jp = FACTORY.createParser(input);                
-            } else {
-                jp = this.createParserUsingStream(input, "UTF-8");
-            }
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(JsonParser.NumberType.BIG_INTEGER, jp.getNumberType());
-            assertEquals(small, jp.getBigIntegerValue());
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(JsonParser.NumberType.BIG_INTEGER, jp.getNumberType());
-            assertEquals(big, jp.getBigIntegerValue());
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());        
-            jp.close();
-        }
-    }
-
-    // for [Issue#78]
-    public void testBigNumbers() throws Exception
-    {
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < 520; ++i) { // input buffer is 512 bytes by default
-            sb.append('1');
-        }
-        final String NUMBER_STR = sb.toString();
-        BigInteger biggie = new BigInteger(NUMBER_STR);
-        
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp;
-            if (i == 0) {
-                jp = FACTORY.createParser(NUMBER_STR);                
-            } else {
-                jp = this.createParserUsingStream(NUMBER_STR, "UTF-8");
-            }
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(JsonParser.NumberType.BIG_INTEGER, jp.getNumberType());
-            assertEquals(NUMBER_STR, jp.getText());
-            assertEquals(biggie, jp.getBigIntegerValue());
-            jp.close();
-        }
-    }
-    
-    public void testSimpleDouble() throws Exception
-    {
-        final String[] INPUTS = new String[] {
-            "1234.00", "2.1101567E-16", "1.0e5", "0.0", "1.0", "-1.0", 
-            "-0.5", "-12.9", "-999.0",
-            "2.5e+5", "9e4", "-12e-3", "0.25",
-        };
-        for (int input = 0; input < 2; ++input) {
-            for (int i = 0; i < INPUTS.length; ++i) {
-
-                // First in array
-                
-                String STR = INPUTS[i];
-                double EXP_D = Double.parseDouble(STR);
-                String DOC = "["+STR+"]";
-
-                JsonParser jp;
-                
-                if (input == 0) {
-                    jp = createParserUsingStream(DOC, "UTF-8");
-                } else {
-                    jp = FACTORY.createParser(DOC);
-                }
-                assertToken(JsonToken.START_ARRAY, jp.nextToken());
-                assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-                assertEquals(STR, jp.getText());
-                assertEquals(EXP_D, jp.getDoubleValue());
-                assertToken(JsonToken.END_ARRAY, jp.nextToken());
-                assertNull(jp.nextToken());
-                jp.close();
-
-                // then outside
-                if (input == 0) {
-                    jp = createParserUsingStream(STR, "UTF-8");
-                } else {
-                    jp = FACTORY.createParser(STR);
-                }
-                JsonToken t = null;
-
-                try {
-                    t = jp.nextToken();
-                } catch (Exception e) {
-                    throw new Exception("Failed to parse input '"+STR+"' (parser of type "+jp.getClass().getSimpleName()+")", e);
-                }
-                
-                assertToken(JsonToken.VALUE_NUMBER_FLOAT, t);
-                assertEquals(STR, jp.getText());
-                assertNull(jp.nextToken());
-                jp.close();
-            }
-        }
-    }
-
-    public void testNumbers() throws Exception
-    {
-        final String DOC = "[ -13, 8100200300, 13.5, 0.00010, -2.033 ]";
-
-        for (int input = 0; input < 2; ++input) {
-            JsonParser jp;
-
-            if (input == 0) {
-                jp = createParserUsingStream(DOC, "UTF-8");
-            } else {
-                jp = FACTORY.createParser(DOC);
-            }
-
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(-13, jp.getIntValue());
-            assertEquals(-13L, jp.getLongValue());
-            assertEquals(-13., jp.getDoubleValue());
-            assertEquals("-13", jp.getText());
-            
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(8100200300L, jp.getLongValue());
-            // Should get exception for overflow:
-            try {
-                /*int x =*/ jp.getIntValue();
-                fail("Expected an exception for overflow");
-            } catch (Exception e) {
-                verifyException(e, "out of range of int");
-            }
-            assertEquals(8100200300., jp.getDoubleValue());
-            assertEquals("8100200300", jp.getText());
-            
-            assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-            assertEquals(13, jp.getIntValue());
-            assertEquals(13L, jp.getLongValue());
-            assertEquals(13.5, jp.getDoubleValue());
-            assertEquals("13.5", jp.getText());
-            
-            assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-            assertEquals(0, jp.getIntValue());
-            assertEquals(0L, jp.getLongValue());
-            assertEquals(0.00010, jp.getDoubleValue());
-            assertEquals("0.00010", jp.getText());
-            
-            assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-            assertEquals(-2, jp.getIntValue());
-            assertEquals(-2L, jp.getLongValue());
-            assertEquals(-2.033, jp.getDoubleValue());
-            assertEquals("-2.033", jp.getText());
-
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());
-
-            jp.close();
-        }
-    }
-
-    public void testLongOverflow() throws Exception
-    {
-        BigInteger below = BigInteger.valueOf(Long.MIN_VALUE);
-        below = below.subtract(BigInteger.ONE);
-        BigInteger above = BigInteger.valueOf(Long.MAX_VALUE);
-        above = above.add(BigInteger.ONE);
-
-        String DOC_BELOW = below.toString() + " ";
-        String DOC_ABOVE = below.toString() + " ";
-        for (int input = 0; input < 2; ++input) {
-            JsonParser jp;
-
-            if (input == 0) {
-                jp = createParserUsingStream(DOC_BELOW, "UTF-8");
-            } else {
-                jp = FACTORY.createParser(DOC_BELOW);
-            }
-            jp.nextToken();
-            try {
-                long x = jp.getLongValue();
-                fail("Expected an exception for underflow (input "+jp.getText()+"): instead, got long value: "+x);
-            } catch (JsonParseException e) {
-                verifyException(e, "out of range of long");
-            }
-            jp.close();
-
-            if (input == 0) {
-                jp = createParserUsingStream(DOC_ABOVE, "UTF-8");
-            } else {
-                jp = createParserUsingReader(DOC_ABOVE);
-            }
-            jp.nextToken();
-            try {
-                long x = jp.getLongValue();
-                fail("Expected an exception for underflow (input "+jp.getText()+"): instead, got long value: "+x);
-            } catch (JsonParseException e) {
-                verifyException(e, "out of range of long");
-            }
-            jp.close();
-            
-        }
-    }
-    
-    /**
-     * Method that tries to test that number parsing works in cases where
-     * input is split between buffer boundaries.
-     */
-    public void testParsingOfLongerSequences()
-        throws Exception
-    {
-        double[] values = new double[] { 0.01, -10.5, 2.1e9, 4.0e-8 };
-        StringBuilder sb = new StringBuilder();
-
-        for (int i = 0; i < values.length; ++i) {
-            if (i > 0) {
-                sb.append(',');
-            }
-            sb.append(values[i]);
-        }
-        String segment = sb.toString();
-
-        int COUNT = 1000;
-        sb = new StringBuilder(COUNT * segment.length() + 20);
-        sb.append("[");
-        for (int i = 0; i < COUNT; ++i) {
-            if (i > 0) {
-                sb.append(',');
-            }
-            sb.append(segment);
-            sb.append('\n');
-            // let's add somewhat arbitrary number of spaces
-            int x = (i & 3);
-            if (i > 300) {
-                x += i % 5;
-            }
-            while (--x > 0) {
-                sb.append(' ');
-            }
-        }
-        sb.append("]");
-        String DOC = sb.toString();
-
-        for (int input = 0; input < 2; ++input) {
-            JsonParser jp;
-
-            if (input == 0) {
-                jp = createParserUsingStream(DOC, "UTF-8");
-            } else {
-                jp = FACTORY.createParser(DOC);
-            }
-
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            for (int i = 0; i < COUNT; ++i) {
-                for (double d : values) {
-                    assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-                    assertEquals(d, jp.getDoubleValue());
-                }
-            }
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());
-            jp.close();
-        }
-    }
-
-    // [jackson-core#157]
-    public void testLongNumbers() throws Exception
-    {
-        StringBuilder sb = new StringBuilder(9000);
-        for (int i = 0; i < 9000; ++i) {
-            sb.append('9');
-        }
-        String NUM = sb.toString();
-        // force use of new factory, just in case (might still recycle same buffers tho?)
-        JsonFactory f = new JsonFactory();
-        _testLongNumbers(f, NUM, false);
-        _testLongNumbers(f, NUM, true);
-    }
-    
-    private void _testLongNumbers(JsonFactory f, String num, boolean useStream) throws Exception
-    {
-        final String doc = "[ "+num+" ]";
-        JsonParser jp = useStream
-                ? f.createParser(doc.getBytes("UTF-8"))
-                        : f.createParser(doc);
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(num, jp.getText());
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-    }
-
-    // and alternate take on for #157 (with negative num)
-    public void testLongNumbers2() throws Exception
-    {
-        StringBuilder input = new StringBuilder();
-        // test this with negative
-        input.append('-');
-        for (int i = 0; i < 2100; i++) {
-            input.append(1);
-        }
-        final String DOC = input.toString();
-        JsonFactory f = new JsonFactory();
-        _testIssue160LongNumbers(f, DOC, false);
-        _testIssue160LongNumbers(f, DOC, true);
-    }
-
-    private void _testIssue160LongNumbers(JsonFactory f, String doc, boolean useStream) throws Exception
-    {
-        JsonParser jp = useStream
-                ? FACTORY.createParser(doc.getBytes("UTF-8"))
-                        : FACTORY.createParser(doc);
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        BigInteger v = jp.getBigIntegerValue();
-        assertNull(jp.nextToken());
-        assertEquals(doc, v.toString());
-    }
-
-    // for [jackson-core#181]
-    /**
-     * Method that tries to test that number parsing works in cases where
-     * input is split between buffer boundaries.
-     */
-    public void testParsingOfLongerSequencesWithNonNumeric() throws Exception
-    {
-        JsonFactory factory = new JsonFactory();
-        factory.enable(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS);
-        double[] values = new double[] {
-                0.01, -10.5, 2.1e9, 4.0e-8,
-                Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY
-        };
-        for (int i = 0; i < values.length; ++i) {
-            int COUNT = 4096;
-            // Don't see the failure with a multiple of 1
-            int VCOUNT = 2 * COUNT;
-            String arrayJson = toJsonArray(values[i], VCOUNT);
-            StringBuilder sb = new StringBuilder(COUNT + arrayJson.length() + 20);
-            for (int j = 0; j < COUNT; ++j) {
-                sb.append(' ');
-            }
-            sb.append(arrayJson);
-            String DOC = sb.toString();
-            for (int input = 0; input < 2; ++input) {
-                JsonParser jp;
-                if (input == 0) {
-                    jp = createParserUsingStream(factory, DOC, "UTF-8");
-                } else {
-                    jp = factory.createParser(DOC);
-                }
-                assertToken(JsonToken.START_ARRAY, jp.nextToken());
-                for (int j = 0; j < VCOUNT; ++j) {
-                    assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-                    assertEquals(values[i], jp.getDoubleValue());
-                }
-                assertToken(JsonToken.END_ARRAY, jp.nextToken());
-                jp.close();
-            }
-        }
-    }
-
-    /*
-    /**********************************************************
-    /* Tests for invalid access
-    /**********************************************************
-     */
-    
-    public void testInvalidBooleanAccess() throws Exception
-    {
-        JsonParser jp = FACTORY.createParser("[ \"abc\" ]");
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        try {
-            jp.getBooleanValue();
-            fail("Expected error trying to call getBooleanValue on non-boolean value");
-        } catch (JsonParseException e) {
-            verifyException(e, "not of boolean type");
-        }
-        jp.close();
-    }
-
-    public void testInvalidIntAccess() throws Exception
-    {
-        JsonParser jp = FACTORY.createParser("[ \"abc\" ]");
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        try {
-            jp.getIntValue();
-            fail("Expected error trying to call getIntValue on non-numeric value");
-        } catch (JsonParseException e) {
-            verifyException(e, "can not use numeric value accessors");
-        }
-        jp.close();
-    }
-
-    // [core#317]
-    public void testLongerFloatingPoint() throws Exception
-    {
-        StringBuilder input = new StringBuilder();
-        for (int i = 1; i < 201; i++) {
-            input.append(1);
-        }
-        input.append(".0");
-        final String DOC = input.toString();
-
-        // test out with both Reader and ByteArrayInputStream
-        JsonParser p;
-
-        p = FACTORY.createParser(new StringReader(DOC));
-        _testLongerFloat(p, DOC);
-        p.close();
-        
-        p = FACTORY.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")));
-        _testLongerFloat(p, DOC);
-        p.close();
-    }
-
-    private void _testLongerFloat(JsonParser p, String text) throws IOException
-    {
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
-        assertEquals(text, p.getText());
-        assertNull(p.nextToken());
-    }
-
-    /*
-    /**********************************************************
-    /* Helper methods
-    /**********************************************************
-     */
-
-    private String toJsonArray(double v, int n) {
-        StringBuilder sb = new StringBuilder().append('[').append(v);
-        for (int i = 1; i < n; ++i) {
-            sb.append(',').append(v);
-        }
-        return sb.append(']').toString();
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestParserDupHandling.java b/src/test/java/com/fasterxml/jackson/core/json/TestParserDupHandling.java
deleted file mode 100644
index 64183c1..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestParserDupHandling.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-import com.fasterxml.jackson.core.*;
-
-public class TestParserDupHandling
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    private final String[] DUP_DOCS = new String[] {
-            "{ 'a':1, 'a':2 }",
-            "[{ 'a':1, 'a':2 }]",
-            "{ 'a':1, 'b':2, 'c':3,'a':true,'e':false }",
-            "{ 'foo': { 'bar': [ [ { 'x':3, 'a':1 } ]], 'x':0, 'a':'y', 'b':3,'a':13 } }",
-            "[{'b':1},{'b\":3},[{'a':3}], {'a':1,'a':2}]",
-            "{'b':1,'array':[{'b':3}],'ob':{'b':4,'x':0,'y':3,'a':true,'a':false }}",
-    };
-    {
-        for (int i = 0; i < DUP_DOCS.length; ++i) {
-            DUP_DOCS[i] = DUP_DOCS[i].replace("'", "\"");
-        }
-    }
-    
-    public void testSimpleDupsDisabled() throws Exception
-    {
-        // first: verify no problems if detection NOT enabled
-        final JsonFactory f = new JsonFactory();
-        assertFalse(f.isEnabled(JsonParser.Feature.STRICT_DUPLICATE_DETECTION));
-        for (String doc : DUP_DOCS) {
-            _testSimpleDupsOk(doc, f, false);
-            _testSimpleDupsOk(doc, f, true);
-        }
-    }
-
-    public void testSimpleDupsBytes() throws Exception
-    {
-        JsonFactory nonDupF = new JsonFactory();
-        JsonFactory dupF = new JsonFactory();
-        dupF.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
-        for (String doc : DUP_DOCS) {
-            // First, with static setting
-            _testSimpleDupsFail(doc, dupF, true, "a", false);
-
-            // and then dynamic
-            _testSimpleDupsFail(doc, nonDupF, true, "a", true);
-        }
-    }
-
-    public void testSimpleDupsChars() throws Exception
-    {
-        JsonFactory nonDupF = new JsonFactory();
-        JsonFactory dupF = new JsonFactory();
-        dupF.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
-        for (String doc : DUP_DOCS) {
-            _testSimpleDupsFail(doc, dupF, false, "a", false);
-            _testSimpleDupsFail(doc, nonDupF, false, "a", true);
-        }
-    }
-    
-    private void _testSimpleDupsOk(final String doc, JsonFactory f,
-            boolean useStream) throws Exception
-    {
-        JsonParser jp = useStream ?
-                createParserUsingStream(f, doc, "UTF-8") : createParserUsingReader(f, doc);
-        JsonToken t = jp.nextToken();
-        assertNotNull(t);
-        assertTrue(t.isStructStart());
-        while (jp.nextToken() != null) { }
-        jp.close();
-    }
-
-    private void _testSimpleDupsFail(final String doc, JsonFactory f,
-            boolean useStream, String name, boolean lazily) throws Exception
-    {
-        JsonParser jp = useStream ?
-                createParserUsingStream(f, doc, "UTF-8") : createParserUsingReader(f, doc);
-        if (lazily) {
-            jp.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
-        }
-        JsonToken t = jp.nextToken();
-        assertNotNull(t);
-        assertTrue(t.isStructStart());
-        try {
-            while (jp.nextToken() != null) { }
-            fail("Should have caught dups in document: "+doc);
-        } catch (JsonParseException e) {
-            verifyException(e, "duplicate field '"+name+"'");
-        }
-        jp.close();
-    }
-    
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestParserErrorHandling.java b/src/test/java/com/fasterxml/jackson/core/json/TestParserErrorHandling.java
deleted file mode 100644
index 15e149f..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestParserErrorHandling.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonToken;
-
-public class TestParserErrorHandling
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    public void testInvalidKeywordsStream() throws Exception {
-        _testInvalidKeywords(true);
-    }
-    
-    public void testInvalidKeywordsReader() throws Exception {
-        _testInvalidKeywords(false);
-    }
-
-    // Tests for #105 ("eager number parsing misses errors")
-    public void testMangledNumbersBytes() throws Exception {
-        _testMangledNumbers(true);
-    }
-
-    public void testMangledNumbersChars() throws Exception {
-        _testMangledNumbers(false);
-    }
-    
-    /*
-    /**********************************************************
-    /* Helper methods
-    /**********************************************************
-     */
-    
-    private void _testInvalidKeywords(boolean useStream) throws Exception
-    {
-        doTestInvalidKeyword1(useStream, "nul");
-        doTestInvalidKeyword1(useStream, "Null");
-        doTestInvalidKeyword1(useStream, "nulla");
-        doTestInvalidKeyword1(useStream, "fal");
-        doTestInvalidKeyword1(useStream, "False");
-        doTestInvalidKeyword1(useStream, "fals0");
-        doTestInvalidKeyword1(useStream, "falsett0");
-        doTestInvalidKeyword1(useStream, "tr");
-        doTestInvalidKeyword1(useStream, "truE");
-        doTestInvalidKeyword1(useStream, "treu");
-        doTestInvalidKeyword1(useStream, "trueenough");
-        doTestInvalidKeyword1(useStream, "C");
-    }
-
-    private void doTestInvalidKeyword1(boolean useStream, String value)
-        throws IOException
-    {
-        final String doc = "{ \"key1\" : "+value+" }";
-        JsonParser jp = useStream ? createParserUsingStream(doc, "UTF-8")
-                : createParserUsingReader(doc);
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        /* 24-Nov-2008, tatu: Note that depending on parser impl, we may
-         *   get the exception early or late...
-         */
-        try {
-            assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-            jp.nextToken();
-            fail("Expected an exception for malformed value keyword");
-        } catch (JsonParseException jex) {
-            verifyException(jex, "Unrecognized token");
-            verifyException(jex, value);
-        } finally {
-            jp.close();
-        }
-
-        // Try as root-level value as well:
-        jp = useStream ? createParserUsingStream(value, "UTF-8")
-                : createParserUsingReader(value);
-        try {
-            jp.nextToken();
-            fail("Expected an exception for malformed value keyword");
-        } catch (JsonParseException jex) {
-            verifyException(jex, "Unrecognized token");
-            verifyException(jex, value);
-        } finally {
-            jp.close();
-        }
-    }
-
-    private void _testMangledNumbers(boolean useStream) throws Exception
-    {
-        String doc = "123true";
-        JsonParser jp = useStream ? createParserUsingStream(doc, "UTF-8")
-                : createParserUsingReader(doc);
-        try {
-            JsonToken t = jp.nextToken();
-            fail("Should have gotten an exception; instead got token: "+t);
-        } catch (JsonParseException e) {
-            verifyException(e, "expected space");
-        }
-        jp.close();
-
-        // Also test with floats
-        doc = "1.5false";
-        jp = useStream ? createParserUsingStream(doc, "UTF-8")
-                : createParserUsingReader(doc);
-        try {
-            JsonToken t = jp.nextToken();
-            fail("Should have gotten an exception; instead got token: "+t);
-        } catch (JsonParseException e) {
-            verifyException(e, "expected space");
-        }
-        jp.close();
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestParserNonStandard.java b/src/test/java/com/fasterxml/jackson/core/json/TestParserNonStandard.java
deleted file mode 100644
index 0538b80..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestParserNonStandard.java
+++ /dev/null
@@ -1,505 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-import com.fasterxml.jackson.core.*;
-
-public class TestParserNonStandard
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    // // // And then tests to verify [JACKSON-69]:
-
-    public void testSimpleUnquotedBytes() throws Exception {
-        _testSimpleUnquoted(true);
-    }
-
-    public void testSimpleUnquotedChars() throws Exception {
-        _testSimpleUnquoted(false);
-    }
-    
-    public void testLargeUnquoted() throws Exception
-    {
-        _testLargeUnquoted(false);
-        _testLargeUnquoted(true);
-    }
-
-    public void testSingleQuotesDefault() throws Exception
-    {
-        _testSingleQuotesDefault(false);
-        _testSingleQuotesDefault(true);
-    }
-
-    public void testSingleQuotesEnabled() throws Exception
-    {
-        _testSingleQuotesEnabled(false);
-        _testSingleQuotesEnabled(true);
-        _testSingleQuotesEscaped(false);
-        _testSingleQuotesEscaped(true);
-    }
-
-    // Test for [JACKSON-267], allowing '@' as name char, for unquoted names
-    public void testNonStandardNameChars() throws Exception
-    {
-        _testNonStandardNameChars(false);
-        _testNonStandardNameChars(true);
-    }
-    
-    // Test for [JACKSON-300]
-    public void testNonStandardAnyCharQuoting() throws Exception
-    {
-        _testNonStandarBackslashQuoting(false);
-        _testNonStandarBackslashQuoting(true);
-    }
-
-    // Test for [JACKSON-358]
-    public void testLeadingZeroesUTF8() throws Exception {
-        _testLeadingZeroes(true, false);
-        _testLeadingZeroes(true, true);
-    }
-
-    public void testLeadingZeroesReader() throws Exception {
-        _testLeadingZeroes(false, false);
-        _testLeadingZeroes(false, true);
-    }
-
-    // [JACKSON-142]: allow NaN
-    public void testAllowNaN() throws Exception {
-        _testAllowNaN(false);
-        _testAllowNaN(true);
-    }
-
-    // [JACKSON-142]: allow +Inf/-Inf
-    public void testAllowInfinity() throws Exception {
-        _testAllowInf(false);
-        _testAllowInf(true);
-    }
-    
-    /*
-    /****************************************************************
-    /* Secondary test methods
-    /****************************************************************
-     */
-
-    private void _testLargeUnquoted(boolean useStream) throws Exception
-    {
-        StringBuilder sb = new StringBuilder(5000);
-        sb.append("[\n");
-        //final int REPS = 2000;
-        final int REPS = 1050;
-        for (int i = 0; i < REPS; ++i) {
-            if (i > 0) {
-                sb.append(',');
-                if ((i & 7) == 0) {
-                    sb.append('\n');
-                }
-            }
-            sb.append("{");
-            sb.append("abc").append(i&127).append(':');
-            sb.append((i & 1) != 0);
-            sb.append("}\n");
-        }
-        sb.append("]");
-        String JSON = sb.toString();
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
-        JsonParser jp = useStream ?
-            createParserUsingStream(f, JSON, "UTF-8")
-            : createParserUsingReader(f, JSON)
-            ;
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        for (int i = 0; i < REPS; ++i) {
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-            assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-            assertEquals("abc"+(i&127), jp.getCurrentName());
-            assertToken(((i&1) != 0) ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE, jp.nextToken());
-            assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        }
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        jp.close();
-    }
-
-    
-    private void _testSimpleUnquoted(boolean useStream) throws Exception
-    {
-        final JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
-
-        String JSON = "{ a : 1, _foo:true, $:\"money!\", \" \":null }";
-        JsonParser jp = useStream ?
-            createParserUsingStream(f, JSON, "UTF-8")
-            : createParserUsingReader(f, JSON)
-            ;
-
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("a", jp.getCurrentName());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("_foo", jp.getCurrentName());
-        assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("$", jp.getCurrentName());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals("money!", jp.getText());
-
-        // and then regular quoted one should still work too:
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals(" ", jp.getCurrentName());
-
-        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
-
-        assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        jp.close();
-
-        // Another thing, as per [Issue#102]: numbers
-
-        JSON = "{ 123:true,4:false }";
-        jp = useStream ?
-            createParserUsingStream(f, JSON, "UTF-8")
-            : createParserUsingReader(f, JSON)
-        ;
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("123", jp.getCurrentName());
-        assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("4", jp.getCurrentName());
-        assertToken(JsonToken.VALUE_FALSE, jp.nextToken());
-
-        assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        jp.close();
-    }
-
-    /**
-     * Test to verify that the default parser settings do not
-     * accept single-quotes for String values (field names,
-     * textual values)
-     */
-    private void _testSingleQuotesDefault(boolean useStream) throws Exception
-    {
-        JsonFactory f = new JsonFactory();
-        // First, let's see that by default they are not allowed
-        String JSON = "[ 'text' ]";
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-            : createParserUsingReader(f, JSON);
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        try {
-            jp.nextToken();
-            fail("Expected exception");
-        } catch (JsonParseException e) {
-            verifyException(e, "Unexpected character ('''");
-        } finally {
-            jp.close();
-        }
-
-        JSON = "{ 'a':1 }";
-        jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-            : createParserUsingReader(f, JSON);
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        try {
-            jp.nextToken();
-            fail("Expected exception");
-        } catch (JsonParseException e) {
-            verifyException(e, "Unexpected character ('''");
-        } finally {
-            jp.close();
-        }
-    }
-
-    /**
-     * Test to verify [JACKSON-173], optional handling of
-     * single quotes, to allow handling invalid (but, alas, common)
-     * JSON.
-     */
-    private void _testSingleQuotesEnabled(boolean useStream) throws Exception
-    {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
-
-        String JSON = "{ 'a' : 1, \"foobar\": 'b', '_abcde1234':'d', '\"' : '\"\"', '':'' }";
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-            : createParserUsingReader(f, JSON);
-
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("a", jp.getText());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals("1", jp.getText());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("foobar", jp.getText());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals("b", jp.getText());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("_abcde1234", jp.getText());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals("d", jp.getText());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("\"", jp.getText());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        //assertEquals("\"\"", jp.getText());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("", jp.getText());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals("", jp.getText());
-
-        assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        jp.close();
-    }
-
-    // test to verify that we implicitly allow escaping of apostrophe [JACKSON-548]
-    private void _testSingleQuotesEscaped(boolean useStream) throws Exception
-    {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
-
-        String JSON = "[ '16\\'' ]";
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-            : createParserUsingReader(f, JSON);
-
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals("16'", jp.getText());
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        jp.close();
-    }
-    
-    private void _testNonStandardNameChars(boolean useStream) throws Exception
-    {
-        JsonFactory f = new JsonFactory();
-        f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
-        String JSON = "{ @type : \"mytype\", #color : 123, *error* : true, "
-            +" hyphen-ated : \"yes\", me+my : null"
-            +"}";
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-                : createParserUsingReader(f, JSON);
-
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("@type", jp.getText());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals("mytype", jp.getText());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("#color", jp.getText());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(123, jp.getIntValue());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("*error*", jp.getText());
-        assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("hyphen-ated", jp.getText());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals("yes", jp.getText());
-
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("me+my", jp.getText());
-        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
-    
-        assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        jp.close();
-    }
-
-    private void _testNonStandarBackslashQuoting(boolean useStream) throws Exception
-    {
-        // first: verify that we get an exception
-        JsonFactory f = new JsonFactory();
-        assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER));
-        final String JSON = quote("\\'");
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")                
-                : createParserUsingReader(f, JSON);
-        try {      
-            jp.nextToken();
-            jp.getText();
-            fail("Should have thrown an exception for doc <"+JSON+">");
-        } catch (JsonParseException e) {
-            verifyException(e, "unrecognized character escape");
-        } finally {
-            jp.close();
-        }
-        // and then verify it's ok...
-        f.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
-        assertTrue(f.isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER));
-        jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")                
-                : createParserUsingReader(f, JSON);
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals("'", jp.getText());
-        jp.close();
-    }
-
-    private void _testLeadingZeroes(boolean useStream, boolean appendSpace) throws Exception
-    {
-        // first: verify that we get an exception
-        JsonFactory f = new JsonFactory();
-        assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS));
-        String JSON = "00003";
-        if (appendSpace) {
-            JSON += " ";
-        }
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")                
-                : createParserUsingReader(f, JSON);
-        try {      
-            jp.nextToken();
-            jp.getText();
-            fail("Should have thrown an exception for doc <"+JSON+">");
-        } catch (JsonParseException e) {
-            verifyException(e, "invalid numeric value");
-        } finally {
-            jp.close();
-        }
-        
-        // and then verify it's ok when enabled
-        f.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
-        assertTrue(f.isEnabled(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS));
-        jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")                
-                : createParserUsingReader(f, JSON);
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(3, jp.getIntValue());
-        assertEquals("3", jp.getText());
-        jp.close();
-    
-        // Plus, also: verify that leading zero magnitude is ok:
-        JSON = "0"+Integer.MAX_VALUE;
-        if (appendSpace) {
-            JSON += " ";
-        }
-        jp = useStream ? createParserUsingStream(f, JSON, "UTF-8") : createParserUsingReader(f, JSON);
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertEquals(String.valueOf(Integer.MAX_VALUE), jp.getText());
-        assertEquals(Integer.MAX_VALUE, jp.getIntValue());
-        Number nr = jp.getNumberValue();
-        assertSame(Integer.class, nr.getClass());
-        jp.close();
-    }
-
-    private void _testAllowNaN(boolean useStream) throws Exception
-    {
-        final String JSON = "[ NaN]";
-        JsonFactory f = new JsonFactory();
-        assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS));
-
-        // without enabling, should get an exception
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-            : createParserUsingReader(f, JSON);
-
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        try {
-            jp.nextToken();
-            fail("Expected exception");
-        } catch (Exception e) {
-            verifyException(e, "non-standard");
-        } finally {
-            jp.close();
-        }
-
-        // we can enable it dynamically (impl detail)
-        f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
-        jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-                : createParserUsingReader(f, JSON);
-        
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        
-        double d = jp.getDoubleValue();
-        assertTrue(Double.isNaN(d));
-        assertEquals("NaN", jp.getText());
-
-        // [Issue#98]
-        try {
-            /*BigDecimal dec =*/ jp.getDecimalValue();
-            fail("Should fail when trying to access NaN as BigDecimal");
-        } catch (NumberFormatException e) {
-            verifyException(e, "can not be represented as BigDecimal");
-        }
-       
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        jp.close();
-
-        // finally, should also work with skipping
-        f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
-        jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-                : createParserUsingReader(f, JSON);
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        jp.close();
-    }
-
-    private void _testAllowInf(boolean useStream) throws Exception
-    {
-        final String JSON = "[ -INF, +INF, +Infinity, Infinity, -Infinity ]";
-        JsonFactory f = new JsonFactory();
-        assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS));
-
-        // without enabling, should get an exception
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-            : createParserUsingReader(f, JSON);
-
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        try {
-            jp.nextToken();
-            fail("Expected exception");
-        } catch (Exception e) {
-            verifyException(e, "Non-standard token '-INF'");
-        } finally {
-            jp.close();
-        }
-
-        f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
-        jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-                : createParserUsingReader(f, JSON);
-
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        double d = jp.getDoubleValue();
-        assertEquals("-INF", jp.getText());
-        assertTrue(Double.isInfinite(d));
-        assertTrue(d == Double.NEGATIVE_INFINITY);
-
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        d = jp.getDoubleValue();
-        assertEquals("+INF", jp.getText());
-        assertTrue(Double.isInfinite(d));
-        assertTrue(d == Double.POSITIVE_INFINITY);
-
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        d = jp.getDoubleValue();
-        assertEquals("+Infinity", jp.getText());
-        assertTrue(Double.isInfinite(d));
-        assertTrue(d == Double.POSITIVE_INFINITY);
-
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        d = jp.getDoubleValue();
-        assertEquals("Infinity", jp.getText());
-        assertTrue(Double.isInfinite(d));
-        assertTrue(d == Double.POSITIVE_INFINITY);
-
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        d = jp.getDoubleValue();
-        assertEquals("-Infinity", jp.getText());
-        assertTrue(Double.isInfinite(d));
-        assertTrue(d == Double.NEGATIVE_INFINITY);
-
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        jp.close();
-
-        // finally, should also work with skipping
-        f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
-        jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
-                : createParserUsingReader(f, JSON);
-
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-        assertToken(JsonToken.END_ARRAY, jp.nextToken());
-        
-        jp.close();
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestParserOverrides.java b/src/test/java/com/fasterxml/jackson/core/json/TestParserOverrides.java
index d382428..244effd 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestParserOverrides.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestParserOverrides.java
@@ -45,14 +45,14 @@
         JsonParser jp = useStream ?
                 jf.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
                 : jf.createParser(DOC);
-        assertNull(jp.getCurrentToken());
+        assertNull(jp.currentToken());
         jp.clearCurrentToken();
-        assertNull(jp.getCurrentToken());
+        assertNull(jp.currentToken());
         assertNull(jp.getEmbeddedObject());
         assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.START_ARRAY, jp.getCurrentToken());
+        assertToken(JsonToken.START_ARRAY, jp.currentToken());
         jp.clearCurrentToken();
-        assertNull(jp.getCurrentToken());
+        assertNull(jp.currentToken());
         // Also: no codec defined by default
         try {
             jp.readValueAsTree();
@@ -69,7 +69,7 @@
         JsonParser jp = useStream ?
                 jf.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
                 : jf.createParser(new StringReader(DOC));
-        assertNull(jp.getCurrentToken());
+        assertNull(jp.currentToken());
         assertToken(JsonToken.START_OBJECT, jp.nextToken());
         assertToken(JsonToken.FIELD_NAME, jp.nextToken());
         assertEquals("first", jp.getCurrentName());
@@ -94,9 +94,7 @@
 
         assertToken(JsonToken.END_OBJECT, jp.nextToken());
         jp.clearCurrentToken();
-        assertNull(jp.getCurrentToken());
+        assertNull(jp.currentToken());
         jp.close();
     }
-    
-
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestRootValues.java b/src/test/java/com/fasterxml/jackson/core/json/TestRootValues.java
index 585dbbe..625d284 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestRootValues.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestRootValues.java
@@ -45,7 +45,7 @@
         // Should fail, right away
         try {
         	p.nextToken();
-        	fail("Ought to fail! Instead, got token: "+p.getCurrentToken());
+        	fail("Ought to fail! Instead, got token: "+p.currentToken());
         } catch (JsonParseException e) {
         	verifyException(e, "unexpected character");
         }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java b/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java
index 3cf4020..50752b2 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java
@@ -1,11 +1,17 @@
 package com.fasterxml.jackson.core.json;
 
-import java.io.*;
-
-import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.BaseTest;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.core.filter.FilteringGeneratorDelegate;
+import com.fasterxml.jackson.core.filter.JsonPointerBasedFilter;
 import com.fasterxml.jackson.core.io.IOContext;
 import com.fasterxml.jackson.core.util.BufferRecycler;
 
+import java.io.ByteArrayOutputStream;
+
 public class TestUtf8Generator extends BaseTest
 {
     private final JsonFactory JSON_F = new JsonFactory();
@@ -42,11 +48,11 @@
     {
         final String VALUE = quote("\ud83d\ude0c");
         ByteArrayOutputStream out = new ByteArrayOutputStream();
-        JsonGenerator jgen = JSON_F.createGenerator(out);
-        jgen.writeStartArray();
-        jgen.writeRaw(VALUE);
-        jgen.writeEndArray();
-        jgen.close();
+        JsonGenerator g = JSON_F.createGenerator(out);
+        g.writeStartArray();
+        g.writeRaw(VALUE);
+        g.writeEndArray();
+        g.close();
 
         final byte[] JSON = out.toByteArray();
 
@@ -60,4 +66,52 @@
         assertToken(JsonToken.END_ARRAY, jp.nextToken());
         jp.close();
     }
+
+    public void testFilteringWithEscapedChars() throws Exception
+    {
+        final String SAMPLE_WITH_QUOTES = "\b\t\f\n\r\"foo\"\u0000";
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        @SuppressWarnings("resource")
+        JsonGenerator g = JSON_F.createGenerator(out);
+
+        FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(g,
+                new JsonPointerBasedFilter("/escapes"),
+                true, // includePath
+                false // multipleMatches
+        );
+
+        //final String JSON = "{'a':123,'array':[1,2],'escapes':'\b\t\f\n\r\"foo\"\u0000'}";
+
+        gen.writeStartObject();
+
+        gen.writeFieldName("a");
+        gen.writeNumber((int) 123);
+
+        gen.writeFieldName("array");
+        gen.writeStartArray();
+        gen.writeNumber((short) 1);
+        gen.writeNumber((short) 2);
+        gen.writeEndArray();
+
+        gen.writeFieldName("escapes");
+
+        final byte[] raw = SAMPLE_WITH_QUOTES.toString().getBytes("UTF-8");
+        gen.writeUTF8String(raw, 0, raw.length);
+
+        gen.writeEndObject();
+        gen.close();
+
+        JsonParser p = JSON_F.createParser(out.toByteArray());
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("escapes", p.getCurrentName());
+
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(SAMPLE_WITH_QUOTES, p.getText());
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        assertNull(p.nextToken());
+        p.close();
+    }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Parser.java b/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Parser.java
deleted file mode 100644
index d7f2f7c..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Parser.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-
-import com.fasterxml.jackson.core.*;
-import com.fasterxml.jackson.core.io.SerializedString;
-
-import java.io.*;
-import java.util.Random;
-
-/**
- * Set of basic unit tests for verifying that the basic parser
- * functionality works as expected.
- */
-public class TestUtf8Parser
-    extends BaseTest
-{
-    final static String[] UTF8_2BYTE_STRINGS = new String[] {
-        /* This may look funny, but UTF8 scanner has fairly
-         * elaborate decoding machinery, and it is indeed
-         * necessary to try out various combinations...
-         */
-        "b", "A\u00D8", "abc", "c3p0",
-        "12345", "......", "Long\u00FAer",
-        "Latin1-fully-\u00BE-develop\u00A8d",
-        "Some very long name, ridiculously long actually to see that buffer expansion works: \u00BF?"
-    };
-
-    final static String[] UTF8_3BYTE_STRINGS = new String[] {
-        "\uC823?", "A\u400F", "1\u1234?",
-        "Ab123\u4034",
-        "Even-longer:\uC023"
-    };
-
-    public void testEmptyName()
-        throws Exception
-    {
-        final String DOC = "{ \"\" : \"\" }";
-
-        JsonParser jp = createParserUsingStream(DOC, "UTF-8");
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals("", jp.getCurrentName());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals("", jp.getText());
-        assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        jp.close();
-    }
-
-    public void testUtf8Name2Bytes() throws Exception
-    {
-        final String[] NAMES = UTF8_2BYTE_STRINGS;
-
-        for (int i = 0; i < NAMES.length; ++i) {
-            String NAME = NAMES[i];
-            String DOC = "{ \""+NAME+"\" : 0 }";
-            JsonParser jp = createParserUsingStream(DOC, "UTF-8");
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-
-            assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-
-            assertTrue(jp.hasToken(JsonToken.FIELD_NAME));
-            assertTrue(jp.hasTokenId(JsonTokenId.ID_FIELD_NAME));
-            
-            assertEquals(NAME, jp.getCurrentName());
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertTrue(jp.hasToken(JsonToken.VALUE_NUMBER_INT));
-            assertTrue(jp.hasTokenId(JsonTokenId.ID_NUMBER_INT));
-
-            // should retain name during value entry, too
-            assertEquals(NAME, jp.getCurrentName());
-            
-            assertToken(JsonToken.END_OBJECT, jp.nextToken());
-            jp.close();
-        }
-    }
-
-    public void testUtf8Name3Bytes() throws Exception
-    {
-        final String[] NAMES = UTF8_3BYTE_STRINGS;
-
-        for (int i = 0; i < NAMES.length; ++i) {
-            String NAME = NAMES[i];
-            String DOC = "{ \""+NAME+"\" : true }";
-
-            JsonParser jp = createParserUsingStream(DOC, "UTF-8");
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-            
-            assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-            assertEquals(NAME, jp.getCurrentName());
-            assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-            assertEquals(NAME, jp.getCurrentName());
-            
-            assertToken(JsonToken.END_OBJECT, jp.nextToken());
-            
-            jp.close();
-        }
-    }
-
-    // How about tests for Surrogate-Pairs?
-
-    public void testUtf8StringTrivial() throws Exception
-    {
-        String[] VALUES = UTF8_2BYTE_STRINGS;
-        for (int i = 0; i < VALUES.length; ++i) {
-            String VALUE = VALUES[i];
-            String DOC = "[ \""+VALUE+"\" ]";
-            JsonParser jp = createParserUsingStream(DOC, "UTF-8");
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            String act = getAndVerifyText(jp);
-            if (act.length() != VALUE.length()) {
-                fail("Failed for value #"+(i+1)+"/"+VALUES.length+": length was "+act.length()+", should be "+VALUE.length());
-            }
-            assertEquals(VALUE, act);
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());
-            jp.close();
-        }
-
-        VALUES = UTF8_3BYTE_STRINGS;
-        for (int i = 0; i < VALUES.length; ++i) {
-            String VALUE = VALUES[i];
-            String DOC = "[ \""+VALUE+"\" ]";
-            JsonParser jp = createParserUsingStream(DOC, "UTF-8");
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertEquals(VALUE, getAndVerifyText(jp));
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());
-            jp.close();
-        }
-    }
-
-    public void testUtf8StringValue() throws Exception
-    {
-        Random r = new Random(13);
-        //int LEN = 72000;
-        int LEN = 720;
-        StringBuilder sb = new StringBuilder(LEN + 20);
-        while (sb.length() < LEN) {
-            int c;
-            if (r.nextBoolean()) { // ascii
-                c = 32 + (r.nextInt() & 0x3F);
-                if (c == '"' || c == '\\') {
-                    c = ' ';
-                }
-            } else if (r.nextBoolean()) { // 2-byte
-                c = 160 + (r.nextInt() & 0x3FF);
-            } else if (r.nextBoolean()) { // 3-byte (non-surrogate)
-                c = 8000 + (r.nextInt() & 0x7FFF);
-            } else { // surrogates (2 chars)
-                int value = r.nextInt() & 0x3FFFF; // 20-bit, ~ 1 million
-                sb.append((char) (0xD800 + (value >> 10)));
-                c = (0xDC00 + (value & 0x3FF));
-
-            }
-            sb.append((char) c);
-        }
-
-        ByteArrayOutputStream bout = new ByteArrayOutputStream(LEN);
-        OutputStreamWriter out = new OutputStreamWriter(bout, "UTF-8");
-        out.write("[\"");
-        String VALUE = sb.toString();
-        out.write(VALUE);
-        out.write("\"]");
-        out.close();
-
-        byte[] data = bout.toByteArray();
-
-        JsonParser jp = new JsonFactory().createParser(new ByteArrayInputStream(data));
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        String act = jp.getText();
-
-        assertEquals(VALUE.length(), act.length());
-        assertEquals(VALUE, act);
-        jp.close();
-    }
-
-    // [JACKSON-889]
-	public void testNextFieldName() throws IOException
-	{
-		JsonFactory f = new JsonFactory();
-		SerializedString id = new SerializedString("id");
-
-		ByteArrayOutputStream os = new ByteArrayOutputStream();
-		os.write('{');
-		for (int i = 0; i < 3994; i++) {
-			os.write(' ');
-		}
-		os.write("\"id\":2".getBytes("UTF-8"));
-		os.write('}');
-
-		JsonParser parser = f.createParser(new ByteArrayInputStream(os.toByteArray()));
-		assertEquals(parser.nextToken(), JsonToken.START_OBJECT);
-		assertTrue(parser.nextFieldName(id));
-		assertEquals(parser.nextToken(), JsonToken.VALUE_NUMBER_INT);
-		assertEquals(parser.nextToken(), JsonToken.END_OBJECT);
-		parser.close();
-	}
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestValueConversions.java b/src/test/java/com/fasterxml/jackson/core/json/TestValueConversions.java
deleted file mode 100644
index 543caac..0000000
--- a/src/test/java/com/fasterxml/jackson/core/json/TestValueConversions.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.fasterxml.jackson.core.json;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonToken;
-
-public class TestValueConversions
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    public void testAsInt() throws Exception
-    {
-        final String input = "[ 1, -3, 4.98, true, false, null, \"-17\", \"foo\" ]";
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp;
-            if (i == 0) {
-                jp = createParserUsingReader(input);                
-            } else {
-                jp = this.createParserUsingStream(input, "UTF-8");
-            }
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertEquals(0, jp.getValueAsLong());
-            assertEquals(9, jp.getValueAsLong(9));
-
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(1, jp.getValueAsLong());
-            assertEquals(1, jp.getValueAsLong(-99));
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(-3, jp.getValueAsLong());
-            assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-            assertEquals(4, jp.getValueAsLong());
-            assertEquals(4, jp.getValueAsLong(99));
-            assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-            assertEquals(1, jp.getValueAsLong());
-            assertToken(JsonToken.VALUE_FALSE, jp.nextToken());
-            assertEquals(0, jp.getValueAsLong());
-            assertToken(JsonToken.VALUE_NULL, jp.nextToken());
-            assertEquals(0, jp.getValueAsLong());
-            assertEquals(0, jp.getValueAsLong(27));
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertEquals(-17, jp.getValueAsLong());
-            assertEquals(-17, jp.getValueAsLong(3));
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertEquals(0, jp.getValueAsLong());
-            assertEquals(9, jp.getValueAsLong(9));
-            
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());
-            assertEquals(0, jp.getValueAsLong());
-            assertEquals(9, jp.getValueAsLong(9));
-
-            jp.close();
-        }     
-    }
-
-    /**
-     * @since 1.7
-     */
-    public void testAsBoolean() throws Exception
-    {
-        final String input = "[ true, false, null, 1, 0, \"true\", \"false\", \"foo\" ]";
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp;
-            if (i == 0) {
-                jp = createParserUsingReader(input);                
-            } else {
-                jp = this.createParserUsingStream(input, "UTF-8");
-            }
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertEquals(false, jp.getValueAsBoolean());
-            assertEquals(true, jp.getValueAsBoolean(true));
-
-            assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-            assertEquals(true, jp.getValueAsBoolean());
-            assertToken(JsonToken.VALUE_FALSE, jp.nextToken());
-            assertEquals(false, jp.getValueAsBoolean());
-            assertToken(JsonToken.VALUE_NULL, jp.nextToken());
-            assertEquals(false, jp.getValueAsBoolean());
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(1, jp.getIntValue());
-            assertEquals(true, jp.getValueAsBoolean());
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(0, jp.getIntValue());
-            assertEquals(false, jp.getValueAsBoolean());
-
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken()); // "true"
-            assertEquals(true, jp.getValueAsBoolean());
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertEquals(false, jp.getValueAsBoolean());
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertEquals(false, jp.getValueAsBoolean());
-            
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());
-            assertEquals(false, jp.getValueAsBoolean());
-            assertEquals(true, jp.getValueAsBoolean(true));
-
-            jp.close();
-        }     
-    }
-
-    public void testAsLong() throws Exception
-    {
-        final String input = "[ 1, -3, 4.98, true, false, null, \"-17\", \"foo\" ]";
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp;
-            if (i == 0) {
-                jp = createParserUsingReader(input);                
-            } else {
-                jp = createParserUsingStream(input, "UTF-8");
-            }
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertEquals(0L, jp.getValueAsLong());
-            assertEquals(9L, jp.getValueAsLong(9L));
-
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(1L, jp.getValueAsLong());
-            assertEquals(1L, jp.getValueAsLong(-99L));
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(-3L, jp.getValueAsLong());
-            assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-            assertEquals(4L, jp.getValueAsLong());
-            assertEquals(4L, jp.getValueAsLong(99L));
-            assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-            assertEquals(1L, jp.getValueAsLong());
-            assertToken(JsonToken.VALUE_FALSE, jp.nextToken());
-            assertEquals(0L, jp.getValueAsLong());
-            assertToken(JsonToken.VALUE_NULL, jp.nextToken());
-            assertEquals(0L, jp.getValueAsLong());
-            assertEquals(0L, jp.getValueAsLong(27L));
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertEquals(-17L, jp.getValueAsLong());
-            assertEquals(-17L, jp.getValueAsLong(3L));
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertEquals(0L, jp.getValueAsLong());
-            assertEquals(9L, jp.getValueAsLong(9L));
-            
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());
-            assertEquals(0L, jp.getValueAsLong());
-            assertEquals(9L, jp.getValueAsLong(9L));
-
-            jp.close();
-        }     
-    }
-
-    public void testAsDouble() throws Exception
-    {
-        final String input = "[ 1, -3, 4.98, true, false, null, \"-17.25\", \"foo\" ]";
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp;
-            if (i == 0) {
-                jp = createParserUsingReader(input);                
-            } else {
-                jp = this.createParserUsingStream(input, "UTF-8");
-            }
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertEquals(0.0, jp.getValueAsDouble());
-            assertEquals(9.0, jp.getValueAsDouble(9.0));
-
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(1., jp.getValueAsDouble());
-            assertEquals(1., jp.getValueAsDouble(-99.0));
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertEquals(-3., jp.getValueAsDouble());
-            assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
-            assertEquals(4.98, jp.getValueAsDouble());
-            assertEquals(4.98, jp.getValueAsDouble(12.5));
-            assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
-            assertEquals(1.0, jp.getValueAsDouble());
-            assertToken(JsonToken.VALUE_FALSE, jp.nextToken());
-            assertEquals(0.0, jp.getValueAsDouble());
-            assertToken(JsonToken.VALUE_NULL, jp.nextToken());
-            assertEquals(0.0, jp.getValueAsDouble());
-            assertEquals(0.0, jp.getValueAsDouble(27.8));
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertEquals(-17.25, jp.getValueAsDouble());
-            assertEquals(-17.25, jp.getValueAsDouble(1.9));
-            assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-            assertEquals(0.0, jp.getValueAsDouble());
-            assertEquals(1.25, jp.getValueAsDouble(1.25));
-            
-            assertToken(JsonToken.END_ARRAY, jp.nextToken());
-            assertEquals(0.0, jp.getValueAsDouble());
-            assertEquals(7.5, jp.getValueAsDouble(7.5));
-
-            jp.close();
-        }     
-    }
-    
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestWithTonsaSymbols.java b/src/test/java/com/fasterxml/jackson/core/json/TestWithTonsaSymbols.java
index 5b553a7..910962d 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestWithTonsaSymbols.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestWithTonsaSymbols.java
@@ -43,18 +43,18 @@
          * state is different between runs.
          */
         for (int x = 0; x < 3; ++x) {
-            JsonParser jp = useStream ?
+            JsonParser p = useStream ?
                 jf.createParser(new ByteArrayInputStream(doc.getBytes("UTF-8")))
                 : jf.createParser(new StringReader(doc));
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
+            assertToken(JsonToken.START_OBJECT, p.nextToken());
             for (int i = 0; i < FIELD_COUNT; ++i) {
-                assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-                assertEquals(fieldNameFor(i), jp.getCurrentName());
-                assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-                assertEquals(i, jp.getIntValue());
+                assertToken(JsonToken.FIELD_NAME, p.nextToken());
+                assertEquals(fieldNameFor(i), p.getCurrentName());
+                assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+                assertEquals(i, p.getIntValue());
             }
-            assertToken(JsonToken.END_OBJECT, jp.nextToken());
-            jp.close();
+            assertToken(JsonToken.END_OBJECT, p.nextToken());
+            p.close();
         }
     }
         
diff --git a/src/test/java/com/fasterxml/jackson/core/main/TestArrayParsing.java b/src/test/java/com/fasterxml/jackson/core/main/TestArrayParsing.java
index 0dff001..b189cb1 100644
--- a/src/test/java/com/fasterxml/jackson/core/main/TestArrayParsing.java
+++ b/src/test/java/com/fasterxml/jackson/core/main/TestArrayParsing.java
@@ -69,4 +69,116 @@
         }
         jp.close();
     }
+    
+    /**
+     * Tests the missing value as 'null' in an array 
+     * This needs enabling of the Feature.ALLOW_MISSING_VALUES in JsonParser
+     * This tests both Stream based parsing and the Reader based parsing
+     * @throws Exception
+     */
+    public void testMissingValueAsNullByEnablingFeature() throws Exception
+    {
+    	_testMissingValueByEnablingFeature(true);
+    	_testMissingValueByEnablingFeature(false);
+    }
+
+    /**
+     * Tests the missing value in an array by not enabling 
+     * the Feature.ALLOW_MISSING_VALUES
+     * @throws Exception
+     */
+    public void testMissingValueAsNullByNotEnablingFeature() throws Exception
+    {
+    	_testMissingValueNotEnablingFeature(true);
+    	_testMissingValueNotEnablingFeature(false);
+    }
+    
+    /**
+     * Tests the not missing any value in an array by enabling the 
+     * Feature.ALLOW_MISSING_VALUES in JsonParser
+     * This tests both Stream based parsing and the Reader based parsing for not missing any value
+     * @throws Exception
+     */
+    public void testNotMissingValueByEnablingFeature() throws Exception
+    {
+    	_testNotMissingValueByEnablingFeature(true);
+    	_testNotMissingValueByEnablingFeature(false);
+    }
+    
+    private void _testMissingValueByEnablingFeature(boolean useStream) throws Exception {
+        String DOC = "[ \"a\",,,,\"abc\", ] ";
+
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true);
+    	
+        JsonParser jp = useStream ? createParserUsingStream(f, DOC, "UTF-8")
+   			          : createParserUsingReader(f, DOC);
+        
+        assertToken(JsonToken.START_ARRAY, jp.nextToken());
+        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
+        assertEquals("a", jp.getValueAsString());
+        
+        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
+        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
+        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
+        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
+        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
+        assertToken(JsonToken.END_ARRAY, jp.nextToken());
+        assertNull(jp.nextToken());
+             
+        jp.close();
+
+        // And another take
+        DOC = "[,] ";
+        jp = useStream ? createParserUsingStream(f, DOC, "UTF-8")
+                : createParserUsingReader(f, DOC);
+
+        assertToken(JsonToken.START_ARRAY, jp.nextToken());
+        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
+        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
+        assertToken(JsonToken.END_ARRAY, jp.nextToken());
+        assertNull(jp.nextToken());
+
+        jp.close();
+    }
+    
+    private void _testMissingValueNotEnablingFeature(boolean useStream) throws Exception {
+    	final String DOC = "[ \"a\",,\"abc\"] ";
+
+    	JsonFactory f = new JsonFactory();
+    	
+        JsonParser jp = useStream ? createParserUsingStream(f, DOC, "UTF-8")
+   			          : createParserUsingReader(f, DOC);
+        
+        assertToken(JsonToken.START_ARRAY, jp.nextToken());
+        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
+        assertEquals("a", jp.getValueAsString());
+        try {
+	        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
+	        fail("Expecting exception here");
+        }
+        catch(JsonParseException ex){
+        	verifyException(ex, "expected a valid value", "expected a value");
+        }
+        jp.close();
+    }
+    
+    private void _testNotMissingValueByEnablingFeature(boolean useStream) throws Exception {
+    	final String DOC = "[ \"a\",\"abc\"] ";
+
+    	JsonFactory f = new JsonFactory();
+    	f.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true);
+    	
+        JsonParser jp = useStream ? createParserUsingStream(f, DOC, "UTF-8")
+   			          : createParserUsingReader(f, DOC);
+        
+        assertToken(JsonToken.START_ARRAY, jp.nextToken());
+        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
+        assertEquals("a", jp.getValueAsString());
+        
+        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
+        assertToken(JsonToken.END_ARRAY, jp.nextToken());
+             
+        jp.close();
+    }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorArray.java b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorArray.java
index 08dfeca..7b86c6d 100644
--- a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorArray.java
+++ b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorArray.java
@@ -36,7 +36,7 @@
         gen.writeEndArray();
 
         ctxt = gen.getOutputContext();
-        assertTrue("Should be in root, was "+ctxt.getTypeDesc(), ctxt.inRoot());
+        assertTrue("Should be in root, was "+ctxt.typeDesc(), ctxt.inRoot());
         assertFalse(ctxt.inArray());
         assertFalse(ctxt.inObject());
         assertEquals(1, ctxt.getEntryCount());
@@ -79,7 +79,7 @@
             gen.writeEndObject();
             fail("Expected an exception for mismatched array/object write");
         } catch (JsonGenerationException e) {
-            verifyException(e, "Current context not an object");
+            verifyException(e, "Current context not Object");
         }
         gen.close();
     }
diff --git a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorCopy.java b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorCopy.java
index 853ecb7..e9e26f2 100644
--- a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorCopy.java
+++ b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorCopy.java
@@ -26,7 +26,7 @@
         while ((t = jp.nextToken()) != null) {
             gen.copyCurrentEvent(jp);
             // should not change parser state:
-            assertToken(t, jp.getCurrentToken());
+            assertToken(t, jp.currentToken());
         }
         jp.close();
         gen.close();
@@ -46,14 +46,14 @@
         assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
         gen.copyCurrentEvent(jp);
         // should not change parser state:
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.getCurrentToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, jp.currentToken());
         assertEquals(123, jp.getIntValue());
 
         // And then let's copy the array
         assertToken(JsonToken.START_ARRAY, jp.nextToken());
         gen.copyCurrentStructure(jp);
         // which will advance parser to matching close Array
-        assertToken(JsonToken.END_ARRAY, jp.getCurrentToken());
+        assertToken(JsonToken.END_ARRAY, jp.currentToken());
         jp.close();
         gen.close();
 
@@ -72,7 +72,7 @@
         assertToken(JsonToken.START_OBJECT, jp.nextToken());
         gen.copyCurrentStructure(jp);
         // which will advance parser to matching end Object
-        assertToken(JsonToken.END_OBJECT, jp.getCurrentToken());
+        assertToken(JsonToken.END_OBJECT, jp.currentToken());
         jp.close();
         gen.close();
 
diff --git a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorMisc.java b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorMisc.java
index 08771c8..ded2380 100644
--- a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorMisc.java
+++ b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorMisc.java
@@ -11,6 +11,7 @@
  * Set of basic unit tests for verifying basic generator
  * features.
  */
+@SuppressWarnings("resource")
 public class TestGeneratorMisc
     extends com.fasterxml.jackson.core.BaseTest
 {
@@ -20,8 +21,7 @@
     /**********************************************************
      */
 
-    public void testIsClosed()
-        throws IOException
+    public void testIsClosed() throws IOException
     {
         JsonFactory jf = new JsonFactory();
         for (int i = 0; i < 2; ++i) {
@@ -240,46 +240,41 @@
      */
     public void testLongerObjects() throws Exception
     {
-        JsonFactory jf = new JsonFactory();
-        for (int i = 0; i < 2; ++i) {
-            boolean useChars = (i == 0);
-            JsonGenerator jgen;
-            ByteArrayOutputStream bout = new ByteArrayOutputStream(200);
-            if (useChars) {
-                jgen = jf.createGenerator(new OutputStreamWriter(bout, "UTF-8"));
-            } else {
-                jgen = jf.createGenerator(bout, JsonEncoding.UTF8);
+        final JsonFactory jf = new JsonFactory();
+        _testLongerObjects(jf, 0);
+        _testLongerObjects(jf, 1);
+        _testLongerObjects(jf, 2);
+    }
+
+    public void _testLongerObjects(JsonFactory jf, int mode) throws Exception
+    {
+        JsonGenerator g;
+        ByteArrayOutputStream bout = new ByteArrayOutputStream(200);
+
+        switch (mode) {
+        case 0:
+            g = jf.createGenerator(new OutputStreamWriter(bout, "UTF-8"));
+            break;
+        case 1:
+            g = jf.createGenerator(bout, JsonEncoding.UTF8);
+            break;
+        case 2:
+            {
+                DataOutputStream dout = new DataOutputStream(bout);
+                g = jf.createGenerator((DataOutput) dout);
             }
+        
+            break;
+        default:
+            fail("Unknown mode "+mode);
+            g = null;
+        }
 
-            jgen.writeStartObject();
+        g.writeStartObject();
 
-            for (int rounds = 0; rounds < 1500; ++rounds) {
-                for (int letter = 'a'; letter <= 'z'; ++letter) {
-                    for (int index = 0; index < 20; ++index) {
-                        String name;
-                        if (letter > 'f') {
-                            name = "X"+letter+index;
-                        } else if (letter > 'p') {
-                            name = ""+letter+index;
-                        } else {
-                            name = "__"+index+letter;
-                        }
-                        jgen.writeFieldName(name);
-                        jgen.writeNumber(index-1);
-                    }
-                    jgen.writeRaw('\n');
-                }
-            }
-            jgen.writeEndObject();
-            jgen.close();
-
-            byte[] json = bout.toByteArray();
-            JsonParser jp = jf.createParser(json);
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-            for (int rounds = 0; rounds < 1500; ++rounds) {
+        for (int rounds = 0; rounds < 1500; ++rounds) {
             for (int letter = 'a'; letter <= 'z'; ++letter) {
                 for (int index = 0; index < 20; ++index) {
-                    assertToken(JsonToken.FIELD_NAME, jp.nextToken());
                     String name;
                     if (letter > 'f') {
                         name = "X"+letter+index;
@@ -288,14 +283,37 @@
                     } else {
                         name = "__"+index+letter;
                     }
-                    assertEquals(name, jp.getCurrentName());
-                    assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-                    assertEquals(index-1, jp.getIntValue());
+                    g.writeFieldName(name);
+                    g.writeNumber(index-1);
                 }
+                g.writeRaw('\n');
             }
-            }
-            assertToken(JsonToken.END_OBJECT, jp.nextToken());
-            jp.close();
         }
+        g.writeEndObject();
+        g.close();
+
+        byte[] json = bout.toByteArray();
+        JsonParser jp = jf.createParser(json);
+        assertToken(JsonToken.START_OBJECT, jp.nextToken());
+        for (int rounds = 0; rounds < 1500; ++rounds) {
+        for (int letter = 'a'; letter <= 'z'; ++letter) {
+            for (int index = 0; index < 20; ++index) {
+                assertToken(JsonToken.FIELD_NAME, jp.nextToken());
+                String name;
+                if (letter > 'f') {
+                    name = "X"+letter+index;
+                } else if (letter > 'p') {
+                    name = ""+letter+index;
+                } else {
+                    name = "__"+index+letter;
+                }
+                assertEquals(name, jp.getCurrentName());
+                assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+                assertEquals(index-1, jp.getIntValue());
+            }
+        }
+        }
+        assertToken(JsonToken.END_OBJECT, jp.nextToken());
+        jp.close();
     }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorObject.java b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorObject.java
index 3f0eaae..e92f1dd 100644
--- a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorObject.java
+++ b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorObject.java
@@ -65,7 +65,7 @@
             gen.writeEndArray();
             fail("Expected an exception for mismatched array/object write");
         } catch (JsonGenerationException e) {
-            verifyException(e, "Current context not an array");
+            verifyException(e, "Current context not Array");
         }
         gen.close();
     }
diff --git a/src/test/java/com/fasterxml/jackson/core/main/TestParserFeatures.java b/src/test/java/com/fasterxml/jackson/core/main/TestParserFeatures.java
index c66d5a6..e1841f1 100644
--- a/src/test/java/com/fasterxml/jackson/core/main/TestParserFeatures.java
+++ b/src/test/java/com/fasterxml/jackson/core/main/TestParserFeatures.java
@@ -1,5 +1,7 @@
 package com.fasterxml.jackson.core.main;
 
+import java.io.*;
+
 import com.fasterxml.jackson.core.*;
 
 /**
@@ -9,7 +11,7 @@
 public class TestParserFeatures
     extends com.fasterxml.jackson.core.BaseTest
 {
-    public void testDefaultSettings()
+    public void testDefaultSettings() throws Exception
     {
         JsonFactory f = new JsonFactory();
         assertTrue(f.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
@@ -17,6 +19,13 @@
         assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES));
         assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_SINGLE_QUOTES));
         assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS));
+
+        JsonParser p = f.createParser(new StringReader("{}"));
+        _testDefaultSettings(p);
+        p.close();
+        p = f.createParser(new ByteArrayInputStream("{}".getBytes("UTF-8")));
+        _testDefaultSettings(p);
+        p.close();
     }
 
     public void testQuotesRequired() throws Exception
@@ -25,7 +34,6 @@
         _testQuotesRequired(true);
     }
 
-
     // // Tests for [JACKSON-208], unquoted tabs:
 
     public void testTabsDefault() throws Exception
@@ -46,23 +54,28 @@
     /****************************************************************
      */
 
+    private void _testDefaultSettings(JsonParser p) {
+        assertFalse(p.canReadObjectId());
+        assertFalse(p.canReadTypeId());
+    }
+    
     private void _testQuotesRequired(boolean useStream) throws Exception
     {
         final String JSON = "{ test : 3 }";
         final String EXP_ERROR_FRAGMENT = "was expecting double-quote to start";
         JsonFactory f = new JsonFactory();
-        JsonParser jp = useStream ?
+        JsonParser p = useStream ?
             createParserUsingStream(f, JSON, "UTF-8")
             : createParserUsingReader(f, JSON)
             ;
 
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
         try {
-            jp.nextToken();
+            p.nextToken();
         } catch (JsonParseException je) {
             verifyException(je, EXP_ERROR_FRAGMENT);
         } finally {
-            jp.close();
+            p.close();
         }
     }
 
@@ -73,16 +86,16 @@
         JsonFactory f = new JsonFactory();
         // First, let's see that by default unquoted tabs are illegal
         String JSON = "[\"tab:\t\"]";
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8") : createParserUsingReader(f, JSON);
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
+        JsonParser p = useStream ? createParserUsingStream(f, JSON, "UTF-8") : createParserUsingReader(f, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
         try {
-            jp.nextToken();
-            jp.getText();
+            p.nextToken();
+            p.getText();
             fail("Expected exception");
         } catch (JsonParseException e) {
             verifyException(e, "Illegal unquoted character");
         } finally {
-            jp.close();
+            p.close();
         }
     }
 
@@ -94,14 +107,14 @@
         String FIELD = "a\tb";
         String VALUE = "\t";
         String JSON = "{ "+quote(FIELD)+" : "+quote(VALUE)+"}";
-        JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8") : createParserUsingReader(f, JSON);
+        JsonParser p = useStream ? createParserUsingStream(f, JSON, "UTF-8") : createParserUsingReader(f, JSON);
 
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertEquals(FIELD, jp.getText());
-        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
-        assertEquals(VALUE, jp.getText());
-        assertToken(JsonToken.END_OBJECT, jp.nextToken());
-        jp.close();
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals(FIELD, p.getText());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(VALUE, p.getText());
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        p.close();
     }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/main/TestScopeMatching.java b/src/test/java/com/fasterxml/jackson/core/main/TestScopeMatching.java
deleted file mode 100644
index 7a55088..0000000
--- a/src/test/java/com/fasterxml/jackson/core/main/TestScopeMatching.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package com.fasterxml.jackson.core.main;
-
-
-import com.fasterxml.jackson.core.*;
-
-/**
- * Set of basic unit tests for verifying that Array/Object scopes
- * are properly matched.
- */
-public class TestScopeMatching
-    extends BaseTest
-{
-    public void testUnclosedArray() throws Exception
-    {
-        @SuppressWarnings("resource")
-        JsonParser jp = createParserUsingReader("[ 1, 2");
-        assertToken(JsonToken.START_ARRAY, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-
-        try {
-            jp.nextToken();
-            fail("Expected an exception for unclosed ARRAY");
-        } catch (JsonParseException jpe) {
-            verifyException(jpe, "expected close marker for ARRAY");
-        }
-    }
-
-    public void testUnclosedObject() throws Exception
-    {
-        @SuppressWarnings("resource")
-        JsonParser jp = createParserUsingReader("{ \"key\" : 3  ");
-        assertToken(JsonToken.START_OBJECT, jp.nextToken());
-        assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-
-        try {
-            jp.nextToken();
-            fail("Expected an exception for unclosed OBJECT");
-        } catch (JsonParseException jpe) {
-            verifyException(jpe, "expected close marker for OBJECT");
-        }
-    }
-
-    public void testEOFInName()
-        throws Exception
-    {
-        final String JSON = "{ \"abcd";
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp = (i == 0) ? createParserUsingReader(JSON)
-                : createParserUsingStream(JSON, "UTF-8");
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-            try {
-                jp.nextToken();
-                fail("Expected an exception for EOF");
-            } catch (JsonParseException jpe) {
-                verifyException(jpe, "Unexpected end-of-input");
-            }
-            jp.close();
-        }
-    }
-
-    public void testWeirdToken()
-        throws Exception
-    {
-        final String JSON = "[ nil ]";
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp = (i == 0) ? createParserUsingReader(JSON)
-                : createParserUsingStream(JSON, "UTF-8");
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            try {
-                jp.nextToken();
-                fail("Expected an exception for weird token");
-            } catch (JsonParseException jpe) {
-                verifyException(jpe, "Unrecognized token");
-            }
-            jp.close();
-        }
-    }
-
-    public void testMismatchArrayToObject()
-        throws Exception
-    {
-        final String JSON = "[ 1, 2 }";
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp = (i == 0) ? createParserUsingReader(JSON)
-                : createParserUsingStream(JSON, "UTF-8");
-            assertToken(JsonToken.START_ARRAY, jp.nextToken());
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
-            try {
-                jp.nextToken();
-                fail("Expected an exception for incorrectly closed ARRAY");
-            } catch (JsonParseException jpe) {
-                verifyException(jpe, "Unexpected close marker '}': expected ']'");
-            }
-            jp.close();
-        }
-    }
-
-    public void testMismatchObjectToArray()
-        throws Exception
-    {
-        final String JSON = "{ ]";
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp = (i == 0) ? createParserUsingReader(JSON)
-                : createParserUsingStream(JSON, "UTF-8");
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-            
-            try {
-                jp.nextToken();
-                fail("Expected an exception for incorrectly closed OBJECT");
-            } catch (JsonParseException jpe) {
-                verifyException(jpe, "Unexpected close marker ']': expected '}'");
-            }
-            jp.close();
-        }
-    }
-
-    public void testMisssingColon()
-        throws Exception
-    {
-        final String JSON = "{ \"a\" \"b\" }";
-        for (int i = 0; i < 2; ++i) {
-            JsonParser jp = (i == 0) ? createParserUsingReader(JSON)
-                : createParserUsingStream(JSON, "UTF-8");
-            assertToken(JsonToken.START_OBJECT, jp.nextToken());
-            try {
-                // can be either here, or with next one...
-                assertToken(JsonToken.FIELD_NAME, jp.nextToken());
-                jp.nextToken();
-                fail("Expected an exception for missing semicolon");
-            } catch (JsonParseException jpe) {
-                verifyException(jpe, "was expecting a colon");
-            }
-            jp.close();
-        }
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/TestBase64Parsing.java b/src/test/java/com/fasterxml/jackson/core/read/Base64BinaryParsingTest.java
similarity index 68%
rename from src/test/java/com/fasterxml/jackson/core/base64/TestBase64Parsing.java
rename to src/test/java/com/fasterxml/jackson/core/read/Base64BinaryParsingTest.java
index 783efa6..fbd7126 100644
--- a/src/test/java/com/fasterxml/jackson/core/base64/TestBase64Parsing.java
+++ b/src/test/java/com/fasterxml/jackson/core/read/Base64BinaryParsingTest.java
@@ -1,4 +1,4 @@
-package com.fasterxml.jackson.core.base64;
+package com.fasterxml.jackson.core.read;
 
 import static org.junit.Assert.assertArrayEquals;
 
@@ -6,24 +6,27 @@
 
 import com.fasterxml.jackson.core.*;
 
-public class TestBase64Parsing
+public class Base64BinaryParsingTest
     extends com.fasterxml.jackson.core.BaseTest
 {
     public void testBase64UsingInputStream() throws Exception
     {
-        _testBase64Text(true);
+        _testBase64Text(MODE_INPUT_STREAM);
+        _testBase64Text(MODE_INPUT_STREAM_THROTTLED);
+        _testBase64Text(MODE_DATA_INPUT);
     }
 
     public void testBase64UsingReader() throws Exception
     {
-        _testBase64Text(false);
+        _testBase64Text(MODE_READER);
     }
 
-    // [Issue-15] (streaming binary reads)
     public void testStreaming() throws IOException
     {
-        _testStreaming(false);
-        _testStreaming(true);
+        _testStreaming(MODE_INPUT_STREAM);
+        _testStreaming(MODE_INPUT_STREAM_THROTTLED);
+        _testStreaming(MODE_DATA_INPUT);
+        _testStreaming(MODE_READER);
     }
 
     /*
@@ -31,10 +34,9 @@
     /* Test helper methods
     /**********************************************************
      */
-    
-    // Test for [JACKSON-631]
+
     @SuppressWarnings("resource")
-    public void _testBase64Text(boolean useBytes) throws Exception
+    public void _testBase64Text(int mode) throws Exception
     {
         // let's actually iterate over sets of encoding modes, lengths
         
@@ -55,26 +57,27 @@
                 input[i] = (byte) i;
             }
             for (Base64Variant variant : VARIANTS) {
-                JsonGenerator jgen;
-                if (useBytes) {
-                    bytes.reset();
-                    jgen = jsonFactory.createGenerator(bytes, JsonEncoding.UTF8);
-                } else {
+                JsonGenerator g;
+
+                if (mode == MODE_READER) {
                     chars = new StringWriter();
-                    jgen = jsonFactory.createGenerator(chars);
-                }
-                jgen.writeBinary(variant, input, 0, input.length);
-                jgen.close();
-                JsonParser jp;
-                if (useBytes) {
-                    jp = jsonFactory.createParser(bytes.toByteArray());
+                    g = jsonFactory.createGenerator(chars);
                 } else {
-                    jp = jsonFactory.createParser(chars.toString());
+                    bytes.reset();
+                    g = jsonFactory.createGenerator(bytes, JsonEncoding.UTF8);
                 }
-                assertToken(JsonToken.VALUE_STRING, jp.nextToken());
+                g.writeBinary(variant, input, 0, input.length);
+                g.close();
+                JsonParser p;
+                if (mode == MODE_READER) {
+                    p = jsonFactory.createParser(chars.toString());
+                } else {
+                    p = createParser(jsonFactory, mode, bytes.toByteArray());
+                }
+                assertToken(JsonToken.VALUE_STRING, p.nextToken());
                 byte[] data = null;
                 try {
-                    data = jp.getBinaryValue(variant);
+                    data = p.getBinaryValue(variant);
                 } catch (Exception e) {
                     IOException ioException = new IOException("Failed (variant "+variant+", data length "+len+"): "+e.getMessage());
                     ioException.initCause(e);
@@ -82,8 +85,10 @@
                 }
                 assertNotNull(data);
                 assertArrayEquals(data, input);
-                assertNull(jp.nextToken());
-                jp.close();
+                if (mode != MODE_DATA_INPUT) { // no look-ahead for DataInput
+                    assertNull(p.nextToken());
+                }
+                p.close();
             }
         }
     }
@@ -97,7 +102,7 @@
         return result;
     }
 
-    private void _testStreaming(boolean useBytes) throws IOException
+    private void _testStreaming(int mode) throws IOException
     {
         final int[] SIZES = new int[] {
             1, 2, 3, 4, 5, 6,
@@ -113,12 +118,12 @@
         for (int size : SIZES) {
             byte[] data = _generateData(size);
             JsonGenerator g;
-            if (useBytes) {
-                bytes.reset();
-                g = jsonFactory.createGenerator(bytes, JsonEncoding.UTF8);
-            } else {
+            if (mode == MODE_READER) {
                 chars = new StringWriter();
                 g = jsonFactory.createGenerator(chars);
+            } else {
+                bytes.reset();
+                g = jsonFactory.createGenerator(bytes, JsonEncoding.UTF8);
             }
 
             g.writeStartObject();
@@ -129,10 +134,10 @@
 
             // and verify
             JsonParser p;
-            if (useBytes) {
-                p = jsonFactory.createParser(bytes.toByteArray());
-            } else {
+            if (mode == MODE_READER) {
                 p = jsonFactory.createParser(chars.toString());
+            } else {
+                p = createParser(jsonFactory, mode, bytes.toByteArray());
             }
             assertToken(JsonToken.START_OBJECT, p.nextToken());
     
@@ -144,7 +149,9 @@
             assertEquals(size, gotten);
             assertArrayEquals(data, result.toByteArray());
             assertToken(JsonToken.END_OBJECT, p.nextToken());
-            assertNull(p.nextToken());
+            if (mode != MODE_DATA_INPUT) { // no look-ahead for DataInput
+                assertNull(p.nextToken());
+            }
             p.close();
         }
     }
diff --git a/src/test/java/com/fasterxml/jackson/core/read/CommentParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/CommentParsingTest.java
new file mode 100644
index 0000000..dfc12c5
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/CommentParsingTest.java
@@ -0,0 +1,286 @@
+package com.fasterxml.jackson.core.read;
+
+import java.io.*;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Unit tests for verifying that support for (non-standard) comments
+ * works as expected.
+ */
+public class CommentParsingTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    final static String DOC_WITH_SLASHSTAR_COMMENT =
+        "[ /* comment:\n ends here */ 1 /* one more ok to have \"unquoted\"  */ ]"
+        ;
+
+    final static String DOC_WITH_SLASHSLASH_COMMENT =
+        "[ // comment...\n 1 \r  // one more, not array: []   \n ]"
+        ;
+
+    /*
+    /**********************************************************
+    /* Test method wrappers
+    /**********************************************************
+     */
+    
+    /**
+     * Unit test for verifying that by default comments are not
+     * recognized.
+     */
+    public void testDefaultSettings() throws Exception
+    {
+        JsonFactory jf = new JsonFactory();
+        assertFalse(jf.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
+        JsonParser p = jf.createParser(new StringReader("[ 1 ]"));
+        assertFalse(p.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
+        p.close();
+    }
+
+    public void testCommentsDisabled() throws Exception
+    {
+        _testDisabled(DOC_WITH_SLASHSTAR_COMMENT, MODE_INPUT_STREAM);
+        _testDisabled(DOC_WITH_SLASHSLASH_COMMENT, MODE_INPUT_STREAM);
+        _testDisabled(DOC_WITH_SLASHSTAR_COMMENT, MODE_INPUT_STREAM_THROTTLED);
+        _testDisabled(DOC_WITH_SLASHSLASH_COMMENT, MODE_INPUT_STREAM_THROTTLED);
+        _testDisabled(DOC_WITH_SLASHSTAR_COMMENT, MODE_READER);
+        _testDisabled(DOC_WITH_SLASHSLASH_COMMENT, MODE_READER);
+        _testDisabled(DOC_WITH_SLASHSTAR_COMMENT, MODE_DATA_INPUT);
+        _testDisabled(DOC_WITH_SLASHSLASH_COMMENT, MODE_DATA_INPUT);
+    }
+
+    public void testCommentsEnabled() throws Exception
+    {
+        _testEnabled(DOC_WITH_SLASHSTAR_COMMENT, MODE_INPUT_STREAM);
+        _testEnabled(DOC_WITH_SLASHSLASH_COMMENT, MODE_INPUT_STREAM);
+        _testEnabled(DOC_WITH_SLASHSTAR_COMMENT, MODE_INPUT_STREAM_THROTTLED);
+        _testEnabled(DOC_WITH_SLASHSLASH_COMMENT, MODE_INPUT_STREAM_THROTTLED);
+        _testEnabled(DOC_WITH_SLASHSTAR_COMMENT, MODE_READER);
+        _testEnabled(DOC_WITH_SLASHSLASH_COMMENT, MODE_READER);
+        _testEnabled(DOC_WITH_SLASHSTAR_COMMENT, MODE_DATA_INPUT);
+        _testEnabled(DOC_WITH_SLASHSLASH_COMMENT, MODE_DATA_INPUT);
+    }
+
+    public void testCommentsWithUTF8() throws Exception
+    {
+        final String JSON = "/* \u00a9 2099 Yoyodyne Inc. */\n [ \"bar? \u00a9\" ]\n";
+        _testWithUTF8Chars(JSON, MODE_INPUT_STREAM);
+        _testWithUTF8Chars(JSON, MODE_INPUT_STREAM_THROTTLED);
+        _testWithUTF8Chars(JSON, MODE_READER);
+        _testWithUTF8Chars(JSON, MODE_DATA_INPUT);
+    }
+
+    public void testYAMLCommentsBytes() throws Exception {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true);
+
+        _testYAMLComments(f, MODE_INPUT_STREAM);
+        _testCommentsBeforePropValue(f, MODE_INPUT_STREAM, "# foo\n");
+        _testYAMLComments(f, MODE_INPUT_STREAM_THROTTLED);
+        _testCommentsBeforePropValue(f, MODE_INPUT_STREAM_THROTTLED, "# foo\n");
+        _testYAMLComments(f, MODE_DATA_INPUT);
+        _testCommentsBeforePropValue(f, MODE_DATA_INPUT, "# foo\n");
+    }
+
+    public void testYAMLCommentsChars() throws Exception {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true);
+        _testYAMLComments(f, MODE_READER);
+        final String COMMENT = "# foo\n";
+        _testCommentsBeforePropValue(f, MODE_READER, COMMENT);
+        _testCommentsBetweenArrayValues(f, MODE_READER, COMMENT);
+    }
+
+    public void testCCommentsBytes() throws Exception {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+        final String COMMENT = "/* foo */\n";
+        _testCommentsBeforePropValue(f, MODE_INPUT_STREAM, COMMENT);
+        _testCommentsBeforePropValue(f, MODE_INPUT_STREAM_THROTTLED, COMMENT);
+        _testCommentsBeforePropValue(f, MODE_DATA_INPUT, COMMENT);
+    }
+
+    public void testCCommentsChars() throws Exception {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+        final String COMMENT = "/* foo */\n";
+        _testCommentsBeforePropValue(f, MODE_READER, COMMENT);
+    }
+
+    public void testCppCommentsBytes() throws Exception {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+        final String COMMENT = "// foo\n";
+        _testCommentsBeforePropValue(f, MODE_INPUT_STREAM, COMMENT);
+        _testCommentsBeforePropValue(f, MODE_INPUT_STREAM_THROTTLED, COMMENT);
+        _testCommentsBeforePropValue(f, MODE_DATA_INPUT, COMMENT);
+    }
+
+    public void testCppCommentsChars() throws Exception {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+        final String COMMENT = "// foo \n";
+        _testCommentsBeforePropValue(f, MODE_READER, COMMENT);
+    }
+
+    @SuppressWarnings("resource")
+    private void _testCommentsBeforePropValue(JsonFactory f,
+            int mode, String comment) throws Exception
+    {
+        for (String arg : new String[] {
+                ":%s123",
+                " :%s123",
+                "\t:%s123",
+                ": %s123",
+                ":\t%s123",
+        }) {
+            String commented = String.format(arg, comment);
+            
+            final String DOC = "{\"abc\"" + commented + "}";
+            JsonParser p = createParser(f, mode, DOC);
+            assertEquals(JsonToken.START_OBJECT, p.nextToken());
+            JsonToken t = null;
+            try {
+                t = p.nextToken();
+            } catch (Exception e) {
+                throw new RuntimeException("Failed on '"+DOC+"' due to "+e, e);
+            }
+            assertEquals(JsonToken.FIELD_NAME, t);
+
+            try {
+                t = p.nextToken();
+            } catch (Exception e) {
+                throw new RuntimeException("Failed on '"+DOC+"' due to "+e, e);
+            }
+            assertEquals(JsonToken.VALUE_NUMBER_INT, t);
+            assertEquals(123, p.getIntValue());
+            assertEquals(JsonToken.END_OBJECT, p.nextToken());
+            p.close();
+        }
+        
+    }
+
+    @SuppressWarnings("resource")
+    private void _testCommentsBetweenArrayValues(JsonFactory f,
+            int mode, String comment) throws Exception
+    {
+        for (String tmpl : new String[] {
+                "%s,",
+                " %s,",
+                "\t%s,",
+                "%s ,",
+                "%s\t,",
+                " %s ,",
+                "\t%s\t,",
+                "\n%s,",
+                "%s\n,",
+        }) {
+            String commented = String.format(tmpl, comment);
+            
+            final String DOC = "[1"+commented+"2]";
+            JsonParser p = createParser(f, mode, DOC);
+            assertEquals(JsonToken.START_ARRAY, p.nextToken());
+            JsonToken t = null;
+            try {
+                t = p.nextToken();
+            } catch (Exception e) {
+                throw new RuntimeException("Failed on '"+DOC+"' due to "+e, e);
+            }
+            assertEquals(JsonToken.VALUE_NUMBER_INT, t);
+            assertEquals(1, p.getIntValue());
+
+            try {
+                t = p.nextToken();
+            } catch (Exception e) {
+                throw new RuntimeException("Failed on '"+DOC+"' due to "+e, e);
+            }
+            assertEquals(JsonToken.VALUE_NUMBER_INT, t);
+            assertEquals(2, p.getIntValue());
+            assertEquals(JsonToken.END_ARRAY, p.nextToken());
+            p.close();
+        }
+        
+    }
+    
+    private void _testYAMLComments(JsonFactory f, int mode) throws Exception
+    {
+        final String DOC = "# foo\n"
+                +" {\"a\" # xyz\n"
+                +" : # foo\n"
+                +" 1, # more\n"
+                +"\"b\": [ \n"
+                +" #all!\n"
+                +" 3 #yay!\n"
+                +"] # foobar\n"
+                +"} # x"
+                ;
+        JsonParser p = createParser(f, mode, DOC);
+        assertEquals(JsonToken.START_OBJECT, p.nextToken());
+        assertEquals(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("a", p.getCurrentName());
+        assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(1, p.getIntValue());
+        assertEquals(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("b", p.getCurrentName());
+        assertEquals(JsonToken.START_ARRAY, p.nextToken());
+        assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(3, p.getIntValue());
+        assertEquals(JsonToken.END_ARRAY, p.nextToken());
+        assertEquals(JsonToken.END_OBJECT, p.nextToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextToken());
+        }
+        p.close();
+    }
+
+    /*
+    /**********************************************************
+    /* Helper methods
+    /**********************************************************
+     */
+
+    private void _testWithUTF8Chars(String doc, int mode) throws IOException
+    {
+        // should basically just stream through
+        JsonParser p = _createParser(doc, mode, true);
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextToken());
+        }
+        p.close();
+    }
+    
+    private void _testDisabled(String doc, int mode) throws IOException
+    {
+        JsonParser p = _createParser(doc, mode, false);
+        try {
+            p.nextToken();
+            fail("Expected exception for unrecognized comment");
+        } catch (JsonParseException je) {
+            // Should have something denoting that user may want to enable 'ALLOW_COMMENTS'
+            verifyException(je, "ALLOW_COMMENTS");
+        }
+        p.close();
+    }
+
+    private void _testEnabled(String doc, int mode) throws IOException
+    {
+        JsonParser p = _createParser(doc, mode, true);
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(1, p.getIntValue());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+    }
+
+    private JsonParser _createParser(String doc, int mode, boolean enabled)
+        throws IOException
+    {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_COMMENTS, enabled);
+        JsonParser p = createParser(f, mode, doc);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        return p;
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/JsonParserTest.java b/src/test/java/com/fasterxml/jackson/core/read/JsonParserTest.java
new file mode 100644
index 0000000..55442e1
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/JsonParserTest.java
@@ -0,0 +1,710 @@
+package com.fasterxml.jackson.core.read;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.testsupport.MockDataInput;
+import com.fasterxml.jackson.core.util.JsonParserDelegate;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+
+/**
+ * Set of basic unit tests for verifying that the basic parser
+ * functionality works as expected.
+ */
+@SuppressWarnings("resource")
+public class JsonParserTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    public void testConfig() throws Exception
+    {
+        JsonParser p = createParserUsingReader("[ ]");
+        p.enable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
+        assertTrue(p.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
+        p.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
+        assertFalse(p.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
+
+        p.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
+        assertTrue(p.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
+        p.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
+        assertFalse(p.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
+        p.close();
+    }
+
+    public void testInterningWithStreams() throws Exception
+    {
+        _testIntern(true, true, "a");
+        _testIntern(true, false, "b");
+    }
+
+    public void testInterningWithReaders() throws Exception
+    {
+        _testIntern(false, true, "c");
+        _testIntern(false, false, "d");
+    }
+    
+    private void _testIntern(boolean useStream, boolean enableIntern, String expName) throws IOException
+    {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonFactory.Feature.INTERN_FIELD_NAMES, enableIntern);
+        assertEquals(enableIntern, f.isEnabled(JsonFactory.Feature.INTERN_FIELD_NAMES));
+        final String JSON = "{ \""+expName+"\" : 1}";
+        JsonParser p = useStream ?
+            createParserUsingStream(f, JSON, "UTF-8") : createParserUsingReader(f, JSON);
+            
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        // needs to be same of cours
+        String actName = p.getCurrentName();
+        assertEquals(expName, actName);
+        if (enableIntern) {
+            assertSame(expName, actName);
+        } else {
+            assertNotSame(expName, actName);
+        }
+        p.close();
+    }
+
+    /**
+     * This basic unit test verifies that example given in the JSON
+     * specification (RFC-4627 or later) is properly parsed at
+     * high-level, without verifying values.
+     */
+    public void testSpecExampleSkipping() throws Exception
+    {
+        _doTestSpec(false);
+    }
+
+    /**
+     * Unit test that verifies that the spec example JSON is completely
+     * parsed, and proper values are given for contents of all
+     * events/tokens.
+     */
+    public void testSpecExampleFully() throws Exception
+    {
+        _doTestSpec(true);
+    }
+
+    /**
+     * Unit test that verifies that 3 basic keywords (null, true, false)
+     * are properly parsed in various contexts.
+     */
+    public void testKeywords() throws Exception
+    {
+        final String DOC = "{\n"
+            +"\"key1\" : null,\n"
+            +"\"key2\" : true,\n"
+            +"\"key3\" : false,\n"
+            +"\"key4\" : [ false, null, true ]\n"
+            +"}"
+            ;
+
+        JsonParser p = createParserUsingStream(JSON_FACTORY, DOC, "UTF-8");
+        _testKeywords(p, true);
+        p.close();
+
+        p = createParserUsingReader(JSON_FACTORY, DOC);
+        _testKeywords(p, true);
+        p.close();
+
+        p = createParserForDataInput(JSON_FACTORY, new MockDataInput(DOC));
+        _testKeywords(p, false);
+        p.close();
+    }
+
+    private void _testKeywords(JsonParser p, boolean checkColumn) throws Exception
+    {
+        JsonStreamContext ctxt = p.getParsingContext();
+        assertEquals("/", ctxt.toString());
+        assertTrue(ctxt.inRoot());
+        assertFalse(ctxt.inArray());
+        assertFalse(ctxt.inObject());
+        assertEquals(0, ctxt.getEntryCount());
+        assertEquals(0, ctxt.getCurrentIndex());
+
+        // Before advancing to content, we should have following default state...
+        assertFalse(p.hasCurrentToken());
+        assertNull(p.getText());
+        assertNull(p.getTextCharacters());
+        assertEquals(0, p.getTextLength());
+        // not sure if this is defined but:
+        assertEquals(0, p.getTextOffset());
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertEquals("/", ctxt.toString());
+
+        assertTrue(p.hasCurrentToken());
+        JsonLocation loc = p.getTokenLocation();
+        assertNotNull(loc);
+        assertEquals(1, loc.getLineNr());
+        if (checkColumn) {
+            assertEquals(1, loc.getColumnNr());
+        }
+
+        ctxt = p.getParsingContext();
+        assertFalse(ctxt.inRoot());
+        assertFalse(ctxt.inArray());
+        assertTrue(ctxt.inObject());
+        assertEquals(0, ctxt.getEntryCount());
+        assertEquals(0, ctxt.getCurrentIndex());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        verifyFieldName(p, "key1");
+        assertEquals("{\"key1\"}", ctxt.toString());
+        assertEquals(2, p.getTokenLocation().getLineNr());
+
+        ctxt = p.getParsingContext();
+        assertFalse(ctxt.inRoot());
+        assertFalse(ctxt.inArray());
+        assertTrue(ctxt.inObject());
+        assertEquals(1, ctxt.getEntryCount());
+        assertEquals(0, ctxt.getCurrentIndex());
+        assertEquals("key1", ctxt.getCurrentName());
+
+        assertToken(JsonToken.VALUE_NULL, p.nextToken());
+        assertEquals("key1", ctxt.getCurrentName());
+
+        ctxt = p.getParsingContext();
+        assertEquals(1, ctxt.getEntryCount());
+        assertEquals(0, ctxt.getCurrentIndex());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        verifyFieldName(p, "key2");
+        ctxt = p.getParsingContext();
+        assertEquals(2, ctxt.getEntryCount());
+        assertEquals(1, ctxt.getCurrentIndex());
+        assertEquals("key2", ctxt.getCurrentName());
+
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertEquals("key2", ctxt.getCurrentName());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        verifyFieldName(p, "key3");
+        assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        verifyFieldName(p, "key4");
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        ctxt = p.getParsingContext();
+        assertTrue(ctxt.inArray());
+        assertNull(ctxt.getCurrentName());
+        assertEquals("key4", ctxt.getParent().getCurrentName());
+        
+        assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+        assertEquals("[0]", ctxt.toString());
+
+        assertToken(JsonToken.VALUE_NULL, p.nextToken());
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+
+        ctxt = p.getParsingContext();
+        assertTrue(ctxt.inObject());
+
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        ctxt = p.getParsingContext();
+        assertTrue(ctxt.inRoot());
+        assertNull(ctxt.getCurrentName());
+    }
+
+    public void testSkipping() throws Exception {
+        _testSkipping(MODE_INPUT_STREAM);
+        _testSkipping(MODE_INPUT_STREAM_THROTTLED);
+        _testSkipping(MODE_READER);
+        _testSkipping(MODE_DATA_INPUT);
+    }
+
+    private void _testSkipping(int mode) throws Exception
+    {
+        // InputData has some limitations to take into consideration
+        boolean isInputData = (mode == MODE_DATA_INPUT);
+        String DOC =
+            "[ 1, 3, [ true, null ], 3, { \"a\":\"b\" }, [ [ ] ], { } ]";
+            ;
+        JsonParser p = createParser(mode, DOC);
+
+        // First, skipping of the whole thing
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        p.skipChildren();
+        assertEquals(JsonToken.END_ARRAY, p.currentToken());
+        if (!isInputData) {
+            JsonToken t = p.nextToken();
+            if (t != null) {
+                fail("Expected null at end of doc, got "+t);
+            }
+        }
+        p.close();
+
+        // Then individual ones
+        p = createParser(mode, DOC);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        p.skipChildren();
+        // shouldn't move
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.currentToken());
+        assertEquals(1, p.getIntValue());
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        // then skip array
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        p.skipChildren();
+        assertToken(JsonToken.END_ARRAY, p.currentToken());
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        p.skipChildren();
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        p.skipChildren();
+        assertToken(JsonToken.END_ARRAY, p.currentToken());
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        p.skipChildren();
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+
+        p.close();
+    }
+
+    public void testNameEscaping() throws IOException
+    {
+        _testNameEscaping(MODE_INPUT_STREAM);
+        _testNameEscaping(MODE_READER);
+        _testNameEscaping(MODE_DATA_INPUT);
+    }
+
+    private void _testNameEscaping(int mode) throws IOException
+    {
+        final Map<String,String> NAME_MAP = new LinkedHashMap<String,String>();
+        NAME_MAP.put("", "");
+        NAME_MAP.put("\\\"funny\\\"", "\"funny\"");
+        NAME_MAP.put("\\\\", "\\");
+        NAME_MAP.put("\\r", "\r");
+        NAME_MAP.put("\\n", "\n");
+        NAME_MAP.put("\\t", "\t");
+        NAME_MAP.put("\\r\\n", "\r\n");
+        NAME_MAP.put("\\\"\\\"", "\"\"");
+        NAME_MAP.put("Line\\nfeed", "Line\nfeed");
+        NAME_MAP.put("Yet even longer \\\"name\\\"!", "Yet even longer \"name\"!");
+
+        int entry = 0;
+        for (Map.Entry<String,String> en : NAME_MAP.entrySet()) {
+            ++entry;
+            String input = en.getKey();
+            String expResult = en.getValue();
+            final String DOC = "{ \""+input+"\":null}";
+            JsonParser p = createParser(mode, DOC);
+
+            assertToken(JsonToken.START_OBJECT, p.nextToken());
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+            // first, sanity check (field name == getText()
+            String act = p.getCurrentName();
+            assertEquals(act, getAndVerifyText(p));
+            if (!expResult.equals(act)) {
+                String msg = "Failed for name #"+entry+"/"+NAME_MAP.size();
+                if (expResult.length() != act.length()) {
+                    fail(msg+": exp length "+expResult.length()+", actual "+act.length());
+                }
+                assertEquals(msg, expResult, act);
+            }
+            assertToken(JsonToken.VALUE_NULL, p.nextToken());
+            assertToken(JsonToken.END_OBJECT, p.nextToken());
+            p.close();
+        }
+    }
+    
+    /**
+     * Unit test that verifies that long text segments are handled
+     * correctly; mostly to stress-test underlying segment-based
+     * text buffer(s).
+     */
+    public void testLongText() throws Exception {
+        // lengths chosen to tease out problems with buffer allocation...
+        _testLongText(310);
+        _testLongText(7700);
+        _testLongText(49000);
+        _testLongText(96000);
+    }
+
+    private void _testLongText(int LEN) throws Exception
+    {
+        StringBuilder sb = new StringBuilder(LEN + 100);
+        Random r = new Random(LEN);
+        while (sb.length() < LEN) {
+            sb.append(r.nextInt());
+            sb.append(" xyz foo");
+            if (r.nextBoolean()) {
+                sb.append(" and \"bar\"");
+            } else if (r.nextBoolean()) {
+                sb.append(" [whatever].... ");
+            } else {
+                // Let's try some more 'exotic' chars
+                sb.append(" UTF-8-fu: try this {\u00E2/\u0BF8/\uA123!} (look funny?)");
+            }
+            if (r.nextBoolean()) {
+                if (r.nextBoolean()) {
+                    sb.append('\n');
+                } else if (r.nextBoolean()) {
+                    sb.append('\r');
+                } else {
+                    sb.append("\r\n");
+                }
+            }
+        }
+        final String VALUE = sb.toString();
+        
+        // Let's use real generator to get JSON done right
+        StringWriter sw = new StringWriter(LEN + (LEN >> 2));
+        JsonGenerator g = JSON_FACTORY.createGenerator(sw);
+        g.writeStartObject();
+        g.writeFieldName("doc");
+        g.writeString(VALUE);
+        g.writeEndObject();
+        g.close();
+        
+        final String DOC = sw.toString();
+
+        for (int type = 0; type < 4; ++type) {
+            JsonParser p;
+            switch (type) {
+            case MODE_INPUT_STREAM:
+            case MODE_READER:
+            case MODE_DATA_INPUT:
+                p = createParser(type, DOC);
+                break;
+            default:
+                p = JSON_FACTORY.createParser(encodeInUTF32BE(DOC));
+            }
+            assertToken(JsonToken.START_OBJECT, p.nextToken());
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+            assertEquals("doc", p.getCurrentName());
+            assertToken(JsonToken.VALUE_STRING, p.nextToken());
+
+            String act = getAndVerifyText(p);
+            if (act.length() != VALUE.length()) {
+                fail("Expected length "+VALUE.length()+", got "+act.length()+" (mode = "+type+")");
+            }
+            if (!act.equals(VALUE)) {
+                fail("Long text differs");
+            }
+
+            // should still know the field name
+            assertEquals("doc", p.getCurrentName());
+            assertToken(JsonToken.END_OBJECT, p.nextToken());
+
+            // InputDate somewhat special, so:
+            if (type != MODE_DATA_INPUT) {
+                assertNull(p.nextToken());
+            }
+            p.close();
+        }
+    }
+
+    /**
+     * Simple unit test that verifies that passing in a byte array
+     * as source works as expected.
+     */
+    public void testBytesAsSource() throws Exception
+    {
+        String JSON = "[ 1, 2, 3, 4 ]";
+        byte[] b = JSON.getBytes("UTF-8");
+        int offset = 50;
+        int len = b.length;
+        byte[] src = new byte[offset + len + offset];
+
+        System.arraycopy(b, 0, src, offset, len);
+
+        JsonParser p = JSON_FACTORY.createParser(src, offset, len);
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(1, p.getIntValue());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(2, p.getIntValue());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(3, p.getIntValue());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(4, p.getIntValue());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        assertNull(p.nextToken());
+
+        p.close();
+    }
+
+    public void testUtf8BOMHandling() throws Exception
+    {
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        // first, write BOM:
+        bytes.write(0xEF);
+        bytes.write(0xBB);
+        bytes.write(0xBF);
+        bytes.write("[ 1 ]".getBytes("UTF-8"));
+        byte[] input = bytes.toByteArray();
+
+        JsonParser p = JSON_FACTORY.createParser(input);
+        assertEquals(JsonToken.START_ARRAY, p.nextToken());
+        // should also have skipped first 3 bytes of BOM; but do we have offset available?
+        /* 08-Oct-2013, tatu: Alas, due to [core#111], we have to omit BOM in calculations
+         *   as we do not know what the offset is due to -- may need to revisit, if this
+         *   discrepancy becomes an issue. For now it just means that BOM is considered
+         *   "out of stream" (not part of input).
+         */
+        JsonLocation loc = p.getTokenLocation();
+        // so if BOM was consider in-stream (part of input), this should expect 3:
+        assertEquals(0, loc.getByteOffset());
+        assertEquals(-1, loc.getCharOffset());
+        assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+
+        p = JSON_FACTORY.createParser(new MockDataInput(input));
+        assertEquals(JsonToken.START_ARRAY, p.nextToken());
+        // same BOM, but DataInput is more restrctive so can skip but offsets
+        // are not reliable...
+        loc = p.getTokenLocation();
+        assertNotNull(loc);
+        assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+    }
+
+    // [core#48]
+    public void testSpacesInURL() throws Exception
+    {
+        File f = File.createTempFile("pre fix&stuff", ".txt");
+        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "UTF-8"));
+        w.write("{ }");
+        w.close();
+        URL url = f.toURI().toURL();
+
+        JsonParser p = JSON_FACTORY.createParser(url);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        p.close();
+    }
+
+    // [core#142]
+    public void testHandlingOfInvalidSpaceByteStream() throws Exception {
+        _testHandlingOfInvalidSpace(MODE_INPUT_STREAM);
+        _testHandlingOfInvalidSpaceFromResource(true);
+    }
+    
+    // [core#142]
+    public void testHandlingOfInvalidSpaceChars() throws Exception {
+        _testHandlingOfInvalidSpace(MODE_READER);
+        _testHandlingOfInvalidSpaceFromResource(false);
+    }
+
+    // [core#142]
+    public void testHandlingOfInvalidSpaceDataInput() throws Exception {
+        _testHandlingOfInvalidSpace(MODE_DATA_INPUT);
+    }
+    
+    private void _testHandlingOfInvalidSpace(int mode) throws Exception
+    {
+        final String JSON = "{ \u00A0 \"a\":1}";
+
+        JsonParser p = createParser(mode, JSON);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Should have failed");
+        } catch (JsonParseException e) {
+            verifyException(e, "unexpected character");
+            // and correct error code
+            verifyException(e, "code 160");
+        }
+        p.close();
+    }
+
+    private void _testHandlingOfInvalidSpaceFromResource(boolean useStream) throws Exception
+    {
+        InputStream in = getClass().getResourceAsStream("/test_0xA0.json");
+        JsonParser p = useStream
+                ? JSON_FACTORY.createParser(in)
+                : JSON_FACTORY.createParser(new InputStreamReader(in, "UTF-8"));
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        try {
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+            assertEquals("request", p.getCurrentName());
+            assertToken(JsonToken.START_OBJECT, p.nextToken());
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+            assertEquals("mac", p.getCurrentName());
+            assertToken(JsonToken.VALUE_STRING, p.nextToken());
+            assertNotNull(p.getText());
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+            assertEquals("data", p.getCurrentName());
+            assertToken(JsonToken.START_OBJECT, p.nextToken());
+
+            // ... and from there on, just loop
+            
+            while (p.nextToken()  != null) { }
+            fail("Should have failed");
+        } catch (JsonParseException e) {
+            verifyException(e, "unexpected character");
+            // and correct error code
+            verifyException(e, "code 160");
+        }
+        p.close();
+    }
+
+    public void testGetValueAsTextBytes() throws Exception
+    {
+        _testGetValueAsText(MODE_INPUT_STREAM, false);
+        _testGetValueAsText(MODE_INPUT_STREAM, true);
+    }
+
+    public void testGetValueAsTextDataInput() throws Exception
+    {
+        _testGetValueAsText(MODE_DATA_INPUT, false);
+        _testGetValueAsText(MODE_DATA_INPUT, true);
+    }
+    
+    public void testGetValueAsTextChars() throws Exception
+    {
+        _testGetValueAsText(MODE_READER, false);
+        _testGetValueAsText(MODE_READER, true);
+    }
+
+    private void _testGetValueAsText(int mode, boolean delegate) throws Exception
+    {
+        String JSON = "{\"a\":1,\"b\":true,\"c\":null,\"d\":\"foo\"}";
+        JsonParser p = createParser(mode, JSON);
+        if (delegate) {
+            p = new JsonParserDelegate(p);
+        }
+        
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertNull(p.getValueAsString());
+        assertEquals("foobar", p.getValueAsString("foobar"));
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("a", p.getText());
+        assertEquals("a", p.getValueAsString());
+        assertEquals("a", p.getValueAsString("default"));
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals("1", p.getValueAsString());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("b", p.getValueAsString());
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertEquals("true", p.getValueAsString());
+        assertEquals("true", p.getValueAsString("foobar"));
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("c", p.getValueAsString());
+        assertToken(JsonToken.VALUE_NULL, p.nextToken());
+        // null token returned as Java null, as per javadoc
+        assertNull(p.getValueAsString());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("d", p.getValueAsString());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("foo", p.getValueAsString("default"));
+        assertEquals("foo", p.getValueAsString());
+
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        assertNull(p.getValueAsString());
+
+        // InputData can't peek into end-of-input so:
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextToken());
+        }
+        p.close();
+    }
+
+    public void testGetTextViaWriter() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testGetTextViaWriter(mode);
+        }
+    }
+
+    private void _testGetTextViaWriter(int mode) throws Exception
+    {
+        final String INPUT_TEXT = "this is a sample text for json parsing using readText() method";
+        final String JSON = "{\"a\":\""+INPUT_TEXT+"\",\"b\":true,\"c\":null,\"d\":\"foo\"}";
+        JsonParser parser = createParser(mode, JSON);
+        assertToken(JsonToken.START_OBJECT, parser.nextToken());
+        assertToken(JsonToken.FIELD_NAME, parser.nextToken());
+        assertEquals("a", parser.getCurrentName());
+        assertToken(JsonToken.VALUE_STRING, parser.nextToken());
+        
+        Writer writer = new StringWriter();
+        int len = parser.getText(writer);
+        String resultString = writer.toString();
+        assertEquals(len, resultString.length());
+        assertEquals(INPUT_TEXT, resultString);
+        parser.close();
+    }
+    
+    public void testLongerReadText() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testLongerReadText(mode);
+        }
+    }
+
+    private void _testLongerReadText(int mode) throws Exception
+    {
+        StringBuilder builder = new StringBuilder();
+        for(int i= 0; i < 1000; i++) {
+            builder.append("Sample Text"+i);
+        }
+        String longText = builder.toString();
+        final String JSON = "{\"a\":\""+ longText +"\",\"b\":true,\"c\":null,\"d\":\"foo\"}";
+        JsonParser parser = createParser(MODE_READER, JSON);
+        assertToken(JsonToken.START_OBJECT, parser.nextToken());
+        assertToken(JsonToken.FIELD_NAME, parser.nextToken());
+        assertEquals("a", parser.getCurrentName());
+        assertToken(JsonToken.VALUE_STRING, parser.nextToken());
+        
+        Writer writer = new StringWriter();
+        int len = parser.getText(writer);
+        String resultString = writer.toString();
+        assertEquals(len, resultString.length());
+        assertEquals(longText, resultString);
+        parser.close();
+    }
+
+    /*
+    /**********************************************************
+    /* Helper methods
+    /**********************************************************
+     */
+
+    private void _doTestSpec(boolean verify) throws IOException
+    {
+        JsonParser p;
+
+        // First, using a StringReader:
+        p = createParserUsingReader(JSON_FACTORY, SAMPLE_DOC_JSON_SPEC);
+        verifyJsonSpecSampleDoc(p, verify);
+        p.close();
+
+        // Then with streams using supported encodings:
+        p = createParserUsingStream(JSON_FACTORY, SAMPLE_DOC_JSON_SPEC, "UTF-8");
+        verifyJsonSpecSampleDoc(p, verify);
+        p.close();
+        p = createParserUsingStream(JSON_FACTORY, SAMPLE_DOC_JSON_SPEC, "UTF-16BE");
+        verifyJsonSpecSampleDoc(p, verify);
+        p.close();
+        p = createParserUsingStream(JSON_FACTORY, SAMPLE_DOC_JSON_SPEC, "UTF-16LE");
+        verifyJsonSpecSampleDoc(p, verify);
+        p.close();
+
+        // Hmmh. UTF-32 is harder only because JDK doesn't come with
+        // a codec for it. Can't test it yet using this method
+        p = createParserUsingStream(JSON_FACTORY, SAMPLE_DOC_JSON_SPEC, "UTF-32");
+        verifyJsonSpecSampleDoc(p, verify);
+        p.close();
+
+        // and finally, new (as of May 2016) source, DataInput:
+        p = createParserForDataInput(JSON_FACTORY, new MockDataInput(SAMPLE_DOC_JSON_SPEC));
+        verifyJsonSpecSampleDoc(p, verify);
+        p.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/NextXxxAccessTest.java b/src/test/java/com/fasterxml/jackson/core/read/NextXxxAccessTest.java
new file mode 100644
index 0000000..6fb4680
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/NextXxxAccessTest.java
@@ -0,0 +1,524 @@
+package com.fasterxml.jackson.core.read;
+
+import java.util.Random;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.io.SerializedString;
+
+public class NextXxxAccessTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    /*
+    /********************************************************
+    /* Wrappers to test InputStream vs Reader
+    /********************************************************
+     */
+
+    public void testIsNextTokenName() throws Exception
+    {
+        _testIsNextTokenName1(MODE_INPUT_STREAM);
+        _testIsNextTokenName1(MODE_INPUT_STREAM_THROTTLED);
+        _testIsNextTokenName1(MODE_DATA_INPUT);
+        _testIsNextTokenName1(MODE_READER);
+    }
+
+    public void testIsNextTokenName2() throws Exception {
+        _testIsNextTokenName2(MODE_INPUT_STREAM);
+        _testIsNextTokenName2(MODE_INPUT_STREAM_THROTTLED);
+        _testIsNextTokenName2(MODE_DATA_INPUT);
+        _testIsNextTokenName2(MODE_READER);
+    }        
+    
+    public void testIsNextTokenName3() throws Exception {
+        _testIsNextTokenName3(MODE_INPUT_STREAM);
+        _testIsNextTokenName3(MODE_INPUT_STREAM_THROTTLED);
+        _testIsNextTokenName3(MODE_DATA_INPUT);
+        _testIsNextTokenName3(MODE_READER);
+    }
+
+    public void testIsNextTokenName4() throws Exception {
+        _testIsNextTokenName4(MODE_INPUT_STREAM);
+        _testIsNextTokenName4(MODE_INPUT_STREAM_THROTTLED);
+        _testIsNextTokenName4(MODE_DATA_INPUT);
+        _testIsNextTokenName4(MODE_READER);
+    }
+    
+    // [jackson-core#34]
+    public void testIssue34() throws Exception
+    {
+        _testIssue34(MODE_INPUT_STREAM);
+        _testIssue34(MODE_INPUT_STREAM_THROTTLED);
+        _testIssue34(MODE_DATA_INPUT);
+        _testIssue34(MODE_READER);
+    }
+
+    // [jackson-core#38] with nextFieldName
+    public void testIssue38() throws Exception
+    {
+        _testIssue38(MODE_INPUT_STREAM);
+        _testIssue38(MODE_INPUT_STREAM_THROTTLED);
+        _testIssue38(MODE_DATA_INPUT);
+        _testIssue38(MODE_READER);
+    }
+
+    public void testNextNameWithLongContent() throws Exception
+    {
+        _testNextNameWithLong(MODE_INPUT_STREAM);
+        _testNextNameWithLong(MODE_INPUT_STREAM_THROTTLED);
+        _testNextNameWithLong(MODE_DATA_INPUT);
+        _testNextNameWithLong(MODE_READER);
+    }
+
+    // for [core#220]: problem with `nextFieldName(str)`, indented content
+    public void testNextNameWithIndentation() throws Exception
+    {
+        _testNextFieldNameIndent(MODE_INPUT_STREAM);
+        _testNextFieldNameIndent(MODE_INPUT_STREAM_THROTTLED);
+        _testNextFieldNameIndent(MODE_DATA_INPUT);
+        _testNextFieldNameIndent(MODE_READER);
+    }
+    
+    public void testNextTextValue() throws Exception
+    {
+        _textNextText(MODE_INPUT_STREAM);
+        _textNextText(MODE_INPUT_STREAM_THROTTLED);
+        _textNextText(MODE_DATA_INPUT);
+        _textNextText(MODE_READER);
+    }
+
+    public void testNextIntValue() throws Exception
+    {
+        _textNextInt(MODE_INPUT_STREAM);
+        _textNextInt(MODE_INPUT_STREAM_THROTTLED);
+        _textNextInt(MODE_DATA_INPUT);
+        _textNextInt(MODE_READER);
+    }
+
+    public void testNextLongValue() throws Exception
+    {
+        _textNextLong(MODE_INPUT_STREAM);
+        _textNextLong(MODE_INPUT_STREAM_THROTTLED);
+        _textNextLong(MODE_DATA_INPUT);
+        _textNextLong(MODE_READER);
+    }
+
+    public void testNextBooleanValue() throws Exception
+    {
+        _textNextBoolean(MODE_INPUT_STREAM);
+        _textNextBoolean(MODE_INPUT_STREAM_THROTTLED);
+        _textNextBoolean(MODE_DATA_INPUT);
+        _textNextBoolean(MODE_READER);
+    }
+    
+    /*
+    /********************************************************
+    /* Actual test code
+    /********************************************************
+     */
+
+    private void _testIsNextTokenName1(int mode) throws Exception
+    {
+        final String DOC = "{\"name\":123,\"name2\":14,\"x\":\"name\"}";
+        JsonParser p = createParser(mode, DOC);
+        final SerializedString NAME = new SerializedString("name");
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.START_OBJECT, p.currentToken());
+        assertEquals(JsonTokenId.ID_START_OBJECT, p.currentTokenId());
+        assertTrue(p.nextFieldName(NAME));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals(NAME.getValue(), p.getCurrentName());
+        assertEquals(NAME.getValue(), p.getText());
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.currentToken());
+        assertEquals(123, p.getIntValue());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("name2", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        // do NOT check number value, to enforce skipping
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("x", p.getCurrentName());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.VALUE_STRING, p.currentToken());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+
+        if (mode != MODE_DATA_INPUT) {
+            assertFalse(p.nextFieldName(NAME));
+            assertNull(p.currentToken());
+        }
+        p.close();
+
+        // Actually, try again with slightly different sequence...
+        p = createParser(mode, DOC);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertFalse(p.nextFieldName(new SerializedString("Nam")));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals(NAME.getValue(), p.getCurrentName());
+        assertEquals(NAME.getValue(), p.getText());
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.currentToken());
+        assertEquals(123, p.getIntValue());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("name2", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("x", p.getCurrentName());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.VALUE_STRING, p.currentToken());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertFalse(p.nextFieldName(NAME));
+            assertNull(p.currentToken());
+        }
+        p.close();
+    }
+
+    private void _testIsNextTokenName2(int mode) throws Exception
+    {
+        final String DOC = "{\"name\":123,\"name2\":14,\"x\":\"name\"}";
+        JsonParser p = createParser(mode, DOC);
+        SerializableString NAME = new SerializedString("name");
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.START_OBJECT, p.currentToken());
+        assertTrue(p.nextFieldName(NAME));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals(NAME.getValue(), p.getCurrentName());
+        assertEquals(NAME.getValue(), p.getText());
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.currentToken());
+        assertEquals(123, p.getIntValue());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("name2", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("x", p.getCurrentName());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.VALUE_STRING, p.currentToken());
+
+        assertFalse(p.nextFieldName(NAME));
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertFalse(p.nextFieldName(NAME));
+            assertNull(p.currentToken());
+        }
+        p.close();
+    }
+
+    private void _testIsNextTokenName3(int mode) throws Exception
+    {
+        final String DOC = "{\"name\":123,\"name2\":14,\"x\":\"name\"}";
+        JsonParser p = createParser(mode, DOC);
+        assertNull(p.nextFieldName());
+        assertToken(JsonToken.START_OBJECT, p.currentToken());
+        assertEquals("name", p.nextFieldName());
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("name", p.getCurrentName());
+        assertEquals("name", p.getText());
+        assertNull(p.nextFieldName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.currentToken());
+        assertEquals(123, p.getIntValue());
+
+        assertEquals("name2", p.nextFieldName());
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("name2", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+
+        assertEquals("x", p.nextFieldName());
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("x", p.getCurrentName());
+
+        assertNull(p.nextFieldName());
+        assertToken(JsonToken.VALUE_STRING, p.currentToken());
+
+        assertNull(p.nextFieldName());
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextFieldName());
+            assertNull(p.currentToken());
+        }
+        p.close();
+    }
+
+    private void _testIsNextTokenName4(int mode) throws Exception
+    {
+        final String DOC = "{\"name\":-123,\"name2\":99}";
+        JsonParser p = createParser(mode, DOC);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+
+        assertTrue(p.nextFieldName(new SerializedString("name")));
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(-123, p.getIntValue());
+
+        assertTrue(p.nextFieldName(new SerializedString("name2")));
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(99, p.getIntValue());
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextToken());
+        }
+        p.close();
+    }
+
+    private void _testNextFieldNameIndent(int mode) throws Exception
+    {
+        final String DOC = "{\n  \"name\" : \n  [\n  ]\n   }";
+        JsonParser p = createParser(mode, DOC);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertTrue(p.nextFieldName(new SerializedString("name")));
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextToken());
+        }
+        p.close();
+    }
+
+    private void _textNextText(int mode) throws Exception
+    {
+        final String DOC = aposToQuotes("{'a':'123','b':5,'c':[false,'foo']}");
+        JsonParser p = createParser(mode, DOC);
+        assertNull(p.nextTextValue());
+        assertToken(JsonToken.START_OBJECT, p.currentToken());
+        assertNull(p.nextTextValue());
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("a", p.getCurrentName());
+
+        assertEquals("123", p.nextTextValue());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("b", p.getCurrentName());
+        assertNull(p.nextFieldName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.currentToken());
+
+        assertEquals("c", p.nextFieldName());
+        
+        assertNull(p.nextTextValue());
+        assertToken(JsonToken.START_ARRAY, p.currentToken());
+        assertNull(p.nextTextValue());
+        assertToken(JsonToken.VALUE_FALSE, p.currentToken());
+        assertEquals("foo", p.nextTextValue());
+        
+        assertNull(p.nextTextValue());
+        assertToken(JsonToken.END_ARRAY, p.currentToken());
+        assertNull(p.nextTextValue());
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextTextValue());
+            assertNull(p.currentToken());
+        }
+        p.close();
+    }
+
+    private void _textNextInt(int mode) throws Exception
+    {
+        final String DOC = aposToQuotes("{'a':'123','b':5,'c':[false,456]}");
+        JsonParser p = createParser(mode, DOC);
+        assertEquals(0, p.nextIntValue(0));
+        assertToken(JsonToken.START_OBJECT, p.currentToken());
+        assertEquals(0, p.nextIntValue(0));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("a", p.getCurrentName());
+
+        assertEquals(0, p.nextIntValue(0));
+        assertToken(JsonToken.VALUE_STRING, p.currentToken());
+        assertEquals("123", p.getText());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("b", p.getCurrentName());
+        assertEquals(5, p.nextIntValue(0));
+
+        assertEquals("c", p.nextFieldName());
+        
+        assertEquals(0, p.nextIntValue(0));
+        assertToken(JsonToken.START_ARRAY, p.currentToken());
+        assertEquals(0, p.nextIntValue(0));
+        assertToken(JsonToken.VALUE_FALSE, p.currentToken());
+        assertEquals(456, p.nextIntValue(0));
+        
+        assertEquals(0, p.nextIntValue(0));
+        assertToken(JsonToken.END_ARRAY, p.currentToken());
+        assertEquals(0, p.nextIntValue(0));
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertEquals(0, p.nextIntValue(0));
+            assertNull(p.currentToken());
+        }
+        p.close();
+    }
+
+    private void _textNextLong(int mode) throws Exception
+    {
+        final String DOC = aposToQuotes("{'a':'xyz','b':-59,'c':[false,-1]}");
+        JsonParser p = createParser(mode, DOC);
+        assertEquals(0L, p.nextLongValue(0L));
+        assertToken(JsonToken.START_OBJECT, p.currentToken());
+        assertEquals(0L, p.nextLongValue(0L));
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("a", p.getCurrentName());
+
+        assertEquals(0L, p.nextLongValue(0L));
+        assertToken(JsonToken.VALUE_STRING, p.currentToken());
+        assertEquals("xyz", p.getText());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("b", p.getCurrentName());
+        assertEquals(-59L, p.nextLongValue(0L));
+
+        assertEquals("c", p.nextFieldName());
+        
+        assertEquals(0L, p.nextLongValue(0L));
+        assertToken(JsonToken.START_ARRAY, p.currentToken());
+        assertEquals(0L, p.nextLongValue(0L));
+        assertToken(JsonToken.VALUE_FALSE, p.currentToken());
+        assertEquals(-1L, p.nextLongValue(0L));
+        
+        assertEquals(0L, p.nextLongValue(0L));
+        assertToken(JsonToken.END_ARRAY, p.currentToken());
+        assertEquals(0L, p.nextLongValue(0L));
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertEquals(0L, p.nextLongValue(0L));
+            assertNull(p.currentToken());
+        }
+        p.close();
+    }
+
+    private void _textNextBoolean(int mode) throws Exception
+    {
+        final String DOC = aposToQuotes("{'a':'xyz','b':true,'c':[false,0]}");
+        JsonParser p = createParser(mode, DOC);
+        assertNull(p.nextBooleanValue());
+        assertToken(JsonToken.START_OBJECT, p.currentToken());
+        assertNull(p.nextBooleanValue());
+        assertToken(JsonToken.FIELD_NAME, p.currentToken());
+        assertEquals("a", p.getCurrentName());
+
+        assertNull(p.nextBooleanValue());
+        assertToken(JsonToken.VALUE_STRING, p.currentToken());
+        assertEquals("xyz", p.getText());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("b", p.getCurrentName());
+        assertEquals(Boolean.TRUE, p.nextBooleanValue());
+
+        assertEquals("c", p.nextFieldName());
+        
+        assertNull(p.nextBooleanValue());
+        assertToken(JsonToken.START_ARRAY, p.currentToken());
+        assertEquals(Boolean.FALSE, p.nextBooleanValue());
+        assertNull(p.nextBooleanValue());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.currentToken());
+        assertEquals(0, p.getIntValue());
+        
+        assertNull(p.nextBooleanValue());
+        assertToken(JsonToken.END_ARRAY, p.currentToken());
+        assertNull(p.nextBooleanValue());
+        assertToken(JsonToken.END_OBJECT, p.currentToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextBooleanValue());
+            assertNull(p.currentToken());
+        }
+        p.close();
+    }
+    
+    private void _testIssue34(int mode) throws Exception
+    {
+        final int TESTROUNDS = 223;
+        final String DOC_PART = "{ \"fieldName\": 1 }";
+
+        // build the big document to trigger issue
+        StringBuilder sb = new StringBuilder(2000);
+        for (int i = 0; i < TESTROUNDS; ++i) {
+            sb.append(DOC_PART);
+        }
+        final String DOC = sb.toString();
+
+        SerializableString fieldName = new SerializedString("fieldName");
+        JsonParser parser = createParser(mode, DOC);
+
+        for (int i = 0; i < TESTROUNDS - 1; i++) {
+            assertEquals(JsonToken.START_OBJECT, parser.nextToken());
+
+            // These will succeed
+            assertTrue(parser.nextFieldName(fieldName));
+
+            parser.nextLongValue(-1);
+            assertEquals(JsonToken.END_OBJECT, parser.nextToken());
+        }
+
+        assertEquals(JsonToken.START_OBJECT, parser.nextToken());
+
+        // This will fail
+        assertTrue(parser.nextFieldName(fieldName));
+        parser.close();
+    }
+
+    private void _testIssue38(int mode) throws Exception
+    {
+        final String DOC = "{\"field\" :\"value\"}";
+        SerializableString fieldName = new SerializedString("field");
+        JsonParser parser = createParser(mode, DOC);
+        assertEquals(JsonToken.START_OBJECT, parser.nextToken());
+        assertTrue(parser.nextFieldName(fieldName));
+        assertEquals(JsonToken.VALUE_STRING, parser.nextToken());
+        assertEquals("value", parser.getText());
+        assertEquals(JsonToken.END_OBJECT, parser.nextToken());
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(parser.nextToken());
+        }
+        parser.close();
+    }
+
+    private void _testNextNameWithLong(int mode) throws Exception
+    {
+        // do 5 meg thingy
+        final int SIZE = 5 * 1024 * 1024;
+        StringBuilder sb = new StringBuilder(SIZE + 20);
+
+        sb.append("{");
+        Random rnd = new Random(1);
+        int count = 0;
+        while (sb.length() < SIZE) {
+            ++count;
+            if (sb.length() > 1) {
+                sb.append(", ");
+            }
+            int val = rnd.nextInt();
+            sb.append('"');
+            sb.append("f"+val);
+            sb.append("\":");
+            sb.append(String.valueOf(val % 1000));
+        }
+        sb.append("}");
+        final String DOC = sb.toString();
+    
+        JsonParser parser = createParser(mode, DOC);
+        assertToken(JsonToken.START_OBJECT, parser.nextToken());
+        rnd = new Random(1);
+        for (int i = 0; i < count; ++i) {
+            int exp = rnd.nextInt();
+            SerializableString expName = new SerializedString("f"+exp);
+            assertTrue(parser.nextFieldName(expName));
+            assertToken(JsonToken.VALUE_NUMBER_INT, parser.nextToken());
+            assertEquals(exp % 1000, parser.getIntValue());
+        }
+        assertToken(JsonToken.END_OBJECT, parser.nextToken());
+        parser.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/NonStandardParserFeaturesTest.java b/src/test/java/com/fasterxml/jackson/core/read/NonStandardParserFeaturesTest.java
new file mode 100644
index 0000000..b26c46e
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/NonStandardParserFeaturesTest.java
@@ -0,0 +1,537 @@
+package com.fasterxml.jackson.core.read;
+
+import com.fasterxml.jackson.core.*;
+
+public class NonStandardParserFeaturesTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    public void testSimpleUnquotedBytes() throws Exception {
+        _testSimpleUnquoted(MODE_INPUT_STREAM);
+        _testSimpleUnquoted(MODE_INPUT_STREAM_THROTTLED);
+        _testSimpleUnquoted(MODE_DATA_INPUT);
+    }
+
+    public void testSimpleUnquotedChars() throws Exception {
+        _testSimpleUnquoted(MODE_READER);
+    }
+    
+    public void testLargeUnquoted() throws Exception
+    {
+        _testLargeUnquoted(MODE_INPUT_STREAM);
+        _testLargeUnquoted(MODE_INPUT_STREAM_THROTTLED);
+        _testLargeUnquoted(MODE_DATA_INPUT);
+        _testLargeUnquoted(MODE_READER);
+    }
+
+    public void testSingleQuotesDefault() throws Exception
+    {
+        _testSingleQuotesDefault(MODE_INPUT_STREAM);
+        _testSingleQuotesDefault(MODE_INPUT_STREAM_THROTTLED);
+        _testSingleQuotesDefault(MODE_DATA_INPUT);
+        _testSingleQuotesDefault(MODE_READER);
+    }
+
+    public void testSingleQuotesEnabled() throws Exception
+    {
+        _testSingleQuotesEnabled(MODE_INPUT_STREAM);
+        _testSingleQuotesEnabled(MODE_INPUT_STREAM_THROTTLED);
+        _testSingleQuotesEnabled(MODE_DATA_INPUT);
+        _testSingleQuotesEnabled(MODE_READER);
+
+        _testSingleQuotesEscaped(MODE_INPUT_STREAM);
+        _testSingleQuotesEscaped(MODE_INPUT_STREAM_THROTTLED);
+        _testSingleQuotesEscaped(MODE_DATA_INPUT);
+        _testSingleQuotesEscaped(MODE_READER);
+    }
+
+    public void testNonStandardNameChars() throws Exception
+    {
+        _testNonStandardNameChars(MODE_INPUT_STREAM);
+        _testNonStandardNameChars(MODE_INPUT_STREAM_THROTTLED);
+        _testNonStandardNameChars(MODE_DATA_INPUT);
+        _testNonStandardNameChars(MODE_READER);
+    }
+
+    public void testNonStandardAnyCharQuoting() throws Exception
+    {
+        _testNonStandarBackslashQuoting(MODE_INPUT_STREAM);
+        _testNonStandarBackslashQuoting(MODE_INPUT_STREAM_THROTTLED);
+        _testNonStandarBackslashQuoting(MODE_DATA_INPUT);
+        _testNonStandarBackslashQuoting(MODE_READER);
+    }
+
+    public void testLeadingZeroesUTF8() throws Exception {
+        _testLeadingZeroes(MODE_INPUT_STREAM, false);
+        _testLeadingZeroes(MODE_INPUT_STREAM, true);
+        _testLeadingZeroes(MODE_INPUT_STREAM_THROTTLED, false);
+        _testLeadingZeroes(MODE_INPUT_STREAM_THROTTLED, true);
+
+        // 17-May-2016, tatu: With DataInput, must have trailing space
+        //   since there's no way to detect end of input
+        _testLeadingZeroes(MODE_DATA_INPUT, true);
+    }
+
+    public void testLeadingZeroesReader() throws Exception {
+        _testLeadingZeroes(MODE_READER, false);
+        _testLeadingZeroes(MODE_READER, true);
+    }
+
+    // allow NaN
+    public void testAllowNaN() throws Exception {
+        _testAllowNaN(MODE_INPUT_STREAM);
+        _testAllowNaN(MODE_INPUT_STREAM_THROTTLED);
+        _testAllowNaN(MODE_DATA_INPUT);
+        _testAllowNaN(MODE_READER);
+    }
+
+    // allow +Inf/-Inf
+    public void testAllowInfinity() throws Exception {
+        _testAllowInf(MODE_INPUT_STREAM);
+        _testAllowInf(MODE_INPUT_STREAM_THROTTLED);
+        _testAllowInf(MODE_DATA_INPUT);
+        _testAllowInf(MODE_READER);
+    }
+
+    /*
+    /****************************************************************
+    /* Secondary test methods
+    /****************************************************************
+     */
+
+    private void _testLargeUnquoted(int mode) throws Exception
+    {
+        StringBuilder sb = new StringBuilder(5000);
+        sb.append("[\n");
+        //final int REPS = 2000;
+        final int REPS = 1050;
+        for (int i = 0; i < REPS; ++i) {
+            if (i > 0) {
+                sb.append(',');
+                if ((i & 7) == 0) {
+                    sb.append('\n');
+                }
+            }
+            sb.append("{");
+            sb.append("abc").append(i&127).append(':');
+            sb.append((i & 1) != 0);
+            sb.append("}\n");
+        }
+        sb.append("]");
+        String JSON = sb.toString();
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+        JsonParser p = createParser(f, mode, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        for (int i = 0; i < REPS; ++i) {
+            assertToken(JsonToken.START_OBJECT, p.nextToken());
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+            assertEquals("abc"+(i&127), p.getCurrentName());
+            assertToken(((i&1) != 0) ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE, p.nextToken());
+            assertToken(JsonToken.END_OBJECT, p.nextToken());
+        }
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+    }
+
+    
+    private void _testSimpleUnquoted(int mode) throws Exception
+    {
+        final JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+
+        String JSON = "{ a : 1, _foo:true, $:\"money!\", \" \":null }";
+        JsonParser p = createParser(f, mode, JSON);
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("a", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("_foo", p.getCurrentName());
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("$", p.getCurrentName());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("money!", p.getText());
+
+        // and then regular quoted one should still work too:
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals(" ", p.getCurrentName());
+
+        assertToken(JsonToken.VALUE_NULL, p.nextToken());
+
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        p.close();
+
+        // Another thing, as per [Issue#102]: numbers
+
+        JSON = "{ 123:true,4:false }";
+        p = createParser(f, mode, JSON);
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("123", p.getCurrentName());
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("4", p.getCurrentName());
+        assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        p.close();
+    }
+
+    /**
+     * Test to verify that the default parser settings do not
+     * accept single-quotes for String values (field names,
+     * textual values)
+     */
+    private void _testSingleQuotesDefault(int mode) throws Exception
+    {
+        JsonFactory f = new JsonFactory();
+        // First, let's see that by default they are not allowed
+        String JSON = "[ 'text' ]";
+        JsonParser p = createParser(f, mode, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Expected exception");
+        } catch (JsonParseException e) {
+            verifyException(e, "Unexpected character ('''");
+        } finally {
+            p.close();
+        }
+
+        JSON = "{ 'a':1 }";
+        p = createParser(f, mode, JSON);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Expected exception");
+        } catch (JsonParseException e) {
+            verifyException(e, "Unexpected character ('''");
+        } finally {
+            p.close();
+        }
+    }
+
+    /**
+     * Test to verify optional handling of
+     * single quotes, to allow handling invalid (but, alas, common)
+     * JSON.
+     */
+    private void _testSingleQuotesEnabled(int mode) throws Exception
+    {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+
+        String JSON = "{ 'a' : 1, \"foobar\": 'b', '_abcde1234':'d', '\"' : '\"\"', '':'' }";
+        JsonParser p = createParser(f, mode, JSON);
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("a", p.getText());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals("1", p.getText());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("foobar", p.getText());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("b", p.getText());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("_abcde1234", p.getText());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("d", p.getText());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("\"", p.getText());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        //assertEquals("\"\"", p.getText());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("", p.getText());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("", p.getText());
+
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        p.close();
+
+
+        JSON = "{'b':1,'array':[{'b':3}],'ob':{'b':4,'x':0,'y':3,'a':false }}";
+        p = createParser(f, mode, JSON);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("b", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("b", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(3, p.getIntValue());
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("b", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(4, p.getIntValue());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("x", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(0, p.getIntValue());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("y", p.getCurrentName());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(3, p.getIntValue());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("a", p.getCurrentName());
+        assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        p.close();
+    }
+
+    // test to verify that we implicitly allow escaping of apostrophe
+    private void _testSingleQuotesEscaped(int mode) throws Exception
+    {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+
+        String JSON = "[ '16\\'' ]";
+        JsonParser p = createParser(f, mode, JSON);
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("16'", p.getText());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+    }
+    
+    private void _testNonStandardNameChars(int mode) throws Exception
+    {
+        JsonFactory f = new JsonFactory();
+        f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+        String JSON = "{ @type : \"mytype\", #color : 123, *error* : true, "
+            +" hyphen-ated : \"yes\", me+my : null"
+            +"}";
+        JsonParser p = createParser(f, mode, JSON);
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("@type", p.getText());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("mytype", p.getText());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("#color", p.getText());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(123, p.getIntValue());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("*error*", p.getText());
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("hyphen-ated", p.getText());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("yes", p.getText());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("me+my", p.getText());
+        assertToken(JsonToken.VALUE_NULL, p.nextToken());
+    
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        p.close();
+    }
+
+    private void _testNonStandarBackslashQuoting(int mode) throws Exception
+    {
+        // first: verify that we get an exception
+        JsonFactory f = new JsonFactory();
+        assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER));
+        final String JSON = quote("\\'");
+        JsonParser p = createParser(f, mode, JSON);
+        try {      
+            p.nextToken();
+            p.getText();
+            fail("Should have thrown an exception for doc <"+JSON+">");
+        } catch (JsonParseException e) {
+            verifyException(e, "unrecognized character escape");
+        } finally {
+            p.close();
+        }
+        // and then verify it's ok...
+        f.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
+        assertTrue(f.isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER));
+        p = createParser(f, mode, JSON);
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("'", p.getText());
+        p.close();
+    }
+
+    private void _testLeadingZeroes(int mode, boolean appendSpace) throws Exception
+    {
+        // first: verify that we get an exception
+        JsonFactory f = new JsonFactory();
+        assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS));
+        String JSON = "00003";
+        if (appendSpace) {
+            JSON += " ";
+        }
+        JsonParser p = createParser(f, mode, JSON);
+        try {      
+            p.nextToken();
+            p.getText();
+            fail("Should have thrown an exception for doc <"+JSON+">");
+        } catch (JsonParseException e) {
+            verifyException(e, "invalid numeric value");
+        } finally {
+            p.close();
+        }
+        
+        // and then verify it's ok when enabled
+        f.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
+        assertTrue(f.isEnabled(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS));
+        p = createParser(f, mode, JSON);
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(3, p.getIntValue());
+        assertEquals("3", p.getText());
+        p.close();
+    
+        // Plus, also: verify that leading zero magnitude is ok:
+        JSON = "0"+Integer.MAX_VALUE;
+        if (appendSpace) {
+            JSON += " ";
+        }
+        p = createParser(f, mode, JSON);
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(String.valueOf(Integer.MAX_VALUE), p.getText());
+        assertEquals(Integer.MAX_VALUE, p.getIntValue());
+        Number nr = p.getNumberValue();
+        assertSame(Integer.class, nr.getClass());
+        p.close();
+    }
+
+    private void _testAllowNaN(int mode) throws Exception
+    {
+        final String JSON = "[ NaN]";
+        JsonFactory f = new JsonFactory();
+        assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS));
+
+        // without enabling, should get an exception
+        JsonParser p = createParser(f, mode, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Expected exception");
+        } catch (Exception e) {
+            verifyException(e, "non-standard");
+        } finally {
+            p.close();
+        }
+
+        // we can enable it dynamically (impl detail)
+        f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
+        p = createParser(f, mode, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        
+        double d = p.getDoubleValue();
+        assertTrue(Double.isNaN(d));
+        assertEquals("NaN", p.getText());
+
+        // [Issue#98]
+        try {
+            /*BigDecimal dec =*/ p.getDecimalValue();
+            fail("Should fail when trying to access NaN as BigDecimal");
+        } catch (NumberFormatException e) {
+            verifyException(e, "can not be represented as BigDecimal");
+        }
+       
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+
+        // finally, should also work with skipping
+        f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
+        p = createParser(f, mode, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+    }
+
+    private void _testAllowInf(int mode) throws Exception
+    {
+        final String JSON = "[ -INF, +INF, +Infinity, Infinity, -Infinity ]";
+        JsonFactory f = new JsonFactory();
+        assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS));
+
+        // without enabling, should get an exception
+        JsonParser p = createParser(f, mode, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Expected exception");
+        } catch (Exception e) {
+            verifyException(e, "Non-standard token '-INF'");
+        } finally {
+            p.close();
+        }
+        f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
+        p = createParser(f, mode, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        double d = p.getDoubleValue();
+        assertEquals("-INF", p.getText());
+        assertTrue(Double.isInfinite(d));
+        assertTrue(d == Double.NEGATIVE_INFINITY);
+
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        d = p.getDoubleValue();
+        assertEquals("+INF", p.getText());
+        assertTrue(Double.isInfinite(d));
+        assertTrue(d == Double.POSITIVE_INFINITY);
+
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        d = p.getDoubleValue();
+        assertEquals("+Infinity", p.getText());
+        assertTrue(Double.isInfinite(d));
+        assertTrue(d == Double.POSITIVE_INFINITY);
+
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        d = p.getDoubleValue();
+        assertEquals("Infinity", p.getText());
+        assertTrue(Double.isInfinite(d));
+        assertTrue(d == Double.POSITIVE_INFINITY);
+
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        d = p.getDoubleValue();
+        assertEquals("-Infinity", p.getText());
+        assertTrue(Double.isInfinite(d));
+        assertTrue(d == Double.NEGATIVE_INFINITY);
+
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+
+        // finally, should also work with skipping
+        f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
+        p = createParser(f, mode, JSON);
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        
+        p.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java
new file mode 100644
index 0000000..6c8da43
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java
@@ -0,0 +1,610 @@
+package com.fasterxml.jackson.core.read;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Set of basic unit tests for verifying that the basic parser
+ * functionality works as expected.
+ */
+@SuppressWarnings("resource")
+public class NumberParsingTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    private final JsonFactory FACTORY = new JsonFactory();
+
+    public void testSimpleBoolean() throws Exception
+    {
+        _testSimpleBoolean(MODE_INPUT_STREAM);
+        _testSimpleBoolean(MODE_INPUT_STREAM_THROTTLED);
+        _testSimpleBoolean(MODE_READER);
+        _testSimpleBoolean(MODE_DATA_INPUT);
+    }
+
+    private void _testSimpleBoolean(int mode) throws Exception
+    {
+        JsonParser p = createParser(mode, "[ true ]");
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertEquals(true, p.getBooleanValue());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+    }
+
+    public void testSimpleInt() throws Exception
+    {
+        for (int EXP_I : new int[] { 1234, -999, 0, 1, -2 }) {
+            _testSimpleInt(EXP_I, MODE_INPUT_STREAM);
+            _testSimpleInt(EXP_I, MODE_INPUT_STREAM_THROTTLED);
+            _testSimpleInt(EXP_I, MODE_READER);
+            _testSimpleInt(EXP_I, MODE_DATA_INPUT);
+        }
+    }
+
+    private void _testSimpleInt(int EXP_I, int mode) throws Exception
+    {
+        String DOC = "[ "+EXP_I+" ]";
+        JsonParser p = createParser(mode, DOC);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(JsonParser.NumberType.INT, p.getNumberType());
+        assertEquals(""+EXP_I, p.getText());
+
+        assertEquals(EXP_I, p.getIntValue());
+        assertEquals(EXP_I, p.getValueAsInt(EXP_I + 3));
+        assertEquals(EXP_I, p.getValueAsInt());
+        assertEquals((long) EXP_I, p.getLongValue());
+        assertEquals((double) EXP_I, p.getDoubleValue());
+        assertEquals(BigDecimal.valueOf((long) EXP_I), p.getDecimalValue());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+
+        DOC = String.valueOf(EXP_I);
+        p = createParser(mode, DOC + " "); // DataInput requires separator
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(DOC, p.getText());
+
+        int i = 0;
+        
+        try {
+            i = p.getIntValue();
+        } catch (Exception e) {
+            throw new Exception("Failed to parse input '"+DOC+"' (parser of type "+p.getClass().getSimpleName()+")", e);
+        }
+        assertEquals(EXP_I, i);
+        assertEquals((long) EXP_I, p.getLongValue());
+        assertEquals((double) EXP_I, p.getDoubleValue());
+        assertEquals(BigDecimal.valueOf((long) EXP_I), p.getDecimalValue());
+        p.close();
+    }
+
+    public void testIntRange() throws Exception
+    {
+        // let's test with readers and streams, separate code paths:
+        for (int mode : ALL_MODES) {
+            String DOC = "[ "+Integer.MAX_VALUE+","+Integer.MIN_VALUE+" ]";
+            JsonParser p = createParser(mode, DOC);
+            assertToken(JsonToken.START_ARRAY, p.nextToken());
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(JsonParser.NumberType.INT, p.getNumberType());
+            assertEquals(Integer.MAX_VALUE, p.getIntValue());
+    
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(JsonParser.NumberType.INT, p.getNumberType());
+            assertEquals(Integer.MIN_VALUE, p.getIntValue());
+            p.close();
+        }
+    }
+
+    public void testSimpleLong() throws Exception
+    {
+        _testSimpleLong(MODE_INPUT_STREAM);
+        _testSimpleLong(MODE_INPUT_STREAM_THROTTLED);
+        _testSimpleLong(MODE_READER);
+        _testSimpleLong(MODE_DATA_INPUT);
+    }
+    
+    private void _testSimpleLong(int mode) throws Exception
+    {
+        long EXP_L = 12345678907L;
+        
+        JsonParser p = createParser(mode, "[ "+EXP_L+" ]");
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        // beyond int, should be long
+        assertEquals(JsonParser.NumberType.LONG, p.getNumberType());
+        assertEquals(""+EXP_L, p.getText());
+
+        assertEquals(EXP_L, p.getLongValue());
+        // Should get an exception if trying to convert to int 
+        try {
+            p.getIntValue();
+        } catch (JsonParseException pe) {
+            verifyException(pe, "out of range");
+        }
+        assertEquals((double) EXP_L, p.getDoubleValue());
+        assertEquals(BigDecimal.valueOf((long) EXP_L), p.getDecimalValue());
+        p.close();
+    }
+
+    public void testLongRange() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            long belowMinInt = -1L + Integer.MIN_VALUE;
+            long aboveMaxInt = 1L + Integer.MAX_VALUE;
+            String input = "[ "+Long.MAX_VALUE+","+Long.MIN_VALUE+","+aboveMaxInt+", "+belowMinInt+" ]";
+            JsonParser p = createParser(mode, input);
+            assertToken(JsonToken.START_ARRAY, p.nextToken());
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(JsonParser.NumberType.LONG, p.getNumberType());
+            assertEquals(Long.MAX_VALUE, p.getLongValue());
+        
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(JsonParser.NumberType.LONG, p.getNumberType());
+            assertEquals(Long.MIN_VALUE, p.getLongValue());
+
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(JsonParser.NumberType.LONG, p.getNumberType());
+            assertEquals(aboveMaxInt, p.getLongValue());
+
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(JsonParser.NumberType.LONG, p.getNumberType());
+            assertEquals(belowMinInt, p.getLongValue());
+
+            
+            assertToken(JsonToken.END_ARRAY, p.nextToken());        
+            p.close();
+        }
+    }
+
+    public void testBigDecimalRange() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            // let's test first values outside of Long range
+            BigInteger small = new BigDecimal(Long.MIN_VALUE).toBigInteger();
+            small = small.subtract(BigInteger.ONE);
+            BigInteger big = new BigDecimal(Long.MAX_VALUE).toBigInteger();
+            big = big.add(BigInteger.ONE);
+            String input = "[ "+small+"  ,  "+big+"]";
+            JsonParser p = createParser(mode, input);
+            assertToken(JsonToken.START_ARRAY, p.nextToken());
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(JsonParser.NumberType.BIG_INTEGER, p.getNumberType());
+            assertEquals(small, p.getBigIntegerValue());
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(JsonParser.NumberType.BIG_INTEGER, p.getNumberType());
+            assertEquals(big, p.getBigIntegerValue());
+            assertToken(JsonToken.END_ARRAY, p.nextToken());        
+            p.close();
+        }
+    }
+
+    // for [core#78]
+    public void testBigNumbers() throws Exception
+    {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < 520; ++i) { // input buffer is 512 bytes by default
+            sb.append('1');
+        }
+        final String NUMBER_STR = sb.toString();
+        BigInteger biggie = new BigInteger(NUMBER_STR);
+
+        for (int mode : ALL_MODES) {
+            JsonParser p = createParser(mode, NUMBER_STR +" ");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(JsonParser.NumberType.BIG_INTEGER, p.getNumberType());
+            assertEquals(NUMBER_STR, p.getText());
+            assertEquals(biggie, p.getBigIntegerValue());
+            p.close();
+        }
+    }
+    
+    public void testSimpleDouble() throws Exception
+    {
+        final String[] INPUTS = new String[] {
+            "1234.00", "2.1101567E-16", "1.0e5", "0.0", "1.0", "-1.0", 
+            "-0.5", "-12.9", "-999.0",
+            "2.5e+5", "9e4", "-12e-3", "0.25",
+        };
+        for (int mode : ALL_MODES) {
+            for (int i = 0; i < INPUTS.length; ++i) {
+
+                // First in array
+                
+                String STR = INPUTS[i];
+                double EXP_D = Double.parseDouble(STR);
+                String DOC = "["+STR+"]";
+
+                JsonParser p = createParser(mode, DOC+" ");
+                assertToken(JsonToken.START_ARRAY, p.nextToken());
+
+                assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+                assertEquals(STR, p.getText());
+                assertEquals(EXP_D, p.getDoubleValue());
+                assertToken(JsonToken.END_ARRAY, p.nextToken());
+                if (mode != MODE_DATA_INPUT) {
+                    assertNull(p.nextToken());
+                }
+                p.close();
+
+                // then outside
+                p = createParser(mode, STR + " ");
+                JsonToken t = null;
+
+                try {
+                    t = p.nextToken();
+                } catch (Exception e) {
+                    throw new Exception("Failed to parse input '"+STR+"' (parser of type "+p.getClass().getSimpleName()+")", e);
+                }
+                
+                assertToken(JsonToken.VALUE_NUMBER_FLOAT, t);
+                assertEquals(STR, p.getText());
+                if (mode != MODE_DATA_INPUT) {
+                    assertNull(p.nextToken());
+                }
+                p.close();
+            }
+        }
+    }
+
+    public void testNumbers() throws Exception
+    {
+        _testNumbers(MODE_INPUT_STREAM);
+        _testNumbers(MODE_INPUT_STREAM_THROTTLED);
+        _testNumbers(MODE_READER);
+        _testNumbers(MODE_DATA_INPUT);
+    }
+    
+    private void _testNumbers(int mode) throws Exception
+    {
+        final String DOC = "[ -13, 8100200300, 13.5, 0.00010, -2.033 ]";
+
+        JsonParser p = createParser(mode, DOC);
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(-13, p.getIntValue());
+        assertEquals(-13L, p.getLongValue());
+        assertEquals(-13., p.getDoubleValue());
+        assertEquals("-13", p.getText());
+        
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(8100200300L, p.getLongValue());
+        // Should get exception for overflow:
+        try {
+            /*int x =*/ p.getIntValue();
+            fail("Expected an exception for overflow");
+        } catch (Exception e) {
+            verifyException(e, "out of range of int");
+        }
+        assertEquals(8100200300.0, p.getDoubleValue());
+        assertEquals("8100200300", p.getText());
+        
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertEquals(13, p.getIntValue());
+        assertEquals(13L, p.getLongValue());
+        assertEquals(13.5, p.getDoubleValue());
+        assertEquals("13.5", p.getText());
+
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertEquals(0, p.getIntValue());
+        assertEquals(0L, p.getLongValue());
+        assertEquals(0.00010, p.getDoubleValue());
+        assertEquals("0.00010", p.getText());
+        
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertEquals(-2, p.getIntValue());
+        assertEquals(-2L, p.getLongValue());
+        assertEquals(-2.033, p.getDoubleValue());
+        assertEquals("-2.033", p.getText());
+
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+
+        p.close();
+    }
+
+    public void testLongOverflow() throws Exception
+    {
+        BigInteger below = BigInteger.valueOf(Long.MIN_VALUE);
+        below = below.subtract(BigInteger.ONE);
+        BigInteger above = BigInteger.valueOf(Long.MAX_VALUE);
+        above = above.add(BigInteger.ONE);
+
+        String DOC_BELOW = below.toString() + " ";
+        String DOC_ABOVE = below.toString() + " ";
+
+        for (int mode : ALL_MODES) {
+            JsonParser p = createParser(mode, DOC_BELOW);
+            p.nextToken();
+            try {
+                long x = p.getLongValue();
+                fail("Expected an exception for underflow (input "+p.getText()+"): instead, got long value: "+x);
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of long");
+            }
+            p.close();
+
+            p = createParser(mode, DOC_ABOVE);
+            p.nextToken();
+            try {
+                long x = p.getLongValue();
+                fail("Expected an exception for underflow (input "+p.getText()+"): instead, got long value: "+x);
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of long");
+            }
+            p.close();
+            
+        }
+    }
+    
+    /**
+     * Method that tries to test that number parsing works in cases where
+     * input is split between buffer boundaries.
+     */
+    public void testParsingOfLongerSequences() throws Exception
+    {
+        double[] values = new double[] { 0.01, -10.5, 2.1e9, 4.0e-8 };
+        StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < values.length; ++i) {
+            if (i > 0) {
+                sb.append(',');
+            }
+            sb.append(values[i]);
+        }
+        String segment = sb.toString();
+
+        int COUNT = 1000;
+        sb = new StringBuilder(COUNT * segment.length() + 20);
+        sb.append("[");
+        for (int i = 0; i < COUNT; ++i) {
+            if (i > 0) {
+                sb.append(',');
+            }
+            sb.append(segment);
+            sb.append('\n');
+            // let's add somewhat arbitrary number of spaces
+            int x = (i & 3);
+            if (i > 300) {
+                x += i % 5;
+            }
+            while (--x > 0) {
+                sb.append(' ');
+            }
+        }
+        sb.append("]");
+        String DOC = sb.toString();
+
+        for (int input = 0; input < 2; ++input) {
+            JsonParser p;
+
+            if (input == 0) {
+                p = createParserUsingStream(DOC, "UTF-8");
+            } else {
+                p = FACTORY.createParser(DOC);
+            }
+
+            assertToken(JsonToken.START_ARRAY, p.nextToken());
+            for (int i = 0; i < COUNT; ++i) {
+                for (double d : values) {
+                    assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+                    assertEquals(d, p.getDoubleValue());
+                }
+            }
+            assertToken(JsonToken.END_ARRAY, p.nextToken());
+            p.close();
+        }
+    }
+
+    // [jackson-core#157]
+    public void testLongNumbers() throws Exception
+    {
+        StringBuilder sb = new StringBuilder(9000);
+        for (int i = 0; i < 9000; ++i) {
+            sb.append('9');
+        }
+        String NUM = sb.toString();
+        // force use of new factory, just in case (might still recycle same buffers tho?)
+        JsonFactory f = new JsonFactory();
+        _testLongNumbers(f, NUM, false);
+        _testLongNumbers(f, NUM, true);
+    }
+    
+    private void _testLongNumbers(JsonFactory f, String num, boolean useStream) throws Exception
+    {
+        final String doc = "[ "+num+" ]";
+        JsonParser p = useStream
+                ? f.createParser(doc.getBytes("UTF-8"))
+                        : f.createParser(doc);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(num, p.getText());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+    }
+
+    // and alternate take on for #157 (with negative num)
+    public void testLongNumbers2() throws Exception
+    {
+        StringBuilder input = new StringBuilder();
+        // test this with negative
+        input.append('-');
+        for (int i = 0; i < 2100; i++) {
+            input.append(1);
+        }
+        final String DOC = input.toString();
+        JsonFactory f = new JsonFactory();
+        _testIssue160LongNumbers(f, DOC, false);
+        _testIssue160LongNumbers(f, DOC, true);
+    }
+
+    private void _testIssue160LongNumbers(JsonFactory f, String doc, boolean useStream) throws Exception
+    {
+        JsonParser p = useStream
+                ? FACTORY.createParser(doc.getBytes("UTF-8"))
+                        : FACTORY.createParser(doc);
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        BigInteger v = p.getBigIntegerValue();
+        assertNull(p.nextToken());
+        assertEquals(doc, v.toString());
+    }
+
+    // for [jackson-core#181]
+    /**
+     * Method that tries to test that number parsing works in cases where
+     * input is split between buffer boundaries.
+     */
+    public void testParsingOfLongerSequencesWithNonNumeric() throws Exception
+    {
+        JsonFactory factory = new JsonFactory();
+        factory.enable(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS);
+        double[] values = new double[] {
+                0.01, -10.5, 2.1e9, 4.0e-8,
+                Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY
+        };
+        for (int i = 0; i < values.length; ++i) {
+            int COUNT = 4096;
+            // Don't see the failure with a multiple of 1
+            int VCOUNT = 2 * COUNT;
+            String arrayJson = toJsonArray(values[i], VCOUNT);
+            StringBuilder sb = new StringBuilder(COUNT + arrayJson.length() + 20);
+            for (int j = 0; j < COUNT; ++j) {
+                sb.append(' ');
+            }
+            sb.append(arrayJson);
+            String DOC = sb.toString();
+            for (int input = 0; input < 2; ++input) {
+                JsonParser p;
+                if (input == 0) {
+                    p = createParserUsingStream(factory, DOC, "UTF-8");
+                } else {
+                    p = factory.createParser(DOC);
+                }
+                assertToken(JsonToken.START_ARRAY, p.nextToken());
+                for (int j = 0; j < VCOUNT; ++j) {
+                    assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+                    assertEquals(values[i], p.getDoubleValue());
+                }
+                assertToken(JsonToken.END_ARRAY, p.nextToken());
+                p.close();
+            }
+        }
+    }
+
+    /*
+    /**********************************************************
+    /* Tests for invalid access
+    /**********************************************************
+     */
+
+    public void testInvalidBooleanAccess() throws Exception {
+        _testInvalidBooleanAccess(MODE_INPUT_STREAM);
+        _testInvalidBooleanAccess(MODE_INPUT_STREAM_THROTTLED);
+        _testInvalidBooleanAccess(MODE_READER);
+        _testInvalidBooleanAccess(MODE_DATA_INPUT);
+    }
+
+    private void _testInvalidBooleanAccess(int mode) throws Exception
+    {
+        JsonParser p = createParser(mode, "[ \"abc\" ]");
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        try {
+            p.getBooleanValue();
+            fail("Expected error trying to call getBooleanValue on non-boolean value");
+        } catch (JsonParseException e) {
+            verifyException(e, "not of boolean type");
+        }
+        p.close();
+    }
+
+    public void testInvalidIntAccess() throws Exception {
+        _testInvalidIntAccess(MODE_INPUT_STREAM);
+        _testInvalidIntAccess(MODE_INPUT_STREAM_THROTTLED);
+        _testInvalidIntAccess(MODE_READER);
+        _testInvalidIntAccess(MODE_DATA_INPUT);
+    }
+    
+    private void _testInvalidIntAccess(int mode) throws Exception
+    {
+        JsonParser p = createParser(mode, "[ \"abc\" ]");
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        try {
+            p.getIntValue();
+            fail("Expected error trying to call getIntValue on non-numeric value");
+        } catch (JsonParseException e) {
+            verifyException(e, "can not use numeric value accessors");
+        }
+        p.close();
+    }
+
+    public void testInvalidLongAccess() throws Exception {
+        _testInvalidLongAccess(MODE_INPUT_STREAM);
+        _testInvalidLongAccess(MODE_INPUT_STREAM_THROTTLED);
+        _testInvalidLongAccess(MODE_READER);
+        _testInvalidLongAccess(MODE_DATA_INPUT);
+    }
+    
+    private void _testInvalidLongAccess(int mode) throws Exception
+    {
+        JsonParser p = createParser(mode, "[ false ]");
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+        try {
+            p.getLongValue();
+            fail("Expected error trying to call getLongValue on non-numeric value");
+        } catch (JsonParseException e) {
+            verifyException(e, "can not use numeric value accessors");
+        }
+        p.close();
+    }
+
+    // [core#317]
+    public void testLongerFloatingPoint() throws Exception
+    {
+        StringBuilder input = new StringBuilder();
+        for (int i = 1; i < 201; i++) {
+            input.append(1);
+        }
+        input.append(".0");
+        final String DOC = input.toString();
+
+        // test out with both Reader and ByteArrayInputStream
+        JsonParser p;
+
+        p = FACTORY.createParser(new StringReader(DOC));
+        _testLongerFloat(p, DOC);
+        p.close();
+        
+        p = FACTORY.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")));
+        _testLongerFloat(p, DOC);
+        p.close();
+    }
+
+    private void _testLongerFloat(JsonParser p, String text) throws IOException
+    {
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertEquals(text, p.getText());
+        assertNull(p.nextToken());
+    }
+
+    /*
+    /**********************************************************
+    /* Helper methods
+    /**********************************************************
+     */
+
+    private String toJsonArray(double v, int n) {
+        StringBuilder sb = new StringBuilder().append('[').append(v);
+        for (int i = 1; i < n; ++i) {
+            sb.append(',').append(v);
+        }
+        return sb.append(']').toString();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/ParserDupHandlingTest.java b/src/test/java/com/fasterxml/jackson/core/read/ParserDupHandlingTest.java
new file mode 100644
index 0000000..79dd355
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/ParserDupHandlingTest.java
@@ -0,0 +1,141 @@
+package com.fasterxml.jackson.core.read;
+
+import com.fasterxml.jackson.core.*;
+
+public class ParserDupHandlingTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    private final String[] DUP_DOCS = new String[] {
+            "{ 'a':1, 'a':2 }",
+            "[{ 'a':1, 'a':2 }]",
+            "{ 'a':1, 'b':2, 'c':3,'a':true,'e':false }",
+            "{ 'foo': { 'bar': [ [ { 'x':3, 'a':1 } ]], 'x':0, 'a':'y', 'b':3,'a':13 } }",
+            "[{'b':1},{'b\":3},[{'a':3}], {'a':1,'a':2}]",
+            "{'b':1,'array':[{'b':3}],'ob':{'b':4,'x':0,'y':3,'a':true,'a':false }}",
+    };
+    {
+        for (int i = 0; i < DUP_DOCS.length; ++i) {
+            DUP_DOCS[i] = aposToQuotes(DUP_DOCS[i]);
+        }
+    }
+
+    public void testSimpleDupCheckDisabled() throws Exception
+    {
+        // first: verify no problems if detection NOT enabled
+        final JsonFactory f = new JsonFactory();
+        assertFalse(f.isEnabled(JsonParser.Feature.STRICT_DUPLICATE_DETECTION));
+        for (String doc : DUP_DOCS) {
+            _testSimpleDupsOk(doc, f, MODE_INPUT_STREAM);
+            _testSimpleDupsOk(doc, f, MODE_INPUT_STREAM_THROTTLED);
+            _testSimpleDupsOk(doc, f, MODE_READER);
+            _testSimpleDupsOk(doc, f, MODE_DATA_INPUT);
+        }
+    }
+
+    public void testSimpleDupsBytes() throws Exception
+    {
+        JsonFactory nonDupF = new JsonFactory();
+        JsonFactory dupF = new JsonFactory();
+        dupF.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
+        for (String doc : DUP_DOCS) {
+            // First, with static setting
+            _testSimpleDupsFail(doc, dupF, MODE_INPUT_STREAM, "a", false);
+            // and then dynamic
+            _testSimpleDupsFail(doc, nonDupF, MODE_INPUT_STREAM, "a", true);
+
+            _testSimpleDupsFail(doc, dupF, MODE_INPUT_STREAM_THROTTLED, "a", false);
+            _testSimpleDupsFail(doc, nonDupF, MODE_INPUT_STREAM_THROTTLED, "a", true);
+        }
+    }
+
+    public void testSimpleDupsDataInput() throws Exception
+    {
+        JsonFactory nonDupF = new JsonFactory();
+        JsonFactory dupF = new JsonFactory();
+        dupF.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
+        for (String doc : DUP_DOCS) {
+            _testSimpleDupsFail(doc, dupF, MODE_DATA_INPUT, "a", false);
+            _testSimpleDupsFail(doc, nonDupF, MODE_DATA_INPUT, "a", true);
+        }
+    }
+    
+    public void testSimpleDupsChars() throws Exception
+    {
+        JsonFactory nonDupF = new JsonFactory();
+        JsonFactory dupF = new JsonFactory();
+        dupF.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
+        for (String doc : DUP_DOCS) {
+            _testSimpleDupsFail(doc, dupF, MODE_READER, "a", false);
+            _testSimpleDupsFail(doc, nonDupF, MODE_READER, "a", true);
+        }
+    }
+    
+    private void _testSimpleDupsOk(final String doc, JsonFactory f,
+            int mode) throws Exception
+    {
+        JsonParser p = createParser(f, mode, doc);
+        JsonToken t = p.nextToken();
+        assertNotNull(t);
+        assertTrue(t.isStructStart());
+
+        int depth = 1;
+
+        while (depth > 0) {
+            switch (p.nextToken()) {
+            case START_ARRAY:
+            case START_OBJECT:
+                ++depth;
+                break;
+            case END_ARRAY:
+            case END_OBJECT:
+                --depth;
+                break;
+            default:
+            }
+        }
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextToken());
+        }
+        p.close();
+    }
+
+    private void _testSimpleDupsFail(final String doc, JsonFactory f,
+            int mode, String name, boolean lazily) throws Exception
+    {
+        JsonParser p = createParser(f, mode, doc);
+        if (lazily) {
+            p.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
+        }
+        JsonToken t = p.nextToken();
+        assertNotNull(t);
+        assertTrue(t.isStructStart());
+
+        int depth = 1;
+        JsonParseException e = null;
+
+        while (depth > 0) {
+            try {
+                switch (p.nextToken()) {
+                case START_ARRAY:
+                case START_OBJECT:
+                    ++depth;
+                    break;
+                case END_ARRAY:
+                case END_OBJECT:
+                    --depth;
+                    break;
+                default:
+                }
+            } catch (JsonParseException e0) {
+                e = e0;
+                break;
+            }
+        }
+        p.close();
+
+        if (e == null) {
+            fail("Should have caught exception for dup");
+        }
+        verifyException(e, "duplicate field '"+name+"'");
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/ParserErrorHandlingTest.java b/src/test/java/com/fasterxml/jackson/core/read/ParserErrorHandlingTest.java
new file mode 100644
index 0000000..bb84134
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/ParserErrorHandlingTest.java
@@ -0,0 +1,111 @@
+package com.fasterxml.jackson.core.read;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+
+public class ParserErrorHandlingTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    public void testInvalidKeywordsBytes() throws Exception {
+        _testInvalidKeywords(MODE_INPUT_STREAM);
+        _testInvalidKeywords(MODE_INPUT_STREAM_THROTTLED);
+        _testInvalidKeywords(MODE_DATA_INPUT);
+    }
+    
+    public void testInvalidKeywordsChars() throws Exception {
+        _testInvalidKeywords(MODE_READER);
+    }
+
+    // Tests for [core#105] ("eager number parsing misses errors")
+    public void testMangledNumbersBytes() throws Exception {
+        _testMangledNumbers(MODE_INPUT_STREAM);
+        _testMangledNumbers(MODE_INPUT_STREAM_THROTTLED);
+        _testInvalidKeywords(MODE_DATA_INPUT);
+    }
+
+    public void testMangledNumbersChars() throws Exception {
+        _testMangledNumbers(MODE_READER);
+    }
+    
+    /*
+    /**********************************************************
+    /* Helper methods
+    /**********************************************************
+     */
+    
+    private void _testInvalidKeywords(int mode) throws Exception
+    {
+        doTestInvalidKeyword1(mode, "nul");
+        doTestInvalidKeyword1(mode, "Null");
+        doTestInvalidKeyword1(mode, "nulla");
+        doTestInvalidKeyword1(mode, "fal");
+        doTestInvalidKeyword1(mode, "False");
+        doTestInvalidKeyword1(mode, "fals0");
+        doTestInvalidKeyword1(mode, "falsett0");
+        doTestInvalidKeyword1(mode, "tr");
+        doTestInvalidKeyword1(mode, "truE");
+        doTestInvalidKeyword1(mode, "treu");
+        doTestInvalidKeyword1(mode, "trueenough");
+        doTestInvalidKeyword1(mode, "C");
+    }
+
+    private void doTestInvalidKeyword1(int mode, String value)
+        throws IOException
+    {
+        String doc = "{ \"key1\" : "+value+" }";
+        JsonParser p = createParser(mode, doc);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        // Note that depending on parser impl, we may
+        // get the exception early or late...
+        try {
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+            p.nextToken();
+            fail("Expected an exception for malformed value keyword");
+        } catch (JsonParseException jex) {
+            verifyException(jex, "Unrecognized token");
+            verifyException(jex, value);
+        } finally {
+            p.close();
+        }
+
+        // Try as root-level value as well:
+        doc = value + " "; // may need space after for DataInput
+        p = createParser(mode, doc);
+        try {
+            p.nextToken();
+            fail("Expected an exception for malformed value keyword");
+        } catch (JsonParseException jex) {
+            verifyException(jex, "Unrecognized token");
+            verifyException(jex, value);
+        } finally {
+            p.close();
+        }
+    }
+
+    private void _testMangledNumbers(int mode) throws Exception
+    {
+        String doc = "123true";
+        JsonParser p = createParser(mode, doc);
+        try {
+            JsonToken t = p.nextToken();
+            fail("Should have gotten an exception; instead got token: "+t);
+        } catch (JsonParseException e) {
+            verifyException(e, "expected space");
+        }
+        p.close();
+
+        // Also test with floats
+        doc = "1.5false";
+        p = createParser(mode, doc);
+        try {
+            JsonToken t = p.nextToken();
+            fail("Should have gotten an exception; instead got token: "+t);
+        } catch (JsonParseException e) {
+            verifyException(e, "expected space");
+        }
+        p.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/ParserScopeMatchingTest.java b/src/test/java/com/fasterxml/jackson/core/read/ParserScopeMatchingTest.java
new file mode 100644
index 0000000..55c261c
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/ParserScopeMatchingTest.java
@@ -0,0 +1,188 @@
+package com.fasterxml.jackson.core.read;
+
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Set of basic unit tests for verifying that Array/Object scopes
+ * are properly matched.
+ */
+@SuppressWarnings("resource")
+public class ParserScopeMatchingTest extends BaseTest
+{
+    public void testUnclosedArray() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testUnclosedArray(mode);
+        }
+    }
+        
+    public void _testUnclosedArray(int mode) throws Exception
+    {
+        JsonParser p = createParser(mode, "[ 1, 2 ");
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+
+        try {
+            p.nextToken();
+        } catch (JsonParseException pe) {
+            verifyException(pe, "expected close marker for ARRAY");
+            return;
+        } catch (IOException ie) {
+            // DataInput behaves bit differently
+            if (mode == MODE_DATA_INPUT) {
+                verifyException(ie, "end-of-input");
+                return;
+            }
+        }
+        fail("Expected an exception for unclosed ARRAY");
+    }
+
+    public void testUnclosedObject() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testUnclosedObject(mode);
+        }
+    }
+    
+    private void _testUnclosedObject(int mode) throws Exception
+    {
+        JsonParser p = createParser(mode, "{ \"key\" : 3  ");
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+
+        try {
+            p.nextToken();
+            fail("Expected an exception for unclosed OBJECT");
+        } catch (JsonParseException pe) {
+            verifyException(pe, "expected close marker for OBJECT");
+        } catch (IOException ie) {
+            // DataInput behaves bit differently
+            if (mode == MODE_DATA_INPUT) {
+                verifyException(ie, "end-of-input");
+                return;
+            }
+        }
+    }
+
+    public void testEOFInName() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testEOFInName(mode);
+        }
+    }
+    
+    public void _testEOFInName(int mode) throws Exception
+    {
+        final String JSON = "{ \"abcd";
+        JsonParser p = createParser(mode, JSON);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Expected an exception for EOF");
+        } catch (JsonParseException pe) {
+            verifyException(pe, "Unexpected end-of-input");
+        } catch (IOException ie) {
+            // DataInput behaves bit differently
+            if (mode == MODE_DATA_INPUT) {
+                verifyException(ie, "end-of-input");
+                return;
+            }
+        }
+    }
+
+    public void testWeirdToken() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testWeirdToken(mode);
+        }
+    }
+    
+    private void _testWeirdToken(int mode) throws Exception
+    {
+        final String JSON = "[ nil ]";
+        JsonParser p = createParser(mode, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Expected an exception for weird token");
+        } catch (JsonParseException pe) {
+            verifyException(pe, "Unrecognized token");
+        }
+        p.close();
+    }
+
+    public void testMismatchArrayToObject() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testMismatchArrayToObject(mode);
+        }
+    }
+
+    private void _testMismatchArrayToObject(int mode) throws Exception
+    {
+        final String JSON = "[ 1, 2 }";
+        JsonParser p = createParser(mode, JSON);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        try {
+            p.nextToken();
+            fail("Expected an exception for incorrectly closed ARRAY");
+        } catch (JsonParseException pe) {
+            verifyException(pe, "Unexpected close marker '}': expected ']'");
+        }
+        p.close();
+    }
+
+    public void testMismatchObjectToArray() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testMismatchObjectToArray(mode);
+        }
+    }
+    
+    private void _testMismatchObjectToArray(int mode) throws Exception
+    {
+        final String JSON = "{ ]";
+        JsonParser p = createParser(mode, JSON);
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+            
+        try {
+            p.nextToken();
+            fail("Expected an exception for incorrectly closed OBJECT");
+        } catch (JsonParseException pe) {
+            verifyException(pe, "Unexpected close marker ']': expected '}'");
+        }
+        p.close();
+    }
+
+    public void testMisssingColon() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testMisssingColon(mode);
+        }
+    }
+
+    private void _testMisssingColon(int mode) throws Exception
+    {
+        final String JSON = "{ \"a\" \"b\" }";
+        JsonParser p = createParser(mode, JSON);
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        try {
+            // can be either here, or with next one...
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+            p.nextToken();
+            fail("Expected an exception for missing semicolon");
+        } catch (JsonParseException pe) {
+            verifyException(pe, "was expecting a colon");
+        }
+        p.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestParserSymbols.java b/src/test/java/com/fasterxml/jackson/core/read/ParserSymbolHandlingTest.java
similarity index 93%
rename from src/test/java/com/fasterxml/jackson/core/json/TestParserSymbols.java
rename to src/test/java/com/fasterxml/jackson/core/read/ParserSymbolHandlingTest.java
index 8d87beb..e2cab9e 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestParserSymbols.java
+++ b/src/test/java/com/fasterxml/jackson/core/read/ParserSymbolHandlingTest.java
@@ -1,11 +1,11 @@
-package com.fasterxml.jackson.core.json;
+package com.fasterxml.jackson.core.read;
 
 import com.fasterxml.jackson.core.*;
 
-public class TestParserSymbols
+public class ParserSymbolHandlingTest
     extends com.fasterxml.jackson.core.BaseTest
 {
-    // For [Issue#148]
+    // For [core#148]
     public void testSymbolsWithNullBytes() throws Exception {
         JsonFactory f = new JsonFactory();
         _testSymbolsWithNull(f, true);
@@ -13,7 +13,7 @@
         _testSymbolsWithNull(f, true);
     }
 
-    // For [Issue#148]
+    // For [core#148]
     public void testSymbolsWithNullChars() throws Exception {
         JsonFactory f = new JsonFactory();
         _testSymbolsWithNull(f, false);
diff --git a/src/test/java/com/fasterxml/jackson/core/read/TestJsonParserBinary.java b/src/test/java/com/fasterxml/jackson/core/read/TestJsonParserBinary.java
new file mode 100644
index 0000000..3c5801c
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/TestJsonParserBinary.java
@@ -0,0 +1,139 @@
+package com.fasterxml.jackson.core.read;
+
+import java.io.*;
+
+import com.fasterxml.jackson.core.*;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for verifying that accessing base64 encoded content works ok.
+ */
+public class TestJsonParserBinary
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    /*
+    /**********************************************************************
+    /* Unit tests
+    /**********************************************************************
+     */
+
+    public void testSimple() throws IOException
+    {
+        for (int mode : ALL_MODES) {
+            _testSimple(mode);
+        }
+    }
+
+    public void testInArray() throws IOException
+    {
+        for (int mode : ALL_MODES) {
+            _testInArray(mode);
+        }
+    }
+
+    public void testWithEscaped() throws IOException {
+        for (int mode : ALL_MODES) {
+            _testEscaped(mode);
+        }
+    }
+
+    /*
+    /**********************************************************************
+    /* Actual test methods
+    /**********************************************************************
+     */
+
+    private void _testSimple(int mode)
+        throws IOException
+    {
+        /* The usual sample input string, from Thomas Hobbes's "Leviathan"
+         * (via Wikipedia)
+         */
+        final String RESULT = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";
+        final byte[] RESULT_BYTES = RESULT.getBytes("US-ASCII");
+
+        // And here's what should produce it...
+        final String INPUT_STR = 
+ "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz"
++"IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg"
++"dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu"
++"dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo"
++"ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="
+            ;
+
+        final String DOC = "\""+INPUT_STR+"\"";
+        JsonParser p = createParser(mode, DOC);
+
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        byte[] data = p.getBinaryValue();
+        assertNotNull(data);
+        assertArrayEquals(RESULT_BYTES, data);
+        p.close();
+    }
+
+    private void _testInArray(int mode) throws IOException
+    {
+        JsonFactory f = new JsonFactory();
+
+        final int entryCount = 7;
+
+        StringWriter sw = new StringWriter();
+        JsonGenerator jg = f.createGenerator(sw);
+        jg.writeStartArray();
+
+        byte[][] entries = new byte[entryCount][];
+        for (int i = 0; i < entryCount; ++i) {
+            byte[] b = new byte[200 + i * 100];
+            for (int x = 0; x < b.length; ++x) {
+                b[x] = (byte) (i + x);
+            }
+            entries[i] = b;
+            jg.writeBinary(b);
+        }
+
+        jg.writeEndArray();
+        jg.close();
+
+        JsonParser p = createParser(f, mode, sw.toString());
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+
+        for (int i = 0; i < entryCount; ++i) {
+            assertToken(JsonToken.VALUE_STRING, p.nextToken());
+            byte[] b = p.getBinaryValue();
+            assertArrayEquals(entries[i], b);
+        }
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+    }
+
+    private void _testEscaped(int mode) throws IOException
+    {
+        // Input: "Test!" -> "VGVzdCE="
+
+        // First, try with embedded linefeed half-way through:
+
+        String DOC = quote("VGVz\\ndCE="); // note: must double-quote to get linefeed
+        JsonParser p = createParser(mode, DOC);
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        byte[] b = p.getBinaryValue();
+        assertEquals("Test!", new String(b, "US-ASCII"));
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextToken());
+        }
+        p.close();
+
+        // and then with escaped chars
+//        DOC = quote("V\\u0047V\\u007AdCE="); // note: must escape backslash...
+        DOC = quote("V\\u0047V\\u007AdCE="); // note: must escape backslash...
+        p = createParser(mode, DOC);
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        b = p.getBinaryValue();
+        assertEquals("Test!", new String(b, "US-ASCII"));
+        if (mode != MODE_DATA_INPUT) {
+            assertNull(p.nextToken());
+        }
+        p.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/UTF8NamesParseTest.java b/src/test/java/com/fasterxml/jackson/core/read/UTF8NamesParseTest.java
new file mode 100644
index 0000000..029bcc3
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/UTF8NamesParseTest.java
@@ -0,0 +1,237 @@
+package com.fasterxml.jackson.core.read;
+
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.io.SerializedString;
+
+import java.io.*;
+import java.util.Random;
+
+/**
+ * Set of basic unit tests for verifying that the basic parser
+ * functionality works as expected.
+ */
+public class UTF8NamesParseTest
+    extends BaseTest
+{
+    final static String[] UTF8_2BYTE_STRINGS = new String[] {
+        /* This may look funny, but UTF8 scanner has fairly
+         * elaborate decoding machinery, and it is indeed
+         * necessary to try out various combinations...
+         */
+        "b", "A\u00D8", "abc", "c3p0",
+        "12345", "......", "Long\u00FAer",
+        "Latin1-fully-\u00BE-develop\u00A8d",
+        "Some very long name, ridiculously long actually to see that buffer expansion works: \u00BF?"
+    };
+
+    final static String[] UTF8_3BYTE_STRINGS = new String[] {
+        "\uC823?", "A\u400F", "1\u1234?",
+        "Ab123\u4034",
+        "Even-longer:\uC023"
+    };
+
+    public void testEmptyName() throws Exception
+    {
+        _testEmptyName(MODE_INPUT_STREAM);
+        _testEmptyName(MODE_INPUT_STREAM_THROTTLED);
+        _testEmptyName(MODE_DATA_INPUT);
+    }
+
+    private void _testEmptyName(int mode) throws Exception
+    {
+        final String DOC = "{ \"\" : \"\" }";
+        JsonParser p = createParser(mode, DOC);
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("", p.getCurrentName());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("", p.getText());
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        p.close();
+    }
+
+    public void testUtf8Name2Bytes() throws Exception
+    {
+        _testUtf8Name2Bytes(MODE_INPUT_STREAM);
+        _testUtf8Name2Bytes(MODE_INPUT_STREAM_THROTTLED);
+        _testUtf8Name2Bytes(MODE_DATA_INPUT);
+    }
+
+    private void _testUtf8Name2Bytes(int mode) throws Exception
+    {
+        final String[] NAMES = UTF8_2BYTE_STRINGS;
+
+        for (int i = 0; i < NAMES.length; ++i) {
+            String NAME = NAMES[i];
+            String DOC = "{ \""+NAME+"\" : 0 }";
+            JsonParser p = createParser(mode, DOC);
+            assertToken(JsonToken.START_OBJECT, p.nextToken());
+
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+
+            assertTrue(p.hasToken(JsonToken.FIELD_NAME));
+            assertTrue(p.hasTokenId(JsonTokenId.ID_FIELD_NAME));
+            
+            assertEquals(NAME, p.getCurrentName());
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertTrue(p.hasToken(JsonToken.VALUE_NUMBER_INT));
+            assertTrue(p.hasTokenId(JsonTokenId.ID_NUMBER_INT));
+
+            // should retain name during value entry, too
+            assertEquals(NAME, p.getCurrentName());
+            
+            assertToken(JsonToken.END_OBJECT, p.nextToken());
+            p.close();
+        }
+    }
+
+    public void testUtf8Name3Bytes() throws Exception
+    {
+        _testUtf8Name3Bytes(MODE_INPUT_STREAM);
+        _testUtf8Name3Bytes(MODE_DATA_INPUT);
+        _testUtf8Name3Bytes(MODE_INPUT_STREAM_THROTTLED);
+    }
+
+    public void _testUtf8Name3Bytes(int mode) throws Exception
+    {
+        final String[] NAMES = UTF8_3BYTE_STRINGS;
+
+        for (int i = 0; i < NAMES.length; ++i) {
+            String NAME = NAMES[i];
+            String DOC = "{ \""+NAME+"\" : true }";
+
+            JsonParser p = createParser(mode, DOC);
+            assertToken(JsonToken.START_OBJECT, p.nextToken());
+            
+            assertToken(JsonToken.FIELD_NAME, p.nextToken());
+            assertEquals(NAME, p.getCurrentName());
+            assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+            assertEquals(NAME, p.getCurrentName());
+            
+            assertToken(JsonToken.END_OBJECT, p.nextToken());
+            
+            p.close();
+        }
+    }
+
+    // How about tests for Surrogate-Pairs?
+
+    public void testUtf8StringTrivial() throws Exception
+    {
+        _testUtf8StringTrivial(MODE_INPUT_STREAM);
+        _testUtf8StringTrivial(MODE_DATA_INPUT);
+        _testUtf8StringTrivial(MODE_INPUT_STREAM_THROTTLED);
+    }
+    
+    public void _testUtf8StringTrivial(int mode) throws Exception
+    {
+        String[] VALUES = UTF8_2BYTE_STRINGS;
+        for (int i = 0; i < VALUES.length; ++i) {
+            String VALUE = VALUES[i];
+            String DOC = "[ \""+VALUE+"\" ]";
+            JsonParser p = createParser(mode, DOC);
+            assertToken(JsonToken.START_ARRAY, p.nextToken());
+            assertToken(JsonToken.VALUE_STRING, p.nextToken());
+            String act = getAndVerifyText(p);
+            if (act.length() != VALUE.length()) {
+                fail("Failed for value #"+(i+1)+"/"+VALUES.length+": length was "+act.length()+", should be "+VALUE.length());
+            }
+            assertEquals(VALUE, act);
+            assertToken(JsonToken.END_ARRAY, p.nextToken());
+            p.close();
+        }
+
+        VALUES = UTF8_3BYTE_STRINGS;
+        for (int i = 0; i < VALUES.length; ++i) {
+            String VALUE = VALUES[i];
+            String DOC = "[ \""+VALUE+"\" ]";
+            JsonParser p = createParser(mode, DOC);
+            assertToken(JsonToken.START_ARRAY, p.nextToken());
+            assertToken(JsonToken.VALUE_STRING, p.nextToken());
+            assertEquals(VALUE, getAndVerifyText(p));
+            assertToken(JsonToken.END_ARRAY, p.nextToken());
+            p.close();
+        }
+    }
+
+    public void testUtf8StringValue() throws Exception
+    {
+        _testUtf8StringValue(MODE_INPUT_STREAM);
+        _testUtf8StringValue(MODE_DATA_INPUT);
+        _testUtf8StringValue(MODE_INPUT_STREAM_THROTTLED);
+    }
+
+    public void _testUtf8StringValue(int mode) throws Exception
+    {
+        Random r = new Random(13);
+        //int LEN = 72000;
+        int LEN = 720;
+        StringBuilder sb = new StringBuilder(LEN + 20);
+        while (sb.length() < LEN) {
+            int c;
+            if (r.nextBoolean()) { // ascii
+                c = 32 + (r.nextInt() & 0x3F);
+                if (c == '"' || c == '\\') {
+                    c = ' ';
+                }
+            } else if (r.nextBoolean()) { // 2-byte
+                c = 160 + (r.nextInt() & 0x3FF);
+            } else if (r.nextBoolean()) { // 3-byte (non-surrogate)
+                c = 8000 + (r.nextInt() & 0x7FFF);
+            } else { // surrogates (2 chars)
+                int value = r.nextInt() & 0x3FFFF; // 20-bit, ~ 1 million
+                sb.append((char) (0xD800 + (value >> 10)));
+                c = (0xDC00 + (value & 0x3FF));
+
+            }
+            sb.append((char) c);
+        }
+
+        ByteArrayOutputStream bout = new ByteArrayOutputStream(LEN);
+        OutputStreamWriter out = new OutputStreamWriter(bout, "UTF-8");
+        out.write("[\"");
+        String VALUE = sb.toString();
+        out.write(VALUE);
+        out.write("\"]");
+        out.close();
+
+        byte[] data = bout.toByteArray();
+
+        JsonParser p = createParser(mode, data);
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        String act = p.getText();
+
+        assertEquals(VALUE.length(), act.length());
+        assertEquals(VALUE, act);
+        p.close();
+    }
+
+    public void testNextFieldName() throws IOException
+    {
+		ByteArrayOutputStream os = new ByteArrayOutputStream();
+		os.write('{');
+		for (int i = 0; i < 3994; i++) {
+			os.write(' ');
+		}
+		os.write("\"id\":2".getBytes("UTF-8"));
+		os.write('}');
+		byte[] data = os.toByteArray();
+
+		_testNextFieldName(MODE_INPUT_STREAM, data);
+          _testNextFieldName(MODE_DATA_INPUT, data);
+          _testNextFieldName(MODE_INPUT_STREAM_THROTTLED, data);
+    }
+
+    private void _testNextFieldName(int mode, byte[] doc) throws IOException
+    {
+        SerializedString id = new SerializedString("id");
+        JsonParser parser = createParser(mode, doc);
+        assertEquals(parser.nextToken(), JsonToken.START_OBJECT);
+        assertTrue(parser.nextFieldName(id));
+        assertEquals(parser.nextToken(), JsonToken.VALUE_NUMBER_INT);
+        assertEquals(parser.nextToken(), JsonToken.END_OBJECT);
+        parser.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/ValueConversionsTest.java b/src/test/java/com/fasterxml/jackson/core/read/ValueConversionsTest.java
new file mode 100644
index 0000000..1ec2d3e
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/ValueConversionsTest.java
@@ -0,0 +1,187 @@
+package com.fasterxml.jackson.core.read;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+
+public class ValueConversionsTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    public void testAsInt() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testAsInt(mode);
+        }
+    }
+
+    private void _testAsInt(int mode) throws Exception
+    {
+        final String input = "[ 1, -3, 4.98, true, false, null, \"-17\", \"foo\" ]";
+        JsonParser p = createParser(mode, input);
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertEquals(0, p.getValueAsLong());
+        assertEquals(9, p.getValueAsLong(9));
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(1, p.getValueAsLong());
+        assertEquals(1, p.getValueAsLong(-99));
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(-3, p.getValueAsLong());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertEquals(4, p.getValueAsLong());
+        assertEquals(4, p.getValueAsLong(99));
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertEquals(1, p.getValueAsLong());
+        assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+        assertEquals(0, p.getValueAsLong());
+        assertToken(JsonToken.VALUE_NULL, p.nextToken());
+        assertEquals(0, p.getValueAsLong());
+        assertEquals(0, p.getValueAsLong(27));
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(-17, p.getValueAsLong());
+        assertEquals(-17, p.getValueAsLong(3));
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(0, p.getValueAsLong());
+        assertEquals(9, p.getValueAsLong(9));
+        
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        assertEquals(0, p.getValueAsLong());
+        assertEquals(9, p.getValueAsLong(9));
+
+        p.close();
+    }
+
+    public void testAsBoolean() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testAsBoolean(mode);
+        }
+    }
+
+    private void _testAsBoolean(int mode) throws Exception
+    {
+        final String input = "[ true, false, null, 1, 0, \"true\", \"false\", \"foo\" ]";
+        JsonParser p = createParser(mode, input);
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertEquals(false, p.getValueAsBoolean());
+        assertEquals(true, p.getValueAsBoolean(true));
+
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertEquals(true, p.getValueAsBoolean());
+        assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+        assertEquals(false, p.getValueAsBoolean());
+        assertToken(JsonToken.VALUE_NULL, p.nextToken());
+        assertEquals(false, p.getValueAsBoolean());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(1, p.getIntValue());
+        assertEquals(true, p.getValueAsBoolean());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(0, p.getIntValue());
+        assertEquals(false, p.getValueAsBoolean());
+
+        assertToken(JsonToken.VALUE_STRING, p.nextToken()); // "true"
+        assertEquals(true, p.getValueAsBoolean());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(false, p.getValueAsBoolean());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(false, p.getValueAsBoolean());
+        
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        assertEquals(false, p.getValueAsBoolean());
+        assertEquals(true, p.getValueAsBoolean(true));
+
+        p.close();
+    }
+
+    public void testAsLong() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testAsLong(mode);
+        }
+    }
+        
+    public void _testAsLong(int mode) throws Exception
+    {
+        final String input = "[ 1, -3, 4.98, true, false, null, \"-17\", \"foo\" ]";
+        JsonParser p = createParser(mode, input);
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertEquals(0L, p.getValueAsLong());
+        assertEquals(9L, p.getValueAsLong(9L));
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(1L, p.getValueAsLong());
+        assertEquals(1L, p.getValueAsLong(-99L));
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(-3L, p.getValueAsLong());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertEquals(4L, p.getValueAsLong());
+        assertEquals(4L, p.getValueAsLong(99L));
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertEquals(1L, p.getValueAsLong());
+        assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+        assertEquals(0L, p.getValueAsLong());
+        assertToken(JsonToken.VALUE_NULL, p.nextToken());
+        assertEquals(0L, p.getValueAsLong());
+        assertEquals(0L, p.getValueAsLong(27L));
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(-17L, p.getValueAsLong());
+        assertEquals(-17L, p.getValueAsLong(3L));
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(0L, p.getValueAsLong());
+        assertEquals(9L, p.getValueAsLong(9L));
+        
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        assertEquals(0L, p.getValueAsLong());
+        assertEquals(9L, p.getValueAsLong(9L));
+
+        p.close();
+    }
+
+    public void testAsDouble() throws Exception
+    {
+        for (int mode : ALL_MODES) {
+            _testAsDouble(mode);
+        }
+    }
+
+    private void _testAsDouble(int mode) throws Exception
+    {
+        final String input = "[ 1, -3, 4.98, true, false, null, \"-17.25\", \"foo\" ]";
+        JsonParser p = createParser(mode, input);
+
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertEquals(0.0, p.getValueAsDouble());
+        assertEquals(9.0, p.getValueAsDouble(9.0));
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(1., p.getValueAsDouble());
+        assertEquals(1., p.getValueAsDouble(-99.0));
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(-3., p.getValueAsDouble());
+        assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+        assertEquals(4.98, p.getValueAsDouble());
+        assertEquals(4.98, p.getValueAsDouble(12.5));
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertEquals(1.0, p.getValueAsDouble());
+        assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+        assertEquals(0.0, p.getValueAsDouble());
+        assertToken(JsonToken.VALUE_NULL, p.nextToken());
+        assertEquals(0.0, p.getValueAsDouble());
+        assertEquals(0.0, p.getValueAsDouble(27.8));
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(-17.25, p.getValueAsDouble());
+        assertEquals(-17.25, p.getValueAsDouble(1.9));
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(0.0, p.getValueAsDouble());
+        assertEquals(1.25, p.getValueAsDouble(1.25));
+        
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        assertEquals(0.0, p.getValueAsDouble());
+        assertEquals(7.5, p.getValueAsDouble(7.5));
+
+        p.close();
+    }
+    
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/testsupport/MockDataInput.java b/src/test/java/com/fasterxml/jackson/core/testsupport/MockDataInput.java
new file mode 100644
index 0000000..bdd71b2
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/testsupport/MockDataInput.java
@@ -0,0 +1,99 @@
+package com.fasterxml.jackson.core.testsupport;
+
+import java.io.*;
+
+public class MockDataInput implements DataInput
+{
+    private final InputStream _input;
+
+    public MockDataInput(byte[] data) {
+        _input = new ByteArrayInputStream(data);
+    }
+
+    public MockDataInput(String utf8Data) throws IOException {
+        _input = new ByteArrayInputStream(utf8Data.getBytes("UTF-8"));
+    }
+
+    public MockDataInput(InputStream in) {
+        _input = in;
+    }
+    
+    @Override
+    public void readFully(byte[] b) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void readFully(byte[] b, int off, int len) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int skipBytes(int n) throws IOException {
+        return (int) _input.skip(n);
+    }
+
+    @Override
+    public boolean readBoolean() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public byte readByte() throws IOException {
+        int ch = _input.read();
+        if (ch < 0) {
+            throw new IOException("End-of-input for readByte()");
+        }
+        return (byte) ch;
+    }
+
+    @Override
+    public int readUnsignedByte() throws IOException {
+        return readByte() & 0xFF;
+    }
+
+    @Override
+    public short readShort() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int readUnsignedShort() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public char readChar() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int readInt() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long readLong() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public float readFloat() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public double readDouble() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String readLine() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String readUTF() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/testsupport/ThrottledInputStream.java b/src/test/java/com/fasterxml/jackson/core/testsupport/ThrottledInputStream.java
new file mode 100644
index 0000000..4b26a1e
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/testsupport/ThrottledInputStream.java
@@ -0,0 +1,32 @@
+package com.fasterxml.jackson.core.testsupport;
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ThrottledInputStream extends FilterInputStream
+{
+    protected final int _maxBytes;
+
+    public ThrottledInputStream(byte[] data, int maxBytes)
+    {
+        this(new ByteArrayInputStream(data), maxBytes);
+    }
+    
+    public ThrottledInputStream(InputStream in, int maxBytes)
+    {
+        super(in);
+        _maxBytes = maxBytes;
+    }
+
+    @Override
+    public int read(byte[] buf) throws IOException {
+        return read(buf, 0, buf.length);
+    }
+    
+    @Override
+    public int read(byte[] buf, int offset, int len) throws IOException {
+        return in.read(buf, offset, Math.min(_maxBytes, len));
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java b/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java
index 9cce04a..8fe7db3 100644
--- a/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java
+++ b/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java
@@ -18,7 +18,7 @@
         JsonParser parser = JSON_F.createParser("[ 1, true, null, { } ]");
         JsonParserDelegate del = new JsonParserDelegate(parser);
         
-        assertNull(del.getCurrentToken());
+        assertNull(del.currentToken());
         assertToken(JsonToken.START_ARRAY, del.nextToken());
         assertEquals("[", del.getText());
         assertToken(JsonToken.VALUE_NUMBER_INT, del.nextToken());
diff --git a/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java b/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
index 4f467fe..bad5bdb 100644
--- a/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
+++ b/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
@@ -11,8 +11,7 @@
 public class TestNumberPrinting
     extends com.fasterxml.jackson.core.BaseTest
 {
-    public void testIntPrinting()
-        throws Exception
+    public void testIntPrinting() throws Exception
     {
         assertIntPrint(0);
         assertIntPrint(-3);
@@ -39,8 +38,7 @@
         }
     }
 
-    public void testLongPrinting()
-        throws Exception
+    public void testLongPrinting() throws Exception
     {
         // First, let's just cover couple of edge cases
         assertLongPrint(0L, 0);
@@ -60,9 +58,9 @@
     }
 
     /*
-    ////////////////////////////////////////////////////////
-    // Internal methods
-    ////////////////////////////////////////////////////////
+    /**********************************************************
+    /* Internal methods
+    /**********************************************************
      */
 
     private void assertIntPrint(int value)
@@ -73,6 +71,10 @@
         if (!exp.equals(act)) {
             assertEquals("Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+")", exp, act);
         }
+        String alt = NumberOutput.toString(value);
+        if (!exp.equals(alt)) {
+            assertEquals("Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+")", exp, act);
+        }
     }
 
     private void assertLongPrint(long value, int index)
@@ -83,6 +85,10 @@
         if (!exp.equals(act)) {
             assertEquals("Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+"; number index "+index+")", exp, act);
         }
+        String alt = NumberOutput.toString(value);
+        if (!exp.equals(alt)) {
+            assertEquals("Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+"; number index "+index+")", exp, act);
+        }
     }
 
     private String printToString(int value)
@@ -99,4 +105,3 @@
         return new String(buffer, 0, offset);
     }
 }
-