13920e296Sopenharmony_ci/*
23920e296Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
33920e296Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43920e296Sopenharmony_ci * you may not use this file except in compliance with the License.
53920e296Sopenharmony_ci * You may obtain a copy of the License at
63920e296Sopenharmony_ci *
73920e296Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
83920e296Sopenharmony_ci *
93920e296Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103920e296Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113920e296Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123920e296Sopenharmony_ci * See the License for the specific language governing permissions and
133920e296Sopenharmony_ci * limitations under the License.
143920e296Sopenharmony_ci */
153920e296Sopenharmony_ci
163920e296Sopenharmony_ci#include "resource_append.h"
173920e296Sopenharmony_ci#include <algorithm>
183920e296Sopenharmony_ci#include <iomanip>
193920e296Sopenharmony_ci#include <iostream>
203920e296Sopenharmony_ci#include <regex>
213920e296Sopenharmony_ci#include "config_parser.h"
223920e296Sopenharmony_ci#include "header.h"
233920e296Sopenharmony_ci#include "id_worker.h"
243920e296Sopenharmony_ci#include "key_parser.h"
253920e296Sopenharmony_ci#include "reference_parser.h"
263920e296Sopenharmony_ci#include "resource_table.h"
273920e296Sopenharmony_ci#include "resource_util.h"
283920e296Sopenharmony_ci#include "select_compile_parse.h"
293920e296Sopenharmony_ci#ifdef __WIN32
303920e296Sopenharmony_ci#include "windows.h"
313920e296Sopenharmony_ci#endif
323920e296Sopenharmony_ci#include "securec.h"
333920e296Sopenharmony_ci
343920e296Sopenharmony_cinamespace OHOS {
353920e296Sopenharmony_cinamespace Global {
363920e296Sopenharmony_cinamespace Restool {
373920e296Sopenharmony_ciusing namespace std;
383920e296Sopenharmony_ci
393920e296Sopenharmony_ciResourceAppend::ResourceAppend(const PackageParser &packageParser) : packageParser_(packageParser)
403920e296Sopenharmony_ci{
413920e296Sopenharmony_ci}
423920e296Sopenharmony_ci
433920e296Sopenharmony_ciuint32_t ResourceAppend::Append()
443920e296Sopenharmony_ci{
453920e296Sopenharmony_ci    string outputPath = packageParser_.GetOutput();
463920e296Sopenharmony_ci    for (const auto &iter : packageParser_.GetAppend()) {
473920e296Sopenharmony_ci        if (!ScanResources(iter, outputPath)) {
483920e296Sopenharmony_ci            return RESTOOL_ERROR;
493920e296Sopenharmony_ci        }
503920e296Sopenharmony_ci    }
513920e296Sopenharmony_ci    return RESTOOL_SUCCESS;
523920e296Sopenharmony_ci}
533920e296Sopenharmony_ci
543920e296Sopenharmony_ciuint32_t ResourceAppend::Combine()
553920e296Sopenharmony_ci{
563920e296Sopenharmony_ci    vector<pair<ResType, string>> noBaseResource;
573920e296Sopenharmony_ci    for (const auto &iter : packageParser_.GetInputs()) {
583920e296Sopenharmony_ci        if (!Combine(iter)) {
593920e296Sopenharmony_ci            return RESTOOL_ERROR;
603920e296Sopenharmony_ci        }
613920e296Sopenharmony_ci        CheckAllItems(noBaseResource);
623920e296Sopenharmony_ci    }
633920e296Sopenharmony_ci    if (!noBaseResource.empty()) {
643920e296Sopenharmony_ci        ResourceUtil::PrintWarningMsg(noBaseResource);
653920e296Sopenharmony_ci    }
663920e296Sopenharmony_ci
673920e296Sopenharmony_ci    if (!ParseRef()) {
683920e296Sopenharmony_ci        return false;
693920e296Sopenharmony_ci    }
703920e296Sopenharmony_ci
713920e296Sopenharmony_ci    ResourceTable resourceTable;
723920e296Sopenharmony_ci    if (resourceTable.CreateResourceTable(items_) != RESTOOL_SUCCESS) {
733920e296Sopenharmony_ci        return RESTOOL_ERROR;
743920e296Sopenharmony_ci    }
753920e296Sopenharmony_ci    return RESTOOL_SUCCESS;
763920e296Sopenharmony_ci}
773920e296Sopenharmony_ci
783920e296Sopenharmony_ci// private
793920e296Sopenharmony_cibool ResourceAppend::Combine(const string &folderPath)
803920e296Sopenharmony_ci{
813920e296Sopenharmony_ci    FileEntry entry(folderPath);
823920e296Sopenharmony_ci    if (!entry.Init()) {
833920e296Sopenharmony_ci        return false;
843920e296Sopenharmony_ci    }
853920e296Sopenharmony_ci
863920e296Sopenharmony_ci    itemsForModule_.clear();
873920e296Sopenharmony_ci    for (const auto &child : entry.GetChilds()) {
883920e296Sopenharmony_ci        if (!child->IsFile()) {
893920e296Sopenharmony_ci            cerr << "Error:" << child->GetFilePath().GetPath()  << " not file" << endl;
903920e296Sopenharmony_ci            return false;
913920e296Sopenharmony_ci        }
923920e296Sopenharmony_ci        if (child->GetFilePath().GetFilename() == ID_DEFINED_FILE) {
933920e296Sopenharmony_ci            continue;
943920e296Sopenharmony_ci        }
953920e296Sopenharmony_ci        if (!LoadResourceItem(child->GetFilePath().GetPath())) {
963920e296Sopenharmony_ci            return false;
973920e296Sopenharmony_ci        }
983920e296Sopenharmony_ci    }
993920e296Sopenharmony_ci    return true;
1003920e296Sopenharmony_ci}
1013920e296Sopenharmony_ci
1023920e296Sopenharmony_cibool ResourceAppend::ParseRef()
1033920e296Sopenharmony_ci{
1043920e296Sopenharmony_ci    for (auto &iter : refs_) {
1053920e296Sopenharmony_ci        ReferenceParser ref;
1063920e296Sopenharmony_ci        if (iter->GetResType() == ResType::PROF || iter->GetResType() == ResType::MEDIA) {
1073920e296Sopenharmony_ci            if (ref.ParseRefInJsonFile(*iter, packageParser_.GetOutput(), true) != RESTOOL_SUCCESS) {
1083920e296Sopenharmony_ci                return false;
1093920e296Sopenharmony_ci            }
1103920e296Sopenharmony_ci        } else if (ref.ParseRefInResourceItem(*iter) != RESTOOL_SUCCESS) {
1113920e296Sopenharmony_ci            return false;
1123920e296Sopenharmony_ci        }
1133920e296Sopenharmony_ci    }
1143920e296Sopenharmony_ci    return true;
1153920e296Sopenharmony_ci}
1163920e296Sopenharmony_ci
1173920e296Sopenharmony_cibool ResourceAppend::ScanResources(const string &resourcePath, const string &outputPath)
1183920e296Sopenharmony_ci{
1193920e296Sopenharmony_ci    if (!ResourceUtil::FileExist(resourcePath)) {
1203920e296Sopenharmony_ci        string filePath = FileEntry::FilePath(outputPath).Append(ResourceUtil::GenerateHash(resourcePath)).GetPath();
1213920e296Sopenharmony_ci        if (remove(filePath.c_str()) != 0) {
1223920e296Sopenharmony_ci            cerr << "Error: remove failed '" << filePath << "', reason: " << strerror(errno) << endl;
1233920e296Sopenharmony_ci            return false;
1243920e296Sopenharmony_ci        }
1253920e296Sopenharmony_ci        return true;
1263920e296Sopenharmony_ci    }
1273920e296Sopenharmony_ci
1283920e296Sopenharmony_ci    FileEntry entry(resourcePath);
1293920e296Sopenharmony_ci    if (!entry.Init()) {
1303920e296Sopenharmony_ci        return false;
1313920e296Sopenharmony_ci    }
1323920e296Sopenharmony_ci
1333920e296Sopenharmony_ci    if (entry.IsFile()) {
1343920e296Sopenharmony_ci        return ScanSingleFile(resourcePath, outputPath);
1353920e296Sopenharmony_ci    }
1363920e296Sopenharmony_ci
1373920e296Sopenharmony_ci    return ScanSubResources(entry, resourcePath, outputPath);
1383920e296Sopenharmony_ci}
1393920e296Sopenharmony_ci
1403920e296Sopenharmony_cibool ResourceAppend::ScanSubResources(const FileEntry entry, const string &resourcePath, const string &outputPath)
1413920e296Sopenharmony_ci{
1423920e296Sopenharmony_ci    vector<KeyParam> keyParams;
1433920e296Sopenharmony_ci    if (KeyParser::Parse(entry.GetFilePath().GetFilename(), keyParams)) {
1443920e296Sopenharmony_ci        for (const auto &child : entry.GetChilds()) {
1453920e296Sopenharmony_ci            if (!ResourceUtil::IslegalPath(child->GetFilePath().GetFilename())) {
1463920e296Sopenharmony_ci                continue;
1473920e296Sopenharmony_ci            }
1483920e296Sopenharmony_ci            if (!ScanIegalResources(child->GetFilePath().GetPath(), outputPath)) {
1493920e296Sopenharmony_ci                return false;
1503920e296Sopenharmony_ci            }
1513920e296Sopenharmony_ci        }
1523920e296Sopenharmony_ci        return true;
1533920e296Sopenharmony_ci    }
1543920e296Sopenharmony_ci
1553920e296Sopenharmony_ci    if (ResourceUtil::IslegalPath(entry.GetFilePath().GetFilename())) {
1563920e296Sopenharmony_ci        return ScanIegalResources(resourcePath, outputPath);
1573920e296Sopenharmony_ci    }
1583920e296Sopenharmony_ci
1593920e296Sopenharmony_ci    return ScanSubLimitkeyResources(entry, resourcePath, outputPath);
1603920e296Sopenharmony_ci}
1613920e296Sopenharmony_ci
1623920e296Sopenharmony_cibool ResourceAppend::ScanSubLimitkeyResources(const FileEntry entry, const string &resourcePath,
1633920e296Sopenharmony_ci    const string &outputPath)
1643920e296Sopenharmony_ci{
1653920e296Sopenharmony_ci    for (const auto &child : entry.GetChilds()) {
1663920e296Sopenharmony_ci        string limitKey = child->GetFilePath().GetFilename();
1673920e296Sopenharmony_ci        if (ResourceUtil::IsIgnoreFile(limitKey, child->IsFile())) {
1683920e296Sopenharmony_ci            continue;
1693920e296Sopenharmony_ci        }
1703920e296Sopenharmony_ci
1713920e296Sopenharmony_ci        if (limitKey == RAW_FILE_DIR || limitKey == RES_FILE_DIR) {
1723920e296Sopenharmony_ci            if (!ScanRawFilesOrResFiles(child->GetFilePath().GetPath(), outputPath, limitKey)) {
1733920e296Sopenharmony_ci                return false;
1743920e296Sopenharmony_ci            }
1753920e296Sopenharmony_ci            continue;
1763920e296Sopenharmony_ci        }
1773920e296Sopenharmony_ci
1783920e296Sopenharmony_ci        if (child->IsFile()) {
1793920e296Sopenharmony_ci            cerr << "Error: " << child->GetFilePath().GetPath() << " not directory" << endl;
1803920e296Sopenharmony_ci            return false;
1813920e296Sopenharmony_ci        }
1823920e296Sopenharmony_ci
1833920e296Sopenharmony_ci        if (!ScanLimitKey(child, limitKey, outputPath)) {
1843920e296Sopenharmony_ci            return false;
1853920e296Sopenharmony_ci        }
1863920e296Sopenharmony_ci    }
1873920e296Sopenharmony_ci    return true;
1883920e296Sopenharmony_ci}
1893920e296Sopenharmony_ci
1903920e296Sopenharmony_cibool ResourceAppend::ScanIegalResources(const string &resourcePath, const string &outputPath)
1913920e296Sopenharmony_ci{
1923920e296Sopenharmony_ci    FileEntry entry(resourcePath);
1933920e296Sopenharmony_ci    if (!entry.Init()) {
1943920e296Sopenharmony_ci        return false;
1953920e296Sopenharmony_ci    }
1963920e296Sopenharmony_ci    for (const auto &child : entry.GetChilds()) {
1973920e296Sopenharmony_ci        if (!ScanSingleFile(child->GetFilePath().GetPath(), outputPath)) {
1983920e296Sopenharmony_ci            return false;
1993920e296Sopenharmony_ci        }
2003920e296Sopenharmony_ci    }
2013920e296Sopenharmony_ci    return true;
2023920e296Sopenharmony_ci}
2033920e296Sopenharmony_cibool ResourceAppend::ScanLimitKey(const unique_ptr<FileEntry> &entry,
2043920e296Sopenharmony_ci    const string &limitKey, const string outputPath)
2053920e296Sopenharmony_ci{
2063920e296Sopenharmony_ci    vector<KeyParam> keyParams;
2073920e296Sopenharmony_ci    if (!KeyParser::Parse(limitKey, keyParams)) {
2083920e296Sopenharmony_ci        cerr << "Error: invalid limit key '" << limitKey << "'.";
2093920e296Sopenharmony_ci        cerr << NEW_LINE_PATH << entry->GetFilePath().GetPath() << endl;
2103920e296Sopenharmony_ci        return false;
2113920e296Sopenharmony_ci    }
2123920e296Sopenharmony_ci
2133920e296Sopenharmony_ci    for (const auto &child : entry->GetChilds()) {
2143920e296Sopenharmony_ci        string fileCuster = child->GetFilePath().GetFilename();
2153920e296Sopenharmony_ci        if (ResourceUtil::IsIgnoreFile(fileCuster, child->IsFile())) {
2163920e296Sopenharmony_ci            continue;
2173920e296Sopenharmony_ci        }
2183920e296Sopenharmony_ci
2193920e296Sopenharmony_ci        if (child->IsFile()) {
2203920e296Sopenharmony_ci            cerr << "Error: " << child->GetFilePath().GetPath() << " not directory" << endl;
2213920e296Sopenharmony_ci            return false;
2223920e296Sopenharmony_ci        }
2233920e296Sopenharmony_ci
2243920e296Sopenharmony_ci        ResType resType = ResourceUtil::GetResTypeByDir(fileCuster);
2253920e296Sopenharmony_ci        if (resType == ResType::INVALID_RES_TYPE) {
2263920e296Sopenharmony_ci            cerr << "Error: invalid resType." << NEW_LINE_PATH << child->GetFilePath().GetPath() << endl;
2273920e296Sopenharmony_ci            return false;
2283920e296Sopenharmony_ci        }
2293920e296Sopenharmony_ci
2303920e296Sopenharmony_ci        DirectoryInfo directoryInfo = { limitKey, fileCuster, child->GetFilePath().GetPath(), keyParams, resType};
2313920e296Sopenharmony_ci        if (!ScanFiles(child, directoryInfo, outputPath)) {
2323920e296Sopenharmony_ci            return false;
2333920e296Sopenharmony_ci        }
2343920e296Sopenharmony_ci    }
2353920e296Sopenharmony_ci    return true;
2363920e296Sopenharmony_ci}
2373920e296Sopenharmony_ci
2383920e296Sopenharmony_ci
2393920e296Sopenharmony_cibool ResourceAppend::ScanFiles(const unique_ptr<FileEntry> &entry,
2403920e296Sopenharmony_ci    const DirectoryInfo &directoryInfo, const string &outputPath)
2413920e296Sopenharmony_ci{
2423920e296Sopenharmony_ci    for (const auto &child : entry->GetChilds()) {
2433920e296Sopenharmony_ci        string filename =  child->GetFilePath().GetFilename();
2443920e296Sopenharmony_ci        if (ResourceUtil::IsIgnoreFile(filename, child->IsFile())) {
2453920e296Sopenharmony_ci            continue;
2463920e296Sopenharmony_ci        }
2473920e296Sopenharmony_ci
2483920e296Sopenharmony_ci        if (!child->IsFile()) {
2493920e296Sopenharmony_ci            cerr << "Error: '" << child->GetFilePath().GetPath() << "' not file." << endl;
2503920e296Sopenharmony_ci            return false;
2513920e296Sopenharmony_ci        }
2523920e296Sopenharmony_ci
2533920e296Sopenharmony_ci        FileInfo fileInfo = {directoryInfo, child->GetFilePath().GetPath(), filename};
2543920e296Sopenharmony_ci        if (!ScanFile(fileInfo, outputPath)) {
2553920e296Sopenharmony_ci            return false;
2563920e296Sopenharmony_ci        }
2573920e296Sopenharmony_ci    }
2583920e296Sopenharmony_ci    return true;
2593920e296Sopenharmony_ci}
2603920e296Sopenharmony_ci
2613920e296Sopenharmony_cibool ResourceAppend::ScanFile(const FileInfo &fileInfo, const string &outputPath)
2623920e296Sopenharmony_ci{
2633920e296Sopenharmony_ci    if (ResourceAppend::IsBaseIdDefined(fileInfo)) {
2643920e296Sopenharmony_ci        cout << "Warning: id_defined.json does not compile to generate intermediate files" << endl;
2653920e296Sopenharmony_ci        FileEntry::FilePath outPath(outputPath);
2663920e296Sopenharmony_ci        return ResourceUtil::CopyFileInner(fileInfo.filePath, outPath.Append(ID_DEFINED_FILE).GetPath());
2673920e296Sopenharmony_ci    }
2683920e296Sopenharmony_ci
2693920e296Sopenharmony_ci    unique_ptr<IResourceCompiler> resourceCompiler =
2703920e296Sopenharmony_ci        FactoryResourceCompiler::CreateCompilerForAppend(fileInfo.dirType, outputPath);
2713920e296Sopenharmony_ci    if (resourceCompiler == nullptr) {
2723920e296Sopenharmony_ci        return true;
2733920e296Sopenharmony_ci    }
2743920e296Sopenharmony_ci
2753920e296Sopenharmony_ci    if (resourceCompiler->CompileForAppend(fileInfo) != RESTOOL_SUCCESS) {
2763920e296Sopenharmony_ci        return false;
2773920e296Sopenharmony_ci    }
2783920e296Sopenharmony_ci
2793920e296Sopenharmony_ci    ostringstream outStream;
2803920e296Sopenharmony_ci    const auto &items = resourceCompiler->GetResourceItems();
2813920e296Sopenharmony_ci    for (const auto &item : items) {
2823920e296Sopenharmony_ci        for (const auto &resourceItem : item.second) {
2833920e296Sopenharmony_ci            if (!WriteResourceItem(resourceItem, outStream)) {
2843920e296Sopenharmony_ci                return false;
2853920e296Sopenharmony_ci            }
2863920e296Sopenharmony_ci        }
2873920e296Sopenharmony_ci    }
2883920e296Sopenharmony_ci
2893920e296Sopenharmony_ci    string hash = ResourceUtil::GenerateHash(fileInfo.filePath);
2903920e296Sopenharmony_ci    FileEntry::FilePath output(outputPath);
2913920e296Sopenharmony_ci    if (!WriteFileInner(outStream, output.Append(hash).GetPath())) {
2923920e296Sopenharmony_ci        return false;
2933920e296Sopenharmony_ci    }
2943920e296Sopenharmony_ci    return true;
2953920e296Sopenharmony_ci}
2963920e296Sopenharmony_ci
2973920e296Sopenharmony_cibool ResourceAppend::ScanSingleFile(const string &filePath, const string &outputPath)
2983920e296Sopenharmony_ci{
2993920e296Sopenharmony_ci    if (filePath.find(RAW_FILE_DIR) != string::npos) {
3003920e296Sopenharmony_ci        return WriteRawFilesOrResFiles(filePath, outputPath, RAW_FILE_DIR);
3013920e296Sopenharmony_ci    }
3023920e296Sopenharmony_ci
3033920e296Sopenharmony_ci    if (filePath.find(RES_FILE_DIR) != string::npos) {
3043920e296Sopenharmony_ci        return WriteRawFilesOrResFiles(filePath, outputPath, RES_FILE_DIR);
3053920e296Sopenharmony_ci    }
3063920e296Sopenharmony_ci
3073920e296Sopenharmony_ci    FileEntry::FilePath path(filePath);
3083920e296Sopenharmony_ci    string fileCuster = path.GetParent().GetFilename();
3093920e296Sopenharmony_ci    ResType resType = ResourceUtil::GetResTypeByDir(fileCuster);
3103920e296Sopenharmony_ci    if (resType == ResType::INVALID_RES_TYPE) {
3113920e296Sopenharmony_ci        cerr << "Error: invalid resType." << NEW_LINE_PATH << filePath << endl;
3123920e296Sopenharmony_ci        return false;
3133920e296Sopenharmony_ci    }
3143920e296Sopenharmony_ci
3153920e296Sopenharmony_ci    string limitKey = path.GetParent().GetParent().GetFilename();
3163920e296Sopenharmony_ci    vector<KeyParam> keyParams;
3173920e296Sopenharmony_ci    if (!KeyParser::Parse(limitKey, keyParams)) {
3183920e296Sopenharmony_ci        cerr << "Error: invalid limit key." << NEW_LINE_PATH << filePath << endl;
3193920e296Sopenharmony_ci        return false;
3203920e296Sopenharmony_ci    }
3213920e296Sopenharmony_ci
3223920e296Sopenharmony_ci    DirectoryInfo directoryInfo = {limitKey, fileCuster, path.GetParent().GetPath(), keyParams, resType};
3233920e296Sopenharmony_ci    FileInfo fileInfo = {directoryInfo, filePath, path.GetFilename() };
3243920e296Sopenharmony_ci    if (!ScanFile(fileInfo, outputPath)) {
3253920e296Sopenharmony_ci        return false;
3263920e296Sopenharmony_ci    }
3273920e296Sopenharmony_ci    return true;
3283920e296Sopenharmony_ci}
3293920e296Sopenharmony_ci
3303920e296Sopenharmony_cibool ResourceAppend::WriteFileInner(ostringstream &outStream, const string &outputPath) const
3313920e296Sopenharmony_ci{
3323920e296Sopenharmony_ci#ifdef __WIN32
3333920e296Sopenharmony_ci    HANDLE hWriteFile = CreateFile(outputPath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
3343920e296Sopenharmony_ci        nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
3353920e296Sopenharmony_ci    if (hWriteFile == INVALID_HANDLE_VALUE) {
3363920e296Sopenharmony_ci        cerr << "Error: '" << outputPath << "' " << GetLastError() << endl;
3373920e296Sopenharmony_ci        return false;
3383920e296Sopenharmony_ci    }
3393920e296Sopenharmony_ci
3403920e296Sopenharmony_ci    DWORD writeBytes;
3413920e296Sopenharmony_ci    if (!WriteFile(hWriteFile, outStream.str().c_str(), outStream.tellp(), &writeBytes, nullptr)) {
3423920e296Sopenharmony_ci        cerr << "Error: write '" << outputPath << "' " << GetLastError() << endl;
3433920e296Sopenharmony_ci        CloseHandle(hWriteFile);
3443920e296Sopenharmony_ci        return false;
3453920e296Sopenharmony_ci    }
3463920e296Sopenharmony_ci    CloseHandle(hWriteFile);
3473920e296Sopenharmony_ci#else
3483920e296Sopenharmony_ci    ofstream out(outputPath, ofstream::out | ofstream::binary);
3493920e296Sopenharmony_ci    if (!out.is_open()) {
3503920e296Sopenharmony_ci        cerr << "Error: open failed '" << outputPath << "', reason: " << strerror(errno) << endl;
3513920e296Sopenharmony_ci        return false;
3523920e296Sopenharmony_ci    }
3533920e296Sopenharmony_ci    out << outStream.str();
3543920e296Sopenharmony_ci#endif
3553920e296Sopenharmony_ci    return true;
3563920e296Sopenharmony_ci}
3573920e296Sopenharmony_ci
3583920e296Sopenharmony_cibool ResourceAppend::WriteResourceItem(const ResourceItem &resourceItem, ostringstream &out)
3593920e296Sopenharmony_ci{
3603920e296Sopenharmony_ci    uint32_t size = resourceItem.GetName().length();
3613920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
3623920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(resourceItem.GetName().c_str()), size);
3633920e296Sopenharmony_ci
3643920e296Sopenharmony_ci    size = resourceItem.GetLimitKey().length();
3653920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
3663920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(resourceItem.GetLimitKey().c_str()), size);
3673920e296Sopenharmony_ci
3683920e296Sopenharmony_ci    size = resourceItem.GetFilePath().length();
3693920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
3703920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(resourceItem.GetFilePath().c_str()), size);
3713920e296Sopenharmony_ci
3723920e296Sopenharmony_ci    int32_t type = static_cast<int32_t>(resourceItem.GetResType());
3733920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(&type), sizeof(int32_t));
3743920e296Sopenharmony_ci
3753920e296Sopenharmony_ci    size = resourceItem.GetKeyParam().size();
3763920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
3773920e296Sopenharmony_ci    for (const auto &keyParam : resourceItem.GetKeyParam()) {
3783920e296Sopenharmony_ci        out.write(reinterpret_cast<const char *>(&keyParam.keyType), sizeof(int32_t));
3793920e296Sopenharmony_ci        out.write(reinterpret_cast<const char *>(&keyParam.value), sizeof(int32_t));
3803920e296Sopenharmony_ci    }
3813920e296Sopenharmony_ci
3823920e296Sopenharmony_ci    size =  resourceItem.GetDataLength();
3833920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
3843920e296Sopenharmony_ci    out.write(reinterpret_cast<const char *>(resourceItem.GetData()), size);
3853920e296Sopenharmony_ci    return true;
3863920e296Sopenharmony_ci}
3873920e296Sopenharmony_ci
3883920e296Sopenharmony_cibool ResourceAppend::LoadResourceItem(const string &filePath)
3893920e296Sopenharmony_ci{
3903920e296Sopenharmony_ci#ifdef __WIN32
3913920e296Sopenharmony_ci    return LoadResourceItemWin(filePath);
3923920e296Sopenharmony_ci#else
3933920e296Sopenharmony_ci    ifstream in(filePath, ifstream::in | ifstream::binary);
3943920e296Sopenharmony_ci    if (!in.is_open()) {
3953920e296Sopenharmony_ci        cerr << "Error: open failed '" << filePath << "', reason: " << strerror(errno) << endl;
3963920e296Sopenharmony_ci        return false;
3973920e296Sopenharmony_ci    }
3983920e296Sopenharmony_ci
3993920e296Sopenharmony_ci    in.seekg(0, in.end);
4003920e296Sopenharmony_ci    int32_t length = in.tellg();
4013920e296Sopenharmony_ci    in.seekg(0, in.beg);
4023920e296Sopenharmony_ci    if (length <= 0) {
4033920e296Sopenharmony_ci        cerr << "Error: invalid file size = " << length << NEW_LINE_PATH << filePath << endl;
4043920e296Sopenharmony_ci        return false;
4053920e296Sopenharmony_ci    }
4063920e296Sopenharmony_ci    char buffer[length];
4073920e296Sopenharmony_ci    in.read(buffer, length);
4083920e296Sopenharmony_ci    return LoadResourceItemFromMem(buffer, length);
4093920e296Sopenharmony_ci#endif
4103920e296Sopenharmony_ci}
4113920e296Sopenharmony_ci
4123920e296Sopenharmony_cibool ResourceAppend::ScanRawFilesOrResFiles(const string &path, const string &outputPath, const string &limit)
4133920e296Sopenharmony_ci{
4143920e296Sopenharmony_ci    FileEntry entry(path);
4153920e296Sopenharmony_ci    if (!entry.Init()) {
4163920e296Sopenharmony_ci        return false;
4173920e296Sopenharmony_ci    }
4183920e296Sopenharmony_ci
4193920e296Sopenharmony_ci    for (const auto &child : entry.GetChilds()) {
4203920e296Sopenharmony_ci        string filename =  child->GetFilePath().GetFilename();
4213920e296Sopenharmony_ci        if (ResourceUtil::IsIgnoreFile(filename, child->IsFile())) {
4223920e296Sopenharmony_ci            continue;
4233920e296Sopenharmony_ci        }
4243920e296Sopenharmony_ci
4253920e296Sopenharmony_ci        bool ret = false;
4263920e296Sopenharmony_ci        if (child->IsFile()) {
4273920e296Sopenharmony_ci            ret = WriteRawFilesOrResFiles(child->GetFilePath().GetPath(), outputPath, limit);
4283920e296Sopenharmony_ci        } else {
4293920e296Sopenharmony_ci            ret = ScanRawFilesOrResFiles(child->GetFilePath().GetPath(), outputPath, limit);
4303920e296Sopenharmony_ci        }
4313920e296Sopenharmony_ci
4323920e296Sopenharmony_ci        if (!ret) {
4333920e296Sopenharmony_ci            return false;
4343920e296Sopenharmony_ci        }
4353920e296Sopenharmony_ci    }
4363920e296Sopenharmony_ci    return true;
4373920e296Sopenharmony_ci}
4383920e296Sopenharmony_ci
4393920e296Sopenharmony_cibool ResourceAppend::WriteRawFilesOrResFiles(const string &filePath, const string &outputPath, const string &limit)
4403920e296Sopenharmony_ci{
4413920e296Sopenharmony_ci    string::size_type pos = filePath.find(limit);
4423920e296Sopenharmony_ci    if (pos == string::npos) {
4433920e296Sopenharmony_ci        cerr << "Error: invalid file path." << NEW_LINE_PATH << filePath << endl;
4443920e296Sopenharmony_ci        return false;
4453920e296Sopenharmony_ci    }
4463920e296Sopenharmony_ci
4473920e296Sopenharmony_ci    string sub = filePath.substr(pos);
4483920e296Sopenharmony_ci    sub = FileEntry::FilePath(RESOURCES_DIR).Append(sub).GetPath();
4493920e296Sopenharmony_ci    vector<KeyParam> keyParams;
4503920e296Sopenharmony_ci    auto iter = g_copyFileMap.find(limit);
4513920e296Sopenharmony_ci    ResourceItem resourceItem("", keyParams, iter->second);
4523920e296Sopenharmony_ci    resourceItem.SetData(sub);
4533920e296Sopenharmony_ci    resourceItem.SetFilePath(filePath);
4543920e296Sopenharmony_ci    resourceItem.SetLimitKey("");
4553920e296Sopenharmony_ci
4563920e296Sopenharmony_ci    ostringstream outStream;
4573920e296Sopenharmony_ci    if (!WriteResourceItem(resourceItem, outStream)) {
4583920e296Sopenharmony_ci        return false;
4593920e296Sopenharmony_ci    }
4603920e296Sopenharmony_ci
4613920e296Sopenharmony_ci    string hash = ResourceUtil::GenerateHash(filePath);
4623920e296Sopenharmony_ci    FileEntry::FilePath output(outputPath);
4633920e296Sopenharmony_ci    if (!WriteFileInner(outStream, output.Append(hash).GetPath())) {
4643920e296Sopenharmony_ci        return false;
4653920e296Sopenharmony_ci    }
4663920e296Sopenharmony_ci    return true;
4673920e296Sopenharmony_ci}
4683920e296Sopenharmony_ci
4693920e296Sopenharmony_cibool ResourceAppend::Push(const shared_ptr<ResourceItem> &resourceItem)
4703920e296Sopenharmony_ci{
4713920e296Sopenharmony_ci    string idName = ResourceUtil::GetIdName(resourceItem->GetName(), resourceItem->GetResType());
4723920e296Sopenharmony_ci    int64_t id = IdWorker::GetInstance().GenerateId(resourceItem->GetResType(), idName);
4733920e296Sopenharmony_ci    if (id < 0) {
4743920e296Sopenharmony_ci        return false;
4753920e296Sopenharmony_ci    }
4763920e296Sopenharmony_ci
4773920e296Sopenharmony_ci    if (!CheckModuleResourceItem(resourceItem, id)) {
4783920e296Sopenharmony_ci        return false;
4793920e296Sopenharmony_ci    }
4803920e296Sopenharmony_ci
4813920e296Sopenharmony_ci    const auto &result = items_.find(id);
4823920e296Sopenharmony_ci    if (result == items_.end()) {
4833920e296Sopenharmony_ci        items_[id].push_back(resourceItem);
4843920e296Sopenharmony_ci        AddRef(resourceItem);
4853920e296Sopenharmony_ci        return true;
4863920e296Sopenharmony_ci    }
4873920e296Sopenharmony_ci
4883920e296Sopenharmony_ci    if (find_if(result->second.begin(), result->second.end(), [resourceItem](auto &iter) {
4893920e296Sopenharmony_ci              return resourceItem->GetLimitKey() == iter->GetLimitKey();
4903920e296Sopenharmony_ci        }) != result->second.end()) {
4913920e296Sopenharmony_ci        return true;
4923920e296Sopenharmony_ci    }
4933920e296Sopenharmony_ci
4943920e296Sopenharmony_ci    items_[id].push_back(resourceItem);
4953920e296Sopenharmony_ci    AddRef(resourceItem);
4963920e296Sopenharmony_ci    return true;
4973920e296Sopenharmony_ci}
4983920e296Sopenharmony_ci
4993920e296Sopenharmony_civoid ResourceAppend::AddRef(const shared_ptr<ResourceItem> &resourceItem)
5003920e296Sopenharmony_ci{
5013920e296Sopenharmony_ci    string data(reinterpret_cast<const char *>(resourceItem->GetData()), resourceItem->GetDataLength());
5023920e296Sopenharmony_ci    ResType resType = resourceItem->GetResType();
5033920e296Sopenharmony_ci    if (resType == ResType::MEDIA) {
5043920e296Sopenharmony_ci        if (FileEntry::FilePath(resourceItem->GetFilePath()).GetExtension() == JSON_EXTENSION) {
5053920e296Sopenharmony_ci            refs_.push_back(resourceItem);
5063920e296Sopenharmony_ci        }
5073920e296Sopenharmony_ci        return;
5083920e296Sopenharmony_ci    }
5093920e296Sopenharmony_ci
5103920e296Sopenharmony_ci    if (resType == ResType::PROF) {
5113920e296Sopenharmony_ci        if (resourceItem->GetLimitKey() != "base" ||
5123920e296Sopenharmony_ci            FileEntry::FilePath(resourceItem->GetFilePath()).GetExtension() != JSON_EXTENSION) {
5133920e296Sopenharmony_ci            return;
5143920e296Sopenharmony_ci        }
5153920e296Sopenharmony_ci        refs_.push_back(resourceItem);
5163920e296Sopenharmony_ci        return;
5173920e296Sopenharmony_ci    }
5183920e296Sopenharmony_ci
5193920e296Sopenharmony_ci    if (regex_match(data, regex(".*\\$.+:.*"))) {
5203920e296Sopenharmony_ci        refs_.push_back(resourceItem);
5213920e296Sopenharmony_ci    }
5223920e296Sopenharmony_ci}
5233920e296Sopenharmony_ci
5243920e296Sopenharmony_cibool ResourceAppend::LoadResourceItemFromMem(const char buffer[], int32_t length)
5253920e296Sopenharmony_ci{
5263920e296Sopenharmony_ci    int32_t offset = 0;
5273920e296Sopenharmony_ci    do {
5283920e296Sopenharmony_ci        // name
5293920e296Sopenharmony_ci        string nameStr = ParseString(buffer, length, offset);
5303920e296Sopenharmony_ci        // limit key
5313920e296Sopenharmony_ci        string limitKeyStr = ParseString(buffer, length, offset);
5323920e296Sopenharmony_ci        // file path
5333920e296Sopenharmony_ci        string filePathStr = ParseString(buffer, length, offset);
5343920e296Sopenharmony_ci        // ResType
5353920e296Sopenharmony_ci        int32_t type = ParseInt32(buffer, length, offset);
5363920e296Sopenharmony_ci        ResType resType = static_cast<ResType>(type);
5373920e296Sopenharmony_ci        // keyParam
5383920e296Sopenharmony_ci        int32_t keyParamSize = ParseInt32(buffer, length, offset);
5393920e296Sopenharmony_ci        vector<KeyParam> keyParams;
5403920e296Sopenharmony_ci        for (int i = 0; i < keyParamSize; i++) {
5413920e296Sopenharmony_ci            KeyParam keyParam;
5423920e296Sopenharmony_ci            keyParam.keyType = static_cast<KeyType>(ParseInt32(buffer, length, offset));
5433920e296Sopenharmony_ci            int32_t value = ParseInt32(buffer, length, offset);
5443920e296Sopenharmony_ci            if (value == -1) {
5453920e296Sopenharmony_ci                return false;
5463920e296Sopenharmony_ci            }
5473920e296Sopenharmony_ci            keyParam.value = static_cast<uint32_t>(value);
5483920e296Sopenharmony_ci            keyParams.push_back(keyParam);
5493920e296Sopenharmony_ci        }
5503920e296Sopenharmony_ci        if (limitKeyStr != "base" && !limitKeyStr.empty() && !SelectCompileParse::IsSelectCompile(keyParams)) {
5513920e296Sopenharmony_ci            return true;
5523920e296Sopenharmony_ci        }
5533920e296Sopenharmony_ci        // data
5543920e296Sopenharmony_ci        string data = ParseString(buffer, length, offset);
5553920e296Sopenharmony_ci        if (resType ==  ResType::RAW || resType ==  ResType::RES) {
5563920e296Sopenharmony_ci            FileEntry::FilePath outPath(packageParser_.GetOutput());
5573920e296Sopenharmony_ci            if (ResourceUtil::FileExist(outPath.Append(data).GetPath())) {
5583920e296Sopenharmony_ci                continue;
5593920e296Sopenharmony_ci            }
5603920e296Sopenharmony_ci            if (!ResourceUtil::CreateDirs(outPath.Append(data).GetParent().GetPath())) {
5613920e296Sopenharmony_ci                return false;
5623920e296Sopenharmony_ci            }
5633920e296Sopenharmony_ci
5643920e296Sopenharmony_ci            if (!ResourceUtil::FileExist(filePathStr)) {
5653920e296Sopenharmony_ci                continue;
5663920e296Sopenharmony_ci            }
5673920e296Sopenharmony_ci
5683920e296Sopenharmony_ci            if (!ResourceUtil::CopyFileInner(filePathStr, outPath.Append(data).GetPath())) {
5693920e296Sopenharmony_ci                return false;
5703920e296Sopenharmony_ci            }
5713920e296Sopenharmony_ci            continue;
5723920e296Sopenharmony_ci        }
5733920e296Sopenharmony_ci
5743920e296Sopenharmony_ci        shared_ptr<ResourceItem> resourceItem = make_shared<ResourceItem>(nameStr, keyParams, resType);
5753920e296Sopenharmony_ci        resourceItem->SetData(reinterpret_cast<const int8_t *>(data.c_str()), data.length());
5763920e296Sopenharmony_ci        resourceItem->SetLimitKey(limitKeyStr);
5773920e296Sopenharmony_ci        resourceItem->SetFilePath(filePathStr);
5783920e296Sopenharmony_ci        if (!Push(resourceItem)) {
5793920e296Sopenharmony_ci            return false;
5803920e296Sopenharmony_ci        }
5813920e296Sopenharmony_ci    } while (offset < length);
5823920e296Sopenharmony_ci    return true;
5833920e296Sopenharmony_ci}
5843920e296Sopenharmony_ci
5853920e296Sopenharmony_cistring ResourceAppend::ParseString(const char buffer[], int32_t length, int32_t &offset) const
5863920e296Sopenharmony_ci{
5873920e296Sopenharmony_ci    int32_t size = ParseInt32(buffer, length, offset);
5883920e296Sopenharmony_ci    if (size < 0 || offset + size > length) {
5893920e296Sopenharmony_ci        offset = length;
5903920e296Sopenharmony_ci        return "";
5913920e296Sopenharmony_ci    }
5923920e296Sopenharmony_ci
5933920e296Sopenharmony_ci    if (size == 0) {
5943920e296Sopenharmony_ci        return "";
5953920e296Sopenharmony_ci    }
5963920e296Sopenharmony_ci
5973920e296Sopenharmony_ci    string value(buffer + offset, size);
5983920e296Sopenharmony_ci    offset += size;
5993920e296Sopenharmony_ci    return value;
6003920e296Sopenharmony_ci}
6013920e296Sopenharmony_ci
6023920e296Sopenharmony_ciint32_t ResourceAppend::ParseInt32(const char buffer[], int32_t length, int32_t &offset) const
6033920e296Sopenharmony_ci{
6043920e296Sopenharmony_ci    if (offset + static_cast<int32_t>(sizeof(int32_t)) > length) {
6053920e296Sopenharmony_ci        offset = length;
6063920e296Sopenharmony_ci        return -1;
6073920e296Sopenharmony_ci    }
6083920e296Sopenharmony_ci
6093920e296Sopenharmony_ci    int32_t size = 0;
6103920e296Sopenharmony_ci    if (memcpy_s(&size, sizeof(int32_t), buffer  + offset, sizeof(int32_t)) != EOK) {
6113920e296Sopenharmony_ci        offset = length;
6123920e296Sopenharmony_ci        return -1;
6133920e296Sopenharmony_ci    }
6143920e296Sopenharmony_ci    offset += sizeof(int32_t);
6153920e296Sopenharmony_ci    return size;
6163920e296Sopenharmony_ci}
6173920e296Sopenharmony_ci
6183920e296Sopenharmony_cibool ResourceAppend::CheckModuleResourceItem(const shared_ptr<ResourceItem> &resourceItem, int64_t id)
6193920e296Sopenharmony_ci{
6203920e296Sopenharmony_ci    const auto &result = itemsForModule_.find(id);
6213920e296Sopenharmony_ci    if (result == itemsForModule_.end()) {
6223920e296Sopenharmony_ci        itemsForModule_[id].push_back(resourceItem);
6233920e296Sopenharmony_ci        return true;
6243920e296Sopenharmony_ci    }
6253920e296Sopenharmony_ci
6263920e296Sopenharmony_ci    const auto &ret = find_if(result->second.begin(), result->second.end(), [resourceItem](auto iter) {
6273920e296Sopenharmony_ci             return  resourceItem->GetLimitKey() == iter->GetLimitKey();
6283920e296Sopenharmony_ci    });
6293920e296Sopenharmony_ci
6303920e296Sopenharmony_ci    if (ret != result->second.end()) {
6313920e296Sopenharmony_ci        cerr << "Error: '" << resourceItem->GetName() << "' conflict, first declared.";
6323920e296Sopenharmony_ci        cerr << NEW_LINE_PATH << (*ret)->GetFilePath() << endl;
6333920e296Sopenharmony_ci        cerr << "but declared again." << NEW_LINE_PATH << resourceItem->GetFilePath() << endl;
6343920e296Sopenharmony_ci        return false;
6353920e296Sopenharmony_ci    }
6363920e296Sopenharmony_ci
6373920e296Sopenharmony_ci    itemsForModule_[id].push_back(resourceItem);
6383920e296Sopenharmony_ci    return true;
6393920e296Sopenharmony_ci}
6403920e296Sopenharmony_ci
6413920e296Sopenharmony_ci#ifdef __WIN32
6423920e296Sopenharmony_cibool ResourceAppend::LoadResourceItemWin(const string &filePath)
6433920e296Sopenharmony_ci{
6443920e296Sopenharmony_ci    bool result = false;
6453920e296Sopenharmony_ci    HANDLE hReadFile = CreateFile(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
6463920e296Sopenharmony_ci        FILE_ATTRIBUTE_READONLY | FILE_FLAG_RANDOM_ACCESS, nullptr);
6473920e296Sopenharmony_ci    if (hReadFile == INVALID_HANDLE_VALUE) {
6483920e296Sopenharmony_ci        cerr << "Error: "<< GetLastError() << NEW_LINE_PATH << filePath << endl;
6493920e296Sopenharmony_ci        return result;
6503920e296Sopenharmony_ci    }
6513920e296Sopenharmony_ci
6523920e296Sopenharmony_ci    DWORD fileSize = GetFileSize(hReadFile, nullptr);
6533920e296Sopenharmony_ci    HANDLE hFileMap = CreateFileMapping(hReadFile, nullptr, PAGE_READONLY, 0, fileSize, nullptr);
6543920e296Sopenharmony_ci    if (hFileMap == INVALID_HANDLE_VALUE) {
6553920e296Sopenharmony_ci        cerr << "Error: create file mapping " << GetLastError() << endl;
6563920e296Sopenharmony_ci        CloseHandle(hReadFile);
6573920e296Sopenharmony_ci        return result;
6583920e296Sopenharmony_ci    }
6593920e296Sopenharmony_ci
6603920e296Sopenharmony_ci    void* pBuffer = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
6613920e296Sopenharmony_ci    if (pBuffer == nullptr) {
6623920e296Sopenharmony_ci        cerr << "Error: map view of file " << GetLastError() << endl;
6633920e296Sopenharmony_ci        CloseHandle(hReadFile);
6643920e296Sopenharmony_ci        return result;
6653920e296Sopenharmony_ci    }
6663920e296Sopenharmony_ci
6673920e296Sopenharmony_ci    char* buffer = reinterpret_cast<char *>(pBuffer);
6683920e296Sopenharmony_ci    result = LoadResourceItemFromMem(buffer, fileSize);
6693920e296Sopenharmony_ci    UnmapViewOfFile(hFileMap);
6703920e296Sopenharmony_ci    CloseHandle(hReadFile);
6713920e296Sopenharmony_ci    return result;
6723920e296Sopenharmony_ci}
6733920e296Sopenharmony_ci#endif
6743920e296Sopenharmony_ci
6753920e296Sopenharmony_cibool ResourceAppend::IsBaseIdDefined(const FileInfo &fileInfo)
6763920e296Sopenharmony_ci{
6773920e296Sopenharmony_ci    FileEntry::FilePath filePath(fileInfo.filePath);
6783920e296Sopenharmony_ci    return filePath.GetParent().GetParent().GetFilename() == "base" &&
6793920e296Sopenharmony_ci        filePath.GetParent().GetFilename() == "element" &&
6803920e296Sopenharmony_ci        fileInfo.filename == ID_DEFINED_FILE;
6813920e296Sopenharmony_ci}
6823920e296Sopenharmony_ci
6833920e296Sopenharmony_civoid ResourceAppend::CheckAllItems(vector<pair<ResType, string>> &noBaseResource)
6843920e296Sopenharmony_ci{
6853920e296Sopenharmony_ci    for (const auto &item : items_) {
6863920e296Sopenharmony_ci        bool found = any_of(item.second.begin(), item.second.end(), [](const auto &iter) {
6873920e296Sopenharmony_ci            return iter->GetLimitKey() == "base";
6883920e296Sopenharmony_ci        });
6893920e296Sopenharmony_ci        if (!found) {
6903920e296Sopenharmony_ci            auto firstItem = item.second.front();
6913920e296Sopenharmony_ci            bool ret = any_of(noBaseResource.begin(), noBaseResource.end(), [firstItem](const auto &iterItem) {
6923920e296Sopenharmony_ci                return (firstItem->GetResType() == iterItem.first)  &&
6933920e296Sopenharmony_ci                    (firstItem->GetName() == iterItem.second);
6943920e296Sopenharmony_ci            });
6953920e296Sopenharmony_ci            if (!ret) {
6963920e296Sopenharmony_ci                noBaseResource.push_back(make_pair(firstItem->GetResType(), firstItem->GetName()));
6973920e296Sopenharmony_ci            }
6983920e296Sopenharmony_ci        }
6993920e296Sopenharmony_ci    }
7003920e296Sopenharmony_ci}
7013920e296Sopenharmony_ci}
7023920e296Sopenharmony_ci}
7033920e296Sopenharmony_ci}