Fixed problems with symbol table, minor numeric parsing improvements, added comments.

diff --git a/src/java/org/codehaus/jackson/JsonGenerator.java b/src/java/org/codehaus/jackson/JsonGenerator.java
index da188df..caa05c4 100644
--- a/src/java/org/codehaus/jackson/JsonGenerator.java
+++ b/src/java/org/codehaus/jackson/JsonGenerator.java
@@ -23,6 +23,15 @@
     ////////////////////////////////////////////////////
       */
 
+    /**
+     * Method for setting a custom pretty printer, which is usually
+     * used to add indentation for improved human readability.
+     * By default, generator does not do pretty printing.
+     *<p>
+     * To use the default pretty printer that comes with core
+     * Jackson distribution, call {@link #useDefaultPrettyPrinter}
+     * instead.
+     */
     public final void setPrettyPrinter(PrettyPrinter pp) {
         mPrettyPrinter = pp;
     }
@@ -101,9 +110,25 @@
     /**
      * Method that will output given chunk of binary data as base64
      * encoded, as a complete String value (surrounded by double quotes).
-     * Note: 
+     *<p>
+     * Note: because JSON Strings can not contain unescaped linefeeds,
+     * if linefeeds are included (as per last argument), they must be
+     * escaped. This adds overhead for decoding without improving
+     * readability.
+     * Alternatively if linefeeds are not included,
+     * resulting String value may violate the requirement of base64
+     * RFC which mandates line-length of 76 characters and use of
+     * linefeeds. However, all {@link JsonParser} implementations
+     * are required to accept such "long line base64"; as do
+     * typical production-level base64 decoders.
+     *
+     * @param includeLFs If true, will add linefeeds (single character,
+     *   "\n") as mandated by
+     *   the RFC that specifies canonical base64 encoding. Due to
+     *   JSON String value requirements, linefeeds must be escaped.
      */
-    public abstract void writeBinary(byte[] data, int offset, int len)
+    public abstract void writeBinary(byte[] data, int offset, int len,
+                                     boolean includeLFs)
         throws IOException, JsonGenerationException;
 
     /*
@@ -127,6 +152,14 @@
     public abstract void writeNumber(BigDecimal dec)
         throws IOException, JsonGenerationException;
 
+    /**
+     * Write method that can be used for custom numeric types that can
+     * not be (easily?) converted to "standard" Java number types.
+     * Because numbers are not surrounded by double quotes, regular
+     * {@link #writeString} method can not be used; nor
+     * {@link #writeRaw} because that does not properly handle
+     * value separators needed in Array or Object contexts.
+     */
     public abstract void writeNumber(String encodedValue)
         throws IOException, JsonGenerationException;
 
