1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "base_message.h"
16
17 #include "securec.h"
18 #include "varint_encode.h"
19
20 namespace OHOS {
21 namespace Developtools {
22 namespace Profiler {
23 namespace ProtoEncoder {
AllocateSubMessage()24 bool BaseMessage::AllocateSubMessage()
25 {
26 if (subMessageStack_ == nullptr) {
27 subMessage_ = new (std::nothrow) BaseMessage(writeCtx_);
28 } else {
29 subMessage_ = subMessageStack_->Get();
30 }
31
32 if (subMessage_ == nullptr) {
33 return false;
34 }
35 subMessage_->Reset(writeCtx_, subMessageStack_);
36 return true;
37 }
38
FinishSubMessage()39 void BaseMessage::FinishSubMessage()
40 {
41 int32_t subSize = subMessage_->Finish();
42 if (subMessageStack_ == nullptr) {
43 delete subMessage_;
44 } else {
45 subMessageStack_->Release();
46 }
47 subMessage_ = nullptr;
48 if (subSize < 0) {
49 Drop();
50 return;
51 }
52
53 uint8_t* fieldMemory = nullptr;
54 // backfill length
55 writeCtx_->seek(writeCtx_, backfillOffset_);
56 if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN,
57 &fieldMemory, &backfillOffset_)) {
58 Drop();
59 return;
60 }
61
62 if (subSize == 0) {
63 // reduce the size
64 *fieldMemory = 0;
65 writeCtx_->seek(writeCtx_, backfillOffset_ + 1);
66 size_++;
67 return;
68 }
69
70 // varint(Length)
71 EncodeVarintPadding(fieldMemory, subSize, SIZE_RESERVED_LEN);
72 size_ += SIZE_RESERVED_LEN + subSize;
73 // seek to tail
74 writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN + subSize);
75 }
76
AddBytes(uint32_t fieldId,const void * data,uint32_t dataSize)77 void BaseMessage::AddBytes(uint32_t fieldId, const void* data, uint32_t dataSize)
78 {
79 if (subMessage_ != nullptr) {
80 FinishSubMessage();
81 }
82 if (!isWriting_) {
83 return;
84 }
85
86 uint8_t* fieldMemory = nullptr;
87 uint32_t fieldOffset = 0;
88 if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN + dataSize,
89 &fieldMemory, &fieldOffset)) {
90 Drop();
91 return;
92 }
93
94 uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
95 fieldSize += EncodeVarint(fieldMemory + fieldSize, dataSize);
96 if (dataSize != 0) {
97 if (memcpy_s(fieldMemory + fieldSize, dataSize, data, dataSize) != EOK) {
98 Drop();
99 return;
100 }
101 }
102 fieldSize += dataSize;
103 size_ += static_cast<int32_t>(fieldSize);
104 // seek to tail
105 writeCtx_->seek(writeCtx_, fieldOffset + fieldSize);
106 }
107
StartAddBytes(uint32_t fieldId)108 RandomWriteCtx* BaseMessage::StartAddBytes(uint32_t fieldId)
109 {
110 if (subMessage_ != nullptr) {
111 FinishSubMessage();
112 }
113 if (!isWriting_) {
114 // finished or dropped
115 return nullptr;
116 }
117
118 uint8_t* fieldMemory = nullptr;
119 // max field size = varint(fieldId + type) + varint(len)
120 if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
121 &fieldMemory, &backfillOffset_)) {
122 Drop();
123 return nullptr;
124 }
125
126 uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
127 backfillOffset_ += tagSize;
128 size_ += static_cast<int32_t>(tagSize);
129 // reserve length space
130 writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN);
131 return writeCtx_;
132 }
133
FinishAddBytes(int32_t size)134 void BaseMessage::FinishAddBytes(int32_t size)
135 {
136 if (size < 0) {
137 Drop();
138 return;
139 }
140
141 uint8_t* fieldMemory = nullptr;
142 // backfill length
143 writeCtx_->seek(writeCtx_, backfillOffset_);
144 if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &backfillOffset_)) {
145 Drop();
146 return;
147 }
148
149 if (size == 0) {
150 // reduce the size
151 *fieldMemory = 0;
152 writeCtx_->seek(writeCtx_, backfillOffset_ + 1);
153 size_++;
154 return;
155 }
156
157 // varint(Length)
158 EncodeVarintPadding(fieldMemory, size, SIZE_RESERVED_LEN);
159 size_ += SIZE_RESERVED_LEN + size;
160 // seek to tail
161 writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN + size);
162 }
163
AddBytesByCallBack(uint32_t fieldId,GetDataCallback getData)164 void BaseMessage::AddBytesByCallBack(uint32_t fieldId, GetDataCallback getData)
165 {
166 if (!getData) {
167 return;
168 }
169
170 if (subMessage_ != nullptr) {
171 FinishSubMessage();
172 }
173 if (!isWriting_) {
174 return;
175 }
176
177 uint8_t* fieldMemory = nullptr;
178 uint32_t fieldOffset = 0;
179 // max field size = varint(fieldId + type) + varint(len)
180 if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
181 &fieldMemory, &fieldOffset)) {
182 Drop();
183 return;
184 }
185
186 uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
187 fieldOffset += tagSize;
188 size_ += static_cast<int32_t>(tagSize);
189 // reserve length space
190 writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN);
191
192 int32_t dataSize = getData(writeCtx_);
193 if (dataSize < 0) {
194 Drop();
195 return;
196 }
197
198 // backfill length
199 writeCtx_->seek(writeCtx_, fieldOffset);
200 if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &fieldOffset)) {
201 Drop();
202 return;
203 }
204
205 if (dataSize == 0) {
206 // reduce the size
207 *fieldMemory = 0;
208 writeCtx_->seek(writeCtx_, fieldOffset + 1);
209 size_++;
210 return;
211 }
212
213 EncodeVarintPadding(fieldMemory, dataSize, SIZE_RESERVED_LEN);
214 size_ += SIZE_RESERVED_LEN + dataSize;
215 // seek to tail
216 writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN + dataSize);
217 }
218 } // namespace ProtoEncoder
219 } // namespace Profiler
220 } // namespace Developtools
221 } // namespace OHOS
222