Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   package com.fasterxml.jackson.core.base;
   
   import java.io.*;
   import java.math.BigDecimal;
   import java.math.BigInteger;
   
Intermediate base class used by all Jackson com.fasterxml.jackson.core.JsonParser implementations. Contains most common things that are independent of actual underlying input source

Author(s):
Tatu Saloranta
  
  public abstract class ParserBase
      extends ParserMinimalBase
  {
      /*
      /**********************************************************
      /* Generic I/O state
      /**********************************************************
       */

    
I/O context for this reader. It handles buffer allocation for the reader.
  
      final protected IOContext _ioContext;

    
Flag that indicates whether parser is closed or not. Gets set when parser is either closed by explicit call (close()) or when end-of-input is reached.
  
      protected boolean _closed;
  
      /*
      /**********************************************************
      /* Current input data
      /**********************************************************
       */
  
      // Note: type of actual buffer depends on sub-class, can't include
  
    
Pointer to next available character in buffer
  
      protected int _inputPtr = 0;

    
Index of character after last available one in the buffer.
  
      protected int _inputEnd = 0;
      
      /*
      /**********************************************************
      /* Current input location information
      /**********************************************************
       */

    
Number of characters/bytes that were contained in previous blocks (blocks that were already processed prior to the current buffer).
  
      protected long _currInputProcessed = 0L;

    
Current row location of current point in input buffer, starting from 1, if available.
  
      protected int _currInputRow = 1;

    
Current index of the first character of the current row in input buffer. Needed to calculate column position, if necessary; benefit of not having column itself is that this only has to be updated once per line.
  
      protected int _currInputRowStart = 0;
  
      /*
      /**********************************************************
      /* Information about starting location of event
      /* Reader is pointing to; updated on-demand
      /**********************************************************
       */
  
      // // // Location info at point when current token was started
  
    
Total number of bytes/characters read before start of current token. For big (gigabyte-sized) sizes are possible, needs to be long, unlike pointers and sizes related to in-memory buffers.
 
     protected long _tokenInputTotal = 0; 

    
Input row on which current token starts, 1-based
 
     protected int _tokenInputRow = 1;

    
Column on input row that current token starts; 0-based (although in the end it'll be converted to 1-based)
 
     protected int _tokenInputCol = 0;
 
     /*
     /**********************************************************
     /* Parsing state
     /**********************************************************
      */

    
Information about parser context, context in which the next token is to be parsed (root, array, object).
 
     protected JsonReadContext _parsingContext;
    
    
Secondary token related to the next token after current one; used if its type is known. This may be value token that follows FIELD_NAME, for example.
 
     protected JsonToken _nextToken;
 
     /*
     /**********************************************************
     /* Buffer(s) for local name(s) and text content
     /**********************************************************
      */

    
Buffer that contains contents of String values, including field names if necessary (name split across boundary, contains escape sequence, or access needed to char array)
 
     protected final TextBuffer _textBuffer;

    
Temporary buffer that is needed if field name is accessed using ParserMinimalBase.getTextCharacters() method (instead of String returning alternatives)
 
     protected char[] _nameCopyBuffer = null;

    
Flag set to indicate whether the field name is available from the name copy buffer or not (in addition to its String representation being available via read context)
 
     protected boolean _nameCopied = false;

    
ByteArrayBuilder is needed if 'getBinaryValue' is called. If so, we better reuse it for remainder of content.
 
     protected ByteArrayBuilder _byteArrayBuilder = null;

    
We will hold on to decoded binary data, for duration of current event, so that multiple calls to com.fasterxml.jackson.core.JsonParser.getBinaryValue() will not need to decode data more than once.
 
     protected byte[] _binaryValue;
 
     /*
     /**********************************************************
     /* Constants and fields of former 'JsonNumericParserBase'
     /**********************************************************
      */
 
     final protected static int NR_UNKNOWN = 0;
 
     // First, integer types
 
     final protected static int NR_INT = 0x0001;
     final protected static int NR_LONG = 0x0002;
     final protected static int NR_BIGINT = 0x0004;
 
     // And then floating point types
 
     final protected static int NR_DOUBLE = 0x008;
     final protected static int NR_BIGDECIMAL = 0x0010;
 
     // Also, we need some numeric constants
 
     final static BigInteger BI_MIN_INT = BigInteger.valueOf(.);
     final static BigInteger BI_MAX_INT = BigInteger.valueOf(.);
 
     final static BigInteger BI_MIN_LONG = BigInteger.valueOf(.);
     final static BigInteger BI_MAX_LONG = BigInteger.valueOf(.);
     
     final static BigDecimal BD_MIN_LONG = new BigDecimal();
     final static BigDecimal BD_MAX_LONG = new BigDecimal();
 
     final static BigDecimal BD_MIN_INT = new BigDecimal();
     final static BigDecimal BD_MAX_INT = new BigDecimal();
 
     final static long MIN_INT_L = (long.;
     final static long MAX_INT_L = (long.;
 
     // These are not very accurate, but have to do... (for bounds checks)
 
     final static double MIN_LONG_D = (double.;
     final static double MAX_LONG_D = (double.;
 
     final static double MIN_INT_D = (double.;
     final static double MAX_INT_D = (double.;
     
     
     // Digits, numeric
     final protected static int INT_0 = '0';
     final protected static int INT_1 = '1';
     final protected static int INT_2 = '2';
     final protected static int INT_3 = '3';
     final protected static int INT_4 = '4';
     final protected static int INT_5 = '5';
     final protected static int INT_6 = '6';
     final protected static int INT_7 = '7';
     final protected static int INT_8 = '8';
     final protected static int INT_9 = '9';
 
     final protected static int INT_MINUS = '-';
     final protected static int INT_PLUS = '+';
     final protected static int INT_DECIMAL_POINT = '.';
 
     final protected static int INT_e = 'e';
     final protected static int INT_E = 'E';
 
     final protected static char CHAR_NULL = '\0';
     
     // Numeric value holders: multiple fields used for
     // for efficiency
 
    
Bitfield that indicates which numeric representations have been calculated for the current type
 
     protected int _numTypesValid = ;
 
     // First primitives
 
     protected int _numberInt;
 
     protected long _numberLong;
 
     protected double _numberDouble;
 
     // And then object types
 
     protected BigInteger _numberBigInt;
 
     protected BigDecimal _numberBigDecimal;
 
     // And then other information about value itself
 
    
Flag that indicates whether numeric value has a negative value. That is, whether its textual representation starts with minus character.
 
     protected boolean _numberNegative;

    
Length of integer part of the number, in characters
 
     protected int _intLength;

    
Length of the fractional part (not including decimal point or exponent), in characters. Not used for pure integer values.
 
     protected int _fractLength;

    
Length of the exponent part of the number, if any, not including 'e' marker or sign, just digits. Not used for pure integer values.
 
     protected int _expLength;
 
     /*
     /**********************************************************
     /* Life-cycle
     /**********************************************************
      */
 
     protected ParserBase(IOContext ctxtint features)
     {
         super();
          = features;
          = ctxt;
          = ctxt.constructTextBuffer();
          = JsonReadContext.createRootContext();
     }
     
     /*
     /**********************************************************
     /* JsonParser impl
     /**********************************************************
      */
    
    
Method that can be called to get the name associated with the current event.
 
     @Override
     public String getCurrentName()
         throws IOExceptionJsonParseException
     {
         // [JACKSON-395]: start markers require information from parent
         if ( == . ||  == .) {
             JsonReadContext parent = .getParent();
             return parent.getCurrentName();
         }
         return .getCurrentName();
     }
 
     @Override
     public void overrideCurrentName(String name)
     {
         // Simple, but need to look for START_OBJECT/ARRAY's "off-by-one" thing:
         JsonReadContext ctxt = ;
         if ( == . ||  == .) {
             ctxt = ctxt.getParent();
         }
         ctxt.setCurrentName(name);
     }
     
     @Override
     public void close() throws IOException
     {
         if (!) {
              = true;
             try {
                 _closeInput();
             } finally {
                 // as per [JACKSON-324], do in finally block
                 // Also, internal buffer(s) can now be released as well
                 _releaseBuffers();
             }
         }
     }
 
     @Override
     public boolean isClosed() { return ; }
 
     @Override
     {
         return ;
     }

    
Method that return the starting location of the current token; that is, position of the first character from input that starts the current token.
 
     @Override
     public JsonLocation getTokenLocation()
     {
         return new JsonLocation(.getSourceReference(),
                                 getTokenCharacterOffset(),
                                 getTokenLineNr(),
                                 getTokenColumnNr());
     }

    
Method that returns location of the last processed character; usually for error reporting purposes
 
     @Override
     public JsonLocation getCurrentLocation()
     {
         int col =  -  + 1; // 1-based
         return new JsonLocation(.getSourceReference(),
                                  +  - 1,
                                 col);
     }
 
     /*
     /**********************************************************
     /* Public API, access to token information, text
     /**********************************************************
      */
 
     @Override
     public boolean hasTextCharacters()
     {
         if ( == .) {
             return true// usually true
         }        
         if ( == .) {
             return ;
         }
         return false;
     }
     
     /*
     /**********************************************************
     /* Public low-level accessors
     /**********************************************************
      */
 
     public long getTokenCharacterOffset() { return ; }
     public int getTokenLineNr() { return ; }
     public int getTokenColumnNr() {
         // note: value of -1 means "not available"; otherwise convert from 0-based to 1-based
         int col = ;
         return (col < 0) ? col : (col + 1);
     }
 
     /*
     /**********************************************************
     /* 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 IOExceptionJsonParseException;
 
     protected abstract void _closeInput() throws IOException;
     
     /*
     /**********************************************************
     /* Low-level reading, other
     /**********************************************************
      */

    
Method called to release internal buffers owned by the base reader. This may be called along with _closeInput() (for example, when explicitly closing this reader instance), or separately (if need be).
 
     protected void _releaseBuffers() throws IOException
     {
         .releaseBuffers();
         char[] buf = ;
         if (buf != null) {
              = null;
             .releaseNameCopyBuffer(buf);
         }
     }
    
    
Method called when an EOF is encountered between tokens. If so, it may be a legitimate EOF, but only iff there is no open non-root context.
 
     @Override
     protected void _handleEOF() throws JsonParseException
     {
         if (!.inRoot()) {
             _reportInvalidEOF(": expected close marker for "+.getTypeDesc()+" (from "+.getStartLocation(.getSourceReference())+")");
         }
     }
 
     /*
     /**********************************************************
     /* Internal/package methods: Error reporting
     /**********************************************************
      */
     
     protected void _reportMismatchedEndMarker(int actChchar expCh)
         throws JsonParseException
     {
         _reportError("Unexpected close marker '"+((charactCh)+"': expected '"+expCh+"' (for "+.getTypeDesc()+" starting at "+startDesc+")");
     }
 
     /*
     /**********************************************************
     /* Internal/package methods: shared/reusable builders
     /**********************************************************
      */
     
     {
         if ( == null) {
              = new ByteArrayBuilder();
         } else {
             .reset();
         }
         return ;
     }
 
     /*
     /**********************************************************
     /* Methods from former JsonNumericParserBase
     /**********************************************************
      */
 
     // // // Life-cycle of number-parsing
     
     protected final JsonToken reset(boolean negativeint intLenint fractLenint expLen)
     {
         if (fractLen < 1 && expLen < 1) { // integer
             return resetInt(negativeintLen);
         }
         return resetFloat(negativeintLenfractLenexpLen);
     }
         
     protected final JsonToken resetInt(boolean negativeint intLen)
     {
          = negative;
          = intLen;
          = 0;
          = 0;
          = // to force parsing
         return .;
     }
     
     protected final JsonToken resetFloat(boolean negativeint intLenint fractLenint expLen)
     {
          = negative;
          = intLen;
          = fractLen;
          = expLen;
          = // to force parsing
         return .;
     }
     
     protected final JsonToken resetAsNaN(String valueStrdouble value)
     {
         .resetWithString(valueStr);
          = value;
          = ;
         return .;
     }
     
     /*
     /**********************************************************
     /* Numeric accessors of public API
     /**********************************************************
      */
     
     @Override
     public Number getNumberValue() throws IOExceptionJsonParseException
     {
         if ( == ) {
             _parseNumericValue(); // will also check event type
         }
         // Separate types for int types
         if ( == .) {
             if (( & ) != 0) {
                 return ;
             }
             if (( & ) != 0) {
                 return ;
             }
             if (( & ) != 0) {
                 return ;
             }
             // Shouldn't get this far but if we do
             return ;
         }
     
         /* And then floating point types. But here optimal type
          * needs to be big decimal, to avoid losing any data?
          */
         if (( & ) != 0) {
             return ;
         }
         if (( & ) == 0) { // sanity check
             _throwInternal();
         }
         return ;
     }
     
     @Override
     {
         if ( == ) {
             _parseNumericValue(); // will also check event type
         }
         if ( == .) {
             if (( & ) != 0) {
                 return .;
             }
             if (( & ) != 0) {
                 return .;
             }
             return .;
         }
     
         /* And then floating point types. Here optimal type
          * needs to be big decimal, to avoid losing any data?
          * 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 (( & ) != 0) {
             return .;
         }
         return .;
     }
     
     @Override
     public int getIntValue() throws IOExceptionJsonParseException
     {
         if (( & ) == 0) {
             if ( == ) { // not parsed at all
                 _parseNumericValue(); // will also check event type
             }
             if (( & ) == 0) { // wasn't an int natively?
                 convertNumberToInt(); // let's make it so, if possible
             }
         }
         return ;
     }
     
     @Override
     public long getLongValue() throws IOExceptionJsonParseException
     {
         if (( & ) == 0) {
             if ( == ) {
                 _parseNumericValue();
             }
             if (( & ) == 0) {
                 convertNumberToLong();
             }
         }
         return ;
     }
     
     @Override
     {
         if (( & ) == 0) {
             if ( == ) {
                 _parseNumericValue();
             }
             if (( & ) == 0) {
                 convertNumberToBigInteger();
             }
         }
         return ;
     }
     
     @Override
     public float getFloatValue() throws IOExceptionJsonParseException
     {
         double value = getDoubleValue();
         /* 22-Jan-2009, tatu: Bounds/range checks would be tricky
          *   here, so let's not bother even trying...
          */
         /*
         if (value < -Float.MAX_VALUE || value > MAX_FLOAT_D) {
             _reportError("Numeric value ("+getText()+") out of range of Java float");
         }
         */
         return (floatvalue;
     }
     
     @Override
     public double getDoubleValue() throws IOExceptionJsonParseException
     {
         if (( & ) == 0) {
             if ( == ) {
                 _parseNumericValue();
             }
             if (( & ) == 0) {
                 convertNumberToDouble();
             }
         }
         return ;
     }
     
     @Override
     {
         if (( & ) == 0) {
             if ( == ) {
                 _parseNumericValue();
             }
             if (( & ) == 0) {
                 convertNumberToBigDecimal();
             }
         }
         return ;
     }
 
     /*
     /**********************************************************
     /* Conversion from textual to numeric representation
     /**********************************************************
      */
    
    
Method that will parse actual numeric value out of a syntactically 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.

Parameters:
expType Numeric type that we will immediately need, if any; mostly necessary to optimize handling of floating point numbers
 
     protected void _parseNumericValue(int expType)
         throws IOExceptionJsonParseException
     {
         // Int or float?
         if ( == .) {
             char[] buf = .getTextBuffer();
             int offset = .getTextOffset();
             int len = ;
             if () {
                 ++offset;
             }
             if (len <= 9) { // definitely fits in int
                 int i = NumberInput.parseInt(bufoffsetlen);
                  =  ? -i : i;
                  = ;
                 return;
             }
             if (len <= 18) { // definitely fits AND is easy to parse using 2 int parse calls
                 long l = NumberInput.parseLong(bufoffsetlen);
                 if () {
                     l = -l;
                 }
                 // [JACKSON-230] Could still fit in int, need to check
                 if (len == 10) {
                     if () {
                         if (l >= ) {
                              = (intl;
                              = ;
                             return;
                         }
                     } else {
                         if (l <= ) {
                              = (intl;
                              = ;
                             return;
                         }
                     }
                 }
                  = l;
                  = ;
                 return;
             }
             _parseSlowIntValue(expTypebufoffsetlen);
             return;
         }
         if ( == .) {
             _parseSlowFloatValue(expType);
             return;
         }
         _reportError("Current token ("++") not numeric, can not use numeric value accessors");
     }
     
     private void _parseSlowFloatValue(int expType)
         throws IOExceptionJsonParseException
     {
         /* 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
          */
         try {
             if (expType == ) {
                  = .contentsAsDecimal();
                  = ;
             } else {
                 // Otherwise double has to do
                  = .contentsAsDouble();
                  = ;
             }
         } catch (NumberFormatException nex) {
             // Can this ever occur? Due to overflow, maybe?
             _wrapError("Malformed numeric value '"+.contentsAsString()+"'"nex);
         }
     }
     
     private void _parseSlowIntValue(int expTypechar[] bufint offsetint len)
         throws IOExceptionJsonParseException
     {
         String numStr = .contentsAsString();
         try {
             // [JACKSON-230] Some long cases still...
             if (NumberInput.inLongRange(bufoffsetlen)) {
                 // Probably faster to construct a String, call parse, than to use BigInteger
                  = Long.parseLong(numStr);
                  = ;
             } else {
                 // nope, need the heavy guns... (rare case)
                  = new BigInteger(numStr);
                  = ;
             }
         } catch (NumberFormatException nex) {
             // Can this ever occur? Due to overflow, maybe?
             _wrapError("Malformed numeric value '"+numStr+"'"nex);
         }
     }
     
     /*
     /**********************************************************
     /* Numeric conversions
     /**********************************************************
      */    
     
     protected void convertNumberToInt()
         throws IOExceptionJsonParseException
     {
         // First, converting from long ought to be easy
         if (( & ) != 0) {
             // Let's verify it's lossless conversion by simple roundtrip
             int result = (int;
             if (((longresult) != ) {
                 _reportError("Numeric value ("+getText()+") out of range of int");
             }
              = result;
         } else if (( & ) != 0) {
             if (.compareTo() > 0 
                     || .compareTo() < 0) {
                 reportOverflowInt();
             }
              = .intValue();
         } else if (( & ) != 0) {
             // Need to check boundaries
             if ( <  ||  > ) {
                 reportOverflowInt();
             }
              = (int;
         } else if (( & ) != 0) {
             if (.compareTo() > 0 
                 || .compareTo() < 0) {
                 reportOverflowInt();
             }
              = .intValue();
         } else {
             _throwInternal(); // should never get here
         }
     
          |= ;
     }
     
     protected void convertNumberToLong()
         throws IOExceptionJsonParseException
     {
         if (( & ) != 0) {
              = (long;
         } else if (( & ) != 0) {
             if (.compareTo() > 0 
                     || .compareTo() < 0) {
                 reportOverflowLong();
             }
              = .longValue();
         } else if (( & ) != 0) {
             // Need to check boundaries
             if ( <  ||  > ) {
                 reportOverflowLong();
             }
              = (long;
         } else if (( & ) != 0) {
             if (.compareTo() > 0 
                 || .compareTo() < 0) {
                 reportOverflowLong();
             }
              = .longValue();
         } else {
             _throwInternal(); // should never get here
         }
     
          |= ;
     }
     
     protected void convertNumberToBigInteger()
         throws IOExceptionJsonParseException
     {
         if (( & ) != 0) {
             // here it'll just get truncated, no exceptions thrown
              = .toBigInteger();
         } else if (( & ) != 0) {
              = BigInteger.valueOf();
         } else if (( & ) != 0) {
              = BigInteger.valueOf();
         } else if (( & ) != 0) {
              = BigDecimal.valueOf().toBigInteger();
         } else {
             _throwInternal(); // should never get here
         }
          |= ;
     }
     
     protected void convertNumberToDouble()
         throws IOExceptionJsonParseException
     {
         /* 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 (( & ) != 0) {
              = .doubleValue();
         } else if (( & ) != 0) {
              = .doubleValue();
         } else if (( & ) != 0) {
              = (double;
         } else if (( & ) != 0) {
              = (double;
         } else {
             _throwInternal(); // should never get here
         }
     
          |= ;
     }
     
     protected void convertNumberToBigDecimal()
         throws IOExceptionJsonParseException
     {
         /* 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 (( & ) != 0) {
             /* Let's actually parse from String representation,
              * to avoid rounding errors that non-decimal floating operations
              * would incur
              */
              = new BigDecimal(getText());
         } else if (( & ) != 0) {
              = new BigDecimal();
         } else if (( & ) != 0) {
              = BigDecimal.valueOf();
         } else if (( & ) != 0) {
              = BigDecimal.valueOf((long);
         } else {
             _throwInternal(); // should never get here
         }
          |= ;
     }
     
     /*
     /**********************************************************
     /* Number handling exceptions
     /**********************************************************
      */    
     
     protected void reportUnexpectedNumberChar(int chString comment)
         throws JsonParseException
     {
         String msg = "Unexpected character ("+_getCharDesc(ch)+") in numeric value";
         if (comment != null) {
             msg += ": "+comment;
         }
         _reportError(msg);
     }
     
     protected void reportInvalidNumber(String msg)
         throws JsonParseException
     {
         _reportError("Invalid numeric value: "+msg);
     }
     
     protected void reportOverflowInt()
         throws IOExceptionJsonParseException
     {
         _reportError("Numeric value ("+getText()+") out of range of int ("+.+" - "+.+")");
     }
     
     protected void reportOverflowLong()
         throws IOExceptionJsonParseException
     {
         _reportError("Numeric value ("+getText()+") out of range of long ("+.+" - "+.+")");
     }    
 
     /*
     /**********************************************************
     /* Base64 handling support
     /**********************************************************
     */

    
Method that sub-classes must implement to support escaped sequences in base64-encoded sections. Sub-classes that do not need base64 support can leave this as is
    protected char _decodeEscaped()
        throws IOExceptionJsonParseException {
        throw new UnsupportedOperationException();
    }
    
    protected final int _decodeBase64Escape(Base64Variant b64variantint chint index)
        throws IOExceptionJsonParseException
    {
        // 17-May-2011, tatu: As per [JACKSON-xxx], need to handle escaped chars
        if (ch != '\\') {
            throw reportInvalidBase64Char(b64variantchindex);
        }
        int unescaped = _decodeEscaped();
        // if white space, skip if first triplet; otherwise errors
        if (unescaped <= ) {
            if (index == 0) { // whitespace only allowed to be skipped between triplets
                return -1;
            }
        }
        // otherwise try to find actual triplet value
        int bits = b64variant.decodeBase64Char(unescaped);
        if (bits < 0) {
            throw reportInvalidBase64Char(b64variantunescapedindex);
        }
        return bits;
    }
    
    protected final int _decodeBase64Escape(Base64Variant b64variantchar chint index)
        throws IOExceptionJsonParseException
    {
        // 17-May-2011, tatu: As per [JACKSON-xxx], need to handle escaped chars
        if (ch != '\\') {
            throw reportInvalidBase64Char(b64variantchindex);
        }
        char unescaped = _decodeEscaped();
        // if white space, skip if first triplet; otherwise errors
        if (unescaped <= ) {
            if (index == 0) { // whitespace only allowed to be skipped between triplets
                return -1;
            }
        }
        // otherwise try to find actual triplet value
        int bits = b64variant.decodeBase64Char(unescaped);
        if (bits < 0) {
            throw reportInvalidBase64Char(b64variantunescapedindex);
        }
        return bits;
    }
    
    protected IllegalArgumentException reportInvalidBase64Char(Base64Variant b64variantint chint bindex)
        throws IllegalArgumentException
    {
        return reportInvalidBase64Char(b64variantchbindexnull);
    }

    

Parameters:
bindex Relative index within base64 character unit; between 0 and 3 (as unit has exactly 4 characters)
    protected IllegalArgumentException reportInvalidBase64Char(Base64Variant b64variantint chint bindexString msg)
        throws IllegalArgumentException
    {
        String base;
        if (ch <= ) {
            base = "Illegal white space character (code 0x"+Integer.toHexString(ch)+") as character #"+(bindex+1)+" of 4-char base64 unit: can only used between units";
        } else if (b64variant.usesPaddingChar(ch)) {
            base = "Unexpected padding character ('"+b64variant.getPaddingChar()+"') as character #"+(bindex+1)+" of 4-char base64 unit: padding only legal as 3rd or 4th character";
        } else if (!Character.isDefined(ch) || Character.isISOControl(ch)) {
            // Not sure if we can really get here... ? (most illegal xml chars are caught at lower level)
            base = "Illegal character (code 0x"+Integer.toHexString(ch)+") in base64 content";
        } else {
            base = "Illegal character '"+((char)ch)+"' (code 0x"+Integer.toHexString(ch)+") in base64 content";
        }
        if (msg != null) {
            base = base + ": " + msg;
        }
        return new IllegalArgumentException(base);
    }