streamoff Serialization::Load()

in native/src/seal/serialization.cpp [341:451]


    streamoff Serialization::Load(
        function<void(istream &, SEALVersion)> load_members, istream &stream, SEAL_MAYBE_UNUSED bool clear_buffers)
    {
        if (!load_members)
        {
            throw invalid_argument("load_members is invalid");
        }

        streamoff in_size = 0;
        SEALHeader header;

        auto old_except_mask = stream.exceptions();
        try
        {
            // Throw exceptions on ios_base::badbit and ios_base::failbit
            stream.exceptions(ios_base::badbit | ios_base::failbit);

            // Save the starting position
            auto stream_start_pos = stream.tellg();

            // First read the header
            LoadHeader(stream, header);
            if (!IsCompatibleVersion(header))
            {
                throw logic_error("incompatible version");
            }
            if (!IsValidHeader(header))
            {
                throw logic_error("loaded SEALHeader is invalid");
            }

            // Read header version information so we can call, if necessary, the
            // correct variant of load_members.
            SEALVersion version{ header.version_major, header.version_minor, 0, 0 };

            switch (header.compr_mode)
            {
            case compr_mode_type::none:
                // Read rest of the data
                load_members(stream, version);
                if (header.size != safe_cast<uint64_t>(stream.tellg() - stream_start_pos))
                {
                    throw logic_error("invalid data size");
                }
                break;
#ifdef SEAL_USE_ZLIB
            case compr_mode_type::zlib:
            {
                auto compr_size = header.size - safe_cast<uint64_t>(stream.tellg() - stream_start_pos);

                // We don't know the decompressed size, but use compr_size as
                // starting point for the buffer.
                SafeByteBuffer safe_buffer(safe_cast<streamsize>(compr_size), clear_buffers);

                iostream temp_stream(&safe_buffer);
                temp_stream.exceptions(ios_base::badbit | ios_base::failbit);

                auto safe_pool = MemoryManager::GetPool(mm_prof_opt::mm_force_new, clear_buffers);

                // Throw an exception on non-zero return value
                if (ztools::zlib_inflate_stream(stream, safe_cast<streamoff>(compr_size), temp_stream, safe_pool))
                {
                    throw logic_error("stream decompression failed");
                }
                load_members(temp_stream, version);
                break;
            }
#endif
#ifdef SEAL_USE_ZSTD
            case compr_mode_type::zstd:
            {
                auto compr_size = header.size - safe_cast<uint64_t>(stream.tellg() - stream_start_pos);

                // We don't know the decompressed size, but use compr_size as
                // starting point for the buffer.
                SafeByteBuffer safe_buffer(safe_cast<streamsize>(compr_size), clear_buffers);

                iostream temp_stream(&safe_buffer);
                temp_stream.exceptions(ios_base::badbit | ios_base::failbit);

                auto safe_pool = MemoryManager::GetPool(mm_prof_opt::mm_force_new, clear_buffers);

                // Throw an exception on non-zero return value
                if (ztools::zstd_inflate_stream(stream, safe_cast<streamoff>(compr_size), temp_stream, safe_pool))
                {
                    throw logic_error("stream decompression failed");
                }
                load_members(temp_stream, version);
                break;
            }
#endif
            default:
                throw invalid_argument("unsupported compression mode");
            }

            in_size = safe_cast<streamoff>(header.size);
        }
        catch (const ios_base::failure &)
        {
            stream.exceptions(old_except_mask);
            expressive_rethrow_on_ios_base_failure(stream);
        }
        catch (...)
        {
            stream.exceptions(old_except_mask);
            throw;
        }
        stream.exceptions(old_except_mask);

        return in_size;
    }