1/*
2 * Copyright (C) 2021 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#include "hc_parcel.h"
17#include "securec.h"
18#include "hc_types.h"
19
20const int PARCEL_DEFAULT_INCREASE_STEP = 16;
21const uint32_t PARCEL_UINT_MAX = 0xffffffffU;
22
23HcParcel CreateParcel(uint32_t size, uint32_t allocUnit)
24{
25    HcParcel parcel;
26    (void)memset_s(&parcel, sizeof(parcel), 0, sizeof(parcel));
27    parcel.allocUnit = allocUnit;
28    if (parcel.allocUnit == 0) {
29        parcel.allocUnit = PARCEL_DEFAULT_INCREASE_STEP;
30    }
31    if (size > 0) {
32        parcel.data = (char *)HcMalloc(size, 0);
33        if (parcel.data != NULL) {
34            parcel.length = size;
35        }
36    }
37    return parcel;
38}
39
40void DeleteParcel(HcParcel *parcel)
41{
42    if (parcel == NULL) {
43        return;
44    }
45
46    if (parcel->data != NULL) {
47        HcFree(parcel->data);
48        parcel->data = 0;
49    }
50    parcel->length = 0;
51    parcel->beginPos = 0;
52    parcel->endPos = 0;
53}
54
55void ClearParcel(HcParcel *parcel)
56{
57    if (parcel != NULL) {
58        parcel->beginPos = 0;
59        parcel->endPos = 0;
60    }
61}
62
63void ResetParcel(HcParcel *parcel, uint32_t size, uint32_t allocUnit)
64{
65    if (parcel != NULL) {
66        DeleteParcel(parcel);
67        HcParcel newParcel = CreateParcel(size, allocUnit);
68        (void)memcpy_s(parcel, sizeof(HcParcel), &newParcel, sizeof(HcParcel));
69    }
70}
71
72uint32_t GetParcelDataSize(const HcParcel *parcel)
73{
74    if (parcel == NULL) {
75        return 0;
76    }
77    if (parcel->endPos >= parcel->beginPos) {
78        return parcel->endPos - parcel->beginPos;
79    }
80    return 0;
81}
82
83const char *GetParcelData(const HcParcel *parcel)
84{
85    if (parcel == NULL) {
86        return NULL;
87    }
88    return parcel->data + parcel->beginPos;
89}
90
91const char *GetParcelLastChar(const HcParcel *parcel)
92{
93    if (parcel == NULL || GetParcelDataSize(parcel) == 0) {
94        return NULL;
95    }
96    return parcel->data + parcel->endPos - 1;
97}
98
99HcBool ParcelReadWithoutPopData(HcParcel *parcel, void *dst, uint32_t dataSize)
100{
101#ifdef IS_BIG_ENDIAN
102    HcBool ret = ParcelReadRevert(parcel, dst, dataSize);
103#else
104    HcBool ret = ParcelRead(parcel, dst, dataSize);
105#endif
106    if (ret == HC_TRUE) {
107        parcel->beginPos -= dataSize;
108    }
109    return ret;
110}
111
112HcBool ParcelRead(HcParcel *parcel, void *dst, uint32_t dataSize)
113{
114    errno_t rc;
115    if (parcel == NULL || dst == NULL || dataSize == 0) {
116        return HC_FALSE;
117    }
118    if (parcel->beginPos > PARCEL_UINT_MAX - dataSize) {
119        return HC_FALSE;
120    }
121    if (parcel->beginPos + dataSize > parcel->endPos) {
122        return HC_FALSE;
123    }
124    rc = memmove_s(dst, dataSize, parcel->data + parcel->beginPos, dataSize);
125    if (rc != EOK) {
126        return HC_FALSE;
127    }
128    parcel->beginPos += dataSize;
129    return HC_TRUE;
130}
131
132HcBool ParcelEraseBlock(HcParcel *parcel, uint32_t start, uint32_t dataSize, void *dst)
133{
134    errno_t rc;
135    if (parcel == NULL || dst == NULL || dataSize == 0) {
136        return HC_FALSE;
137    }
138    if (start > PARCEL_UINT_MAX - dataSize) {
139        return HC_FALSE;
140    }
141    uint32_t parcelSizeOrg = GetParcelDataSize(parcel);
142    if (parcelSizeOrg < start + dataSize) {
143        return HC_FALSE;
144    }
145    char *beginCopy = parcel->data + parcel->beginPos + start;
146    uint32_t copySize = parcelSizeOrg - start - dataSize;
147
148    rc = memmove_s(dst, dataSize, beginCopy, dataSize);
149    if (rc != EOK) {
150        return HC_FALSE;
151    }
152    if (copySize != 0) {
153        rc = memmove_s(beginCopy, copySize, beginCopy + dataSize, copySize);
154        if (rc != EOK) {
155            return HC_FALSE;
156        }
157    }
158    parcel->endPos -= dataSize;
159    return HC_TRUE;
160}
161
162HcBool ParcelReadRevert(HcParcel *parcel, void *dst, uint32_t dataSize)
163{
164    if (ParcelRead(parcel, dst, dataSize)) {
165        DataRevert(dst, dataSize);
166        return HC_TRUE;
167    } else {
168        return HC_FALSE;
169    }
170}
171
172HcBool ParcelWriteRevert(HcParcel *parcel, const void *src, uint32_t dataSize)
173{
174    errno_t rc;
175    void *srcCopy = HcMalloc(dataSize, 0);
176    if (srcCopy == NULL) {
177        return HC_FALSE;
178    }
179    rc = memmove_s(srcCopy, dataSize, src, dataSize);
180    if (rc != EOK) {
181        HcFree(srcCopy);
182        return HC_FALSE;
183    }
184    DataRevert(srcCopy, dataSize);
185    HcBool ret = ParcelWrite(parcel, srcCopy, dataSize);
186    HcFree(srcCopy);
187    return ret;
188}
189
190HcBool ParcelReadInt32(HcParcel *parcel, int *dst)
191{
192    return ParcelRead(parcel, dst, sizeof(int));
193}
194
195HcBool ParcelReadUint32(HcParcel *parcel, uint32_t *dst)
196{
197    return ParcelRead(parcel, dst, sizeof(uint32_t));
198}
199
200HcBool ParcelReadInt16(HcParcel *parcel, short *dst)
201{
202    return ParcelRead(parcel, dst, sizeof(short));
203}
204
205HcBool ParcelReadUint16(HcParcel *parcel, uint16_t *dst)
206{
207    return ParcelRead(parcel, dst, sizeof(uint16_t));
208}
209
210HcBool ParcelReadInt8(HcParcel *parcel, char *dst)
211{
212    return ParcelRead(parcel, dst, sizeof(char));
213}
214
215HcBool ParcelReadUint8(HcParcel *parcel, uint8_t *dst)
216{
217    return ParcelRead(parcel, dst, sizeof(uint8_t));
218}
219
220HcBool ParcelReadUint64(HcParcel *parcel, uint64_t *dst)
221{
222    return ParcelRead(parcel, dst, sizeof(uint64_t));
223}
224
225HcBool ParcelReadInt64(HcParcel *parcel, int64_t *dst)
226{
227    return ParcelRead(parcel, dst, sizeof(int64_t));
228}
229
230static HcBool ParcelRealloc(HcParcel *parcel, uint32_t size)
231{
232    if (parcel->length >= size) {
233        return HC_FALSE;
234    }
235    char *newData = (char *)HcMalloc(size, 0);
236    if (newData == NULL) {
237        return HC_FALSE;
238    }
239    if (memcpy_s(newData, size, parcel->data, parcel->length) != EOK) {
240        HcFree(newData);
241        return HC_FALSE;
242    }
243    HcFree(parcel->data);
244    parcel->data = newData;
245    parcel->length = size;
246    return HC_TRUE;
247}
248
249static HcBool ParcelIncrease(HcParcel *parcel, uint32_t size)
250{
251    if (parcel == NULL || size == 0) {
252        return HC_FALSE;
253    }
254    if (parcel->data == NULL) {
255        if (parcel->length != 0) {
256            return HC_FALSE;
257        }
258        *parcel = CreateParcel(size, parcel->allocUnit);
259        if (parcel->data == NULL) {
260            return HC_FALSE;
261        } else {
262            return HC_TRUE;
263        }
264    } else {
265        return ParcelRealloc(parcel, size);
266    }
267}
268
269static void ParcelRecycle(HcParcel *parcel)
270{
271    if (parcel == NULL) {
272        return;
273    }
274    if (parcel->data == NULL || parcel->beginPos < parcel->allocUnit) {
275        return;
276    }
277
278    uint32_t contentSize = parcel->endPos - parcel->beginPos;
279    if (contentSize > 0) {
280        if (memmove_s(parcel->data, parcel->endPos - parcel->beginPos,
281            parcel->data + parcel->beginPos, parcel->endPos - parcel->beginPos) != EOK) {
282        }
283    }
284    parcel->beginPos = 0;
285    parcel->endPos = contentSize;
286}
287
288static uint32_t GetParcelIncreaseSize(HcParcel *parcel, uint32_t newSize)
289{
290    if (parcel == NULL || parcel->allocUnit == 0) {
291        return 0;
292    }
293    if (newSize % parcel->allocUnit) {
294        return (newSize / parcel->allocUnit + 1) * parcel->allocUnit;
295    } else {
296        return (newSize / parcel->allocUnit) * parcel->allocUnit;
297    }
298}
299
300HcBool ParcelWrite(HcParcel *parcel, const void *src, uint32_t dataSize)
301{
302    errno_t rc;
303    if (parcel == NULL || src == NULL || dataSize == 0) {
304        return HC_FALSE;
305    }
306    if (parcel->endPos > PARCEL_UINT_MAX - dataSize) {
307        return HC_FALSE;
308    }
309    if (parcel->endPos + dataSize > parcel->length) {
310        ParcelRecycle(parcel);
311        if (parcel->endPos + dataSize > parcel->length) {
312            uint32_t newSize = GetParcelIncreaseSize(parcel, parcel->endPos + dataSize);
313            if (!ParcelIncrease(parcel, newSize)) {
314                return HC_FALSE;
315            }
316        }
317    }
318    rc = memmove_s(parcel->data + parcel->endPos, dataSize, src, dataSize);
319    if (rc != EOK) {
320        return HC_FALSE;
321    }
322    parcel->endPos += dataSize;
323    return HC_TRUE;
324}
325
326HcBool ParcelWriteInt32(HcParcel *parcel, int src)
327{
328    return ParcelWrite(parcel, &src, sizeof(src));
329}
330
331HcBool ParcelWriteUint32(HcParcel *parcel, uint32_t src)
332{
333    return ParcelWrite(parcel, &src, sizeof(src));
334}
335
336HcBool ParcelWriteInt16(HcParcel *parcel, short src)
337{
338    return ParcelWrite(parcel, &src, sizeof(src));
339}
340
341HcBool ParcelWriteUint16(HcParcel *parcel, uint16_t src)
342{
343    return ParcelWrite(parcel, &src, sizeof(src));
344}
345
346HcBool ParcelWriteInt8(HcParcel *parcel, char src)
347{
348    return ParcelWrite(parcel, &src, sizeof(src));
349}
350
351HcBool ParcelWriteUint8(HcParcel *parcel, uint8_t src)
352{
353    return ParcelWrite(parcel, &src, sizeof(src));
354}
355
356HcBool ParcelWriteUint64(HcParcel *parcel, uint64_t src)
357{
358    return ParcelWrite(parcel, &src, sizeof(src));
359}
360
361HcBool ParcelWriteInt64(HcParcel *parcel, int64_t src)
362{
363    return ParcelWrite(parcel, &src, sizeof(src));
364}
365
366HcBool ParcelReadParcel(HcParcel *src, HcParcel *dst, uint32_t size, HcBool copy)
367{
368    if (src == NULL || dst == NULL) {
369        return HC_FALSE;
370    }
371    if (GetParcelDataSize(src) < size) {
372        return HC_FALSE;
373    }
374    if (!ParcelWrite(dst, (void *)GetParcelData(src), size)) {
375        return HC_FALSE;
376    }
377
378    if (!copy) {
379        src->beginPos += size;
380    }
381    return HC_TRUE;
382}
383
384HcBool ParcelCopy(HcParcel *src, HcParcel *dst)
385{
386    if (src == NULL || dst == NULL) {
387        return HC_FALSE;
388    }
389    if (GetParcelDataSize(src) == 0) {
390        return HC_TRUE;
391    }
392    return ParcelReadParcel(src, dst, GetParcelDataSize(src), HC_TRUE);
393}
394
395void DataRevert(void *data, uint32_t length)
396{
397    if (data != NULL) {
398        uint8_t *pc = (uint8_t *) data;
399        uint32_t i = 0;
400        for (; i < length / 2; ++i) { /* half of the length */
401            /* swap p[i] and p[length-i-1] */
402            pc[i] ^= pc[length - i - 1];
403            pc[length - i - 1] ^= pc[i];
404            pc[i] ^= pc[length - i - 1];
405        }
406    }
407}
408
409HcBool ParcelReadInt32Revert(HcParcel *parcel, int32_t *dst)
410{
411    HcBool ret = ParcelRead(parcel, dst, sizeof(int));
412    if (ret) {
413        DataRevert(dst, sizeof(int));
414    }
415    return ret;
416}
417
418HcBool ParcelReadUint32Revert(HcParcel *parcel, uint32_t *dst)
419{
420    HcBool ret = ParcelRead(parcel, dst, sizeof(uint32_t));
421    if (ret) {
422        DataRevert(dst, sizeof(uint32_t));
423    }
424    return ret;
425}
426
427HcBool ParcelReadInt16Revert(HcParcel *parcel, short *dst)
428{
429    HcBool ret = ParcelRead(parcel, dst, sizeof(short));
430    if (ret) {
431        DataRevert(dst, sizeof(short));
432    }
433    return ret;
434}
435
436HcBool ParcelReadUint16Revert(HcParcel *parcel, uint16_t *dst)
437{
438    if (parcel == NULL || dst == NULL) {
439        return HC_FALSE;
440    }
441    HcBool ret = ParcelRead(parcel, dst, sizeof(uint16_t));
442    if (ret) {
443        DataRevert(dst, sizeof(uint16_t));
444    }
445    return ret;
446}
447
448HcBool ParcelReadInt8Revert(HcParcel *parcel, char *dst)
449{
450    return ParcelRead(parcel, dst, sizeof(char));
451}
452
453HcBool ParcelReadUint8Revert(HcParcel *parcel, uint8_t *dst)
454{
455    return ParcelRead(parcel, dst, sizeof(uint8_t));
456}
457
458HcBool ParcelReadUint64Revert(HcParcel *parcel, uint64_t *dst)
459{
460    HcBool ret = ParcelRead(parcel, dst, sizeof(uint64_t));
461    if (ret) {
462        DataRevert(dst, sizeof(uint64_t));
463    }
464    return ret;
465}
466
467HcBool ParcelReadInt64Revert(HcParcel *parcel, int64_t *dst)
468{
469    HcBool ret = ParcelRead(parcel, dst, sizeof(int64_t));
470    if (ret) {
471        DataRevert(dst, sizeof(int64_t));
472    }
473    return ret;
474}
475
476HcBool ParcelWriteInt32Revert(HcParcel *parcel, int src)
477{
478    DataRevert(&src, sizeof(src));
479    return ParcelWriteInt32(parcel, src);
480}
481
482HcBool ParcelWriteUint32Revert(HcParcel *parcel, uint32_t src)
483{
484    DataRevert(&src, sizeof(src));
485    return ParcelWriteUint32(parcel, src);
486}
487
488HcBool ParcelWriteInt16Revert(HcParcel *parcel, short src)
489{
490    DataRevert(&src, sizeof(src));
491    return ParcelWriteInt16(parcel, src);
492}
493
494HcBool ParcelWriteUint16Revert(HcParcel *parcel, uint16_t src)
495{
496    DataRevert(&src, sizeof(src));
497    return ParcelWriteUint16(parcel, src);
498}
499
500HcBool ParcelWriteInt8Revert(HcParcel *parcel, char src)
501{
502    return ParcelWriteInt8(parcel, src);
503}
504
505HcBool ParcelWriteUint8Revert(HcParcel *parcel, uint8_t src)
506{
507    return ParcelWriteUint8(parcel, src);
508}
509
510HcBool ParcelWriteUint64Revert(HcParcel *parcel, uint64_t src)
511{
512    DataRevert(&src, sizeof(src));
513    return ParcelWriteUint64(parcel, src);
514}
515
516HcBool ParcelWriteInt64Revert(HcParcel *parcel, int64_t src)
517{
518    DataRevert(&src, sizeof(src));
519    return ParcelWriteInt64(parcel, src);
520}
521
522HcBool ParcelPopBack(HcParcel *parcel, uint32_t size)
523{
524    if (parcel != NULL && size > 0 && GetParcelDataSize(parcel) >= size) {
525        parcel->endPos -= size;
526        return HC_TRUE;
527    }
528    return HC_FALSE;
529}
530
531HcBool ParcelPopFront(HcParcel *parcel, uint32_t size)
532{
533    if ((parcel != NULL) && (size > 0) && (GetParcelDataSize(parcel) >= size)) {
534        parcel->beginPos += size;
535        return HC_TRUE;
536    }
537    return HC_FALSE;
538}
539