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 "i_resource_compiler.h"
17 #include <algorithm>
18 #include <iostream>
19 #include "file_entry.h"
20 #include "id_worker.h"
21 #include "resource_util.h"
22 #include "restool_errors.h"
23 
24 namespace OHOS {
25 namespace Global {
26 namespace Restool {
27 using namespace std;
IResourceCompiler(ResType type, const string &output)28 IResourceCompiler::IResourceCompiler(ResType type, const string &output)
29     :type_(type), output_(output)
30 {
31 }
32 
~IResourceCompiler()33 IResourceCompiler::~IResourceCompiler()
34 {
35     nameInfos_.clear();
36     resourceInfos_.clear();
37 }
38 
Compile(const vector<DirectoryInfo> &directoryInfos)39 uint32_t IResourceCompiler::Compile(const vector<DirectoryInfo> &directoryInfos)
40 {
41     vector<FileInfo> fileInfos;
42     map<string, vector<FileInfo>> setsByDirectory;
43     for (const auto &directoryInfo : directoryInfos) {
44         string outputFolder = GetOutputFolder(directoryInfo);
45         FileEntry f(directoryInfo.dirPath);
46         if (!f.Init()) {
47             return RESTOOL_ERROR;
48         }
49         for (const auto &it : f.GetChilds()) {
50             if (ResourceUtil::IsIgnoreFile(it->GetFilePath().GetFilename(), it->IsFile())) {
51                 continue;
52             }
53 
54             if (!it->IsFile()) {
55                 cerr << "Error: '" << it->GetFilePath().GetPath() << "' must be a file." << endl;
56                 return RESTOOL_ERROR;
57             }
58 
59             FileInfo fileInfo = { directoryInfo, it->GetFilePath().GetPath(), it->GetFilePath().GetFilename() };
60             fileInfos.push_back(fileInfo);
61             setsByDirectory[outputFolder].push_back(fileInfo);
62         }
63     }
64 
65     sort(fileInfos.begin(), fileInfos.end(), [](const auto &a, const auto &b) {
66         return a.filePath < b.filePath;
67     });
68     if (CompileFiles(fileInfos) != RESTOOL_SUCCESS) {
69         return RESTOOL_ERROR;
70     }
71     return PostCommit();
72 }
73 
CompileFiles(const std::vector<FileInfo> &fileInfos)74 uint32_t IResourceCompiler::CompileFiles(const std::vector<FileInfo> &fileInfos)
75 {
76     for (const auto &fileInfo : fileInfos) {
77         if (CompileSingleFile(fileInfo) != RESTOOL_SUCCESS) {
78             return RESTOOL_ERROR;
79         }
80     }
81     return RESTOOL_SUCCESS;
82 }
83 
GetResult() const84 const map<int64_t, vector<ResourceItem>> &IResourceCompiler::GetResult() const
85 {
86     return resourceInfos_;
87 }
88 
Compile(const FileInfo &fileInfo)89 uint32_t IResourceCompiler::Compile(const FileInfo &fileInfo)
90 {
91     if (CompileSingleFile(fileInfo) != RESTOOL_SUCCESS) {
92         return RESTOOL_ERROR;
93     }
94     return PostCommit();
95 }
96 
CompileForAppend(const FileInfo &fileInfo)97 uint32_t IResourceCompiler::CompileForAppend(const FileInfo &fileInfo)
98 {
99     return CompileSingleFile(fileInfo);
100 }
101 
GetResourceItems() const102 const map<pair<ResType, string>, vector<ResourceItem>> &IResourceCompiler::GetResourceItems() const
103 {
104     return nameInfos_;
105 }
106 
SetModuleName(const string &moduleName)107 void IResourceCompiler::SetModuleName(const string &moduleName)
108 {
109     moduleName_ = moduleName;
110 }
111 
CompileSingleFile(const FileInfo &fileInfo)112 uint32_t IResourceCompiler::CompileSingleFile(const FileInfo &fileInfo)
113 {
114     return RESTOOL_SUCCESS;
115 }
116 
PostCommit()117 uint32_t IResourceCompiler::PostCommit()
118 {
119     IdWorker &idWorker = IdWorker::GetInstance();
120     for (const auto &nameInfo : nameInfos_) {
121         int64_t id = idWorker.GenerateId(nameInfo.first.first, nameInfo.first.second);
122         if (id < 0) {
123             cerr << "Error: restype='" << ResourceUtil::ResTypeToString(nameInfo.first.first) << "' name='";
124             cerr << nameInfo.first.second << "' id not be defined." << endl;
125             return RESTOOL_ERROR;
126         }
127         resourceInfos_.emplace(id, nameInfo.second);
128     }
129     return RESTOOL_SUCCESS;
130 }
131 
MergeResourceItem(const ResourceItem &resourceItem)132 bool IResourceCompiler::MergeResourceItem(const ResourceItem &resourceItem)
133 {
134     string idName = ResourceUtil::GetIdName(resourceItem.GetName(), resourceItem.GetResType());
135     if (!ResourceUtil::IsValidName(idName)) {
136         cerr << "Error: invalid idName '" << idName << "'."<< NEW_LINE_PATH <<  resourceItem.GetFilePath() << endl;
137         cerr << SOLUTIONS << endl;
138         cerr << SOLUTIONS_ARROW << "Modify the name '" << idName << "' to match [a-zA-Z0-9_]." << endl;
139         return false;
140     }
141     auto item = nameInfos_.find(make_pair(resourceItem.GetResType(), idName));
142     if (item == nameInfos_.end()) {
143         nameInfos_[make_pair(resourceItem.GetResType(), idName)].push_back(resourceItem);
144         return true;
145     }
146 
147     auto ret = find_if(item->second.begin(), item->second.end(), [resourceItem](auto &iter) {
148         return resourceItem.GetLimitKey() == iter.GetLimitKey();
149     });
150     if (ret != item->second.end()) {
151         cerr << "Error: resource '" << idName << "' first declared." << NEW_LINE_PATH << ret->GetFilePath() << endl;
152         cerr << "but declare again." << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
153         return false;
154     }
155 
156     nameInfos_[make_pair(resourceItem.GetResType(), idName)].push_back(resourceItem);
157     return true;
158 }
159 
GetOutputFolder(const DirectoryInfo &directoryInfo) const160 string IResourceCompiler::GetOutputFolder(const DirectoryInfo &directoryInfo) const
161 {
162     string outputFolder = FileEntry::FilePath(output_).Append(RESOURCES_DIR)
163         .Append(directoryInfo.limitKey).Append(directoryInfo.fileCluster).GetPath();
164     return outputFolder;
165 }
166 }
167 }
168 }
169