1 /*
2  * Copyright (c) 2022 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 "print_utils.h"
17 
18 #include <chrono>
19 #include <cstdlib>
20 #include <ctime>
21 #include <fcntl.h>
22 #include <random>
23 #include <sstream>
24 #include "ability.h"
25 #include "print_util.h"
26 #include "securec.h"
27 
28 namespace OHOS::Print {
29 
30 using json = nlohmann::json;
31 
32 std::mutex PrintUtils::instanceLock_;
33 
34 static const std::string LAUNCH_PARAMETER_DOCUMENT_NAME = "documentName";
35 static const std::string LAUNCH_PARAMETER_PRINT_ATTRIBUTE = "printAttributes";
36 
37 static std::map<uint32_t, std::string> jobStateMap_;
38 const std::string GLOBAL_ID_DELIMITER = ":";
39 const std::string EXTENSION_CID_DELIMITER = ":";
40 const std::string TASK_EVENT_DELIMITER = "-";
41 const std::string USER_ID_DELIMITER = ":";
42 const int32_t DEFAULT_FD = 99;
43 const int32_t MINIMUN_RANDOM_NUMBER_100 = 100;
44 const int32_t MAXIMUN_RANDOM_NUMBER_999 = 999;
45 
ToLower(const std::string & s)46 std::string PrintUtils::ToLower(const std::string &s)
47 {
48     std::string res = s;
49     std::transform(res.begin(), res.end(), res.begin(), tolower);
50     return res;
51 }
52 
GetExtensionId(const std::string & globalId)53 std::string PrintUtils::GetExtensionId(const std::string &globalId)
54 {
55     auto pos = globalId.find(GLOBAL_ID_DELIMITER);
56     if (pos == std::string::npos) {
57         return "";
58     }
59     return globalId.substr(0, pos);
60 }
61 
GetGlobalId(const std::string & extensionId,const std::string & localId)62 std::string PrintUtils::GetGlobalId(const std::string& extensionId, const std::string& localId)
63 {
64     return extensionId + GLOBAL_ID_DELIMITER + localId;
65 }
66 
GetLocalId(const std::string & globalId,const std::string & extensionId)67 std::string PrintUtils::GetLocalId(const std::string& globalId, const std::string& extensionId)
68 {
69     auto pos = globalId.find(GLOBAL_ID_DELIMITER);
70     if (pos == std::string::npos) {
71         return "";
72     }
73 
74     if (globalId.substr(0, pos) != extensionId) {
75         return "";
76     }
77     return globalId.substr(pos + 1);
78 }
79 
EncodeExtensionCid(const std::string & extensionId,uint32_t callbackId)80 std::string PrintUtils::EncodeExtensionCid(const std::string &extensionId, uint32_t callbackId)
81 {
82     return extensionId + EXTENSION_CID_DELIMITER + std::to_string(callbackId);
83 }
84 
DecodeExtensionCid(const std::string & cid,std::string & extensionId,uint32_t & callbackId)85 bool PrintUtils::DecodeExtensionCid(const std::string &cid, std::string &extensionId, uint32_t &callbackId)
86 {
87     auto pos = cid.find(EXTENSION_CID_DELIMITER);
88     if (pos == std::string::npos) {
89         return false;
90     }
91     extensionId = cid.substr(0, pos);
92     int32_t callbackIdTmp = 0;
93     if (!PrintUtil::ConvertToInt(cid.substr(pos + 1), callbackIdTmp)) {
94         return false;
95     }
96     callbackId = static_cast<uint32_t>(callbackIdTmp);
97     return true;
98 }
99 
GetTaskEventId(const std::string & taskId,const std::string & type)100 std::string PrintUtils::GetTaskEventId(const std::string &taskId, const std::string &type)
101 {
102     return type + TASK_EVENT_DELIMITER + taskId;
103 }
104 
GetEventTypeWithToken(int32_t userId,int64_t pid,const std::string & type)105 std::string PrintUtils::GetEventTypeWithToken(int32_t userId, int64_t pid, const std::string &type)
106 {
107     std::string eventType =
108         std::to_string(userId) + USER_ID_DELIMITER + std::to_string(pid) + TASK_EVENT_DELIMITER + type;
109     PRINT_HILOGD("eventType: %{public}s", eventType.c_str());
110     return eventType;
111 }
112 
GetEventType(const std::string & type)113 std::string PrintUtils::GetEventType(const std::string &type)
114 {
115     auto pos = type.find(TASK_EVENT_DELIMITER);
116     if (pos == std::string::npos || pos + 1 >= type.length()) {
117         return type;
118     }
119     std::string eventType = type.substr(pos + 1);
120     PRINT_HILOGD("eventType: %{public}s", eventType.c_str());
121     return eventType;
122 }
123 
CheckUserIdInEventType(const std::string & type,int32_t callerUserId)124 bool PrintUtils::CheckUserIdInEventType(const std::string &type, int32_t callerUserId)
125 {
126     auto userIdPos = type.find(USER_ID_DELIMITER);
127     if (userIdPos == std::string::npos || userIdPos >= type.length()) {
128         return false;
129     }
130     std::string userIdStr = type.substr(0, userIdPos);
131     PRINT_HILOGD("userId: %{public}s", userIdStr.c_str());
132     if (userIdStr == std::to_string(callerUserId)) {
133         return true;
134     }
135     return false;
136 }
137 
OpenFile(const std::string & filePath)138 int32_t PrintUtils::OpenFile(const std::string &filePath)
139 {
140     if (filePath.find("content://") == 0) {
141         return DEFAULT_FD;
142     }
143     if (!IsPathValid(filePath)) {
144         return PRINT_INVALID_ID;
145     }
146     int32_t fd = open(filePath.c_str(), O_RDONLY);
147     PRINT_HILOGD("fd: %{public}d", fd);
148     if (fd < 0) {
149         PRINT_HILOGE("Failed to open file errno: %{public}s", std::to_string(errno).c_str());
150         close(fd);
151         return PRINT_INVALID_ID;
152     }
153     return fd;
154 }
155 
IsPathValid(const std::string & filePath)156 bool PrintUtils::IsPathValid(const std::string &filePath)
157 {
158     auto path = filePath.substr(0, filePath.rfind('/'));
159     char resolvedPath[PATH_MAX] = { 0 };
160     if (path.length() >= PATH_MAX || realpath(path.c_str(), resolvedPath) == nullptr ||
161         strncmp(resolvedPath, path.c_str(), path.length()) != 0) {
162         PRINT_HILOGE("invalid file path!");
163         return false;
164     }
165     return true;
166 }
167 
GetIdFromFdPath(const std::string & fdPath)168 uint32_t PrintUtils::GetIdFromFdPath(const std::string &fdPath)
169 {
170     std::string fd_str = fdPath.substr(fdPath.rfind('/') + 1, fdPath.length());
171     std::stringstream getStrStream(fd_str);
172     uint32_t fd = 0;
173     if (!(getStrStream >> fd)) {
174         PRINT_HILOGD("failed to convert to uint32");
175     }
176     return fd;
177 }
178 
GetJobStateChar(const uint32_t state)179 std::string PrintUtils::GetJobStateChar(const uint32_t state)
180 {
181     if (jobStateMap_.size() == 0) {
182         jobStateMap_[PRINT_JOB_PREPARED] = "PRINT_JOB_PREPARED";
183         jobStateMap_[PRINT_JOB_QUEUED] = "PRINT_JOB_QUEUED";
184         jobStateMap_[PRINT_JOB_RUNNING] = "PRINT_JOB_RUNNING";
185         jobStateMap_[PRINT_JOB_BLOCKED] = "PRINT_JOB_BLOCKED";
186         jobStateMap_[PRINT_JOB_COMPLETED] = "PRINT_JOB_COMPLETED";
187         jobStateMap_[PRINT_JOB_CREATE_FILE_COMPLETED] = "PRINT_JOB_CREATE_FILE_COMPLETED";
188         jobStateMap_[PRINT_JOB_UNKNOWN] = "PRINT_JOB_UNKNOWN";
189     }
190     auto it = jobStateMap_.find(state);
191     if (it != jobStateMap_.end()) {
192         return it -> second;
193     }
194     return "PRINT_JOB_UNKNOWN";
195 }
196 
BuildAdapterParam(const std::shared_ptr<AdapterParam> & adapterParam,AAFwk::Want & want)197 void PrintUtils::BuildAdapterParam(const std::shared_ptr<AdapterParam> &adapterParam, AAFwk::Want &want)
198 {
199     want.SetParam(LAUNCH_PARAMETER_DOCUMENT_NAME, adapterParam->documentName);
200     if (adapterParam->isCheckFdList) {
201         std::string defaultAttribute = "";
202         want.SetParam(LAUNCH_PARAMETER_PRINT_ATTRIBUTE, defaultAttribute);
203         return;
204     }
205     BuildPrintAttributesParam(adapterParam, want);
206 }
207 
BuildPrintAttributesParam(const std::shared_ptr<AdapterParam> & adapterParam,AAFwk::Want & want)208 void PrintUtils::BuildPrintAttributesParam(const std::shared_ptr<AdapterParam> &adapterParam, AAFwk::Want &want)
209 {
210     json attrJson;
211     PrintAttributes attrParam = adapterParam->printAttributes;
212     if (attrParam.HasCopyNumber()) {
213         attrJson["copyNumber"] = attrParam.GetCopyNumber();
214     }
215     if (attrParam.HasSequential()) {
216         attrJson["isSequential"] = attrParam.GetIsSequential();
217     }
218     if (attrParam.HasLandscape()) {
219         attrJson["isLandscape"] = attrParam.GetIsLandscape();
220     }
221     if (attrParam.HasDirectionMode()) {
222         attrJson["directionMode"] = attrParam.GetDirectionMode();
223     }
224     if (attrParam.HasColorMode()) {
225         attrJson["colorMode"] = attrParam.GetColorMode();
226     }
227     if (attrParam.HasDuplexMode()) {
228         attrJson["duplexMode"] = attrParam.GetDuplexMode();
229     }
230     ParseAttributesObjectParamForJson(attrParam, attrJson);
231     if (attrParam.HasOption()) {
232         attrJson["options"] = attrParam.GetOption();
233     }
234     want.SetParam(LAUNCH_PARAMETER_PRINT_ATTRIBUTE, attrJson.dump());
235     PRINT_HILOGD("CallSpooler set printAttributes: %{public}s", attrJson.dump().c_str());
236 }
237 
ParseAttributesObjectParamForJson(const PrintAttributes & attrParam,nlohmann::json & attrJson)238 void PrintUtils::ParseAttributesObjectParamForJson(const PrintAttributes &attrParam, nlohmann::json &attrJson)
239 {
240     if (attrParam.HasPageRange()) {
241         json pageRangeJson;
242         PrintRange printRangeAttr;
243         attrParam.GetPageRange(printRangeAttr);
244         if (printRangeAttr.HasStartPage()) {
245             pageRangeJson["startPage"] = printRangeAttr.GetStartPage();
246         }
247         if (printRangeAttr.HasEndPage()) {
248             pageRangeJson["endPage"] = printRangeAttr.GetEndPage();
249         }
250         if (printRangeAttr.HasPages()) {
251             std::vector<uint32_t> pages;
252             printRangeAttr.GetPages(pages);
253             pageRangeJson["pages"] = pages;
254         }
255         attrJson["pageRange"] = pageRangeJson;
256     }
257     if (attrParam.HasPageSize()) {
258         json pageSizeJson;
259         PrintPageSize pageSizeAttr;
260         attrParam.GetPageSize(pageSizeAttr);
261         pageSizeJson["id"] = pageSizeAttr.GetId();
262         pageSizeJson["name"] = pageSizeAttr.GetName();
263         pageSizeJson["width"] = pageSizeAttr.GetWidth();
264         pageSizeJson["height"] = pageSizeAttr.GetHeight();
265         attrJson["pageSize"] = pageSizeJson;
266     }
267     if (attrParam.HasMargin()) {
268         json marginJson;
269         PrintMargin marginAttr;
270         attrParam.GetMargin(marginAttr);
271         if (marginAttr.HasTop()) {
272             marginJson["top"] = marginAttr.GetTop();
273         }
274         if (marginAttr.HasBottom()) {
275             marginJson["bottom"] = marginAttr.GetBottom();
276         }
277         if (marginAttr.HasLeft()) {
278             marginJson["left"] = marginAttr.GetLeft();
279         }
280         if (marginAttr.HasRight()) {
281             marginJson["right"] = marginAttr.GetRight();
282         }
283         attrJson["margin"] = marginJson;
284     }
285 }
286 
GetBundleNameForUid(const int uid)287 std::string PrintUtils::GetBundleNameForUid(const int uid)
288 {
289     OHOS::AppExecFwk::BundleMgrClient bmsClient;
290     std::string bundleName = "";
291     auto ret = bmsClient.GetNameForUid(uid, bundleName);
292     if (ret != OHOS::ERR_OK || bundleName.empty()) {
293         PRINT_HILOGE("get bundleName failed.");
294     }
295     PRINT_HILOGI("bundleName: %{public}s", bundleName.c_str());
296     return bundleName;
297 }
298 
GetPrintJobId()299 std::string PrintUtils::GetPrintJobId()
300 {
301     std::lock_guard<std::mutex> autoLock(instanceLock_);
302     auto nowTime = std::chrono::system_clock::now();
303     auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime.time_since_epoch()).count();
304     std::stringstream ss;
305     ss << timestamp;
306 
307     std::random_device rd;
308     std::mt19937 gen(rd());
309     std::uniform_int_distribution<> dis(MINIMUN_RANDOM_NUMBER_100, MAXIMUN_RANDOM_NUMBER_999);
310     int32_t randomNumber = dis(gen);
311     std::string jobId = ss.str() + "_" + std::to_string(randomNumber);
312     PRINT_HILOGI("jobId: %{public}s", jobId.c_str());
313     return jobId;
314 }
315 }  // namespace OHOS::Print
316