Backport fix for [Issue#42] (NPE for UTF-32 reader)

diff --git a/release-notes/VERSION b/release-notes/VERSION
index cbc5154..a77b7b0 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -14,6 +14,8 @@
 * [Issue#38]: Infinite loop in `JsonParser.nextFieldName()` with trailing
  space after field name
  (reported by matjazs@github)
+* [Issue#42]: NPE in UTF-32 parser
+ (reported by James R)
 
 ------------------------------------------------------------------------
 === History: ===
diff --git a/src/java/org/codehaus/jackson/io/UTF32Reader.java b/src/java/org/codehaus/jackson/io/UTF32Reader.java
index 35dc712..61ec711 100644
--- a/src/java/org/codehaus/jackson/io/UTF32Reader.java
+++ b/src/java/org/codehaus/jackson/io/UTF32Reader.java
@@ -2,52 +2,54 @@
 
 import java.io.*;
 
-
 /**
  * Since JDK does not come with UTF-32/UCS-4, let's implement a simple
  * decoder to use.
  */
-public final class UTF32Reader
+public class UTF32Reader
     extends BaseReader
 {
-    final boolean mBigEndian;
+    protected final boolean _bigEndian;
 
     /**
      * Although input is fine with full Unicode set, Java still uses
      * 16-bit chars, so we may have to split high-order chars into
      * surrogate pairs.
      */
-    char mSurrogate = NULL_CHAR;
+    protected char _surrogate = NULL_CHAR;
 
     /**
      * Total read character count; used for error reporting purposes
      */
-    int mCharCount = 0;
+    protected int _charCount = 0;
 
     /**
      * Total read byte count; used for error reporting purposes
      */
-    int mByteCount = 0;
+    protected int _byteCount = 0;
 
+    protected final boolean _managedBuffers;
+    
     /*
-    ////////////////////////////////////////
-    // Life-cycle
-    ////////////////////////////////////////
-    */
+    /**********************************************************
+    /* Life-cycle
+    /**********************************************************
+     */
 
     public UTF32Reader(IOContext ctxt,
-                       InputStream in, byte[] buf, int ptr, int len,
-                       boolean isBigEndian)
+            InputStream in, byte[] buf, int ptr, int len,
+            boolean isBigEndian)
     {
         super(ctxt, in, buf, ptr, len);
-        mBigEndian = isBigEndian;
+        _bigEndian = isBigEndian;
+        _managedBuffers = (in != null);
     }
 
     /*
-    ////////////////////////////////////////
-    // Public API
-    ////////////////////////////////////////
-    */
+    /**********************************************************
+    /* Public API
+    /**********************************************************
+     */
 
     @Override
 	public int read(char[] cbuf, int start, int len)
@@ -69,9 +71,9 @@
         int outPtr = start;
 
         // Ok, first; do we have a surrogate from last round?
-        if (mSurrogate != NULL_CHAR) {
-            cbuf[outPtr++] = mSurrogate;
-            mSurrogate = NULL_CHAR;
+        if (_surrogate != NULL_CHAR) {
+            cbuf[outPtr++] = _surrogate;
+            _surrogate = NULL_CHAR;
             // No need to load more, already got one char
         } else {
             /* Note: we'll try to avoid blocking as much as possible. As a
@@ -90,7 +92,7 @@
             int ptr = _ptr;
             int ch;
 
-            if (mBigEndian) {
+            if (_bigEndian) {
                 ch = (_buffer[ptr] << 24) | ((_buffer[ptr+1] & 0xFF) << 16)
                     | ((_buffer[ptr+2] & 0xFF) << 8) | (_buffer[ptr+3] & 0xFF);
             } else {
@@ -112,7 +114,7 @@
                 ch = (0xDC00 | (ch & 0x03FF));
                 // Room for second part?
                 if (outPtr >= len) { // nope
-                    mSurrogate = (char) ch;
+                    _surrogate = (char) ch;
                     break main_loop;
                 }
             }
@@ -123,36 +125,34 @@
         }
 
         len = outPtr - start;
-        mCharCount += len;
+        _charCount += len;
         return len;
     }
 
     /*
-    ////////////////////////////////////////
-    // Internal methods
-    ////////////////////////////////////////
-    */
+    /**********************************************************
+    /* Internal methods
+    /**********************************************************
+     */
 
     private void reportUnexpectedEOF(int gotBytes, int needed)
         throws IOException
     {
-        int bytePos = mByteCount + gotBytes;
-        int charPos = mCharCount;
+        int bytePos = _byteCount + gotBytes;
+        int charPos = _charCount;
 
         throw new CharConversionException("Unexpected EOF in the middle of a 4-byte UTF-32 char: got "
-                                          +gotBytes+", needed "+needed
-                                          +", at char #"+charPos+", byte #"+bytePos+")");
+                +gotBytes+", needed "+needed+", at char #"+charPos+", byte #"+bytePos+")");
     }
 
     private void reportInvalid(int value, int offset, String msg)
         throws IOException
     {
-        int bytePos = mByteCount + _ptr - 1;
-        int charPos = mCharCount + offset;
+        int bytePos = _byteCount + _ptr - 1;
+        int charPos = _charCount + offset;
 
         throw new CharConversionException("Invalid UTF-32 character 0x"
-                                          +Integer.toHexString(value)
-                                          +msg+" at char #"+charPos+", byte #"+bytePos+")");
+                +Integer.toHexString(value)+msg+" at char #"+charPos+", byte #"+bytePos+")");
     }
 
     /**
@@ -164,7 +164,7 @@
     private boolean loadMore(int available)
         throws IOException
     {
-        mByteCount += (_length - available);
+        _byteCount += (_length - available);
 
         // Bytes that need to be moved to the beginning of buffer?
         if (available > 0) {
@@ -180,11 +180,13 @@
              * so let's do a separate read right away:
              */
             _ptr = 0;
-            int count = _in.read(_buffer);
+            int count = (_in == null) ? -1 : _in.read(_buffer);
             if (count < 1) {
                 _length = 0;
                 if (count < 0) { // -1
-                    freeBuffers(); // to help GC?
+                    if (_managedBuffers) {
+                        freeBuffers(); // to help GC?
+                    }
                     return false;
                 }
                 // 0 count is no good; let's err out
@@ -197,10 +199,12 @@
          * error.
          */
         while (_length < 4) {
-            int count = _in.read(_buffer, _length, _buffer.length - _length);
+            int count = (_in == null) ? -1 : _in.read(_buffer, _length, _buffer.length - _length);
             if (count < 1) {
                 if (count < 0) { // -1, EOF... no good!
-                    freeBuffers(); // to help GC?
+                    if (_managedBuffers) {
+                        freeBuffers(); // to help GC?
+                    }
                     reportUnexpectedEOF(_length, 4);
                 }
                 // 0 count is no good; let's err out
@@ -211,4 +215,3 @@
         return true;
     }
 }
-
diff --git a/src/test/org/codehaus/jackson/impl/TestJsonParser.java b/src/test/org/codehaus/jackson/impl/TestJsonParser.java
index c73c0b2..6b54584 100644
--- a/src/test/org/codehaus/jackson/impl/TestJsonParser.java
+++ b/src/test/org/codehaus/jackson/impl/TestJsonParser.java
@@ -411,6 +411,7 @@
             // should still know the field name
             assertEquals("doc", jp.getCurrentName());
             assertToken(JsonToken.END_OBJECT, jp.nextToken());
+            assertNull(jp.nextToken());
             jp.close();
         }
     }