def read_exactly(f, size):
    """Makes repeated `f.read` calls until the buffer is of the specified size (or the file is empty).

    This is needed because `read()` will happily return less than the provided size, but we want fixed size
    chunks.
    """
    buffer = b''
    while len(buffer) < size:
        chunk = f.read(size - len(buffer))
        if not chunk:
            break
        buffer += chunk
    return buffer