private DecodedChar getAllMalformedBytes(final int bytesInBufferCount) {
        int goodCharByteOffset = -1;

        // As we need to go looking for some good chars, we need more bytes to work with
        largeInputBuffer.clear();
        for (int i = 0; i < bytesInBufferCount; i++) {
            largeInputBuffer.put(inputBuffer.get(i));
        }
        // Now try to fill it up using bytes from the supplier
        while (largeInputBuffer.hasRemaining()) {
            final Byte suppliedByte = getNextByte();
            if (suppliedByte == null) {
                break;
            }
            largeInputBuffer.put(suppliedByte);
        }

        largeInputBuffer.flip();
        int byteCount = largeInputBuffer.remaining();

        // Assume that at least the first byte is bad, so keep slicing the bytebuffer
        // to cut off the first n bytes, then decode the remainder (replacing malformed bytes
        // with a replacement char) to find a valid char. We need to do this so we can establish how
        // big the block of bad bytes is.
        for (int i = 1; i < byteCount; i++) {
            final ByteBuffer slicedInputBuffer = largeInputBuffer.slice(i, byteCount - i);
//            LOGGER.trace("slicedInputBuffer: {}", ByteBufferUtils.byteBufferInfo(slicedInputBuffer));
            outputBuffer.clear();
            final CoderResult result = lenientCharsetDecoder.decode(
                    slicedInputBuffer, outputBuffer, true);
            outputBuffer.flip();
            if (outputBuffer.get(0) != DecodedChar.UNKNOWN_CHAR_REPLACEMENT) {
                goodCharByteOffset = i;
                break;
            }
        }

        if (goodCharByteOffset == -1) {
            if (isEndOfStream) {
                byte[] malformedBytes = new byte[byteCount];
                inputBuffer.get(0, malformedBytes, 0, byteCount);
                return DecodedChar.unknownChar(malformedBytes);
            } else {
                // If we couldn't find a valid char in 20 bytes then just give up
                final long offsetOfBadBytes = lastSuppliedByteOffset - (byteCount - 1);
                throw new DecoderException(
                        charsetDecoder.charset(),
                        Arrays.copyOf(largeInputBuffer.array(), largeInputBuffer.array().length),
                        offsetOfBadBytes);
            }
        } else {
            // Queue any unused bytes, so they can be decoded on next call to decodeNextChar
            for (int i = goodCharByteOffset; i < byteCount; i++) {
                final byte unusedByte = largeInputBuffer.get(i);
                unConsumedBytes.add(unusedByte);
                // Need to return the offset back to the last of the malformed bytes
                lastSuppliedByteOffset--;
            }
            //noinspection UnnecessaryLocalVariable // Added for clarity
            final int malformedBytesCount = goodCharByteOffset;

            byte[] malformedBytes = new byte[malformedBytesCount];
            inputBuffer.get(0, malformedBytes, 0, malformedBytesCount);

            // Keep a record of some of the nasty bits we have found
            final int offsetOfFirstBadByte = lastSuppliedByteOffset - malformedBytesCount - 1;
            malformedBytesReport.putMalformedBytes(
                    malformedBytes,
                    offsetOfFirstBadByte);

            return DecodedChar.unknownChar(malformedBytes);
        }
    }
@return A {@link DecodedChar} representing the character decoded from n bytes supplied by byteSupplier or
null if byteSupplier has no bytes to supply.
@throws DecoderException If it fails to decode a char after consuming MAX_BYTES_PER_CHAR bytes
                         from byteSupplier
stroom-pipeline/src/main/java/stroom/pipeline/reader/ByteStreamDecoder.java