Implemented [JACKSON-24], some testing improvements.

diff --git a/build-coverage.xml b/build-coverage.xml
index a3a5d9f..6cd7da4 100644
--- a/build-coverage.xml
+++ b/build-coverage.xml
@@ -18,9 +18,12 @@
       <!-- First, need to instrument classes -->
       <property name="cobertura.instr.dir" value="${dir.build}/cobertura-instr" />
       <cobertura-instrument todir="${cobertura.instr.dir}">
-        <fileset dir="${dir.build.classes}">
+        <fileset dir="${dir.build.classes.core}">
           <include name="org/codehaus/jackson/**/*.class"/>
         </fileset>
+        <fileset dir="${dir.build.classes.mapper}">
+          <include name="org/codehaus/jackson/map/**/*.class"/>
+        </fileset>
       </cobertura-instrument>
 
       <junit fork="once" printsummary="yes" haltonfailure="no" showoutput="yes"
@@ -39,7 +42,6 @@
             <!-- Order is important: must first have instrumented classes -->
             <classpath location="${cobertura.instr.dir}" />
 
-            <classpath refid="compile-classpath" />
             <!-- Actual tests: -->
             <classpath path="${dir.test.classes}" />
             <!-- Cobertura support: -->
@@ -50,7 +52,8 @@
                      like interfaces. So some of the class files are
                      needed from non-instrumented location
                   -->
-                <pathelement path="${dir.build.classes}" />
+                <pathelement path="${dir.build.classes.core}" />
+                <pathelement path="${dir.build.classes.mapper}" />
                 <path refid="junit-libs"/>
             </classpath>     
         </junit>
@@ -79,9 +82,9 @@
         <junit fork="no" maxmemory="128M" showoutput="no" printsummary="yes">
           <formatter type="plain" usefile="no" />
           <test name="${test}" />
-          <classpath refid="compile-classpath" />
           <classpath>
-                <pathelement path="${dir.build.classes}" />
+                <pathelement path="${dir.build.classes.core}" />
+                <pathelement path="${dir.build.classes.mapper}" />
                 <pathelement location="${dir.test.classes}" /> 
                 <path refid="junit-libs"/>
           </classpath>     
diff --git a/release-notes/VERSION b/release-notes/VERSION
index 0c6ba92..ce55867 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -27,6 +27,9 @@
 
   Improvements:
 
+  * [JACKSON-24]: Add efficient byte-array - based parser factory
+    method to JsonFactory (has maybe 5% improvement over wrapping
+    in ByteArrayInputStream).
   * [JACKSON-29]: Split classes in 2 jars: core that has parser and
     generator APIs and implementations; and mapper jar that has object
     and tree mapper code.
diff --git a/run-json-perf.sh b/run-json-perf.sh
index fd71819..01cfe8b 100755
--- a/run-json-perf.sh
+++ b/run-json-perf.sh
@@ -1,5 +1,6 @@
 #!/bin/sh
 
-java -Xmx48m -server -cp build/perf-classes:build/classes:lib/perf/\* \
+java -Xmx48m -server -cp build/perf-classes:build/classes/core\
+:build/classes/mapper:lib/perf/\* \
  TestJsonPerf \
  $*
diff --git a/src/java/org/codehaus/jackson/JsonFactory.java b/src/java/org/codehaus/jackson/JsonFactory.java
index e34daf8..8e2d955 100644
--- a/src/java/org/codehaus/jackson/JsonFactory.java
+++ b/src/java/org/codehaus/jackson/JsonFactory.java
@@ -254,21 +254,20 @@
         return new ReaderBasedParser(_createContext(r, false), _parserFeatures, r, _charSymbols.makeChild());
     }
 
-    public JsonParser createJsonParser(byte[] data, int offset, int len)
-        throws IOException, JsonParseException
-    {
-        // !!! TODO: make efficient (see [JACKSON-24])
-        InputStream in = new ByteArrayInputStream(data, offset, len);
-        // true -> must be managed as caller didn't hand stream
-        return _createJsonParser(in,  _createContext(in, true));
-    }
-
     public final JsonParser createJsonParser(byte[] data)
         throws IOException, JsonParseException
     {
         return createJsonParser(data, 0, data.length);
     }
 
