1 /*
2 * Copyright (c) 2023 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 <vector>
17 #include <string>
18
19 #include "print_cups_attribute.h"
20 #include "print_service_converter.h"
21 #include "print_log.h"
22
23 namespace OHOS::Print {
24 template <typename T>
ParseAttributeToValue(ipp_t * response,const std::string & keyword,T & value,bool (* convertAttr)(const char * src,T & dst))25 bool ParseAttributeToValue(ipp_t *response, const std::string &keyword, T &value,
26 bool (*convertAttr)(const char *src, T &dst))
27 {
28 if (convertAttr == nullptr) {
29 PRINT_HILOGW("convertAttr is null");
30 return false;
31 }
32 ipp_attribute_t *attrPtr = ippFindAttribute(response, keyword.c_str(), IPP_TAG_KEYWORD);
33 if (attrPtr == nullptr) {
34 PRINT_HILOGW("attrPtr is null");
35 return false;
36 }
37 const char *attrString = ippGetString(attrPtr, 0, NULL);
38 if (attrString == nullptr) {
39 PRINT_HILOGW("attrString is null");
40 return false;
41 }
42 PRINT_HILOGD("attrString: %{public}s", attrString);
43 if (!convertAttr(attrString, value)) {
44 PRINT_HILOGW("ConvertFunction fail");
45 return false;
46 }
47 return true;
48 }
49
50 template <typename T>
ParseAttributesToList(ipp_t * response,const std::string & keyword,std::vector<T> & list,bool (* convertAttr)(const char * src,T & dst))51 bool ParseAttributesToList(ipp_t *response, const std::string &keyword, std::vector<T> &list,
52 bool (*convertAttr)(const char *src, T &dst))
53 {
54 if (convertAttr == nullptr) {
55 PRINT_HILOGW("convertAttr is null");
56 return false;
57 }
58 ipp_attribute_t *attrPtr = ippFindAttribute(response, keyword.c_str(), IPP_TAG_KEYWORD);
59 if (attrPtr == nullptr) {
60 PRINT_HILOGW("attrPtr is null");
61 return false;
62 }
63 int num = ippGetCount(attrPtr);
64 PRINT_HILOGD("number of values %{public}d", num);
65 for (int i = 0; i < num; i++) {
66 const char *attrString = ippGetString(attrPtr, i, NULL);
67 if (attrString == nullptr) {
68 PRINT_HILOGW("attrString is null");
69 continue;
70 }
71 PRINT_HILOGD("attrString: %{public}s", attrString);
72 T attrValue;
73 if (!convertAttr(attrString, attrValue)) {
74 PRINT_HILOGW("ConvertFunction fail");
75 continue;
76 }
77 AddToUniqueList<T>(list, attrValue);
78 }
79 return true;
80 }
81
ConvertDuplexModeCode(const char * src,DuplexModeCode & dst)82 bool ConvertDuplexModeCode(const char *src, DuplexModeCode &dst)
83 {
84 if (src == nullptr) {
85 return false;
86 }
87 if (strcasestr(src, CUPS_SIDES_ONE_SIDED)) {
88 dst = DUPLEX_MODE_ONE_SIDED;
89 } else if (strcasestr(src, CUPS_SIDES_TWO_SIDED_PORTRAIT)) {
90 dst = DUPLEX_MODE_TWO_SIDED_LONG_EDGE;
91 } else if (strcasestr(src, CUPS_SIDES_TWO_SIDED_LANDSCAPE)) {
92 dst = DUPLEX_MODE_TWO_SIDED_SHORT_EDGE;
93 } else {
94 return false;
95 }
96 return true;
97 }
98
ConvertIppAttributesToJsonString(ipp_t * response,const std::string & keyword,ipp_tag_t tag)99 std::string ConvertIppAttributesToJsonString(ipp_t *response, const std::string &keyword, ipp_tag_t tag)
100 {
101 ipp_attribute_t *attrPtr = ippFindAttribute(response, keyword.c_str(), tag);
102 if (attrPtr == nullptr) {
103 return "";
104 }
105 nlohmann::json jsonArray = nlohmann::json::array();
106 for (int i = 0; i < ippGetCount(attrPtr); i++) {
107 const char *attrString = ippGetString(attrPtr, i, NULL);
108 if (attrString == nullptr) {
109 continue;
110 }
111 jsonArray.push_back(attrString);
112 }
113 return jsonArray.dump();
114 }
115
SetCapabilityGroupAttribute(ipp_t * response,PrinterCapability & printerCaps)116 void SetCapabilityGroupAttribute(ipp_t *response, PrinterCapability &printerCaps)
117 {
118 ipp_attribute_t *attrPtr;
119 if ((attrPtr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
120 printerCaps.SetPrinterAttrNameAndValue("printer-state",
121 ippEnumString("printer-state", ippGetInteger(attrPtr, 0)));
122 }
123 if ((attrPtr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXTLANG)) != NULL) {
124 printerCaps.SetPrinterAttrNameAndValue("printer-info", ippGetString(attrPtr, 0, NULL));
125 }
126 if ((attrPtr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL) {
127 printerCaps.SetPrinterAttrNameAndValue("printer-location", ippGetString(attrPtr, 0, NULL));
128 }
129 }
130
ParseDuplexModeAttributes(ipp_t * response,PrinterCapability & printerCaps)131 void ParseDuplexModeAttributes(ipp_t *response, PrinterCapability &printerCaps)
132 {
133 std::string keyword = "sides-supported";
134 std::vector<DuplexModeCode> list;
135 ParseAttributesToList(response, keyword, list, ConvertDuplexModeCode);
136 std::string duplexModeJson = ConvertListToJson<DuplexModeCode>(list, ConvertDuplexModeToJson);
137 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), duplexModeJson.c_str());
138 size_t num = list.size();
139 if (static_cast<int>(num) <= 1) {
140 printerCaps.SetDuplexMode((uint32_t)DUPLEX_MODE_ONE_SIDED);
141 } else {
142 printerCaps.SetDuplexMode((uint32_t)DUPLEX_MODE_TWO_SIDED_LONG_EDGE);
143 }
144
145 keyword = "sides-default";
146 DuplexModeCode code;
147 if (ParseAttributeToValue<DuplexModeCode>(response, keyword, code, ConvertDuplexModeCode)) {
148 uint32_t value = static_cast<uint32_t>(code);
149 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), std::to_string(value).c_str());
150 }
151 }
152
ParseColorModeAttributes(ipp_t * response,PrinterCapability & printerCaps)153 void ParseColorModeAttributes(ipp_t *response, PrinterCapability &printerCaps)
154 {
155 std::string keyword = "print-color-mode-supported";
156 std::vector<ColorModeCode> supportedColorModes;
157 ParseAttributesToList<ColorModeCode>(response, keyword, supportedColorModes, ConvertColorModeCode);
158 std::string colorModeJson = ConvertListToJson<ColorModeCode>(supportedColorModes, ConvertColorModeToJson);
159 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), colorModeJson.c_str());
160
161 keyword = "print-color-mode-default";
162 ColorModeCode code;
163 if (ParseAttributeToValue<ColorModeCode>(response, keyword, code, ConvertColorModeCode)) {
164 uint32_t mode = static_cast<uint32_t>(code);
165 printerCaps.SetPrinterAttrNameAndValue("defaultColorMode", std::to_string(mode).c_str());
166 }
167 for (auto& color : supportedColorModes) {
168 if (color == ColorModeCode::COLOR_MODE_COLOR) {
169 printerCaps.SetColorMode(ColorModeCode::COLOR_MODE_COLOR);
170 break;
171 }
172 }
173 }
174
ParsePageSizeAttributes(ipp_t * response,PrinterCapability & printerCaps)175 void ParsePageSizeAttributes(ipp_t *response, PrinterCapability &printerCaps)
176 {
177 std::string keyword = "media-supported";
178 std::vector<PrintPageSize> supportedPageSizes;
179 ParseAttributesToList<PrintPageSize>(response, keyword, supportedPageSizes, ConvertPrintPageSize);
180 std::string pageSizeJson = ConvertListToJson<PrintPageSize>(supportedPageSizes, ConvertPageSizeToJson);
181 printerCaps.SetPageSize(supportedPageSizes);
182 printerCaps.SetPrinterAttrNameAndValue("supportedPageSizeArray", pageSizeJson.c_str());
183
184 std::string defaultPageSizeId;
185 keyword = "media-default";
186 if (ParseAttributeToValue<std::string>(response, keyword, defaultPageSizeId, ConvertPageSizeId)) {
187 printerCaps.SetPrinterAttrNameAndValue("defaultPageSizeId", defaultPageSizeId.c_str());
188 }
189 }
190
ParseQualityAttributes(ipp_t * response,PrinterCapability & printerCaps)191 void ParseQualityAttributes(ipp_t *response, PrinterCapability &printerCaps)
192 {
193 std::string keyword = "print-quality-supported";
194 ipp_attribute_t *attrPtr = ippFindAttribute(response, keyword.c_str(), IPP_TAG_ENUM);
195 if (attrPtr == nullptr) {
196 PRINT_HILOGW("%{public}s missing", keyword.c_str());
197 return;
198 }
199 nlohmann::json supportedQualities = nlohmann::json::array();
200 for (int i = 0; i < ippGetCount(attrPtr); i++) {
201 nlohmann::json jsonObject;
202 jsonObject["quality"] = ippGetInteger(attrPtr, i);
203 supportedQualities.push_back(jsonObject);
204 }
205 std::string attrString = supportedQualities.dump();
206 PRINT_HILOGD("%{public}s: %{public}s", keyword.c_str(), attrString.c_str());
207 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), attrString.c_str());
208 }
209
ParseCopiesAttributes(ipp_t * response,PrinterCapability & printerCaps)210 void ParseCopiesAttributes(ipp_t *response, PrinterCapability &printerCaps)
211 {
212 ipp_attribute_t *attrPtr = ippFindAttribute(response, "copies-supported", IPP_TAG_RANGE);
213 if (attrPtr != nullptr) {
214 int upper = 0;
215 for (int i = 0; i < ippGetCount(attrPtr); i++) {
216 ippGetRange(attrPtr, i, &upper);
217 }
218 printerCaps.SetPrinterAttrNameAndValue("copies-supported", std::to_string(upper).c_str());
219 }
220 attrPtr = ippFindAttribute(response, "copies-default", IPP_TAG_INTEGER);
221 if (attrPtr != nullptr) {
222 printerCaps.SetPrinterAttrNameAndValue("copies-default", std::to_string(ippGetInteger(attrPtr, 0)).c_str());
223 }
224 }
225
ParseSupportedResolutionAttribute(ipp_t * response,PrinterCapability & printerCaps)226 void ParseSupportedResolutionAttribute(ipp_t *response, PrinterCapability &printerCaps)
227 {
228 std::string keyword = "printer-resolution-supported";
229 ipp_attribute_t *attrPtr = ippFindAttribute(response, keyword.c_str(), IPP_TAG_RESOLUTION);
230 if (attrPtr == nullptr) {
231 PRINT_HILOGW("attrPtr is null");
232 return;
233 }
234 int num = ippGetCount(attrPtr);
235 PRINT_HILOGD("number of values %{public}d", num);
236 nlohmann::json resolutionArray = nlohmann::json::array();
237 for (int i = 0; i < num; i++) {
238 ipp_res_t units = IPP_RES_PER_INCH;
239 int xres = 0;
240 int yres = 0;
241 xres = ippGetResolution(attrPtr, i, &yres, &units);
242 if (xres == 0 || yres == 0) {
243 continue;
244 }
245 if (units == IPP_RES_PER_CM) {
246 xres = DpcToDpi(xres);
247 yres = DpcToDpi(yres);
248 } else if (units != IPP_RES_PER_INCH) {
249 PRINT_HILOGW("unknown dpi unit: %{public}d", static_cast<int>(units));
250 continue;
251 }
252 nlohmann::json object;
253 object["horizontalDpi"] = xres;
254 object["verticalDpi"] = yres;
255 resolutionArray.push_back(object);
256 }
257 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), resolutionArray.dump().c_str());
258 }
259
ParseDefaultResolutionAttribute(ipp_t * response,PrinterCapability & printerCaps)260 void ParseDefaultResolutionAttribute(ipp_t *response, PrinterCapability &printerCaps)
261 {
262 std::string keyword = "printer-resolution-default";
263 ipp_attribute_t *attrPtr = ippFindAttribute(response, keyword.c_str(), IPP_TAG_RESOLUTION);
264 if (attrPtr == nullptr) {
265 PRINT_HILOGW("attrPtr is null");
266 return;
267 }
268 int num = ippGetCount(attrPtr);
269 PRINT_HILOGD("number of values %{public}d", num);
270 for (int i = 0; i < num; i++) {
271 ipp_res_t units = IPP_RES_PER_INCH;
272 int xres = 0;
273 int yres = 0;
274 xres = ippGetResolution(attrPtr, i, &yres, &units);
275 if (xres == 0 || yres == 0) {
276 continue;
277 }
278 if (units == IPP_RES_PER_CM) {
279 xres = DpcToDpi(xres);
280 yres = DpcToDpi(yres);
281 } else if (units != IPP_RES_PER_INCH) {
282 PRINT_HILOGW("unknown dpi unit: %{public}d", static_cast<int>(units));
283 continue;
284 }
285 nlohmann::json object;
286 object["horizontalDpi"] = xres;
287 object["verticalDpi"] = yres;
288 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), object.dump().c_str());
289 break;
290 }
291 }
292
ParseMediaColDefaultAttributes(ipp_t * response,PrinterCapability & printerCaps)293 void ParseMediaColDefaultAttributes(ipp_t *response, PrinterCapability &printerCaps)
294 {
295 ipp_attribute_t *defaultMediaPtr = ippFindAttribute(response, "media-col-default", IPP_TAG_BEGIN_COLLECTION);
296 if (defaultMediaPtr == nullptr) {
297 PRINT_HILOGW("media-col-default missing");
298 return;
299 }
300 ipp_t *defaultMediaCol = defaultMediaPtr->values[0].collection;
301 std::vector<std::string> keywordList;
302 keywordList.push_back("media-top-margin");
303 keywordList.push_back("media-bottom-margin");
304 keywordList.push_back("media-left-margin");
305 keywordList.push_back("media-right-margin");
306 for (auto &keyword : keywordList) {
307 ipp_attribute_t *attrPtr = ippFindAttribute(defaultMediaCol, keyword.c_str(), IPP_TAG_INTEGER);
308 if (attrPtr != nullptr) {
309 int value = ippGetInteger(attrPtr, 0);
310 PRINT_HILOGD("%{public}s found: %{public}d", keyword.c_str(), value);
311 std::string defaultKeyword = keyword + "-default";
312 printerCaps.SetPrinterAttrNameAndValue(defaultKeyword.c_str(), std::to_string(value).c_str());
313 }
314 }
315 ipp_attribute_t *attrPtr = ippFindAttribute(defaultMediaCol, "duplex-supported", IPP_TAG_BOOLEAN);
316 if (attrPtr != nullptr) {
317 PRINT_HILOGD("duplex-supported found: %{public}d", ippGetBoolean(attrPtr, 0));
318 }
319 attrPtr = ippFindAttribute(defaultMediaCol, "media-source", IPP_TAG_KEYWORD);
320 if (attrPtr != nullptr) {
321 PRINT_HILOGD("media-source-default found: %{public}s", ippGetString(attrPtr, 0, NULL));
322 printerCaps.SetPrinterAttrNameAndValue("media-source-default", ippGetString(attrPtr, 0, NULL));
323 }
324 attrPtr = ippFindAttribute(defaultMediaCol, "media-type", IPP_TAG_KEYWORD);
325 if (attrPtr != nullptr) {
326 PRINT_HILOGD("media-type-default found: %{public}s", ippGetString(attrPtr, 0, NULL));
327 printerCaps.SetPrinterAttrNameAndValue("media-type-default", ippGetString(attrPtr, 0, NULL));
328 }
329 }
330
ParseMediaMarginAttributes(ipp_t * response,PrinterCapability & printerCaps)331 void ParseMediaMarginAttributes(ipp_t *response, PrinterCapability &printerCaps)
332 {
333 ipp_attribute_t *attrPtr;
334 if ((attrPtr = ippFindAttribute(response, "media-bottom-margin-supported", IPP_TAG_INTEGER)) != NULL) {
335 printerCaps.SetPrinterAttrNameAndValue("media-bottom-margin-supported",
336 std::to_string(ippGetInteger(attrPtr, 0)).c_str());
337 }
338 if ((attrPtr = ippFindAttribute(response, "media-top-margin-supported", IPP_TAG_INTEGER)) != NULL) {
339 printerCaps.SetPrinterAttrNameAndValue("media-top-margin-supported",
340 std::to_string(ippGetInteger(attrPtr, 0)).c_str());
341 }
342 if ((attrPtr = ippFindAttribute(response, "media-left-margin-supported", IPP_TAG_INTEGER)) != NULL) {
343 printerCaps.SetPrinterAttrNameAndValue("media-left-margin-supported",
344 std::to_string(ippGetInteger(attrPtr, 0)).c_str());
345 }
346 if ((attrPtr = ippFindAttribute(response, "media-right-margin-supported", IPP_TAG_INTEGER)) != NULL) {
347 printerCaps.SetPrinterAttrNameAndValue("media-right-margin-supported",
348 std::to_string(ippGetInteger(attrPtr, 0)).c_str());
349 }
350 }
351
ParseOrientationAttributes(ipp_t * response,PrinterCapability & printerCaps)352 void ParseOrientationAttributes(ipp_t *response, PrinterCapability &printerCaps)
353 {
354 std::string keyword = "orientation-requested-default";
355 ipp_attribute_t *attrPtr = ippFindAttribute(response, keyword.c_str(), IPP_TAG_ENUM);
356 if (attrPtr != NULL) {
357 int orientationEnum = ippGetInteger(attrPtr, 0);
358 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), std::to_string(orientationEnum).c_str());
359 PRINT_HILOGD("orientation-default found: %{public}d", orientationEnum);
360 }
361 keyword = "orientation-requested-supported";
362 attrPtr = ippFindAttribute(response, keyword.c_str(), IPP_TAG_ENUM);
363 if (attrPtr != NULL) {
364 int num = ippGetCount(attrPtr);
365 if (num > 0) {
366 nlohmann::json supportedOrientationArray = nlohmann::json::array();
367 for (int i = 0; i < ippGetCount(attrPtr); i++) {
368 int orientationEnum = ippGetInteger(attrPtr, i);
369 supportedOrientationArray.push_back(orientationEnum);
370 PRINT_HILOGD("orientation-supported found: %{public}d", orientationEnum);
371 }
372 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), supportedOrientationArray.dump().c_str());
373 }
374 }
375 }
376
ParseOtherAttributes(ipp_t * response,PrinterCapability & printerCaps)377 void ParseOtherAttributes(ipp_t *response, PrinterCapability &printerCaps)
378 {
379 std::string keyword = "media-source-supported";
380 std::string attrString = ConvertIppAttributesToJsonString(response, keyword, IPP_TAG_KEYWORD);
381 PRINT_HILOGD("%{public}s: %{public}s", keyword.c_str(), attrString.c_str());
382 if (!attrString.empty()) {
383 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), attrString.c_str());
384 }
385
386 keyword = "multiple-document-handling-supported";
387 attrString = ConvertIppAttributesToJsonString(response, keyword, IPP_TAG_KEYWORD);
388 PRINT_HILOGD("%{public}s: %{public}s", keyword.c_str(), attrString.c_str());
389 if (!attrString.empty()) {
390 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), attrString.c_str());
391 }
392 }
393
SetOptionAttribute(ipp_t * response,PrinterCapability & printerCaps)394 void SetOptionAttribute(ipp_t *response, PrinterCapability &printerCaps)
395 {
396 ipp_attribute_t *attrPtr;
397 nlohmann::json options;
398 if ((attrPtr = ippFindAttribute(response, "printer-make-and-model", IPP_TAG_TEXT)) != NULL) {
399 options["make"] = ippGetString(attrPtr, 0, NULL);
400 }
401 if ((attrPtr = ippFindAttribute(response, "printer-uuid", IPP_TAG_URI)) != NULL) {
402 options["uuid"] = ippGetString(attrPtr, 0, NULL);
403 }
404 if ((attrPtr = ippFindAttribute(response, "printer-name", IPP_TAG_TEXT)) != NULL) {
405 options["printerName"] = ippGetString(attrPtr, 0, NULL);
406 }
407 std::string keyword = "media-type-supported";
408 std::string supportTypes = ConvertIppAttributesToJsonString(response, keyword, IPP_TAG_ZERO);
409 PRINT_HILOGD("%{public}s: %{public}s", keyword.c_str(), supportTypes.c_str());
410 if (!supportTypes.empty()) {
411 printerCaps.SetPrinterAttrNameAndValue(keyword.c_str(), supportTypes.c_str());
412 }
413
414 nlohmann::json cupsOptionsJson = printerCaps.GetPrinterAttrGroupJson();
415 options["cupsOptions"] = cupsOptionsJson;
416
417 std::string optionStr = options.dump();
418 PRINT_HILOGD("SetOption: %{public}s", optionStr.c_str());
419 printerCaps.SetOption(optionStr);
420 }
421
ParsePrinterAttributes(ipp_t * response,PrinterCapability & printerCaps)422 void ParsePrinterAttributes(ipp_t *response, PrinterCapability &printerCaps)
423 {
424 SetCapabilityGroupAttribute(response, printerCaps);
425 ParseColorModeAttributes(response, printerCaps);
426 ParseDuplexModeAttributes(response, printerCaps);
427 ParsePageSizeAttributes(response, printerCaps);
428 ParseQualityAttributes(response, printerCaps);
429 ParseSupportedResolutionAttribute(response, printerCaps);
430 ParseDefaultResolutionAttribute(response, printerCaps);
431 ParseMediaColDefaultAttributes(response, printerCaps);
432 ParseMediaMarginAttributes(response, printerCaps);
433 ParseOrientationAttributes(response, printerCaps);
434 ParseCopiesAttributes(response, printerCaps);
435 ParseOtherAttributes(response, printerCaps);
436 SetOptionAttribute(response, printerCaps);
437 }
438 } // namespace OHOS::Print