Repository: ktorio/ktor
File: ktor-shared/ktor-websockets/jvm/src/io/ktor/websocket/internals/DeflaterUtils.kt (Kotlin)

Code before:
    }.readByteArray()
}

internal fun Inflater.inflateFully(data: ByteArray): ByteArray =
    inflateFully(data, MAX_INFLATED_FRAME_SIZE)

internal fun Inflater.inflateFully(data: ByteArray, maxOutputSize: Int): ByteArray {
    require(maxOutputSize >= 0) { "maxOutputSize should be >= 0" }

    val dataToInflate = data + EMPTY_CHUNK
    setInput(dataToInflate)

    var totalWritten: Long = 0

    val packet = buildPacket {
        KtorDefaultPool.useInstance { buffer ->
            val limit = dataToInflate.size + bytesRead
            while (bytesRead < limit) {
                buffer.clear()

                val beforeBytesRead = bytesRead
                val inflated = inflate(buffer.array(), buffer.position(), buffer.limit())
                val afterBytesRead = bytesRead

                if (inflated == 0 && afterBytesRead == beforeBytesRead) {
                    throw IOException("Inflater made no progress: bytesRead=$afterBytesRead, limit=$limit")
                }

                buffer.position(buffer.position() + inflated)
                buffer.flip()

                totalWritten += buffer.remaining().toLong()
                if (totalWritten > maxOutputSize.toLong()) {
                    throw IOException("Inflated data exceeds limit: $totalWritten > $maxOutputSize")
                }

                writeFully(buffer)
            }
        }
    }

    return packet.readByteArray()
}

private fun Sink.deflateTo(
    deflater: Deflater,
    buffer: ByteBuffer,
    flush: Boolean
): Int {
    buffer.clear()


Review comment (suggestion):
well that's not necessarily error by itself, right? it can mean we have consumed all input including the appended EMPTY_CHUNK, and there's no more output to produce. 
I'd say what should happen here is 
```
reset()
setInput()
buildPacket{
...
...
    while(true){
        if(finished()) break;
        if(inflated > 0){
            ...
            writeFully()
           if(writtenBytes > maxOutput) throw
           continue;
        }
       if(inflated <= 0){
           if(needsDictionary()) throw
           if(needsInput()) break;
           // if it reaches the end, it means no progress but not finished/needsInput, indicates corrupted stream
           throw
       }
    }
}
```

Code after:
    }.readByteArray()
}

internal fun Inflater.inflateFully(data: ByteArray): ByteArray =
    inflateFully(data, MAX_INFLATED_FRAME_SIZE)

internal fun Inflater.inflateFully(data: ByteArray, maxOutputSize: Int): ByteArray {
    require(maxOutputSize >= 0) { "maxOutputSize should be >= 0" }
    reset()

    val dataToInflate = data + EMPTY_CHUNK
    setInput(dataToInflate)

    var totalWritten: Long = 0

    val packet = buildPacket {
        KtorDefaultPool.useInstance { buffer ->
            while (true) {
                if (finished()) break

                buffer.clear()
                val inflated = inflate(buffer.array(), buffer.position(), buffer.limit())

                if (inflated > 0) {
                    buffer.position(buffer.position() + inflated)
                    buffer.flip()

                    totalWritten += buffer.remaining().toLong()
                    if (totalWritten > maxOutputSize.toLong()) {
                        throw IOException("Inflated data exceeds limit: $totalWritten > $maxOutputSize")
                    }

                    writeFully(buffer)
                    continue
                }

                if (needsDictionary()) {
                    throw IOException("Inflater needs a preset dictionary")
                }

                if (needsInput()) {
                    break
                }

                throw IOException("Inflater made no progress; data probably corrupted")
            }
        }
    }

    return packet.readByteArray()
}