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 "hcf_parcel.h"
17#include "securec.h"
18#include "memory.h"
19
20const int PARCEL_DEFAULT_INCREASE_STEP = 16;
21const uint32_t PARCEL_UINT_MAX = 0xffffffffU;
22const int HALF_LEN = 2;
23
24HcParcel CreateParcel(uint32_t size, uint32_t allocUnit)
25{
26    HcParcel parcel;
27    (void)memset_s(&parcel, sizeof(parcel), 0, sizeof(parcel));
28    parcel.allocUnit = allocUnit;
29    if (parcel.allocUnit == 0) {
30        parcel.allocUnit = PARCEL_DEFAULT_INCREASE_STEP;
31    }
32    if (size > 0) {
33        parcel.data = (char *)HcfMalloc(size, 0);
34        if (parcel.data != NULL) {
35            parcel.length = size;
36        }
37    }
38    return parcel;
39}
40
41void DeleteParcel(HcParcel *parcel)
42{
43    if (parcel == NULL) {
44        return;
45    }
46
47    if (parcel->data != NULL) {
48        HcfFree(parcel->data);
49        parcel->data = NULL;
50    }
51    parcel->length = 0;
52    parcel->beginPos = 0;
53    parcel->endPos = 0;
54}
55
56uint32_t GetParcelDataSize(const HcParcel *parcel)
57{
58    if (parcel == NULL) {
59        return 0;
60    }
61    if (parcel->endPos >= parcel->beginPos) {
62        return parcel->endPos - parcel->beginPos;
63    }
64    return 0;
65}
66
67const char *GetParcelData(const HcParcel *parcel)
68{
69    if (parcel == NULL || parcel->data == NULL) {
70        return NULL;
71    }
72    return parcel->data + parcel->beginPos;
73}
74
75static bool ParcelRealloc(HcParcel *parcel, uint32_t size)
76{
77    if (parcel->length >= size) {
78        return false;
79    }
80    char *newData = (char *)HcfMalloc(size, 0);
81    if (newData == NULL) {
82        return false;
83    }
84    if (memcpy_s(newData, size, parcel->data, parcel->length) != EOK) {
85        HcfFree(newData);
86        return false;
87    }
88    HcfFree(parcel->data);
89    parcel->data = newData;
90    parcel->length = size;
91    return true;
92}
93
94static bool ParcelIncrease(HcParcel *parcel, uint32_t size)
95{
96    if (parcel == NULL || size == 0) {
97        return false;
98    }
99    if (parcel->data == NULL) {
100        if (parcel->length != 0) {
101            return false;
102        }
103        *parcel = CreateParcel(size, parcel->allocUnit);
104        if (parcel->data == NULL) {
105            return false;
106        } else {
107            return true;
108        }
109    } else {
110        return ParcelRealloc(parcel, size);
111    }
112}
113
114static void ParcelRecycle(HcParcel *parcel)
115{
116    if (parcel == NULL) {
117        return;
118    }
119    if (parcel->data == NULL || parcel->beginPos < parcel->allocUnit) {
120        return;
121    }
122
123    uint32_t contentSize = parcel->endPos - parcel->beginPos;
124    if (contentSize > 0) {
125        (void)memmove_s(parcel->data, parcel->endPos - parcel->beginPos,
126            parcel->data + parcel->beginPos, parcel->endPos - parcel->beginPos);
127    }
128    parcel->beginPos = 0;
129    parcel->endPos = contentSize;
130}
131
132static uint32_t GetParcelIncreaseSize(HcParcel *parcel, uint32_t newSize)
133{
134    if (parcel == NULL || parcel->allocUnit == 0) {
135        return 0;
136    }
137    if (newSize % parcel->allocUnit) {
138        return (newSize / parcel->allocUnit + 1) * parcel->allocUnit;
139    } else {
140        return (newSize / parcel->allocUnit) * parcel->allocUnit;
141    }
142}
143
144bool ParcelWrite(HcParcel *parcel, const void *src, uint32_t dataSize)
145{
146    errno_t rc;
147    if (parcel == NULL || src == NULL || dataSize == 0) {
148        return false;
149    }
150    if (parcel->endPos > PARCEL_UINT_MAX - dataSize) {
151        return false;
152    }
153    if (parcel->endPos + dataSize > parcel->length) {
154        ParcelRecycle(parcel);
155        if (parcel->endPos + dataSize > parcel->length) {
156            uint32_t newSize = GetParcelIncreaseSize(parcel, parcel->endPos + dataSize);
157            if (!ParcelIncrease(parcel, newSize)) {
158                return false;
159            }
160        }
161    }
162    rc = memmove_s(parcel->data + parcel->endPos, dataSize, src, dataSize);
163    if (rc != EOK) {
164        return false;
165    }
166    parcel->endPos += dataSize;
167    return true;
168}
169
170bool ParcelWriteInt8(HcParcel *parcel, char src)
171{
172    return ParcelWrite(parcel, &src, sizeof(src));
173}
174
175bool ParcelPopBack(HcParcel *parcel, uint32_t size)
176{
177    if (parcel != NULL && size > 0 && GetParcelDataSize(parcel) >= size) {
178        parcel->endPos -= size;
179        return true;
180    }
181    return false;
182}
183