aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase/firestore/nanopb/reader.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Firestore/core/src/firebase/firestore/nanopb/reader.cc')
-rw-r--r--Firestore/core/src/firebase/firestore/nanopb/reader.cc141
1 files changed, 141 insertions, 0 deletions
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<pb_byte_t*>(&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