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 
16 #define LOG_TAG "TlvObject"
17 #include "tlv_object.h"
18 #include "logger.h"
19 
20 namespace OHOS {
21 namespace UDMF {
TLVObject(std::vector<std::uint8_t> & buffer)22 TLVObject::TLVObject(std::vector<std::uint8_t> &buffer)
23 {
24     total_ += buffer.size();
25     buffer_ = &buffer;
26     cursor_ = 0;
27     file_ = nullptr;
28 }
29 
SetFile(std::FILE * file)30 void TLVObject::SetFile(std::FILE *file)
31 {
32     file_ = file;
33     if (fseek(file_, 0, SEEK_END) != 0) {
34         LOG_ERROR(UDMF_SERVICE, "fseek to end error!");
35     }
36 
37     auto total = ftell(file_);
38     if (total < 0) {
39         LOG_ERROR(UDMF_SERVICE, "Values are out of range, total:%{public}ld", total);
40         return;
41     }
42     total_ = static_cast<size_t>(total);
43     ResetCursor();
44 }
45 
UpdateSize()46 void TLVObject::UpdateSize()
47 {
48     if (file_ != nullptr) {
49         return;
50     }
51     buffer_->resize(total_);
52 }
53 
GetBuffer()54 std::vector<std::uint8_t> TLVObject::GetBuffer()
55 {
56     return *buffer_;
57 }
58 
GetTotal()59 size_t TLVObject::GetTotal()
60 {
61     return total_;
62 }
63 
GetCursor()64 size_t TLVObject::GetCursor()
65 {
66     return cursor_;
67 }
68 
OffsetHead()69 size_t TLVObject::OffsetHead()
70 {
71     if (file_ != nullptr) {
72         if (fseek(file_, sizeof(TLVHead), SEEK_CUR) != 0) {
73             LOG_ERROR(UDMF_SERVICE, "OffsetHead file error!");
74             return 0;
75         }
76     }
77     cursor_ += sizeof(TLVHead);
78     return cursor_;
79 }
80 
ResetCursor()81 void TLVObject::ResetCursor()
82 {
83     cursor_ = 0;
84     if (file_ != nullptr) {
85         if (fseek(file_, 0, SEEK_SET) != 0) {
86             LOG_ERROR(UDMF_SERVICE, "ResetCursor file error!");
87         }
88     }
89 }
90 
Count(const std::string & value)91 size_t TLVObject::Count(const std::string &value)
92 {
93     auto size = sizeof(TLVHead) + value.size();
94     total_ += size;
95     return size;
96 }
97 
Count(const std::vector<uint8_t> & value)98 size_t TLVObject::Count(const std::vector<uint8_t> &value)
99 {
100     auto size = sizeof(TLVHead) + value.size();
101     total_ += size;
102     return size;
103 }
104 
Count(const OHOS::AAFwk::Want & value)105 size_t TLVObject::Count(const OHOS::AAFwk::Want &value)
106 {
107     Parcel parcel;
108     if (!value.Marshalling(parcel)) {
109         LOG_ERROR(UDMF_FRAMEWORK, "Marshalling want error when Count");
110         return 0;
111     }
112     auto size = sizeof(TLVHead) + parcel.GetDataSize();
113     total_ += size;
114     return size;
115 }
116 
Count(const std::monostate & value)117 size_t TLVObject::Count(const std::monostate &value)
118 {
119     auto size = sizeof(TLVHead);
120     total_ += size;
121     return size;
122 }
123 
Count(const void * value)124 size_t TLVObject::Count(const void *value)
125 {
126     auto size = sizeof(TLVHead);
127     total_ += size;
128     return size;
129 }
130 
Write(TAG tag,const std::string & value)131 bool TLVObject::Write(TAG tag, const std::string &value)
132 {
133     if (!HasExpectBuffer(sizeof(TLVHead) + value.size())) {
134         LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv write. tag=%{public}hu, value=%{public}s", tag,
135             value.c_str());
136         return false;
137     }
138     auto tlvHead = reinterpret_cast<TLVHead *>(GetStartCursor());
139     tlvHead->tag = HostToNet(static_cast<uint16_t>(tag));
140     tlvHead->len = HostToNet((uint32_t)value.size());
141     if (!value.empty()) {
142         auto err = memcpy_s(tlvHead->value, value.size(), value.c_str(), value.size());
143         if (err != EOK) {
144             LOG_ERROR(UDMF_FRAMEWORK, "memcpy error in tlv write. tag=%{public}hu, value=%{public}s", tag,
145                 value.c_str());
146             return false;
147         }
148     }
149     cursor_ += sizeof(TLVHead) + value.size();
150     return SaveBufferToFile();
151 }
152 
Read(std::string & value,const TLVHead & head)153 bool TLVObject::Read(std::string &value, const TLVHead &head)
154 {
155     if (!HasExpectBuffer(head.len)) {
156         LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read string. tag=%{public}hu", head.tag);
157         return false;
158     }
159     if (!LoadBufferFormFile(head.len)) {
160         LOG_ERROR(UDMF_FRAMEWORK, "LoadBufferFormFile error in tlv read string. tag=%{public}hu", head.tag);
161         return false;
162     }
163     auto startCursor = GetStartCursor();
164     value.append(reinterpret_cast<const char *>(startCursor), head.len);
165     cursor_ += head.len;
166     return true;
167 }
168 
Write(TAG tag,const std::vector<uint8_t> & value)169 bool TLVObject::Write(TAG tag, const std::vector<uint8_t> &value)
170 {
171     if (!HasExpectBuffer(sizeof(TLVHead) + value.size())) {
172         LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv write u8 vector. tag=%{public}hu", tag);
173         return false;
174     }
175     auto tlvHead = reinterpret_cast<TLVHead *>(GetStartCursor());
176     tlvHead->tag = HostToNet(static_cast<uint16_t>(tag));
177     tlvHead->len = HostToNet(static_cast<uint32_t>(value.size()));
178     if (!value.empty()) {
179         auto err = memcpy_s(tlvHead->value, value.size(), value.data(), value.size());
180         if (err != EOK) {
181             LOG_ERROR(UDMF_FRAMEWORK, "memcpy error in tlv write u8 vector. tag=%{public}hu", tag);
182             return false;
183         }
184     }
185     cursor_ += sizeof(TLVHead) + value.size();
186     return SaveBufferToFile();
187 }
188 
189 
Read(std::vector<uint8_t> & value,const TLVHead & head)190 bool TLVObject::Read(std::vector<uint8_t> &value, const TLVHead &head)
191 {
192     if (!HasExpectBuffer(head.len)) {
193         LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read u8 vector. tag=%{public}hu", head.tag);
194         return false;
195     }
196     if (!LoadBufferFormFile(head.len)) {
197         LOG_ERROR(UDMF_FRAMEWORK, "LoadBufferFormFile error in tlv read u8 vector. tag=%{public}hu", head.tag);
198         return false;
199     }
200     auto startCursor = GetStartCursor();
201     std::vector<uint8_t> buff(startCursor, startCursor + head.len);
202     value = std::move(buff);
203     cursor_ += head.len;
204     return true;
205 }
206 
Write(TAG tag,const OHOS::AAFwk::Want & value)207 bool TLVObject::Write(TAG tag, const OHOS::AAFwk::Want &value)
208 {
209     Parcel parcel;
210     if (!value.Marshalling(parcel)) {
211         LOG_ERROR(UDMF_FRAMEWORK, "Marshalling want error in tlv write. tag=%{public}hu", tag);
212         return false;
213     }
214     auto size = parcel.GetDataSize();
215     auto buffer = parcel.GetData();
216 
217     if (!HasExpectBuffer(sizeof(TLVHead) + size)) {
218         LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv write want. tag=%{public}hu", tag);
219         return false;
220     }
221     auto tlvHead = reinterpret_cast<TLVHead *>(GetStartCursor());
222     tlvHead->tag = HostToNet(static_cast<uint16_t>(tag));
223     tlvHead->len = HostToNet(static_cast<uint32_t>(size));
224     if (size != 0) {
225         auto err = memcpy_s(tlvHead->value, size, reinterpret_cast<const void *>(buffer), size);
226         if (err != EOK) {
227             LOG_ERROR(UDMF_FRAMEWORK, "memcpy error in tlv write want. tag=%{public}hu", tag);
228             return false;
229         }
230     }
231     cursor_ += sizeof(TLVHead) + size;
232     return SaveBufferToFile();
233 }
234 
Read(OHOS::AAFwk::Want & value,const TLVHead & head)235 bool TLVObject::Read(OHOS::AAFwk::Want &value, const TLVHead &head)
236 {
237     if (!HasExpectBuffer(head.len)) {
238         LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read want. tag=%{public}hu", head.tag);
239         return false;
240     }
241     if (!LoadBufferFormFile(head.len)) {
242         LOG_ERROR(UDMF_FRAMEWORK, "LoadBufferFormFile error in tlv read want. tag=%{public}hu", head.tag);
243         return false;
244     }
245     auto startCursor = GetStartCursor();
246     std::vector<uint8_t> buff(startCursor, startCursor + head.len);
247 
248     auto buffer = (uintptr_t)(buff.data() + cursor_);
249     cursor_ += head.len;
250 
251     Parcel parcel;
252     if (!parcel.ParseFrom(buffer, head.len)) {
253         LOG_ERROR(UDMF_FRAMEWORK, "ParseFrom error in tlv read want. tag=%{public}hu", head.tag);
254         return false;
255     }
256     auto want = AAFwk::Want::Unmarshalling(parcel);
257     if (want == nullptr) {
258         LOG_ERROR(UDMF_FRAMEWORK, "Unmarshalling want error in tlv read. tag=%{public}hu", head.tag);
259         return false;
260     }
261     value = *want;
262     return true;
263 }
264 
Write(TAG tag,const std::monostate & value)265 bool TLVObject::Write(TAG tag, const std::monostate &value)
266 {
267     return WriteHead(static_cast<uint16_t>(tag), (uint32_t)0);
268 }
269 
Read(std::monostate & value,const TLVHead & head)270 bool TLVObject::Read(std::monostate &value, const TLVHead &head)
271 {
272     return true;
273 }
274 
Write(TAG tag,const void * value)275 bool TLVObject::Write(TAG tag, const void *value)
276 {
277     return WriteHead(static_cast<uint16_t>(tag), (uint32_t)0);
278 }
279 
280 
Read(void * value,const TLVHead & head)281 bool TLVObject::Read(void *value, const TLVHead &head)
282 {
283     value = nullptr;
284     return true;
285 }
286 
CountHead()287 size_t TLVObject::CountHead()
288 {
289     total_ += sizeof(TLVHead);
290     return sizeof(TLVHead);
291 }
292 
WriteHead(uint16_t tag,uint32_t len)293 bool TLVObject::WriteHead(uint16_t tag, uint32_t len)
294 {
295     if (!HasExpectBuffer(sizeof(TLVHead))) {
296         LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv write head. tag=%{public}hu", tag);
297         return false;
298     }
299     PrepareBufferForFile(sizeof(TLVHead));
300     auto tlvHead = reinterpret_cast<TLVHead *>(GetStartCursor());
301     tlvHead->tag = HostToNet(tag);
302     tlvHead->len = HostToNet(len);
303     cursor_ += sizeof(TLVHead);
304     return SaveBufferToFile();
305 }
306 
WriteBackHead(uint16_t tag,size_t tagCursor,uint32_t len)307 bool TLVObject::WriteBackHead(uint16_t tag, size_t tagCursor, uint32_t len)
308 {
309     auto startCursor = buffer_->data();
310     if (file_ == nullptr) {
311         startCursor += tagCursor;
312     }
313     auto tlvHead = reinterpret_cast<TLVHead *>(startCursor);
314     tlvHead->tag = HostToNet(tag);
315     tlvHead->len = HostToNet(len);
316     return SaveBufferToFileFront(tagCursor, sizeof(TLVHead));
317 }
318 
ReadHead(TLVHead & head)319 bool TLVObject::ReadHead(TLVHead &head)
320 {
321     if (!HasExpectBuffer(sizeof(TLVHead))) {
322         LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read head. tag=%{public}hu", head.tag);
323         return false;
324     }
325     if (!LoadBufferFormFile(sizeof(TLVHead))) {
326         LOG_ERROR(UDMF_FRAMEWORK, "LoadBufferFormFile error in tlv read head. tag=%{public}hu", head.tag);
327         return false;
328     }
329     auto startCursor = GetStartCursor();
330     const auto *pHead = reinterpret_cast<const TLVHead *>(startCursor);
331     auto len = NetToHost(pHead->len);
332     if (file_ == nullptr) {
333         if (!HasExpectBuffer(len + sizeof(TLVHead))) {
334             LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read head and len. tag=%{public}hu", head.tag);
335             return false;
336         }
337     }
338 
339     head.tag = NetToHost(pHead->tag);
340     head.len = len;
341     cursor_ += sizeof(TLVHead);
342     return true;
343 }
344 
Skip(TLVHead & head)345 bool TLVObject::Skip(TLVHead &head)
346 {
347     if (file_ != nullptr) {
348         cursor_ += head.len;
349         return fseek(file_, head.len * sizeof(uint8_t), SEEK_CUR) == 0;
350     }
351     if (total_ < head.len || total_ - head.len < cursor_) {
352         LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv skip. tag=%{public}hu", head.tag);
353         return false;
354     }
355     cursor_ += head.len;
356     return true;
357 }
358 
HasExpectBuffer(const uint32_t expectLen) const359 bool TLVObject::HasExpectBuffer(const uint32_t expectLen) const
360 {
361     if (buffer_ == nullptr) {
362         return false;
363     }
364     if (file_ != nullptr) {
365         buffer_->resize(expectLen);
366         return true;
367     }
368     return buffer_->size() >= cursor_ && buffer_->size() - cursor_ >= expectLen;
369 }
370 
PrepareBufferForFile(size_t size)371 void TLVObject::PrepareBufferForFile(size_t size)
372 {
373     if (file_ == nullptr) {
374         return;
375     }
376     buffer_->resize(size);
377 }
378 
GetStartCursor()379 std::uint8_t *TLVObject::GetStartCursor()
380 {
381     auto startCursor = buffer_->data();
382     if (file_ == nullptr) {
383         startCursor += cursor_;
384     }
385     return startCursor;
386 }
387 
SaveBufferToFile()388 bool TLVObject::SaveBufferToFile()
389 {
390     if (file_ == nullptr) {
391         return true;
392     }
393     auto count = fwrite(buffer_->data(), sizeof(uint8_t), buffer_->size(), file_);
394     if (count != buffer_->size()) {
395         LOG_ERROR(UDMF_FRAMEWORK, "fwrite error!");
396         return false;
397     }
398     return true;
399 }
400 
SaveBufferToFileFront(size_t tagCursor,uint32_t len)401 bool TLVObject::SaveBufferToFileFront(size_t tagCursor, uint32_t len)
402 {
403     if (file_ == nullptr) {
404         return true;
405     }
406     int32_t leftOffset =
407         -((static_cast<int32_t>(cursor_) - static_cast<int32_t>(tagCursor))) * static_cast<int32_t>(sizeof(uint8_t));
408     if (fseek(file_, leftOffset * sizeof(uint8_t), SEEK_CUR) != 0) {
409         LOG_ERROR(UDMF_FRAMEWORK, "file fseek left error!");
410         return false;
411     }
412     auto count = fwrite(buffer_->data(), sizeof(uint8_t), sizeof(TLVHead), file_);
413     if (count != sizeof(TLVHead)) {
414         LOG_ERROR(UDMF_FRAMEWORK, "file write error!");
415         return false;
416     }
417     int32_t rightOffset =
418         static_cast<int32_t>(cursor_) - static_cast<int32_t>(tagCursor) - static_cast<int32_t>(sizeof(TLVHead));
419     if (fseek(file_, rightOffset * sizeof(uint8_t), SEEK_CUR) != 0) {
420         LOG_ERROR(UDMF_FRAMEWORK, "file fseek right error!");
421         return false;
422     }
423     return true;
424 }
425 
LoadBufferFormFile(size_t size)426 bool TLVObject::LoadBufferFormFile(size_t size)
427 {
428     if (file_ == nullptr) {
429         return true;
430     }
431     auto count = fread(buffer_->data(), sizeof(uint8_t), buffer_->size(), file_);
432     if (count != buffer_->size()) {
433         return false;
434     }
435     return true;
436 }
437 } // namespace UDMF
438 } // namespace OHOS
439