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/compiler.h"
20 #include "perfetto/base/logging.h"
21
22 #if !PERFETTO_IS_LITTLE_ENDIAN()
23 // The memcpy() for fixed32/64 below needs to be adjusted if we want to
24 // support big endian CPUs. There doesn't seem to be a compelling need today.
25 #error Unimplemented for big endian archs.
26 #endif
27
28 namespace protozero {
29
30 template <typename Container>
SerializeAndAppendToInternal(Container * dst) const31 void Field::SerializeAndAppendToInternal(Container* dst) const {
32 namespace pu = proto_utils;
33 size_t initial_size = dst->size();
34 dst->resize(initial_size + pu::kMaxSimpleFieldEncodedSize + size_);
35 uint8_t* start = reinterpret_cast<uint8_t*>(&(*dst)[initial_size]);
36 uint8_t* wptr = start;
37 switch (type_) {
38 case static_cast<int>(pu::ProtoWireType::kVarInt): {
39 wptr = pu::WriteVarInt(pu::MakeTagVarInt(id_), wptr);
40 wptr = pu::WriteVarInt(int_value_, wptr);
41 break;
42 }
43 case static_cast<int>(pu::ProtoWireType::kFixed32): {
44 wptr = pu::WriteVarInt(pu::MakeTagFixed<uint32_t>(id_), wptr);
45 uint32_t value32 = static_cast<uint32_t>(int_value_);
46 memcpy(wptr, &value32, sizeof(value32));
47 wptr += sizeof(uint32_t);
48 break;
49 }
50 case static_cast<int>(pu::ProtoWireType::kFixed64): {
51 wptr = pu::WriteVarInt(pu::MakeTagFixed<uint64_t>(id_), wptr);
52 memcpy(wptr, &int_value_, sizeof(int_value_));
53 wptr += sizeof(uint64_t);
54 break;
55 }
56 case static_cast<int>(pu::ProtoWireType::kLengthDelimited): {
57 ConstBytes payload = as_bytes();
58 wptr = pu::WriteVarInt(pu::MakeTagLengthDelimited(id_), wptr);
59 wptr = pu::WriteVarInt(payload.size, wptr);
60 memcpy(wptr, payload.data, payload.size);
61 wptr += payload.size;
62 break;
63 }
64 default:
65 PERFETTO_FATAL("Unknown field type %u", type_);
66 }
67 size_t written_size = static_cast<size_t>(wptr - start);
68 PERFETTO_DCHECK(written_size > 0 && written_size < pu::kMaxMessageLength);
69 PERFETTO_DCHECK(initial_size + written_size <= dst->size());
70 dst->resize(initial_size + written_size);
71 }
72
SerializeAndAppendTo(std::string * dst) const73 void Field::SerializeAndAppendTo(std::string* dst) const {
74 SerializeAndAppendToInternal(dst);
75 }
76
SerializeAndAppendTo(std::vector<uint8_t> * dst) const77 void Field::SerializeAndAppendTo(std::vector<uint8_t>* dst) const {
78 SerializeAndAppendToInternal(dst);
79 }
80
81 } // namespace protozero
82