1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
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 // max field size = varint(fieldId + type) + varint(dataSize) + dataSize
89 if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN + dataSize,
90 &fieldMemory, &fieldOffset)) {
91 Drop();
92 return;
93 }
94
95 uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
96 fieldSize += EncodeVarint(fieldMemory + fieldSize, dataSize);
97 if (dataSize != 0) {
98 if (memcpy_s(fieldMemory + fieldSize, dataSize, data, dataSize) != EOK) {
99 Drop();
100 return;
101 }
102 }
103 fieldSize += dataSize;
104 size_ += static_cast<int32_t>(fieldSize);
105 // seek to tail
106 writeCtx_->seek(writeCtx_, fieldOffset + fieldSize);
107 }
108
StartAddBytes(uint32_t fieldId)109 RandomWriteCtx* BaseMessage::StartAddBytes(uint32_t fieldId)
110 {
111 if (subMessage_ != nullptr) {
112 FinishSubMessage();
113 }
114 if (!isWriting_) {
115 // finished or dropped
116 return nullptr;
117 }
118
119 uint8_t* fieldMemory = nullptr;
120 // max field size = varint(fieldId + type) + varint(len)
121 if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
122 &fieldMemory, &backfillOffset_)) {
123 Drop();
124 return nullptr;
125 }
126
127 uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
128 backfillOffset_ += tagSize;
129 size_ += static_cast<int32_t>(tagSize);
130 // reserve length space
131 writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN);
132 return writeCtx_;
133 }
134
FinishAddBytes(int32_t size)135 void BaseMessage::FinishAddBytes(int32_t size)
136 {
137 if (size < 0) {
138 Drop();
139 return;
140 }
141
142 uint8_t* fieldMemory = nullptr;
143 // backfill length
144 writeCtx_->seek(writeCtx_, backfillOffset_);
145 if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &backfillOffset_)) {
146 Drop();
147 return;
148 }
149
150 if (size == 0) {
151 // reduce the size
152 *fieldMemory = 0;
153 writeCtx_->seek(writeCtx_, backfillOffset_ + 1);
154 size_++;
155 return;
156 }
157
158 // varint(Length)
159 EncodeVarintPadding(fieldMemory, size, SIZE_RESERVED_LEN);
160 size_ += SIZE_RESERVED_LEN + size;
161 // seek to tail
162 writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN + size);
163 }
164
AddBytesByCallBack(uint32_t fieldId,GetDataCallback getData)165 void BaseMessage::AddBytesByCallBack(uint32_t fieldId, GetDataCallback getData)
166 {
167 if (!getData) {
168 return;
169 }
170
171 if (subMessage_ != nullptr) {
172 FinishSubMessage();
173 }
174 if (!isWriting_) {
175 return;
176 }
177
178 uint8_t* fieldMemory = nullptr;
179 uint32_t fieldOffset = 0;
180 // max field size = varint(fieldId + type) + varint(len)
181 if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
182 &fieldMemory, &fieldOffset)) {
183 Drop();
184 return;
185 }
186
187 uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
188 fieldOffset += tagSize;
189 size_ += static_cast<int32_t>(tagSize);
190 // reserve length space
191 writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN);
192
193 int32_t dataSize = getData(writeCtx_);
194 if (dataSize < 0) {
195 Drop();
196 return;
197 }
198
199 // backfill length
200 writeCtx_->seek(writeCtx_, fieldOffset);
201 if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &fieldOffset)) {
202 Drop();
203 return;
204 }
205
206 if (dataSize == 0) {
207 // reduce the size
208 *fieldMemory = 0;
209 writeCtx_->seek(writeCtx_, fieldOffset + 1);
210 size_++;
211 return;
212 }
213
214 EncodeVarintPadding(fieldMemory, dataSize, SIZE_RESERVED_LEN);
215 size_ += SIZE_RESERVED_LEN + dataSize;
216 // seek to tail
217 writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN + dataSize);
218 }
219 } // namespace ProtoEncoder
220 } // namespace Profiler
221 } // namespace Developtools
222 } // namespace OHOS
223