public static InputStream limitedInputStream(final InputStream is, final int limit) throws IOException {
        return new InputStream() {
            private int mPosition = 0;
            private int mMark = 0;
            private final int mLimit = Math.min(limit, is.available());

            @Override
            public int read() throws IOException {
                if (mPosition < mLimit) {
                    mPosition++;
                    return is.read();
                }
                return -1;
            }

            @Override
            public int read(byte[] b, int off, int len) throws IOException {
                if (b == null) {
                    throw new NullPointerException();
                }

                if (off < 0 || len < 0 || len > b.length - off) {
                    throw new IndexOutOfBoundsException();
                }

                if (mPosition >= mLimit) {
                    return -1;
                }

                if (mPosition + len > mLimit) {
                    len = mLimit - mPosition;
                }

                if (len <= 0) {
                    return 0;
                }

                is.read(b, off, len);
                mPosition += len;
                return len;
            }

            @Override
            public long skip(long len) throws IOException {
                if (mPosition + len > mLimit) {
                    len = mLimit - mPosition;
                }

                if (len <= 0) {
                    return 0;
                }

                is.skip(len);
                mPosition += len;
                return len;
            }

            @Override
            public int available() {
                return mLimit - mPosition;
            }

            @Override
            public boolean markSupported() {
                return is.markSupported();
            }

            @Override
            public synchronized void mark(int readlimit) {
                is.mark(readlimit);
                mMark = mPosition;
            }

            @Override
            public synchronized void reset() throws IOException {
                is.reset();
                mPosition = mMark;
            }

            @Override
            public void close() throws IOException {
                is.close();
            }
        };
    }
@Test
    void testLimitedInputStream() throws Exception {
        InputStream is = StreamUtilsTest.class.getResourceAsStream("/StreamUtilsTest.txt");
        assertThat(10, is(is.available()));

        is = StreamUtils.limitedInputStream(is, 2);
        assertThat(2, is(is.available()));
        assertThat(is.markSupported(), is(true));

        is.mark(0);
        assertEquals((int) '0', is.read());
        assertEquals((int) '1', is.read());
        assertEquals(-1, is.read());

        is.reset();
        is.skip(1);
        assertEquals((int) '1', is.read());

        is.reset();
        is.skip(-1);
        assertEquals((int) '0', is.read());

        is.reset();
        byte[] bytes = new byte[2];
        int read = is.read(bytes, 1, 1);
        assertThat(read, is(1));

        is.reset();
        StreamUtils.skipUnusedStream(is);
        assertEquals(-1, is.read());

        is.close();
    }