// Path: src/main/java/ch/digitalfondue/jfiveparse/ProcessedInputStream.java
// static class StringProcessedInputStream extends ProcessedInputStream {
//     private int pos = 0;
//     private final char[] input;
// 
//     StringProcessedInputStream(String input) {
//         this.input = input.toCharArray();
//     }
// 
//     @Override
//     protected int read() {
//         try {
//             return input[pos++];
//         } catch (IndexOutOfBoundsException s) {
//             return -1;
//         }
//     }
// 
//     @Override
//     protected int getCharAt(int position) {
//         try {
//             return input[position];
//         } catch (IndexOutOfBoundsException s) {
//             return -1;
//         }
//     }
// }


import ch.digitalfondue.jfiveparse.ProcessedInputStream.StringProcessedInputStream;
        final int previousInputChar = previousCharacter;
        boolean isCurrentCharHighSurrogate = Character.isHighSurrogate((char) currentInputChar);
        boolean isLowSurrogatePeekedNextInputChar = Character.isLowSurrogate((char) peekedNextInputChar);

        boolean isLowSurrogate = Character.isLowSurrogate((char) currentInputChar);
        boolean isHighSurrogatePeekendPreviousInputChar = Character.isHighSurrogate((char) previousInputChar);
        // various check here:
        // - if invalid char
        // - check the surrogate pair
        if (position > alreadyVisitedPosition && (invalidCharacters(currentInputChar) || //
                (isLowSurrogate && !isHighSurrogatePeekendPreviousInputChar) || //
                (isCurrentCharHighSurrogate && !isLowSurrogatePeekedNextInputChar) || //
                (isCurrentCharHighSurrogate && isLowSurrogatePeekedNextInputChar && invalidCharacters(Character.toCodePoint((char) currentInputChar,
                        (char) peekedNextInputChar))))) {
            tokenHandler.emitParseError();
        }

        alreadyVisitedPosition = Math.max(position, alreadyVisitedPosition);
    }
    
    
    
 // U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF,
    // U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF,
    // U+6FFFE, U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF,
    // U+9FFFE, U+9FFFF, U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF,
    // U+CFFFE, U+CFFFF, U+DFFFE, U+DFFFF, U+EFFFE, U+EFFFF,
    // U+FFFFE, U+FFFFF, U+10FFFE, U+10FFFF

    private static boolean isInInvalidChars(int chr) {
// Path: src/main/java/ch/digitalfondue/jfiveparse/ProcessedInputStream.java
// static class StringProcessedInputStream extends ProcessedInputStream {
//     private int pos = 0;
//     private final char[] input;
// 
//     StringProcessedInputStream(String input) {
//         this.input = input.toCharArray();
//     }
// 
//     @Override
//     protected int read() {
//         try {
//             return input[pos++];
//         } catch (IndexOutOfBoundsException s) {
//             return -1;
//         }
//     }
// 
//     @Override
//     protected int getCharAt(int position) {
//         try {
//             return input[position];
//         } catch (IndexOutOfBoundsException s) {
//             return -1;
//         }
//     }
// }


// Path: src/test/java/ch/digitalfondue/jfiveparse/ProcessedInputStreamWithParseError.java
import ch.digitalfondue.jfiveparse.ProcessedInputStream.StringProcessedInputStream;

        final int previousInputChar = previousCharacter;
        boolean isCurrentCharHighSurrogate = Character.isHighSurrogate((char) currentInputChar);
        boolean isLowSurrogatePeekedNextInputChar = Character.isLowSurrogate((char) peekedNextInputChar);

        boolean isLowSurrogate = Character.isLowSurrogate((char) currentInputChar);
        boolean isHighSurrogatePeekendPreviousInputChar = Character.isHighSurrogate((char) previousInputChar);
        // various check here:
        // - if invalid char
        // - check the surrogate pair
        if (position > alreadyVisitedPosition && (invalidCharacters(currentInputChar) || //
                (isLowSurrogate && !isHighSurrogatePeekendPreviousInputChar) || //
                (isCurrentCharHighSurrogate && !isLowSurrogatePeekedNextInputChar) || //
                (isCurrentCharHighSurrogate && isLowSurrogatePeekedNextInputChar && invalidCharacters(Character.toCodePoint((char) currentInputChar,
                        (char) peekedNextInputChar))))) {
            tokenHandler.emitParseError();
        }

        alreadyVisitedPosition = Math.max(position, alreadyVisitedPosition);
    }
    
    
    
 // U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF,
    // U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF,
    // U+6FFFE, U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF,
    // U+9FFFE, U+9FFFF, U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF,
    // U+CFFFE, U+CFFFF, U+DFFFE, U+DFFFF, U+EFFFE, U+EFFFF,
    // U+FFFFE, U+FFFFF, U+10FFFE, U+10FFFF

    private static boolean isInInvalidChars(int chr) {
        return chr == 0x000B || //