class ContentDefinedChunker implements Chunker {

    @Override
    public void chunkify(InputStream inputStream, ChunkConsumer chunkConsumer)
            throws IOException, GeneralSecurityException {
        int chunkLength;
        int initialReadLength = mMinChunkSize - WINDOW_SIZE;

        // Performance optimization - there is no reason to calculate fingerprints for windows
        // ending before the minimum chunk size.
        while ((chunkLength =
                        inputStream.read(mChunkBuffer, /*off=*/ 0, /*len=*/ initialReadLength))
                != -1) {
            int b;
            long fingerprint = 0L;

            while ((b = inputStream.read()) != -1) {
                byte inByte = (byte) b;
                byte outByte = getCurrentWindowStartByte(chunkLength);
                mChunkBuffer[chunkLength++] = inByte;

                fingerprint =
                        mRabinFingerprint64.computeFingerprint64(inByte, outByte, fingerprint);

                if (chunkLength >= mMaxChunkSize
                        || (chunkLength >= mMinChunkSize
                                && mBreakpointPredicate.isBreakpoint(
                                        mFingerprintMixer.mix(fingerprint)))) {
                    chunkConsumer.accept(Arrays.copyOf(mChunkBuffer, chunkLength));
                    chunkLength = 0;
                    break;
                }
            }

            if (chunkLength > 0) {
                chunkConsumer.accept(Arrays.copyOf(mChunkBuffer, chunkLength));
            }
        }
    }

    public  ContentDefinedChunker(
            int minChunkSize,
            int maxChunkSize,
            RabinFingerprint64 rabinFingerprint64,
            FingerprintMixer fingerprintMixer,
            BreakpointPredicate breakpointPredicate);

}