From 56cfe9306ab60af2a17c26b291438a9449d30f5d Mon Sep 17 00:00:00 2001 From: rsgowman Date: Fri, 11 May 2018 10:27:48 -0400 Subject: Refactor serializer (#1250) Moved Tag, Reader, Writer from serializer.cc's anon namespace to firebase::firestore::nanopb This should be bug-for-bug compatible. No changes were made to the moved methods. --- .../core/src/firebase/firestore/nanopb/reader.cc | 141 +++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 Firestore/core/src/firebase/firestore/nanopb/reader.cc (limited to 'Firestore/core/src/firebase/firestore/nanopb/reader.cc') diff --git a/Firestore/core/src/firebase/firestore/nanopb/reader.cc b/Firestore/core/src/firebase/firestore/nanopb/reader.cc new file mode 100644 index 0000000..86e38ac --- /dev/null +++ b/Firestore/core/src/firebase/firestore/nanopb/reader.cc @@ -0,0 +1,141 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/nanopb/reader.h" + +#include "Firestore/Protos/nanopb/google/firestore/v1beta1/document.pb.h" + +namespace firebase { +namespace firestore { +namespace nanopb { + +using firebase::firestore::util::Status; +using std::int64_t; +using std::uint64_t; + +Reader Reader::Wrap(const uint8_t* bytes, size_t length) { + return Reader{pb_istream_from_buffer(bytes, length)}; +} + +Tag Reader::ReadTag() { + Tag tag; + if (!status_.ok()) return tag; + + bool eof; + if (!pb_decode_tag(&stream_, &tag.wire_type, &tag.field_number, &eof)) { + status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_)); + return tag; + } + + // nanopb code always returns a false status when setting eof. + FIREBASE_ASSERT_MESSAGE(!eof, "nanopb set both ok status and eof to true"); + + return tag; +} + +void Reader::ReadNanopbMessage(const pb_field_t fields[], void* dest_struct) { + if (!status_.ok()) return; + + if (!pb_decode(&stream_, fields, dest_struct)) { + status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_)); + } +} + +/** + * Note that (despite the return type) this works for bool, enum, int32, int64, + * uint32 and uint64 proto field types. + * + * Note: This is not expected to be called directly, but rather only via the + * other Decode* methods (i.e. DecodeBool, DecodeLong, etc) + * + * @return The decoded varint as a uint64_t. + */ +uint64_t Reader::ReadVarint() { + if (!status_.ok()) return 0; + + uint64_t varint_value = 0; + if (!pb_decode_varint(&stream_, &varint_value)) { + status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_)); + } + return varint_value; +} + +void Reader::ReadNull() { + uint64_t varint = ReadVarint(); + if (!status_.ok()) return; + + if (varint != google_protobuf_NullValue_NULL_VALUE) { + status_ = Status(FirestoreErrorCode::DataLoss, + "Input proto bytes cannot be parsed (invalid null value)"); + } +} + +bool Reader::ReadBool() { + uint64_t varint = ReadVarint(); + if (!status_.ok()) return false; + + switch (varint) { + case 0: + return false; + case 1: + return true; + default: + status_ = + Status(FirestoreErrorCode::DataLoss, + "Input proto bytes cannot be parsed (invalid bool value)"); + return false; + } +} + +int64_t Reader::ReadInteger() { + return ReadVarint(); +} + +std::string Reader::ReadString() { + if (!status_.ok()) return ""; + + pb_istream_t substream; + if (!pb_make_string_substream(&stream_, &substream)) { + status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_)); + pb_close_string_substream(&stream_, &substream); + return ""; + } + + std::string result(substream.bytes_left, '\0'); + if (!pb_read(&substream, reinterpret_cast(&result[0]), + substream.bytes_left)) { + status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_)); + pb_close_string_substream(&stream_, &substream); + return ""; + } + + // NB: future versions of nanopb read the remaining characters out of the + // substream (and return false if that fails) as an additional safety + // check within pb_close_string_substream. Unfortunately, that's not present + // in the current version (0.38). We'll make a stronger assertion and check + // to make sure there *are* no remaining characters in the substream. + FIREBASE_ASSERT_MESSAGE( + substream.bytes_left == 0, + "Bytes remaining in substream after supposedly reading all of them."); + + pb_close_string_substream(&stream_, &substream); + + return result; +} + +} // namespace nanopb +} // namespace firestore +} // namespace firebase -- cgit v1.2.3