diff --git a/src/java/org/codehaus/jackson/JsonParser.java b/src/java/org/codehaus/jackson/JsonParser.java
index 49383cc..331aff0 100644
--- a/src/java/org/codehaus/jackson/JsonParser.java
+++ b/src/java/org/codehaus/jackson/JsonParser.java
@@ -163,7 +163,7 @@
      * If current event is of type 
      * {@link JsonToken#VALUE_NUMBER_INT} or
      * {@link JsonToken#VALUE_NUMBER_FLOAT}, returns
-     * one of type constants; otherwise returns null.
+     * one of {@link NumberType} constants; otherwise returns null.
      */
     public abstract NumberType getNumberType()
         throws IOException, JsonParseException;
@@ -197,4 +197,31 @@
 
     public abstract BigDecimal getDecimalValue()
         throws IOException, JsonParseException;
+
+    /*
+    ////////////////////////////////////////////////////
+    // Public API, access to token information, binary
+    ////////////////////////////////////////////////////
+     */
+
+    /**
+     * Method that can be used to read (and consume -- results
+     * may not be accessible using other methods after the call)
+     * base64-encoded binary data
+     * included in the current textual json value. It is equivalent
+     * to getting String value via {@link #getText} and decoding
+     * result, but should be significantly more performant.
+     *<p>
+     * Note that the contents may be consumed by this call, and thus
+     * only first call to method will produce any output. Likewise,
+     * calls to methods like {@link #getText} are not guaranteed
+     * to return anything.
+     *
+     * @param results Output stream used for returning decoded binary
+     *   data
+     *
+     * @return Number of bytes decoded and written to <b>results</b>
+     */
+    public abstract int readBinaryValue(OutputStream results)
+        throws IOException, JsonParseException;
 }
diff --git a/src/java/org/codehaus/jackson/impl/JsonGeneratorBase.java b/src/java/org/codehaus/jackson/impl/JsonGeneratorBase.java
index 42cc157..488a702 100644
--- a/src/java/org/codehaus/jackson/impl/JsonGeneratorBase.java
+++ b/src/java/org/codehaus/jackson/impl/JsonGeneratorBase.java
@@ -130,20 +130,15 @@
     ////////////////////////////////////////////////////
      */
 
-    public abstract void writeString(String text)
-        throws IOException, JsonGenerationException;
+    //public abstract void writeString(String text) throws IOException, JsonGenerationException;
 
-    public abstract void writeString(char[] text, int offset, int len)
-        throws IOException, JsonGenerationException;
+    //public abstract void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException;
 
-    public abstract void writeRaw(String text)
-        throws IOException, JsonGenerationException;
+    //public abstract void writeRaw(String text) throws IOException, JsonGenerationException;
 
-    public abstract void writeRaw(char[] text, int offset, int len)
-        throws IOException, JsonGenerationException;
+    //public abstract void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException;
 
-    public abstract void writeBinary(byte[] data, int offset, int len)
-        throws IOException, JsonGenerationException;
+    //public abstract void writeBinary(byte[] data, int offset, int len, boolean includeLFs) throws IOException, JsonGenerationException;
 
     /*
     ////////////////////////////////////////////////////
diff --git a/src/java/org/codehaus/jackson/impl/JsonNumericParserBase.java b/src/java/org/codehaus/jackson/impl/JsonNumericParserBase.java
index c2c3086..233de51 100644
--- a/src/java/org/codehaus/jackson/impl/JsonNumericParserBase.java
+++ b/src/java/org/codehaus/jackson/impl/JsonNumericParserBase.java
@@ -24,6 +24,8 @@
      * the fastest one that works for given textual representation.
      */
 
+    final protected static int NR_UNKNOWN = 0;
+
     // First, integer types
 
     final protected static int NR_INT = 0x0001;
@@ -84,7 +86,7 @@
      * Bitfield that indicates which numeric representations
      * have been calculated for the current type
      */
-    protected int mNumTypesValid = 0;
+    protected int mNumTypesValid = NR_UNKNOWN;
 
     // First primitives
 
@@ -145,7 +147,7 @@
         mIntLength = intLen;
         mFractLength = fractLen;
         mExpLength = expLen;
-        mNumTypesValid = 0; // to force parsing
+        mNumTypesValid = NR_UNKNOWN; // to force parsing
         if (fractLen < 1 && expLen < 1) { // integer
             return (mCurrToken = JsonToken.VALUE_NUMBER_INT);
         }
@@ -171,8 +173,8 @@
     public Number getNumberValue()
         throws IOException, JsonParseException
     {
-        if (mNumTypesValid == 0) {
-            parseNumericValue(); // will also check event type
+        if (mNumTypesValid == NR_UNKNOWN) {
+            parseNumericValue(NR_UNKNOWN); // will also check event type
         }
         // Separate types for int types
         if (mCurrToken == JsonToken.VALUE_NUMBER_INT) {
@@ -204,8 +206,8 @@
     public NumberType getNumberType()
         throws IOException, JsonParseException
     {
-        if (mNumTypesValid == 0) {
-            parseNumericValue(); // will also check event type
+        if (mNumTypesValid == NR_UNKNOWN) {
+            parseNumericValue(NR_UNKNOWN); // will also check event type
         }
         if (mCurrToken == JsonToken.VALUE_NUMBER_INT) {
             if ((mNumTypesValid & NR_INT) != 0) {
@@ -219,7 +221,9 @@
 
         /* And then floating point types. Here optimal type
          * needs to be big decimal, to avoid losing any data?
-         * However...
+         * However... using BD is slow, so let's allow returning
+         * double as type if no explicit call has been made to access
+         * data as BD?
          */
         if ((mNumTypesValid & NR_BIGDECIMAL) != 0) {
             return NumberType.BIG_DECIMAL;
@@ -231,8 +235,8 @@
         throws IOException, JsonParseException
     {
         if ((mNumTypesValid & NR_INT) == 0) {
-            if (mNumTypesValid == 0) { // not parsed at all
-                parseNumericValue(); // will also check event type
+            if (mNumTypesValid == NR_UNKNOWN) { // not parsed at all
+                parseNumericValue(NR_INT); // will also check event type
             }
             if ((mNumTypesValid & NR_INT) == 0) { // wasn't an int natively?
                 convertNumberToInt(); // let's make it so, if possible
@@ -245,8 +249,8 @@
         throws IOException, JsonParseException
     {
         if ((mNumTypesValid & NR_LONG) == 0) {
-            if (mNumTypesValid == 0) {
-                parseNumericValue();
+            if (mNumTypesValid == NR_UNKNOWN) {
+                parseNumericValue(NR_LONG);
             }
             if ((mNumTypesValid & NR_LONG) == 0) {
                 convertNumberToLong();
@@ -259,8 +263,8 @@
         throws IOException, JsonParseException
     {
         if ((mNumTypesValid & NR_DOUBLE) == 0) {
-            if (mNumTypesValid == 0) {
-                parseNumericValue();
+            if (mNumTypesValid == NR_UNKNOWN) {
+                parseNumericValue(NR_DOUBLE);
             }
             if ((mNumTypesValid & NR_DOUBLE) == 0) {
                 convertNumberToDouble();
@@ -273,8 +277,8 @@
         throws IOException, JsonParseException
     {
         if ((mNumTypesValid & NR_BIGDECIMAL) == 0) {
-            if (mNumTypesValid == 0) {
-                parseNumericValue();
+            if (mNumTypesValid == NR_UNKNOWN) {
+                parseNumericValue(NR_BIGDECIMAL);
             }
             if ((mNumTypesValid & NR_BIGDECIMAL) == 0) {
                 convertNumberToBigDecimal();
@@ -295,8 +299,11 @@
      * valid number value. Type it will parse into depends on whether
      * it is a floating point number, as well as its magnitude: smallest
      * legal type (of ones available) is used for efficiency.
+     *
+     * @param neededType Numeric type that we will immediately need, if any;
+     *   mostly necessary to optimize handling of floating point numbers
      */
-    protected final void parseNumericValue()
+    protected final void parseNumericValue(int expType)
         throws JsonParseException
     {
         // First things first: must be a numeric event
@@ -323,21 +330,28 @@
                     mNumTypesValid = NR_LONG;
                     return;
                 }
-                // nope, need the heavy guns...
+                // nope, need the heavy guns... (rare case)
                 BigInteger bi = new BigInteger(mTextBuffer.contentsAsString());
                 mNumberBigDecimal = new BigDecimal(bi);
                 mNumTypesValid = NR_BIGDECIMAL;
                 return;
             }
 
-            // Nope: floating point
-
-            /* !!! TBI: Use BigDecimal if need be? And/or optimize with
-             *   faster parsing
+            /* Nope: floating point. Here we need to be careful to get
+             * optimal parsing strategy: choice is between accurate but
+             * slow (BigDecimal) and lossy but fast (Double). For now
+             * let's only use BD when explicitly requested -- it can
+             * still be constructed correctly at any point since we do
+             * retain textual representation
              */
-            String value = mTextBuffer.contentsAsString();
-            mNumberDouble = Double.parseDouble(value);
-            mNumTypesValid = NR_DOUBLE;
+            if (expType == NR_BIGDECIMAL) {
+                mNumberBigDecimal = mTextBuffer.contentsAsDecimal();
+                mNumTypesValid = NR_BIGDECIMAL;
+            } else {
+                // Otherwise double has to do
+                mNumberDouble = mTextBuffer.contentsAsDouble();
+                mNumTypesValid = NR_DOUBLE;
+            }
         } catch (NumberFormatException nex) {
             // Can this ever occur? Due to overflow, maybe?
             wrapError("Malformed numeric value '"+mTextBuffer.contentsAsString()+"'", nex);
@@ -372,7 +386,7 @@
                 || BD_MAX_INT.compareTo(mNumberBigDecimal) < 0) {
                 reportOverflowInt();
             }
-            mNumberLong = mNumberBigDecimal.longValue();
+            mNumberInt = mNumberBigDecimal.intValue();
         } else {
             throwInternal(); // should never get here
         }
@@ -407,12 +421,18 @@
     protected void convertNumberToDouble()
         throws IOException, JsonParseException
     {
-        if ((mNumTypesValid & NR_INT) != 0) {
-            mNumberDouble = (double) mNumberInt;
+        /* 05-Aug-2008, tatus: Important note: this MUST start with
+         *   more accurate representations, since we don't know which
+         *   value is the original one (others get generated when
+         *   requested)
+         */
+
+        if ((mNumTypesValid & NR_BIGDECIMAL) != 0) {
+            mNumberDouble = mNumberBigDecimal.doubleValue();
         } else if ((mNumTypesValid & NR_LONG) != 0) {
             mNumberDouble = (double) mNumberLong;
-        } else if ((mNumTypesValid & NR_BIGDECIMAL) != 0) {
-            mNumberDouble = mNumberBigDecimal.doubleValue();
+        } else if ((mNumTypesValid & NR_INT) != 0) {
+            mNumberDouble = (double) mNumberInt;
         } else {
             throwInternal(); // should never get here
         }
@@ -423,16 +443,24 @@
     protected void convertNumberToBigDecimal()
         throws IOException, JsonParseException
     {
-        if ((mNumTypesValid & NR_INT) != 0) {
-            mNumberBigDecimal = BigDecimal.valueOf((long) mNumberInt);
-        } else if ((mNumTypesValid & NR_LONG) != 0) {
-            mNumberBigDecimal = BigDecimal.valueOf(mNumberLong);
-        } else {
-            /* Otherwise, let's actually parse from String representation,
+        /* 05-Aug-2008, tatus: Important note: this MUST start with
+         *   more accurate representations, since we don't know which
+         *   value is the original one (others get generated when
+         *   requested)
+         */
+
+        if ((mNumTypesValid & NR_DOUBLE) != 0) {
+            /* Let's actually parse from String representation,
              * to avoid rounding errors that non-decimal floating operations
              * would incur
              */
             mNumberBigDecimal = new BigDecimal(getText());
+        } else if ((mNumTypesValid & NR_LONG) != 0) {
+            mNumberBigDecimal = BigDecimal.valueOf(mNumberLong);
+        } else if ((mNumTypesValid & NR_INT) != 0) {
+            mNumberBigDecimal = BigDecimal.valueOf((long) mNumberInt);
+        } else {
+            throwInternal(); // should never get here
         }
         mNumTypesValid |= NR_BIGDECIMAL;
     }
diff --git a/src/java/org/codehaus/jackson/impl/ReaderBasedParser.java b/src/java/org/codehaus/jackson/impl/ReaderBasedParser.java
index cf7ff02..3a13990 100644
--- a/src/java/org/codehaus/jackson/impl/ReaderBasedParser.java
+++ b/src/java/org/codehaus/jackson/impl/ReaderBasedParser.java
@@ -200,6 +200,20 @@
 
     /*
     ////////////////////////////////////////////////////
+    // Public API, binary access
+    ////////////////////////////////////////////////////
+     */
+
+    @Override
+    public int readBinaryValue(OutputStream results)
+        throws IOException, JsonParseException
+    {
+        // !!! TBI: implemented base64 decoding
+        return -1;
+    }
+
+    /*
+    ////////////////////////////////////////////////////
     // Internal methods, secondary parsing
     ////////////////////////////////////////////////////
      */
diff --git a/src/java/org/codehaus/jackson/impl/Utf8StreamParser.java b/src/java/org/codehaus/jackson/impl/Utf8StreamParser.java
index 033a23f..1da5ec9 100644
--- a/src/java/org/codehaus/jackson/impl/Utf8StreamParser.java
+++ b/src/java/org/codehaus/jackson/impl/Utf8StreamParser.java
@@ -210,6 +210,20 @@
 
     /*
     ////////////////////////////////////////////////////
+    // Public API, binary access
+    ////////////////////////////////////////////////////
+     */
+
+    @Override
+    public int readBinaryValue(OutputStream results)
+        throws IOException, JsonParseException
+    {
+        // !!! TBI: implemented base64 decoding
+        return -1;
+    }
+
+    /*
+    ////////////////////////////////////////////////////
     // Internal methods, secondary parsing
     ////////////////////////////////////////////////////
      */
diff --git a/src/java/org/codehaus/jackson/impl/WriterBasedGenerator.java b/src/java/org/codehaus/jackson/impl/WriterBasedGenerator.java
index 9441160..cc61f21 100644
--- a/src/java/org/codehaus/jackson/impl/WriterBasedGenerator.java
+++ b/src/java/org/codehaus/jackson/impl/WriterBasedGenerator.java
@@ -238,12 +238,13 @@
         mOutputBuffer[mOutputTail++] = c;
     }
 
-    public void writeBinary(byte[] data, int offset, int len)
+    public void writeBinary(byte[] data, int offset, int len,
+                            boolean includeLFs)
         throws IOException, JsonGenerationException
     {
         // !!! TBI: base64-based binary output
 
-        throw new RuntimeException("Not yet implemented");
+        throw new UnsupportedOperationException("Not yet implemented");
     }
 
     private void writeRawLong(String text)
@@ -300,13 +301,14 @@
         mOutputTail = NumberOutput.outputLong(l, mOutputBuffer, mOutputTail);
     }
 
+    /* !!! 05-Aug-2008, tatus: Any ways to optimize these?
+     */
+
     public void writeNumber(double d)
         throws IOException, JsonGenerationException
     {
         // What is the max length for doubles? 40 chars?
         verifyValueWrite("write number");
-
-        // !!! TODO: use a more efficient printing method?
         writeRaw(String.valueOf(d));
     }
 
@@ -315,8 +317,6 @@
     {
         // What is the max length for floats?
         verifyValueWrite("write number");
-
-        // !!! TODO: use a more efficient printing method?
         writeRaw(String.valueOf(f));
     }
 
@@ -325,11 +325,12 @@
     {
         // Don't really know max length for big decimal, no point checking
         verifyValueWrite("write number");
-
-        // !!! TODO: use a more efficient printing method?
         writeRaw(dec.toString());
     }
 
+    /**
+     *
+     */
     public void writeNumber(String encodedValue)
         throws IOException, JsonGenerationException
     {
diff --git a/src/java/org/codehaus/jackson/io/NumberOutput.java b/src/java/org/codehaus/jackson/io/NumberOutput.java
index 9f89c5e..e70cfcc 100644
--- a/src/java/org/codehaus/jackson/io/NumberOutput.java
+++ b/src/java/org/codehaus/jackson/io/NumberOutput.java
@@ -49,6 +49,12 @@
         "-1","-2","-3","-4","-5","-6","-7","-8","-9","-10"
     };
 
+    /*
+    ////////////////////////////////////////////////////
+    // Efficient serialization methods using raw buffers
+    ////////////////////////////////////////////////////
+     */
+
     /**
      * @return Offset within buffer after outputting int
      */
@@ -170,6 +176,16 @@
         return offset;
     }
 
+    /*
+    ////////////////////////////////////////////////////
+    // Secondary 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 value)
     {
         // Lookup table for small values
@@ -182,7 +198,6 @@
                 return sSmallIntStrs2[v2];
             }
         }
-        // !!! TODO: further optimize?
         return Integer.toString(value);
     }
 
@@ -192,13 +207,11 @@
             value >= Integer.MIN_VALUE) {
             return toString((int) value);
         }
-        // !!! TODO: further optimize?
         return Long.toString(value);
     }
 
     public static String toString(double value)
     {
-        // !!! TODO: optimize?
         return Double.toString(value);
     }
 
diff --git a/src/java/org/codehaus/jackson/map/BaseMapper.java b/src/java/org/codehaus/jackson/map/BaseMapper.java
index 1aa58ef..1cacc5f 100644
--- a/src/java/org/codehaus/jackson/map/BaseMapper.java
+++ b/src/java/org/codehaus/jackson/map/BaseMapper.java
@@ -37,6 +37,20 @@
      */
     protected DupFields mCfgDupFields = DupFields.ERROR;
 
+    /**
+     * Defines whether (escaped) linefeeds are included when serializing
+     * binary data into base64 values or not.
+     *<p>
+     * Default setting is <b>false</b> mostly because linefeeds can not
+     * be included natively anyway, and instead encoded/escaped entries
+     * have to be used. Additionally it is unlikely that recipient would
+     * not be able to decode data (since it needs to be json aware and
+     * do fair bit of handling before being able to access data).
+     * Nonetheless, for maximum interoperability it may be desireable
+     * to enable this setting.
+     */
+    protected boolean mCfgBase64LFs = false;
+
     /*
     ////////////////////////////////////////////////////
     // Life-cycle (construction, configuration)
@@ -48,6 +62,10 @@
     public void setDupFieldHandling(DupFields mode) { mCfgDupFields = mode; }
     public DupFields getDupFieldHandling() { return mCfgDupFields; }
 
+    public void setAddLinefeedsToBase64(boolean state) { mCfgBase64LFs = state; }
+
+    public boolean getAddLinefeedsToBase64() { return mCfgBase64LFs; }
+
     /*
     ////////////////////////////////////////////////////
     // Methods for sub-classes
diff --git a/src/java/org/codehaus/jackson/map/JavaTypeMapper.java b/src/java/org/codehaus/jackson/map/JavaTypeMapper.java
index 22bffd5..372f5e0 100644
--- a/src/java/org/codehaus/jackson/map/JavaTypeMapper.java
+++ b/src/java/org/codehaus/jackson/map/JavaTypeMapper.java
@@ -191,7 +191,7 @@
     public JsonParser createParserFor(Object data)
         throws JsonParseException
     {
-        // !!! TBI
+        // !!! TBI: parser for reading from Object (array/map, primitives)
         return null;
     }
 
@@ -200,10 +200,17 @@
      * Java objects as members of the current list, appending
      * them at the end of the list.
      */
-    public JsonGenerator createParserFor(List<Object> context)
+    public JsonGenerator createGeneratorFor(List<Object> context)
         throws JsonParseException
     {
-        // !!! TBI
+        // !!! TBI: generator for writing (appending) to Json Arrays (Java lists)
+        return null;
+    }
+
+    public JsonGenerator createGeneratorFor(Map<Object,Object> context)
+        throws JsonParseException
+    {
+        // !!! TBI: generator for writing (appending) to Json Objects (Java maps)
         return null;
     }
 
@@ -328,7 +335,7 @@
              */
             {
                 byte[] data = (byte[]) value;
-                jgen.writeBinary(data, 0, data.length);
+                jgen.writeBinary(data, 0, data.length, mCfgBase64LFs);
             }
             break;
 
diff --git a/src/java/org/codehaus/jackson/map/JsonTypeMapper.java b/src/java/org/codehaus/jackson/map/JsonTypeMapper.java
index bc14330..b633f3e 100644
--- a/src/java/org/codehaus/jackson/map/JsonTypeMapper.java
+++ b/src/java/org/codehaus/jackson/map/JsonTypeMapper.java
@@ -71,6 +71,38 @@
 
     /*
     ////////////////////////////////////////////////////
+    // Public API, exposing JsonNode(s) via stream
+    // parsers/generators
+    ////////////////////////////////////////////////////
+     */
+
+    /**
+     * Method that will take in a Java object that could have
+     * been created by mappers write methods, and construct
+     * a {@link JsonParser} that exposes contents as JSON
+     * tokens
+     */
+    public JsonParser createParserFor(JsonNode node)
+        throws JsonParseException
+    {
+        // !!! TBI: parser for reading from JsonNode (array/map, primitives)
+        return null;
+    }
+
+    /**
+     * Method that will create a JSON generator that will build
+     * Java objects as members of the current list, appending
+     * them at the end of the list.
+     */
+    public JsonGenerator createGeneratorFor(JsonNode context)
+        throws JsonParseException
+    {
+        // !!! TBI: generator for writing (appending) to Objects (array/map, primitives)
+        return null;
+    }
+
+    /*
+    ////////////////////////////////////////////////////
     // Factory methods
     ////////////////////////////////////////////////////
      */
diff --git a/src/java/org/codehaus/jackson/map/impl/JsonTypeMapperBase.java b/src/java/org/codehaus/jackson/map/impl/JsonTypeMapperBase.java
index 18b6356..605f76c 100644
--- a/src/java/org/codehaus/jackson/map/impl/JsonTypeMapperBase.java
+++ b/src/java/org/codehaus/jackson/map/impl/JsonTypeMapperBase.java
@@ -96,9 +96,9 @@
             return numberNode(jp.getLongValue());
 
         case VALUE_NUMBER_FLOAT:
-            /* !!! Should we try to see if we should use some
-             *  other representation (BigDecimal)?
-             */
+            if (jp.getNumberType() == JsonParser.NumberType.BIG_DECIMAL) {
+                return numberNode(jp.getDecimalValue());
+            }
             return numberNode(jp.getDoubleValue());
 
         case VALUE_TRUE:
diff --git a/src/java/org/codehaus/jackson/sym/NameCanonicalizer.java b/src/java/org/codehaus/jackson/sym/NameCanonicalizer.java
index 432ae31..1929cde 100644
--- a/src/java/org/codehaus/jackson/sym/NameCanonicalizer.java
+++ b/src/java/org/codehaus/jackson/sym/NameCanonicalizer.java
@@ -597,6 +597,7 @@
             if (mCollListShared) {
                 unshareCollision(); // also allocates if list was null
             }
+
             ++mCollCount;
             int entryValue = mMainHash[ix];
             int bucket = entryValue & 0xFF;
@@ -645,7 +646,6 @@
         mNeedRehash = false;
         // Note: since we'll make copies, no need to unshare, can just mark as such:
         mMainNamesShared = false;
-        mCollListShared = false;
 
         /* And then we can first deal with the main hash area. Since we
          * are expanding linearly (double up), we know there'll be no
@@ -680,6 +680,7 @@
 
         mCollCount = 0;
         mCollEnd = 0;
+        mCollListShared = false;
 
         Bucket[] oldBuckets = mCollList;
         mCollList = new Bucket[oldBuckets.length];
diff --git a/src/java/org/codehaus/jackson/util/TextBuffer.java b/src/java/org/codehaus/jackson/util/TextBuffer.java
index 7ad1c83..c36da9b 100644
--- a/src/java/org/codehaus/jackson/util/TextBuffer.java
+++ b/src/java/org/codehaus/jackson/util/TextBuffer.java
@@ -1,6 +1,7 @@
 package org.codehaus.jackson.util;
 
 import java.io.*;
+import java.math.BigDecimal;
 import java.util.ArrayList;
 
 /**
@@ -315,6 +316,7 @@
     public int contentsToArray(int srcStart, char[] dst, int dstStart, int len) {
 
         // Easy to copy from shared buffer:
+
         if (mInputStart >= 0) {
 
             int amount = mInputLen - srcStart;
@@ -414,6 +416,39 @@
         return rlen;
     }
 
+    /**
+     * Convenience method for converting contents of the buffer
+     * into a {@link BigDecimal}.
+     */
+    public BigDecimal contentsAsDecimal()
+        throws NumberFormatException
+    {
+        // Already got a pre-cut array?
+        if (mResultArray != null) {
+            return new BigDecimal(mResultArray);
+        }
+        // Or a shared buffer?
+        if (mInputStart >= 0) {
+            return new BigDecimal(mInputBuffer, mInputStart, mInputLen);
+        }
+        // Or if not, just a single buffer (the usual case)
+        if (mSegmentSize == 0) {
+            return new BigDecimal(mCurrentSegment, 0, mCurrentSize);
+        }
+        // If not, let's just get it aggregated...
+        return new BigDecimal(contentsAsArray());
+    }
+
+    /**
+     * Convenience method for converting contents of the buffer
+     * into a Double value.
+     */
+    public double contentsAsDouble()
+        throws NumberFormatException
+    {
+        return Double.parseDouble(contentsAsString());
+    }
+
     /*
     //////////////////////////////////////////////
     // Public mutators:
diff --git a/src/perf/TestJsonPerf.java b/src/perf/TestJsonPerf.java
index 7afb854..b28aeda 100644
--- a/src/perf/TestJsonPerf.java
+++ b/src/perf/TestJsonPerf.java
@@ -204,7 +204,8 @@
     {
         int sum = 0;
         for (int i = 0; i < reps; ++i) {
-            JsonParser jp = mJsonFactory.createJsonParser(new ByteArrayInputStream(mData), fast);
+            // note: fast is not used any more
+            JsonParser jp = mJsonFactory.createJsonParser(new ByteArrayInputStream(mData));
             JsonToken t;
             while ((t = jp.nextToken()) != null) {
                 // Field names are always constructed
diff --git a/src/perf/TestReadPerf.java b/src/perf/TestReadPerf.java
index bc4c46b..d28df3c 100644
--- a/src/perf/TestReadPerf.java
+++ b/src/perf/TestReadPerf.java
@@ -52,8 +52,12 @@
         JsonParser jp = null;
         while (--reps >= 0) {
             jp = mJsonFactory.createJsonParser(new ByteArrayInputStream(mData));
-            while (jp.nextToken() != null) {
-                ;
+            JsonToken t;
+
+            while ((t = jp.nextToken()) != null) {
+                if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+                    jp.getDoubleValue();
+                }
             }
             jp.close();
         }
diff --git a/src/test/impl/TestByteBasedSymbols.java b/src/test/impl/TestByteBasedSymbols.java
new file mode 100644
index 0000000..450c094
--- /dev/null
+++ b/src/test/impl/TestByteBasedSymbols.java
@@ -0,0 +1,112 @@
+package impl;
+
+import java.io.*;
+
+import org.codehaus.jackson.*;
+
+import main.BaseTest;
+
+/**
+ * Unit test(s) to verify that handling of byte-based symbol tables
+ * is working. Created to verify fix to [JACKSON-5]
+ */
+public class TestByteBasedSymbols
+    extends BaseTest
+{
+    final static String[] FIELD_NAMES = new String[] {
+        "a", "b", "c", "x", "y", "b13", "abcdefg", "a123",
+        "a0", "b0", "c0", "d0", "e0", "f0", "g0", "h0",
+        "x2", "aa", "ba", "ab", "b31", "___x", "aX", "xxx",
+        "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
+        "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
+        "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
+    };
+
+    /**
+     * This unit test checks that [JACKSON-5] is fixed; if not, a
+     * symbol table corruption should result in odd problems.
+     */
+    public void testSharedSymbols()
+        throws Exception
+    {
+        // MUST share a single json factory
+        JsonFactory jf = new JsonFactory();
+
+        /* First things first: parse a dummy doc to populate
+         * shared symbol table with some stuff
+         */
+        String DOC0 = "{ \"a\" : 1, \"x\" : [ ] }";
+        JsonParser jp0 = createParser(jf, DOC0);
+
+        /* Important: don't close, don't traverse past end.
+         * This is needed to create partial still-in-use symbol
+         * table...
+         */
+        while (jp0.nextToken() != JsonToken.START_ARRAY) { }
+
+        String doc1 = createDoc(FIELD_NAMES, true);
+        String doc2 = createDoc(FIELD_NAMES, false);
+
+        // Let's run it twice... shouldn't matter
+        for (int x = 0; x < 2; ++x) {
+            JsonParser jp1 = createParser(jf, doc1);
+            JsonParser jp2 = createParser(jf, doc2);
+
+            assertToken(JsonToken.START_OBJECT, jp1.nextToken());
+            assertToken(JsonToken.START_OBJECT, jp2.nextToken());
+            
+            int len = FIELD_NAMES.length;
+            for (int i = 0; i < len; ++i) {
+                assertToken(JsonToken.FIELD_NAME, jp1.nextToken());
+                assertToken(JsonToken.FIELD_NAME, jp2.nextToken());
+                assertEquals(FIELD_NAMES[i], jp1.getCurrentName());
+                assertEquals(FIELD_NAMES[len-(i+1)], jp2.getCurrentName());
+                assertToken(JsonToken.VALUE_NUMBER_INT, jp1.nextToken());
+                assertToken(JsonToken.VALUE_NUMBER_INT, jp2.nextToken());
+                assertEquals(i, jp1.getIntValue());
+                assertEquals(i, jp2.getIntValue());
+            }
+            
+            assertToken(JsonToken.END_OBJECT, jp1.nextToken());
+            assertToken(JsonToken.END_OBJECT, jp2.nextToken());
+            
+            jp1.close();
+            jp2.close();
+        }
+    }
+
+    /*
+    ////////////////////////////////////////////
+    // Helper methods
+    ////////////////////////////////////////////
+     */
+
+    protected JsonParser createParser(JsonFactory jf, String input)
+        throws IOException, JsonParseException
+    {
+        byte[] data = input.getBytes("UTF-8");
+        InputStream is = new ByteArrayInputStream(data);
+        return jf.createJsonParser(is);
+    }
+
+    private String createDoc(String[] fieldNames, boolean add)
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{ ");
+
+        int len = fieldNames.length;
+        for (int i = 0; i < len; ++i) {
+            if (i > 0) {
+                sb.append(", ");
+            }
+            sb.append('"');
+            sb.append(add ? fieldNames[i] : fieldNames[len - (i+1)]);
+            sb.append("\" : ");
+            sb.append(i);
+        }
+        sb.append(" }");
+        return sb.toString();
+    }
+}
+
+