1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/protozero/field.h"
18
19 #include "perfetto/base/logging.h"
20
21 #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
22 // The memcpy() for fixed32/64 below needs to be adjusted if we want to
23 // support big endian CPUs. There doesn't seem to be a compelling need today.
24 #error Unimplemented for big endian archs.
25 #endif
26
27 namespace protozero {
28
29 template <typename Container>
SerializeAndAppendToInternal(Container * dst) const30 void Field::SerializeAndAppendToInternal(Container* dst) const {
31 namespace pu = proto_utils;
32 size_t initial_size = dst->size();
33 dst->resize(initial_size + pu::kMaxSimpleFieldEncodedSize + size_);
34 uint8_t* start = reinterpret_cast<uint8_t*>(&(*dst)[initial_size]);
35 uint8_t* wptr = start;
36 switch (type_) {
37 case static_cast<int>(pu::ProtoWireType::kVarInt): {
38 wptr = pu::WriteVarInt(pu::MakeTagVarInt(id_), wptr);
39 wptr = pu::WriteVarInt(int_value_, wptr);
40 break;
41 }
42 case static_cast<int>(pu::ProtoWireType::kFixed32): {
43 wptr = pu::WriteVarInt(pu::MakeTagFixed<uint32_t>(id_), wptr);
44 uint32_t value32 = static_cast<uint32_t>(int_value_);
45 memcpy(wptr, &value32, sizeof(value32));
46 wptr += sizeof(uint32_t);
47 break;
48 }
49 case static_cast<int>(pu::ProtoWireType::kFixed64): {
50 wptr = pu::WriteVarInt(pu::MakeTagFixed<uint64_t>(id_), wptr);
51 memcpy(wptr, &int_value_, sizeof(int_value_));
52 wptr += sizeof(uint64_t);
53 break;
54 }
55 case static_cast<int>(pu::ProtoWireType::kLengthDelimited): {
56 ConstBytes payload = as_bytes();
57 wptr = pu::WriteVarInt(pu::MakeTagLengthDelimited(id_), wptr);
58 wptr = pu::WriteVarInt(payload.size, wptr);
59 memcpy(wptr, payload.data, payload.size);
60 wptr += payload.size;
61 break;
62 }
63 default:
64 PERFETTO_FATAL("Unknown field type %u", type_);
65 }
66 size_t written_size = static_cast<size_t>(wptr - start);
67 PERFETTO_DCHECK(written_size > 0 && written_size < pu::kMaxMessageLength);
68 PERFETTO_DCHECK(initial_size + written_size <= dst->size());
69 dst->resize(initial_size + written_size);
70 }
71
SerializeAndAppendTo(std::string * dst) const72 void Field::SerializeAndAppendTo(std::string* dst) const {
73 SerializeAndAppendToInternal(dst);
74 }
75
SerializeAndAppendTo(std::vector<uint8_t> * dst) const76 void Field::SerializeAndAppendTo(std::vector<uint8_t>* dst) const {
77 SerializeAndAppendToInternal(dst);
78 }
79
80 } // namespace protozero
81