1/*
2 * Copyright (c) 2020-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 "imgdecode/cache_manager.h"
17#include "gfx_utils/graphic_log.h"
18#include "hal_tick.h"
19#include "securec.h"
20
21namespace OHOS {
22const uint8_t* CacheEntry::GetImgData() const
23{
24    return dsc_.imgInfo.data;
25}
26
27RetCode CacheEntry::ReadLine(const Point& start, int16_t len, uint8_t* buf)
28{
29    RetCode ret;
30    if (dsc_.decoder != nullptr) {
31        ret = dsc_.decoder->ReadLine(dsc_, start, len, buf);
32    } else {
33        ret = RetCode::FAIL;
34    }
35
36    return ret;
37}
38
39void CacheEntry::Clear()
40{
41    if (dsc_.decoder != nullptr) {
42        dsc_.decoder->Close(dsc_);
43    }
44
45    dsc_.decoder = nullptr;
46    ClearSrc();
47    dsc_.imgInfo.data = nullptr;
48    dsc_.fd = -1;
49    dsc_.srcType = IMG_SRC_UNKNOWN;
50    life_ = 0;
51}
52
53void CacheEntry::ClearSrc()
54{
55    if (dsc_.srcType == IMG_SRC_FILE) {
56        UIFree(const_cast<char*>(dsc_.path));
57    }
58    dsc_.path = nullptr;
59}
60
61RetCode CacheEntry::SetSrc(const char* path)
62{
63    ClearSrc();
64    if (dsc_.srcType == IMG_SRC_FILE) {
65        size_t strLen = strlen(path);
66        if (strLen > MAX_SRC_LENGTH) {
67            return RetCode::FAIL;
68        }
69        char* newStr = static_cast<char*>(UIMalloc(static_cast<uint32_t>(strLen) + 1));
70        if (newStr == nullptr) {
71            return RetCode::FAIL;
72        }
73        if (memcpy_s(newStr, strLen + 1, path, strLen) != EOK) {
74            UIFree(reinterpret_cast<void*>(newStr));
75            newStr = nullptr;
76            return RetCode::FAIL;
77        }
78        newStr[strLen] = '\0';
79        dsc_.path = newStr;
80    } else {
81        dsc_.path = path;
82    }
83    return RetCode::OK;
84}
85
86CacheManager& CacheManager::GetInstance()
87{
88    static CacheManager instance;
89    return instance;
90}
91
92RetCode CacheManager::Init(uint16_t size)
93{
94    if ((size == 0) || (size > DEFAULT_MAX_CACHE_ENTRY_NUM)) {
95        return RetCode::FAIL;
96    }
97    Reset();
98    if (entryArr_ != nullptr) {
99        UIFree(reinterpret_cast<void*>(entryArr_));
100    }
101
102    uint32_t tmpCacheSize = size * sizeof(CacheEntry);
103    entryArr_ = static_cast<CacheEntry*>(UIMalloc(tmpCacheSize));
104    if (entryArr_ == nullptr) {
105        size_ = 0;
106        return RetCode::FAIL;
107    }
108
109    if (memset_s(entryArr_, tmpCacheSize, 0, tmpCacheSize) != EOK) {
110        UIFree(reinterpret_cast<void*>(entryArr_));
111        entryArr_ = nullptr;
112        return RetCode::FAIL;
113    }
114
115    size_ = size;
116    return RetCode::OK;
117}
118
119RetCode CacheManager::Open(const char* path, const Style& style, CacheEntry& entry)
120{
121    if ((path == nullptr) || (GetSize() <= 0)) {
122        return RetCode::FAIL;
123    }
124
125    AgingAll();
126    uint16_t indexHitted = 0;
127    RetCode ret = GetIndex(path, indexHitted);
128    if (ret == RetCode::OK) {
129        ReadToCache(entryArr_[indexHitted]);
130        entry = entryArr_[indexHitted];
131        return RetCode::OK;
132    }
133
134    SelectEntryToReplace(indexHitted);
135    if ((entryArr_[indexHitted].dsc_.path != nullptr) && (entryArr_[indexHitted].dsc_.decoder != nullptr)) {
136        entryArr_[indexHitted].dsc_.decoder->Close(entryArr_[indexHitted].dsc_);
137    }
138
139    uint32_t startTime = HALTick::GetInstance().GetTime();
140    entryArr_[indexHitted].life_ = 0;
141
142    ret = TryDecode(path, style, entryArr_[indexHitted]);
143    if (ret != RetCode::OK) {
144        return ret;
145    }
146    ReadToCache(entryArr_[indexHitted]);
147    entryArr_[indexHitted].life_ = HALTick::GetInstance().GetElapseTime(startTime);
148    entry = entryArr_[indexHitted];
149    return RetCode::OK;
150}
151
152RetCode CacheManager::Close(const char* path)
153{
154    if (path == nullptr) {
155        return RetCode::FAIL;
156    }
157
158    for (uint16_t index = 0; index < GetSize(); index++) {
159        if (entryArr_[index].dsc_.srcType == IMG_SRC_FILE) {
160            if (entryArr_[index].dsc_.path == nullptr) {
161                continue;
162            }
163            if (strcmp(entryArr_[index].dsc_.path, path) == 0) {
164                Clear(entryArr_[index]);
165                break;
166            }
167        } else {
168            if (entryArr_[index].dsc_.path == path) {
169                Clear(entryArr_[index]);
170                break;
171            }
172        }
173    }
174
175    return RetCode::OK;
176}
177
178bool CacheManager::GetImageHeader(const char* path, ImageHeader& header)
179{
180    CacheEntry entry;
181    Style useless;
182    RetCode ret = Open(path, useless, entry);
183    if (ret != RetCode::OK) {
184        GRAPHIC_LOGW("CacheManager::GetImageHeader Image get info found unknown src type\n");
185        return false;
186    }
187
188    header = entry.GetImgHeader();
189    return true;
190}
191
192RetCode CacheManager::Reset()
193{
194    if (entryArr_ == nullptr) {
195        return RetCode::OK;
196    }
197
198    for (uint16_t index = 0; index < GetSize(); index++) {
199        if (entryArr_[index].dsc_.path != nullptr) {
200            Clear(entryArr_[index]);
201        }
202    }
203
204    return RetCode::OK;
205}
206
207RetCode CacheManager::ReadToCache(CacheEntry& entry)
208{
209    if (entry.dsc_.decoder == nullptr) {
210        return RetCode::FAIL;
211    }
212    return entry.dsc_.decoder->ReadToCache(entry.dsc_);
213}
214
215void CacheManager::Clear(CacheEntry& entry)
216{
217    entry.Clear();
218}
219
220void CacheManager::AgingAll(int32_t time)
221{
222    for (uint16_t index = 0; index < GetSize(); index++) {
223        if (entryArr_[index].life_ > INT32_MIN + AGING_INTERVAL) {
224            entryArr_[index].life_ -= time;
225        }
226    }
227}
228
229RetCode CacheManager::GetIndex(const char* path, uint16_t& hittedIndex)
230{
231    for (uint16_t index = 0; index < GetSize(); index++) {
232        if (entryArr_[index].dsc_.srcType == IMG_SRC_FILE) {
233            if ((entryArr_[index].dsc_.path != nullptr) && !strcmp(path, entryArr_[index].dsc_.path)) {
234                entryArr_[index].life_ += entryArr_[index].dsc_.timeToOpen * LIFE_GAIN_INTERVAL;
235                if (entryArr_[index].life_ > LIFE_LIMIT) {
236                    entryArr_[index].life_ = LIFE_LIMIT;
237                }
238                hittedIndex = index;
239                return RetCode::OK;
240            }
241        } else {
242            ImageInfo* imgDsc = reinterpret_cast<ImageInfo*>(const_cast<char*>(path));
243            if ((entryArr_[index].dsc_.path == path) && (entryArr_[index].dsc_.imgInfo.data == imgDsc->data)) {
244                entryArr_[index].life_ += entryArr_[index].dsc_.timeToOpen * LIFE_GAIN_INTERVAL;
245                if (entryArr_[index].life_ > LIFE_LIMIT) {
246                    entryArr_[index].life_ = LIFE_LIMIT;
247                }
248                hittedIndex = index;
249                return RetCode::OK;
250            }
251        }
252    }
253
254    return RetCode::FAIL;
255}
256
257RetCode CacheManager::SelectEntryToReplace(uint16_t& selectedIndex)
258{
259    selectedIndex = 0;
260    for (uint16_t index = 0; index < GetSize(); index++) {
261        if (entryArr_[index].life_ < entryArr_[selectedIndex].life_) {
262            selectedIndex = index;
263        }
264    }
265
266    return RetCode::OK;
267}
268
269RetCode CacheManager::TryDecode(const char* path, const Style& style, CacheEntry& entry)
270{
271    FileImgDecoder* decoder = &(FileImgDecoder::GetInstance());
272    if (decoder == nullptr) {
273        Clear(entry);
274        return RetCode::FAIL;
275    }
276
277    entry.dsc_.srcType = IMG_SRC_FILE;
278    RetCode ret = entry.SetSrc(path);
279    if (ret != RetCode::OK) {
280        Clear(entry);
281        return ret;
282    }
283    entry.dsc_.decoder = decoder;
284
285    ret = entry.dsc_.decoder->GetHeader(entry.dsc_);
286    if (ret != RetCode::OK) {
287        Clear(entry);
288        return ret;
289    }
290
291    ret = entry.dsc_.decoder->Open(entry.dsc_);
292    if (ret != RetCode::OK) {
293        Clear(entry);
294        return ret;
295    }
296
297    return ret;
298}
299} // namespace OHOS
300