From 2b82a2eef7e897203a191adca996435d091fe4c2 Mon Sep 17 00:00:00 2001 From: rsgowman Date: Mon, 12 Mar 2018 18:15:08 -0400 Subject: Allow serializing arbitrary length FieldValues (#889) Uses a custom pb_ostream_t. Previously used a stack allocated 1k buffer. --- .../src/firebase/firestore/remote/serializer.cc | 29 +++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'Firestore/core/src/firebase/firestore/remote') diff --git a/Firestore/core/src/firebase/firestore/remote/serializer.cc b/Firestore/core/src/firebase/firestore/remote/serializer.cc index 02ed1ae..fcf8633 100644 --- a/Firestore/core/src/firebase/firestore/remote/serializer.cc +++ b/Firestore/core/src/firebase/firestore/remote/serializer.cc @@ -550,13 +550,30 @@ std::map DecodeObject(pb_istream_t* stream) { void Serializer::EncodeFieldValue(const FieldValue& field_value, std::vector* out_bytes) { - // TODO(rsgowman): how large should the output buffer be? Do some - // investigation to see if we can get nanopb to tell us how much space it's - // going to need. (Hint: use a sizing stream, i.e. PB_OSTREAM_SIZING) - uint8_t buf[1024]; - pb_ostream_t stream = pb_ostream_from_buffer(buf, sizeof(buf)); + // TODO(rsgowman): find a better home for this constant. + // A document is defined to have a max size of 1MiB - 4 bytes. + static const size_t kMaxDocumentSize = 1 * 1024 * 1024 - 4; + + // Construct a nanopb output stream. + // + // Set the max_size to be the max document size (as an upper bound; one would + // expect individual FieldValue's to be smaller than this). + // + // bytes_written is (always) initialized to 0. (NB: nanopb does not know or + // care about the underlying output vector, so where we are in the vector + // itself is irrelevant. i.e. don't use out_bytes->size()) + pb_ostream_t stream = { + /*callback=*/[](pb_ostream_t* stream, const pb_byte_t* buf, + size_t count) -> bool { + auto* out_bytes = static_cast*>(stream->state); + out_bytes->insert(out_bytes->end(), buf, buf + count); + return true; + }, + /*state=*/out_bytes, + /*max_size=*/kMaxDocumentSize, + /*bytes_written=*/0, + /*errmsg=*/NULL}; EncodeFieldValueImpl(&stream, field_value); - out_bytes->insert(out_bytes->end(), buf, buf + stream.bytes_written); } FieldValue Serializer::DecodeFieldValue(const uint8_t* bytes, size_t length) { -- cgit v1.2.3