in native/src/seal/serialization.cpp [224:339]
streamoff Serialization::Save(
function<void(ostream &)> save_members, streamoff raw_size, ostream &stream, compr_mode_type compr_mode,
SEAL_MAYBE_UNUSED bool clear_buffers)
{
if (!save_members)
{
throw invalid_argument("save_members is invalid");
}
if (raw_size < static_cast<streamoff>(sizeof(SEALHeader)))
{
throw invalid_argument("raw_size is too small");
}
if (!IsSupportedComprMode(compr_mode))
{
throw invalid_argument("unsupported compression mode");
}
streamoff out_size = 0;
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.tellp();
// Create the header
SEALHeader header;
switch (compr_mode)
{
case compr_mode_type::none:
// We set the compression mode and size here, and save the header
header.compr_mode = compr_mode;
header.size = safe_cast<uint64_t>(raw_size);
SaveHeader(header, stream);
// Write rest of the data
save_members(stream);
break;
#ifdef SEAL_USE_ZLIB
case compr_mode_type::zlib:
{
// First save_members to a temporary byte stream; set the size of the temporary stream to be right from
// the start to avoid extra reallocs.
SafeByteBuffer safe_buffer(
ztools::zlib_deflate_size_bound(raw_size - static_cast<streamoff>(sizeof(SEALHeader))),
clear_buffers);
iostream temp_stream(&safe_buffer);
temp_stream.exceptions(ios_base::badbit | ios_base::failbit);
save_members(temp_stream);
auto safe_pool(MemoryManager::GetPool(mm_prof_opt::mm_force_new, clear_buffers));
// Create temporary aliasing DynArray to wrap safe_buffer
DynArray<seal_byte> safe_buffer_array(
Pointer<seal_byte>::Aliasing(safe_buffer.data()), safe_buffer.size(),
static_cast<size_t>(temp_stream.tellp()), false, safe_pool);
// After compression, write_header_deflate_buffer will write the final size to the given header and
// write the header to stream, before writing the compressed output.
ztools::zlib_write_header_deflate_buffer(
safe_buffer_array, reinterpret_cast<void *>(&header), stream, safe_pool);
break;
}
#endif
#ifdef SEAL_USE_ZSTD
case compr_mode_type::zstd:
{
// First save_members to a temporary byte stream; set the size of the temporary stream to be right from
// the start to avoid extra reallocs.
SafeByteBuffer safe_buffer(
ztools::zstd_deflate_size_bound(raw_size - static_cast<streamoff>(sizeof(SEALHeader))),
clear_buffers);
iostream temp_stream(&safe_buffer);
temp_stream.exceptions(ios_base::badbit | ios_base::failbit);
save_members(temp_stream);
auto safe_pool(MemoryManager::GetPool(mm_prof_opt::mm_force_new, clear_buffers));
// Create temporary aliasing DynArray to wrap safe_buffer
DynArray<seal_byte> safe_buffer_array(
Pointer<seal_byte>::Aliasing(safe_buffer.data()), safe_buffer.size(),
static_cast<size_t>(temp_stream.tellp()), false, safe_pool);
// After compression, write_header_deflate_buffer will write the final size to the given header and
// write the header to stream, before writing the compressed output.
ztools::zstd_write_header_deflate_buffer(
safe_buffer_array, reinterpret_cast<void *>(&header), stream, safe_pool);
break;
}
#endif
default:
throw invalid_argument("unsupported compression mode");
}
// Compute how many bytes were written
auto stream_end_pos = stream.tellp();
out_size = stream_end_pos - stream_start_pos;
}
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 out_size;
}