+    public JsonParser createJsonParser(byte[] data, int offset, int len)
+        throws IOException, JsonParseException
+    {
+        // true -> managed (doesn't really matter; we have no stream!)
+        IOContext ctxt = _createContext(data, true);
+        return new ByteSourceBootstrapper(ctxt, data, offset, len).constructParser(_parserFeatures, _byteSymbols.makeChild(), _charSymbols.makeChild());
+    }
+
     public final JsonParser createJsonParser(String content)
         throws IOException, JsonParseException
     {
@@ -280,7 +279,7 @@
     private JsonParser _createJsonParser(InputStream in, IOContext ctxt)
         throws IOException, JsonParseException
     {
-        return new ByteSourceBootstrapper(ctxt, in).constructParser(_parserFeatures, _byteSymbols, _charSymbols);
+        return new ByteSourceBootstrapper(ctxt, in).constructParser(_parserFeatures, _byteSymbols.makeChild(), _charSymbols.makeChild());
     }
 
     /*
diff --git a/src/java/org/codehaus/jackson/map/ObjectMapper.java b/src/java/org/codehaus/jackson/map/ObjectMapper.java
index eb4ab25..f6e3d55 100644
--- a/src/java/org/codehaus/jackson/map/ObjectMapper.java
+++ b/src/java/org/codehaus/jackson/map/ObjectMapper.java
@@ -257,6 +257,22 @@
         return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), TypeFactory.instance.fromTypeReference(valueTypeRef));
     } 
 
+    @SuppressWarnings("unchecked")
+    public <T> T readValue(byte[] src, int offset, int len, 
+                               Class<T> valueType)
+        throws IOException, JsonParseException, JsonMappingException
+    {
+        return (T) _readMapAndClose(_jsonFactory.createJsonParser(src, offset, len), TypeFactory.instance.fromClass(valueType));
+    } 
+
+    @SuppressWarnings("unchecked")
+    public <T> T readValue(byte[] src, int offset, int len,
+                           TypeReference valueTypeRef)
+        throws IOException, JsonParseException, JsonMappingException
+    {
+        return (T) _readMapAndClose(_jsonFactory.createJsonParser(src, offset, len), TypeFactory.instance.fromTypeReference(valueTypeRef));
+    } 
+
     /*
     ////////////////////////////////////////////////////
     // Public API: serialization
diff --git a/src/perf/TestCopyPerf.java b/src/perf/TestCopyPerf.java
index 73e5c84..d81cace 100644
--- a/src/perf/TestCopyPerf.java
+++ b/src/perf/TestCopyPerf.java
@@ -1,7 +1,7 @@
 import java.io.*;
 
 import org.codehaus.jackson.*;
-import org.codehaus.jackson.map.JsonTypeMapper;
+import org.codehaus.jackson.map.TreeMapper;
 import org.codehaus.jackson.map.JsonNode;
 
 public final class TestCopyPerf
@@ -17,9 +17,9 @@
     {
         mJsonFactory = new JsonFactory();
         FileInputStream fis = new FileInputStream(f);
-        JsonTypeMapper mapper = new JsonTypeMapper();
+        TreeMapper mapper = new TreeMapper();
         JsonParser jp = mJsonFactory.createJsonParser(fis);
-        mTree = mapper.read(jp);
+        mTree = mapper.readTree(jp);
         jp.close();
     }
 
diff --git a/src/perf/TestJsonPerf.java b/src/perf/TestJsonPerf.java
index e37b561..4c6ebc5 100644
--- a/src/perf/TestJsonPerf.java
+++ b/src/perf/TestJsonPerf.java
@@ -33,8 +33,8 @@
         mJsonFactory = new JsonFactory();
         mData = readData(f);
 
-        // Let's try to guestimate suitable size... to get to 100 megs parsed
-        REPS = (int) ((double) (100 * 1000 * 1000) / (double) mData.length);
+        // Let's try to guestimate suitable size... to get to 50 megs parsed
+        REPS = (int) ((double) (50 * 1000 * 1000) / (double) mData.length);
 
         System.out.println("Read "+mData.length+" bytes from '"+f+"'; will do "+REPS+" reps");
         System.out.println();
@@ -49,7 +49,7 @@
         while (true) {
             try {  Thread.sleep(100L); } catch (InterruptedException ie) { }
             // Use 9 to test all...
-            int round = (i++ % 7);
+            int round = (i++ % 2);
 
             long curr = System.currentTimeMillis();
             String msg;
@@ -226,7 +226,13 @@
         int sum = 0;
         for (int i = 0; i < reps; ++i) {
             // note: fast is not used any more
-            JsonParser jp = mJsonFactory.createJsonParser(new ByteArrayInputStream(mData));
+            JsonParser jp;
+
+            if (fast) {
+                jp = mJsonFactory.createJsonParser(mData, 0, mData.length);
+            } else {
+                jp = mJsonFactory.createJsonParser(new ByteArrayInputStream(mData));
+            }
             JsonToken t;
             while ((t = jp.nextToken()) != null) {
                 // Field names are always constructed
diff --git a/src/test/main/TestJsonParser.java b/src/test/main/TestJsonParser.java
index 52f642c..f96b4d8 100644
--- a/src/test/main/TestJsonParser.java
+++ b/src/test/main/TestJsonParser.java
@@ -320,6 +320,38 @@
         }
     }
 
+    /**
+     * 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);
+
+        JsonFactory jf = new JsonFactory();
+        JsonParser jp = jf.createJsonParser(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();
+    }
+
     /*
     /////////////////////////////////////////////
     // Helper methods