Shared library ABI for decoding protobufs
For now it's required for tests.
Bug: 184929776
Change-Id: I9a4194dc4f2b1e6bf4fcb90ce542e81dd09e2ef1
diff --git a/src/shared_lib/pb_decoder.cc b/src/shared_lib/pb_decoder.cc
new file mode 100644
index 0000000..02a1254
--- /dev/null
+++ b/src/shared_lib/pb_decoder.cc
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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 "perfetto/public/abi/pb_decoder_abi.h"
+
+#include <limits>
+#include <type_traits>
+
+#include "perfetto/public/pb_utils.h"
+
+namespace {
+template <typename T>
+bool Uint64RepresentableIn(uint64_t val) {
+ return val <= std::numeric_limits<T>::max();
+}
+} // namespace
+
+struct PerfettoPbDecoderField PerfettoPbDecoderParseField(
+ struct PerfettoPbDecoder* decoder) {
+ struct PerfettoPbDecoderField field;
+ const uint8_t* read_ptr = decoder->read_ptr;
+ if (read_ptr >= decoder->end_ptr) {
+ field.status = PERFETTO_PB_DECODER_DONE;
+ return field;
+ }
+ field.status = PERFETTO_PB_DECODER_ERROR;
+ uint64_t tag;
+ const uint8_t* end_of_tag =
+ PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &tag);
+ if (end_of_tag == read_ptr) {
+ field.status = PERFETTO_PB_DECODER_ERROR;
+ return field;
+ }
+ read_ptr = end_of_tag;
+ constexpr uint8_t kFieldTypeNumBits = 3;
+
+ field.wire_type = tag & ((1 << kFieldTypeNumBits) - 1);
+ uint64_t id = tag >> kFieldTypeNumBits;
+ static_assert(std::is_same<uint32_t, decltype(field.id)>::value);
+ if (id > std::numeric_limits<uint32_t>::max()) {
+ field.status = PERFETTO_PB_DECODER_ERROR;
+ return field;
+ }
+ field.id = static_cast<uint32_t>(id);
+
+ switch (field.wire_type) {
+ case PERFETTO_PB_WIRE_TYPE_DELIMITED: {
+ uint64_t len;
+ const uint8_t* end_of_len =
+ PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &len);
+ if (end_of_len == read_ptr || !Uint64RepresentableIn<size_t>(len)) {
+ field.status = PERFETTO_PB_DECODER_ERROR;
+ return field;
+ }
+ read_ptr = end_of_len;
+ field.value.delimited.len = static_cast<size_t>(len);
+ field.value.delimited.start = read_ptr;
+ read_ptr += len;
+ if (read_ptr > decoder->end_ptr) {
+ field.status = PERFETTO_PB_DECODER_ERROR;
+ return field;
+ }
+ field.status = PERFETTO_PB_DECODER_OK;
+ decoder->read_ptr = read_ptr;
+ break;
+ }
+ case PERFETTO_PB_WIRE_TYPE_VARINT: {
+ uint64_t val;
+ const uint8_t* end_of_val =
+ PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &val);
+ if (end_of_val == read_ptr) {
+ field.status = PERFETTO_PB_DECODER_ERROR;
+ return field;
+ }
+ read_ptr = end_of_val;
+ field.value.integer64 = val;
+ field.status = PERFETTO_PB_DECODER_OK;
+ decoder->read_ptr = read_ptr;
+ break;
+ }
+ case PERFETTO_PB_WIRE_TYPE_FIXED32: {
+ const uint8_t* end_of_val = read_ptr + sizeof(uint32_t);
+ if (end_of_val > decoder->end_ptr) {
+ field.status = PERFETTO_PB_DECODER_ERROR;
+ return field;
+ }
+ // Little endian on the wire.
+ field.value.integer32 = read_ptr[0] |
+ (static_cast<uint32_t>(read_ptr[1]) << 8) |
+ (static_cast<uint32_t>(read_ptr[2]) << 16) |
+ (static_cast<uint32_t>(read_ptr[3]) << 24);
+ read_ptr = end_of_val;
+ decoder->read_ptr = read_ptr;
+ field.status = PERFETTO_PB_DECODER_OK;
+ break;
+ }
+ case PERFETTO_PB_WIRE_TYPE_FIXED64: {
+ const uint8_t* end_of_val = read_ptr + sizeof(uint64_t);
+ if (end_of_val > decoder->end_ptr) {
+ field.status = PERFETTO_PB_DECODER_ERROR;
+ return field;
+ }
+ // Little endian on the wire.
+ field.value.integer64 = read_ptr[0] |
+ (static_cast<uint64_t>(read_ptr[1]) << 8) |
+ (static_cast<uint64_t>(read_ptr[2]) << 16) |
+ (static_cast<uint64_t>(read_ptr[3]) << 24) |
+ (static_cast<uint64_t>(read_ptr[4]) << 32) |
+ (static_cast<uint64_t>(read_ptr[5]) << 40) |
+ (static_cast<uint64_t>(read_ptr[6]) << 48) |
+ (static_cast<uint64_t>(read_ptr[7]) << 56);
+ read_ptr = end_of_val;
+ decoder->read_ptr = read_ptr;
+ field.status = PERFETTO_PB_DECODER_OK;
+ break;
+ }
+ default:
+ field.status = PERFETTO_PB_DECODER_ERROR;
+ return field;
+ }
+ return field;
+}
+
+uint32_t PerfettoPbDecoderSkipField(struct PerfettoPbDecoder* decoder) {
+ const uint8_t* read_ptr = decoder->read_ptr;
+ if (read_ptr >= decoder->end_ptr) {
+ return PERFETTO_PB_DECODER_DONE;
+ }
+ uint64_t tag;
+ const uint8_t* end_of_tag =
+ PerfettoPbParseVarInt(decoder->read_ptr, decoder->end_ptr, &tag);
+ if (end_of_tag == read_ptr) {
+ return PERFETTO_PB_DECODER_ERROR;
+ }
+ read_ptr = end_of_tag;
+ constexpr uint8_t kFieldTypeNumBits = 3;
+
+ uint32_t wire_type = tag & ((1 << kFieldTypeNumBits) - 1);
+ switch (wire_type) {
+ case PERFETTO_PB_WIRE_TYPE_DELIMITED: {
+ uint64_t len;
+ const uint8_t* end_of_len =
+ PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &len);
+ if (end_of_len == read_ptr) {
+ return PERFETTO_PB_DECODER_ERROR;
+ }
+ read_ptr = end_of_len;
+ read_ptr += len;
+ if (read_ptr > decoder->end_ptr) {
+ return PERFETTO_PB_DECODER_ERROR;
+ }
+ decoder->read_ptr = read_ptr;
+ return PERFETTO_PB_DECODER_OK;
+ }
+ case PERFETTO_PB_WIRE_TYPE_VARINT: {
+ uint64_t val;
+ const uint8_t* end_of_val =
+ PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &val);
+ if (end_of_val == read_ptr) {
+ return PERFETTO_PB_DECODER_ERROR;
+ }
+ read_ptr = end_of_val;
+ decoder->read_ptr = read_ptr;
+ return PERFETTO_PB_DECODER_OK;
+ }
+ case PERFETTO_PB_WIRE_TYPE_FIXED32: {
+ const uint8_t* end_of_val = read_ptr + sizeof(uint32_t);
+ if (end_of_val > decoder->end_ptr) {
+ return PERFETTO_PB_DECODER_ERROR;
+ }
+ read_ptr = end_of_val;
+ decoder->read_ptr = read_ptr;
+ return PERFETTO_PB_DECODER_OK;
+ }
+ case PERFETTO_PB_WIRE_TYPE_FIXED64: {
+ const uint8_t* end_of_val = read_ptr + sizeof(uint64_t);
+ if (read_ptr > decoder->end_ptr) {
+ return PERFETTO_PB_DECODER_ERROR;
+ }
+ read_ptr = end_of_val;
+ decoder->read_ptr = read_ptr;
+ return PERFETTO_PB_DECODER_OK;
+ }
+ default:
+ break;
+ }
+ return PERFETTO_PB_DECODER_ERROR;
+}