xmllite/writer: Implement WriteNodeShallow().
[wine.git] / dlls / prntvpt / ticket.c
bloba8c5134e1ecd3d9b5e5f6624bf127c6b1d4533cb
1 /*
2 * Copyright 2019 Dmitry Timoshkov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #define COBJMACROS
22 #define NONAMELESSSTRUCT
23 #define NONAMELESSUNION
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winspool.h"
29 #include "objbase.h"
30 #include "prntvpt.h"
31 #include "initguid.h"
32 #include "msxml2.h"
33 #include "wine/debug.h"
35 #include "prntvpt_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(prntvpt);
39 struct size
41 int width;
42 int height;
45 struct media
47 int paper;
48 struct size size;
51 struct resolution
53 int x;
54 int y;
57 struct page
59 struct media media;
60 struct resolution resolution;
61 int orientation;
62 int scaling;
63 int color;
66 struct document
68 int collate;
71 struct job
73 int nup;
74 int copies;
75 int input_bin;
78 struct ticket
80 struct job job;
81 struct document document;
82 struct page page;
85 static const struct
87 const WCHAR *name;
88 int paper;
89 } psk_media[] =
91 { L"psk:ISOA4", DMPAPER_A4 },
94 static int media_to_paper(const WCHAR *name)
96 int i;
98 for (i = 0 ; i < ARRAY_SIZE(psk_media); i++)
99 if (!wcscmp(name, psk_media[i].name))
100 return psk_media[i].paper;
102 FIXME("%s\n", wine_dbgstr_w(name));
103 return DMPAPER_A4;
106 static const WCHAR *paper_to_media(int paper)
108 int i;
110 for (i = 0 ; i < ARRAY_SIZE(psk_media); i++)
111 if (psk_media[i].paper == paper)
112 return psk_media[i].name;
114 FIXME("%d\n", paper);
115 return psk_media[0].name;
118 static BOOL is_valid_node_name(const WCHAR *name)
120 static const WCHAR * const psf_names[] = { L"psf:ParameterInit", L"psf:Feature" };
121 int i;
123 for (i = 0 ; i < ARRAY_SIZE(psf_names); i++)
124 if (!wcscmp(name, psf_names[i])) return TRUE;
126 return FALSE;
129 static HRESULT verify_ticket(IXMLDOMDocument2 *doc)
131 IXMLDOMElement *element;
132 IXMLDOMNode *node = NULL;
133 BSTR str;
134 HRESULT hr;
136 hr = IXMLDOMDocument2_get_documentElement(doc, &element);
137 if (hr != S_OK) return E_PRINTTICKET_FORMAT;
139 hr = IXMLDOMElement_get_tagName(element, &str);
140 if (hr != S_OK) goto fail;
141 if (wcscmp(str, L"psf:PrintTicket") != 0)
142 hr = E_FAIL;
143 SysFreeString(str);
144 if (hr != S_OK) goto fail;
146 hr = IXMLDOMElement_get_firstChild(element, &node);
147 IXMLDOMElement_Release(element);
148 if (hr != S_OK) return S_OK;
150 for (;;)
152 VARIANT var;
153 IXMLDOMNode *next_node;
155 hr = IXMLDOMNode_get_nodeName(node, &str);
156 if (hr != S_OK) break;
157 if (!is_valid_node_name(str))
158 hr = E_FAIL;
159 SysFreeString(str);
160 if (hr != S_OK) break;
162 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void **)&element);
163 if (hr != S_OK) break;
165 VariantInit(&var);
166 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
167 IXMLDOMElement_Release(element);
168 if (hr != S_OK) break;
169 if (V_VT(&var) != VT_BSTR)
170 hr = E_FAIL;
171 VariantClear(&var);
172 if (hr != S_OK) break;
174 hr = IXMLDOMNode_get_nextSibling(node, &next_node);
175 if (hr != S_OK)
177 hr = S_OK;
178 break;
181 IXMLDOMNode_Release(node);
182 node = next_node;
185 fail:
186 if (node) IXMLDOMNode_Release(node);
188 return hr != S_OK ? E_PRINTTICKET_FORMAT : S_OK;
191 static HRESULT read_int_value(IXMLDOMNode *node, int *value)
193 IXMLDOMNode *val;
194 HRESULT hr;
195 VARIANT var1, var2;
197 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Value[@xsi:type='xsd:integer']", &val);
198 if (hr != S_OK) return hr;
200 VariantInit(&var1);
201 hr = IXMLDOMNode_get_nodeTypedValue(val, &var1);
202 if (hr == S_OK)
204 VariantInit(&var2);
205 hr = VariantChangeTypeEx(&var2, &var1, 0, 0, VT_I4);
206 if (hr == S_OK)
207 *value = V_I4(&var2);
209 VariantClear(&var1);
212 IXMLDOMNode_Release(val);
213 return hr;
216 static void read_PageMediaSize(IXMLDOMDocument2 *doc, struct ticket *ticket)
218 IXMLDOMNode *node, *option, *child;
219 HRESULT hr;
221 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageMediaSize']", &node);
222 if (hr != S_OK) return;
224 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
225 if (hr == S_OK)
227 IXMLDOMElement *element;
229 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
230 if (hr == S_OK)
232 VARIANT var;
234 VariantInit(&var);
235 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
236 if (hr == S_OK && V_VT(&var) == VT_BSTR)
238 ticket->page.media.paper = media_to_paper(V_BSTR(&var));
239 TRACE("paper: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.media.paper);
241 VariantClear(&var);
243 IXMLDOMElement_Release(element);
246 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:MediaSizeWidth']", &child);
247 if (hr == S_OK)
249 if (read_int_value(child, &ticket->page.media.size.width) == S_OK)
250 TRACE("width: %d\n", ticket->page.media.size.width);
251 IXMLDOMNode_Release(child);
254 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:MediaSizeHeight']", &child);
255 if (hr == S_OK)
257 if (read_int_value(child, &ticket->page.media.size.height) == S_OK)
258 TRACE("height: %d\n", ticket->page.media.size.height);
259 IXMLDOMNode_Release(child);
262 IXMLDOMNode_Release(option);
265 IXMLDOMNode_Release(node);
268 static void read_PageOutputColor(IXMLDOMDocument2 *doc, struct ticket *ticket)
270 IXMLDOMNode *node, *option;
271 HRESULT hr;
273 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageOutputColor']", &node);
274 if (hr != S_OK) return;
276 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
277 if (hr == S_OK)
279 IXMLDOMElement *element;
281 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
282 if (hr == S_OK)
284 VARIANT var;
286 VariantInit(&var);
287 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
288 if (hr == S_OK && V_VT(&var) == VT_BSTR)
290 if (!wcscmp(V_BSTR(&var), L"psk:Color"))
291 ticket->page.color = DMCOLOR_COLOR;
292 else if (!wcscmp(V_BSTR(&var), L"psk:Monochrome"))
293 ticket->page.color = DMCOLOR_MONOCHROME;
294 else
296 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
297 ticket->page.color = DMCOLOR_MONOCHROME;
299 TRACE("color: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.color);
301 VariantClear(&var);
303 IXMLDOMElement_Release(element);
307 IXMLDOMNode_Release(node);
310 static void read_PageScaling(IXMLDOMDocument2 *doc, struct ticket *ticket)
312 IXMLDOMNode *node, *option;
313 int scaling = 0;
314 HRESULT hr;
316 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageScaling']", &node);
317 if (hr != S_OK) return;
319 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
320 if (hr == S_OK)
322 IXMLDOMElement *element;
324 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
325 if (hr == S_OK)
327 VARIANT var;
329 VariantInit(&var);
330 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
331 if (hr == S_OK && V_VT(&var) == VT_BSTR)
333 if (!wcscmp(V_BSTR(&var), L"psk:None"))
334 scaling = 100;
335 else if (!wcscmp(V_BSTR(&var), L"psk:CustomSquare"))
336 scaling = 0; /* psk:PageScalingScale */
337 else
338 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
340 VariantClear(&var);
342 IXMLDOMElement_Release(element);
346 IXMLDOMNode_Release(node);
348 if (!scaling)
350 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:ParameterInit[@name='psk:PageScalingScale']", &node);
351 if (hr == S_OK)
353 read_int_value(node, &scaling);
354 IXMLDOMNode_Release(node);
358 if (scaling)
359 ticket->page.scaling = scaling;
360 else
361 ticket->page.scaling = 100;
363 TRACE("page.scaling: %d\n", ticket->page.scaling);
366 static void read_PageResolution(IXMLDOMDocument2 *doc, struct ticket *ticket)
368 IXMLDOMNode *node, *option, *child;
369 HRESULT hr;
371 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageResolution']", &node);
372 if (hr != S_OK) return;
374 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
375 if (hr == S_OK)
377 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:ResolutionX']", &child);
378 if (hr == S_OK)
380 if (read_int_value(child, &ticket->page.resolution.x) == S_OK)
381 TRACE("resolution.x: %d\n", ticket->page.resolution.x);
382 IXMLDOMNode_Release(child);
385 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:ResolutionY']", &child);
386 if (hr == S_OK)
388 if (read_int_value(child, &ticket->page.resolution.y) == S_OK)
389 TRACE("resolution.y: %d\n", ticket->page.resolution.y);
390 IXMLDOMNode_Release(child);
393 IXMLDOMNode_Release(option);
396 IXMLDOMNode_Release(node);
399 static void read_PageOrientation(IXMLDOMDocument2 *doc, struct ticket *ticket)
401 IXMLDOMNode *node, *option;
402 HRESULT hr;
404 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageOrientation']", &node);
405 if (hr != S_OK) return;
407 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
408 if (hr == S_OK)
410 IXMLDOMElement *element;
412 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
413 if (hr == S_OK)
415 VARIANT var;
417 VariantInit(&var);
418 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
419 if (hr == S_OK && V_VT(&var) == VT_BSTR)
421 if (!wcscmp(V_BSTR(&var), L"psk:Portrait"))
422 ticket->page.orientation = DMORIENT_PORTRAIT;
423 else if (!wcscmp(V_BSTR(&var), L"psk:Landscape"))
424 ticket->page.orientation = DMORIENT_LANDSCAPE;
425 else
427 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
428 ticket->page.orientation = DMORIENT_PORTRAIT;
430 TRACE("orientation: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.orientation);
432 VariantClear(&var);
434 IXMLDOMElement_Release(element);
438 IXMLDOMNode_Release(node);
441 static void read_DocumentCollate(IXMLDOMDocument2 *doc, struct ticket *ticket)
443 IXMLDOMNode *node, *option;
444 HRESULT hr;
446 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:DocumentCollate']", &node);
447 if (hr != S_OK) return;
449 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
450 if (hr == S_OK)
452 IXMLDOMElement *element;
454 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
455 if (hr == S_OK)
457 VARIANT var;
459 VariantInit(&var);
460 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
461 if (hr == S_OK && V_VT(&var) == VT_BSTR)
463 if (!wcscmp(V_BSTR(&var), L"psk:Collated"))
464 ticket->document.collate = DMCOLLATE_TRUE;
465 else if (!wcscmp(V_BSTR(&var), L"psk:Uncollated"))
466 ticket->document.collate = DMCOLLATE_FALSE;
467 else
469 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
470 ticket->document.collate = DMCOLLATE_FALSE;
472 TRACE("document.collate: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->document.collate);
474 VariantClear(&var);
476 IXMLDOMElement_Release(element);
480 IXMLDOMNode_Release(node);
483 static void read_JobInputBin(IXMLDOMDocument2 *doc, struct ticket *ticket)
485 IXMLDOMNode *node, *option;
486 HRESULT hr;
488 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:JobInputBin']", &node);
489 if (hr != S_OK) return;
491 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
492 if (hr == S_OK)
494 IXMLDOMElement *element;
496 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
497 if (hr == S_OK)
499 VARIANT var;
501 VariantInit(&var);
502 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
503 if (hr == S_OK && V_VT(&var) == VT_BSTR)
505 if (!wcscmp(V_BSTR(&var), L"psk:AutoSelect"))
506 ticket->job.input_bin = DMBIN_AUTO;
507 else
509 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
510 ticket->job.input_bin = DMBIN_AUTO;
512 TRACE("input_bin: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->job.input_bin);
514 VariantClear(&var);
516 IXMLDOMElement_Release(element);
520 IXMLDOMNode_Release(node);
523 static void read_JobCopies(IXMLDOMDocument2 *doc, struct ticket *ticket)
525 IXMLDOMNode *node;
526 HRESULT hr;
528 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:ParameterInit[@name='psk:JobCopiesAllDocuments']", &node);
529 if (hr != S_OK) return;
531 if (read_int_value(node, &ticket->job.copies) == S_OK)
532 TRACE("job.copies: %d\n", ticket->job.copies);
534 IXMLDOMNode_Release(node);
537 static void set_SelectionNamespaces(IXMLDOMDocument2 *doc)
539 IStream *stream;
540 IXMLDOMElement *element = NULL;
541 IXMLDOMNamedNodeMap *map = NULL;
542 HRESULT hr;
543 LONG count, i;
544 HGLOBAL hmem;
545 BSTR str;
546 VARIANT var;
548 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
549 if (hr != S_OK) return;
551 hr = IXMLDOMDocument2_get_documentElement(doc, &element);
552 if (hr != S_OK) goto fail;
554 hr = IXMLDOMElement_get_attributes(element, &map);
555 if (hr != S_OK) goto fail;
557 hr = IXMLDOMNamedNodeMap_get_length(map, &count);
558 if (hr != S_OK) goto fail;
560 for (i = 0; i < count; i++)
562 IXMLDOMNode *node;
564 hr = IXMLDOMNamedNodeMap_get_item(map, i, &node);
565 if (hr == S_OK)
567 hr = IXMLDOMNode_get_nodeName(node, &str);
568 if (hr == S_OK)
570 VariantInit(&var);
571 hr = IXMLDOMNode_get_nodeValue(node, &var);
572 if (hr == S_OK)
574 if (!wcscmp(str, L"xmlns") || !wcsncmp(str, L"xmlns:", 6))
576 TRACE("ns[%ld]: %s=%s\n", i, wine_dbgstr_w(str), wine_dbgstr_w(V_BSTR(&var)));
577 IStream_Write(stream, str, wcslen(str) * sizeof(WCHAR), NULL);
578 IStream_Write(stream, L"=\"", 2 * sizeof(WCHAR), NULL);
579 IStream_Write(stream, V_BSTR(&var), wcslen(V_BSTR(&var)) * sizeof(WCHAR), NULL);
580 IStream_Write(stream, L"\" ", 2 * sizeof(WCHAR), NULL);
582 VariantClear(&var);
584 SysFreeString(str);
586 IXMLDOMNode_Release(node);
590 IStream_Write(stream, L"", sizeof(WCHAR), NULL);
592 hr = GetHGlobalFromStream(stream, &hmem);
593 if (hr != S_OK) goto fail;
595 str = GlobalLock(hmem);
596 V_VT(&var) = VT_BSTR;
597 V_BSTR(&var) = SysAllocString(str);
598 IXMLDOMDocument2_setProperty(doc, (BSTR)L"SelectionNamespaces", var);
599 SysFreeString(V_BSTR(&var));
600 GlobalUnlock(hmem);
602 fail:
603 if (map) IXMLDOMNamedNodeMap_Release(map);
604 if (element) IXMLDOMElement_Release(element);
605 IStream_Release(stream);
608 static HRESULT parse_ticket(IStream *stream, EPrintTicketScope scope, struct ticket *ticket)
610 IXMLDOMDocument2 *doc;
611 VARIANT src;
612 VARIANT_BOOL ret;
613 HRESULT hr;
615 hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
616 &IID_IXMLDOMDocument2, (void **)&doc);
617 if (hr != S_OK) return hr;
619 V_VT(&src) = VT_UNKNOWN;
620 V_UNKNOWN(&src) = (IUnknown *)stream;
621 hr = IXMLDOMDocument2_load(doc, src, &ret);
622 if (hr != S_OK) goto fail;
624 hr = verify_ticket(doc);
625 if (hr != S_OK) goto fail;
627 set_SelectionNamespaces(doc);
629 /* PageScope is always added */
630 read_PageMediaSize(doc, ticket);
631 read_PageOutputColor(doc, ticket);
632 read_PageScaling(doc, ticket);
633 read_PageResolution(doc, ticket);
634 read_PageOrientation(doc, ticket);
636 if (scope > kPTPageScope)
637 read_DocumentCollate(doc, ticket);
639 if (scope > kPTDocumentScope)
641 read_JobInputBin(doc, ticket);
642 read_JobCopies(doc, ticket);
645 fail:
646 IXMLDOMDocument2_Release(doc);
647 return hr;
650 static void ticket_to_devmode(const struct ticket *ticket, DEVMODEW *dm)
652 memset(dm, 0, sizeof(*dm));
654 dm->dmSize = sizeof(*dm);
655 dm->dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_SCALE |
656 DM_COPIES | DM_COLOR | DM_PRINTQUALITY | DM_YRESOLUTION | DM_COLLATE;
657 dm->u1.s1.dmOrientation = ticket->page.orientation;
658 dm->u1.s1.dmPaperSize = ticket->page.media.paper;
659 dm->u1.s1.dmPaperWidth = ticket->page.media.size.width / 100;
660 dm->u1.s1.dmPaperLength = ticket->page.media.size.height / 100;
661 dm->u1.s1.dmScale = ticket->page.scaling;
662 dm->u1.s1.dmCopies = ticket->job.copies;
663 dm->dmColor = ticket->page.color;
664 dm->u1.s1.dmPrintQuality = ticket->page.resolution.x;
665 dm->dmYResolution = ticket->page.resolution.y;
666 dm->dmCollate = ticket->document.collate;
669 static void devmode_to_ticket(const DEVMODEW *dm, struct ticket *ticket)
671 if (dm->dmFields & DM_ORIENTATION)
672 ticket->page.orientation = dm->u1.s1.dmOrientation;
673 if (dm->dmFields & DM_PAPERSIZE)
674 ticket->page.media.paper = dm->u1.s1.dmPaperSize;
675 if (dm->dmFields & DM_PAPERLENGTH)
676 ticket->page.media.size.width = dm->u1.s1.dmPaperWidth * 100;
677 if (dm->dmFields & DM_PAPERWIDTH)
678 ticket->page.media.size.height = dm->u1.s1.dmPaperLength * 100;
679 if (dm->dmFields & DM_SCALE)
680 ticket->page.scaling = dm->u1.s1.dmScale;
681 if (dm->dmFields & DM_COPIES)
682 ticket->job.copies = dm->u1.s1.dmCopies;
683 if (dm->dmFields & DM_COLOR)
684 ticket->page.color = dm->dmColor;
685 if (dm->dmFields & DM_PRINTQUALITY)
687 ticket->page.resolution.x = dm->u1.s1.dmPrintQuality;
688 ticket->page.resolution.y = dm->u1.s1.dmPrintQuality;
690 if (dm->dmFields & DM_YRESOLUTION)
691 ticket->page.resolution.y = dm->dmYResolution;
692 if (dm->dmFields & DM_LOGPIXELS)
694 ticket->page.resolution.x = dm->dmLogPixels;
695 ticket->page.resolution.y = dm->dmLogPixels;
697 if (dm->dmFields & DM_COLLATE)
698 ticket->document.collate = dm->dmCollate;
701 static HRESULT initialize_ticket(struct prn_provider *prov, struct ticket *ticket)
703 PRINTER_INFO_2W *pi2;
704 DWORD size;
705 HRESULT hr = S_OK;
707 GetPrinterW(prov->hprn, 2, NULL, 0, &size);
708 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
709 return HRESULT_FROM_WIN32(GetLastError());
711 pi2 = malloc(size);
712 if (!pi2) return E_OUTOFMEMORY;
714 if (!GetPrinterW(prov->hprn, 2, (LPBYTE)pi2, size, NULL))
715 hr = HRESULT_FROM_WIN32(GetLastError());
716 else
717 devmode_to_ticket(pi2->pDevMode, ticket);
719 free(pi2);
720 return hr;
723 HRESULT WINAPI PTConvertPrintTicketToDevMode(HPTPROVIDER provider, IStream *stream, EDefaultDevmodeType type,
724 EPrintTicketScope scope, ULONG *size, PDEVMODEW *dm, BSTR *error)
726 struct prn_provider *prov = (struct prn_provider *)provider;
727 HRESULT hr;
728 struct ticket ticket;
730 TRACE("%p,%p,%d,%d,%p,%p,%p\n", provider, stream, type, scope, size, dm, error);
732 if (!is_valid_provider(provider) || !stream || !size || !dm)
733 return E_INVALIDARG;
735 hr = initialize_ticket(prov, &ticket);
736 if (hr != S_OK) return hr;
738 hr = parse_ticket(stream, scope, &ticket);
739 if (hr != S_OK) return hr;
741 *dm = malloc(sizeof(**dm));
742 if (!*dm) return E_OUTOFMEMORY;
744 ticket_to_devmode(&ticket, *dm);
745 *size = sizeof(**dm);
747 return S_OK;
750 static HRESULT add_attribute(IXMLDOMElement *element, const WCHAR *attr, const WCHAR *value)
752 VARIANT var;
753 BSTR name;
754 HRESULT hr;
756 name = SysAllocString(attr);
757 V_VT(&var) = VT_BSTR;
758 V_BSTR(&var) = SysAllocString(value);
760 hr = IXMLDOMElement_setAttribute(element, name, var);
762 SysFreeString(name);
763 SysFreeString(V_BSTR(&var));
765 return hr;
768 static HRESULT create_element(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
770 IXMLDOMDocument *doc;
771 HRESULT hr;
773 hr = IXMLDOMElement_get_ownerDocument(root, &doc);
774 if (hr != S_OK) return hr;
776 hr = IXMLDOMDocument_createElement(doc, (BSTR)name, child);
777 if (hr == S_OK)
778 hr = IXMLDOMElement_appendChild(root, (IXMLDOMNode *)*child, NULL);
780 IXMLDOMDocument_Release(doc);
781 return hr;
784 static HRESULT write_int_value(IXMLDOMElement *root, int value)
786 HRESULT hr;
787 IXMLDOMElement *child;
788 VARIANT var;
790 hr = create_element(root, L"psf:Value", &child);
791 if (hr != S_OK) return hr;
793 hr = add_attribute(child, L"xsi:type", L"xsd:integer");
794 if (hr != S_OK) return hr;
796 V_VT(&var) = VT_I4;
797 V_I4(&var) = value;
798 hr = IXMLDOMElement_put_nodeTypedValue(child, var);
800 IXMLDOMElement_Release(child);
801 return hr;
804 static HRESULT create_Feature(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
806 HRESULT hr;
808 hr = create_element(root, L"psf:Feature", child);
809 if (hr != S_OK) return hr;
811 return add_attribute(*child, L"name", name);
814 static HRESULT create_Option(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
816 HRESULT hr;
818 hr = create_element(root, L"psf:Option", child);
819 if (hr != S_OK) return hr;
821 if (name)
822 hr = add_attribute(*child, L"name", name);
824 return hr;
827 static HRESULT create_ParameterInit(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
829 HRESULT hr;
831 hr = create_element(root, L"psf:ParameterInit", child);
832 if (hr != S_OK) return hr;
834 return add_attribute(*child, L"name", name);
837 static HRESULT create_ParameterRef(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
839 HRESULT hr;
841 hr = create_element(root, L"psf:ParameterRef", child);
842 if (hr != S_OK) return hr;
844 return add_attribute(*child, L"name", name);
847 static HRESULT create_ParameterDef(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
849 HRESULT hr;
851 hr = create_element(root, L"psf:ParameterDef", child);
852 if (hr != S_OK) return hr;
854 return add_attribute(*child, L"name", name);
857 static HRESULT create_ScoredProperty(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
859 HRESULT hr;
861 hr = create_element(root, L"psf:ScoredProperty", child);
862 if (hr != S_OK) return hr;
864 return add_attribute(*child, L"name", name);
867 static HRESULT write_PageMediaSize(IXMLDOMElement *root, const struct ticket *ticket)
869 IXMLDOMElement *feature, *option = NULL, *property;
870 HRESULT hr;
872 hr = create_Feature(root, L"psk:PageMediaSize", &feature);
873 if (hr != S_OK) return hr;
875 hr = create_Option(feature, paper_to_media(ticket->page.media.paper), &option);
876 if (hr != S_OK) goto fail;
878 hr = create_ScoredProperty(option, L"psk:MediaSizeWidth", &property);
879 if (hr != S_OK) goto fail;
880 hr = write_int_value(property, ticket->page.media.size.width);
881 IXMLDOMElement_Release(property);
882 if (hr != S_OK) goto fail;
884 hr = create_ScoredProperty(option, L"psk:MediaSizeHeight", &property);
885 if (hr != S_OK) goto fail;
886 hr = write_int_value(property, ticket->page.media.size.height);
887 IXMLDOMElement_Release(property);
889 fail:
890 if (option) IXMLDOMElement_Release(option);
891 IXMLDOMElement_Release(feature);
892 return hr;
895 static HRESULT write_PageOutputColor(IXMLDOMElement *root, const struct ticket *ticket)
897 IXMLDOMElement *feature, *option = NULL;
898 HRESULT hr;
900 hr = create_Feature(root, L"psk:PageOutputColor", &feature);
901 if (hr != S_OK) return hr;
903 if (ticket->page.color == DMCOLOR_COLOR)
904 hr = create_Option(feature, L"psk:Color", &option);
905 else /* DMCOLOR_MONOCHROME */
906 hr = create_Option(feature, L"psk:Monochrome", &option);
908 if (option) IXMLDOMElement_Release(option);
909 IXMLDOMElement_Release(feature);
910 return hr;
913 static HRESULT write_PageScaling(IXMLDOMElement *root, const struct ticket *ticket)
915 IXMLDOMElement *feature, *option = NULL;
916 HRESULT hr;
918 hr = create_Feature(root, L"psk:PageScaling", &feature);
919 if (hr != S_OK) return hr;
921 if (ticket->page.scaling == 100)
923 hr = create_Option(feature, L"psk:None", &option);
924 if (hr == S_OK) IXMLDOMElement_Release(option);
926 else
928 hr = create_Option(feature, L"psk:CustomSquare", &option);
929 if (hr == S_OK)
931 IXMLDOMElement *property, *parameter;
933 hr = create_ScoredProperty(option, L"psk:Scale", &property);
934 if (hr == S_OK)
936 hr = create_ParameterRef(property, L"psk:PageScalingScale", &parameter);
937 if (hr == S_OK)
939 IXMLDOMElement_Release(parameter);
941 hr = create_ParameterInit(root, L"psk:PageScalingScale", &parameter);
942 if (hr == S_OK)
944 hr = write_int_value(parameter, ticket->page.scaling);
945 IXMLDOMElement_Release(parameter);
949 IXMLDOMElement_Release(property);
952 IXMLDOMElement_Release(option);
956 IXMLDOMElement_Release(feature);
957 return hr;
960 static HRESULT write_PageResolution(IXMLDOMElement *root, const struct ticket *ticket)
962 IXMLDOMElement *feature, *option = NULL, *property;
963 HRESULT hr;
965 hr = create_Feature(root, L"psk:PageResolution", &feature);
966 if (hr != S_OK) return hr;
968 hr = create_Option(feature, NULL, &option);
969 if (hr != S_OK) goto fail;
971 hr = create_ScoredProperty(option, L"psk:ResolutionX", &property);
972 if (hr != S_OK) goto fail;
973 hr = write_int_value(property, ticket->page.resolution.x);
974 IXMLDOMElement_Release(property);
975 if (hr != S_OK) goto fail;
977 hr = create_ScoredProperty(option, L"psk:ResolutionY", &property);
978 if (hr != S_OK) goto fail;
979 hr = write_int_value(property, ticket->page.resolution.y);
980 IXMLDOMElement_Release(property);
982 fail:
983 if (option) IXMLDOMElement_Release(option);
984 IXMLDOMElement_Release(feature);
985 return hr;
988 static HRESULT write_PageOrientation(IXMLDOMElement *root, const struct ticket *ticket)
990 IXMLDOMElement *feature, *option = NULL;
991 HRESULT hr;
993 hr = create_Feature(root, L"psk:PageOrientation", &feature);
994 if (hr != S_OK) return hr;
996 if (ticket->page.orientation == DMORIENT_PORTRAIT)
997 hr = create_Option(feature, L"psk:Portrait", &option);
998 else /* DMORIENT_LANDSCAPE */
999 hr = create_Option(feature, L"psk:Landscape", &option);
1001 if (option) IXMLDOMElement_Release(option);
1002 IXMLDOMElement_Release(feature);
1003 return hr;
1006 static HRESULT write_DocumentCollate(IXMLDOMElement *root, const struct ticket *ticket)
1008 IXMLDOMElement *feature, *option = NULL;
1009 HRESULT hr;
1011 hr = create_Feature(root, L"psk:DocumentCollate", &feature);
1012 if (hr != S_OK) return hr;
1014 if (ticket->document.collate == DMCOLLATE_TRUE)
1015 hr = create_Option(feature, L"psk:Collated", &option);
1016 else /* DMCOLLATE_FALSE */
1017 hr = create_Option(feature, L"psk:Uncollated", &option);
1019 if (option) IXMLDOMElement_Release(option);
1020 IXMLDOMElement_Release(feature);
1021 return hr;
1024 static HRESULT write_JobInputBin(IXMLDOMElement *root, const struct ticket *ticket)
1026 IXMLDOMElement *feature, *option = NULL;
1027 HRESULT hr;
1029 hr = create_Feature(root, L"psk:JobInputBin", &feature);
1030 if (hr != S_OK) return hr;
1032 if (ticket->job.input_bin != DMBIN_AUTO)
1033 FIXME("job.input_bin: %d\n", ticket->job.input_bin);
1035 hr = create_Option(feature, L"psk:AutoSelect", &option);
1037 if (option) IXMLDOMElement_Release(option);
1038 IXMLDOMElement_Release(feature);
1039 return hr;
1042 static HRESULT write_JobCopies(IXMLDOMElement *root, const struct ticket *ticket)
1044 IXMLDOMElement *parameter;
1045 HRESULT hr;
1047 hr = create_ParameterInit(root, L"psk:JobCopiesAllDocuments", &parameter);
1048 if (hr != S_OK) return hr;
1050 hr = write_int_value(parameter, ticket->job.copies);
1052 IXMLDOMElement_Release(parameter);
1053 return hr;
1056 static HRESULT write_attributes(IXMLDOMElement *element)
1058 HRESULT hr;
1060 hr = add_attribute(element, L"xmlns:psf", L"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework");
1061 if (hr != S_OK) return hr;
1062 hr = add_attribute(element, L"xmlns:psk", L"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords");
1063 if (hr != S_OK) return hr;
1064 hr = add_attribute(element, L"xmlns:xsi", L"http://www.w3.org/2001/XMLSchema-instance");
1065 if (hr != S_OK) return hr;
1066 hr = add_attribute(element, L"xmlns:xsd", L"http://www.w3.org/2001/XMLSchema");
1067 if (hr != S_OK) return hr;
1069 return add_attribute(element, L"version", L"1");
1072 static HRESULT write_ticket(IStream *stream, const struct ticket *ticket, EPrintTicketScope scope)
1074 static const char xmldecl[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1075 HRESULT hr;
1076 IXMLDOMDocument *doc;
1077 IXMLDOMElement *root = NULL;
1078 VARIANT var;
1080 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
1081 &IID_IXMLDOMDocument, (void **)&doc);
1082 if (hr != S_OK) return hr;
1084 hr = IXMLDOMDocument_createElement(doc, (BSTR)L"psf:PrintTicket", &root);
1085 if (hr != S_OK) goto fail;
1087 hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)root, NULL);
1088 if (hr != S_OK) goto fail;
1090 hr = write_attributes(root);
1091 if (hr != S_OK) goto fail;
1093 hr = write_PageMediaSize(root, ticket);
1094 if (hr != S_OK) goto fail;
1095 hr = write_PageOutputColor(root, ticket);
1096 if (hr != S_OK) goto fail;
1097 hr = write_PageScaling(root, ticket);
1098 if (hr != S_OK) goto fail;
1099 hr = write_PageResolution(root, ticket);
1100 if (hr != S_OK) goto fail;
1101 hr = write_PageOrientation(root, ticket);
1102 if (hr != S_OK) goto fail;
1104 if (scope >= kPTDocumentScope)
1106 hr = write_DocumentCollate(root, ticket);
1107 if (hr != S_OK) goto fail;
1110 if (scope >= kPTJobScope)
1112 hr = write_JobInputBin(root, ticket);
1113 if (hr != S_OK) goto fail;
1114 hr = write_JobCopies(root, ticket);
1115 if (hr != S_OK) goto fail;
1118 hr = IStream_Write(stream, xmldecl, strlen(xmldecl), NULL);
1119 if (hr != S_OK) goto fail;
1121 V_VT(&var) = VT_UNKNOWN;
1122 V_UNKNOWN(&var) = (IUnknown *)stream;
1123 hr = IXMLDOMDocument_save(doc, var);
1125 fail:
1126 if (root) IXMLDOMElement_Release(root);
1127 IXMLDOMDocument_Release(doc);
1128 return hr;
1131 static void dump_fields(DWORD fields)
1133 int add_space = 0;
1135 #define CHECK_FIELD(flag) \
1136 do \
1138 if (fields & flag) \
1140 if (add_space++) TRACE(" "); \
1141 TRACE(#flag); \
1142 fields &= ~flag; \
1145 while (0)
1147 CHECK_FIELD(DM_ORIENTATION);
1148 CHECK_FIELD(DM_PAPERSIZE);
1149 CHECK_FIELD(DM_PAPERLENGTH);
1150 CHECK_FIELD(DM_PAPERWIDTH);
1151 CHECK_FIELD(DM_SCALE);
1152 CHECK_FIELD(DM_POSITION);
1153 CHECK_FIELD(DM_NUP);
1154 CHECK_FIELD(DM_DISPLAYORIENTATION);
1155 CHECK_FIELD(DM_COPIES);
1156 CHECK_FIELD(DM_DEFAULTSOURCE);
1157 CHECK_FIELD(DM_PRINTQUALITY);
1158 CHECK_FIELD(DM_COLOR);
1159 CHECK_FIELD(DM_DUPLEX);
1160 CHECK_FIELD(DM_YRESOLUTION);
1161 CHECK_FIELD(DM_TTOPTION);
1162 CHECK_FIELD(DM_COLLATE);
1163 CHECK_FIELD(DM_FORMNAME);
1164 CHECK_FIELD(DM_LOGPIXELS);
1165 CHECK_FIELD(DM_BITSPERPEL);
1166 CHECK_FIELD(DM_PELSWIDTH);
1167 CHECK_FIELD(DM_PELSHEIGHT);
1168 CHECK_FIELD(DM_DISPLAYFLAGS);
1169 CHECK_FIELD(DM_DISPLAYFREQUENCY);
1170 CHECK_FIELD(DM_ICMMETHOD);
1171 CHECK_FIELD(DM_ICMINTENT);
1172 CHECK_FIELD(DM_MEDIATYPE);
1173 CHECK_FIELD(DM_DITHERTYPE);
1174 CHECK_FIELD(DM_PANNINGWIDTH);
1175 CHECK_FIELD(DM_PANNINGHEIGHT);
1176 if (fields) TRACE(" %#lx", fields);
1177 TRACE("\n");
1178 #undef CHECK_FIELD
1181 /* Dump DEVMODE structure without a device specific part.
1182 * Some applications and drivers fail to specify correct field
1183 * flags (like DM_FORMNAME), so dump everything.
1185 static void dump_devmode(const DEVMODEW *dm)
1187 if (!TRACE_ON(prntvpt)) return;
1189 TRACE("dmDeviceName: %s\n", debugstr_w(dm->dmDeviceName));
1190 TRACE("dmSpecVersion: 0x%04x\n", dm->dmSpecVersion);
1191 TRACE("dmDriverVersion: 0x%04x\n", dm->dmDriverVersion);
1192 TRACE("dmSize: 0x%04x\n", dm->dmSize);
1193 TRACE("dmDriverExtra: 0x%04x\n", dm->dmDriverExtra);
1194 TRACE("dmFields: 0x%04lx\n", dm->dmFields);
1195 dump_fields(dm->dmFields);
1196 TRACE("dmOrientation: %d\n", dm->u1.s1.dmOrientation);
1197 TRACE("dmPaperSize: %d\n", dm->u1.s1.dmPaperSize);
1198 TRACE("dmPaperLength: %d\n", dm->u1.s1.dmPaperLength);
1199 TRACE("dmPaperWidth: %d\n", dm->u1.s1.dmPaperWidth);
1200 TRACE("dmScale: %d\n", dm->u1.s1.dmScale);
1201 TRACE("dmCopies: %d\n", dm->u1.s1.dmCopies);
1202 TRACE("dmDefaultSource: %d\n", dm->u1.s1.dmDefaultSource);
1203 TRACE("dmPrintQuality: %d\n", dm->u1.s1.dmPrintQuality);
1204 TRACE("dmColor: %d\n", dm->dmColor);
1205 TRACE("dmDuplex: %d\n", dm->dmDuplex);
1206 TRACE("dmYResolution: %d\n", dm->dmYResolution);
1207 TRACE("dmTTOption: %d\n", dm->dmTTOption);
1208 TRACE("dmCollate: %d\n", dm->dmCollate);
1209 TRACE("dmFormName: %s\n", debugstr_w(dm->dmFormName));
1210 TRACE("dmLogPixels %u\n", dm->dmLogPixels);
1211 TRACE("dmBitsPerPel %lu\n", dm->dmBitsPerPel);
1212 TRACE("dmPelsWidth %lu\n", dm->dmPelsWidth);
1213 TRACE("dmPelsHeight %lu\n", dm->dmPelsHeight);
1216 HRESULT WINAPI PTConvertDevModeToPrintTicket(HPTPROVIDER provider, ULONG size, PDEVMODEW dm,
1217 EPrintTicketScope scope, IStream *stream)
1219 struct prn_provider *prov = (struct prn_provider *)provider;
1220 struct ticket ticket;
1221 HRESULT hr;
1223 TRACE("%p,%lu,%p,%d,%p\n", provider, size, dm, scope, stream);
1225 if (!is_valid_provider(provider) || !dm || !stream)
1226 return E_INVALIDARG;
1228 dump_devmode(dm);
1230 if (!IsValidDevmodeW(dm, size))
1231 return E_INVALIDARG;
1233 hr = initialize_ticket(prov, &ticket);
1234 if (hr != S_OK) return hr;
1235 devmode_to_ticket(dm, &ticket);
1237 return write_ticket(stream, &ticket, scope);
1240 HRESULT WINAPI PTMergeAndValidatePrintTicket(HPTPROVIDER provider, IStream *base, IStream *delta,
1241 EPrintTicketScope scope, IStream *result, BSTR *error)
1243 struct prn_provider *prov = (struct prn_provider *)provider;
1244 struct ticket ticket;
1245 HRESULT hr;
1247 TRACE("%p,%p,%p,%d,%p,%p\n", provider, base, delta, scope, result, error);
1249 if (!is_valid_provider(provider) || !base || !result)
1250 return E_INVALIDARG;
1252 hr = initialize_ticket(prov, &ticket);
1253 if (hr != S_OK) return hr;
1255 hr = parse_ticket(base, scope, &ticket);
1256 if (hr != S_OK) return hr;
1258 if (delta)
1260 hr = parse_ticket(delta, scope, &ticket);
1261 if (hr != S_OK) return hr;
1264 hr = write_ticket(result, &ticket, scope);
1265 return hr ? hr : S_PT_NO_CONFLICT;
1268 static HRESULT write_PageMediaSize_caps(const WCHAR *device, IXMLDOMElement *root)
1270 HRESULT hr = S_OK;
1271 int count, i;
1272 POINT *pt;
1273 IXMLDOMElement *feature = NULL;
1275 FIXME("stub\n");
1277 count = DeviceCapabilitiesW(device, NULL, DC_PAPERSIZE, NULL, NULL);
1278 if (count <= 0)
1279 return HRESULT_FROM_WIN32(GetLastError());
1281 pt = calloc(count, sizeof(*pt));
1282 if (!pt) return E_OUTOFMEMORY;
1284 count = DeviceCapabilitiesW(device, NULL, DC_PAPERSIZE, (LPWSTR)pt, NULL);
1285 if (count <= 0)
1287 hr = HRESULT_FROM_WIN32(GetLastError());
1288 goto fail;
1291 hr = create_Feature(root, L"psk:PageMediaSize", &feature);
1292 if (hr != S_OK) goto fail;
1294 for (i = 0; i < count; i++)
1298 fail:
1299 if (feature) IXMLDOMElement_Release(feature);
1300 free(pt);
1301 return hr;
1304 static HRESULT write_PageOutputColor_caps(const WCHAR *device, IXMLDOMElement *root)
1306 HRESULT hr = S_OK;
1307 int color;
1308 IXMLDOMElement *feature = NULL;
1310 FIXME("stub\n");
1312 color = DeviceCapabilitiesW(device, NULL, DC_COLORDEVICE, NULL, NULL);
1313 TRACE("DC_COLORDEVICE: %d\n", color);
1315 hr = create_Feature(root, L"psk:PageOutputColor", &feature);
1316 if (hr != S_OK) goto fail;
1318 fail:
1319 if (feature) IXMLDOMElement_Release(feature);
1320 return hr;
1323 static HRESULT write_PageScaling_caps(const WCHAR *device, IXMLDOMElement *root)
1325 HRESULT hr = S_OK;
1326 IXMLDOMElement *feature = NULL;
1328 FIXME("stub\n");
1330 hr = create_Feature(root, L"psk:PageScaling", &feature);
1331 if (hr != S_OK) goto fail;
1333 fail:
1334 if (feature) IXMLDOMElement_Release(feature);
1335 return hr;
1338 static HRESULT write_PageResolution_caps(const WCHAR *device, IXMLDOMElement *root)
1340 HRESULT hr = S_OK;
1341 int count, i;
1342 struct
1344 LONG x;
1345 LONG y;
1346 } *res;
1347 IXMLDOMElement *feature = NULL;
1349 FIXME("stub\n");
1351 count = DeviceCapabilitiesW(device, NULL, DC_ENUMRESOLUTIONS, NULL, NULL);
1352 if (count <= 0)
1353 return HRESULT_FROM_WIN32(GetLastError());
1355 res = calloc(count, sizeof(*res));
1356 if (!res) return E_OUTOFMEMORY;
1358 count = DeviceCapabilitiesW(device, NULL, DC_ENUMRESOLUTIONS, (LPWSTR)res, NULL);
1359 if (count <= 0)
1361 hr = HRESULT_FROM_WIN32(GetLastError());
1362 goto fail;
1365 hr = create_Feature(root, L"psk:PageResolution", &feature);
1366 if (hr != S_OK) goto fail;
1368 for (i = 0; i < count; i++)
1372 fail:
1373 if (feature) IXMLDOMElement_Release(feature);
1374 free(res);
1375 return hr;
1378 static HRESULT write_PageOrientation_caps(const WCHAR *device, IXMLDOMElement *root)
1380 HRESULT hr = S_OK;
1381 int landscape;
1382 IXMLDOMElement *feature = NULL;
1384 FIXME("stub\n");
1386 landscape = DeviceCapabilitiesW(device, NULL, DC_ORIENTATION, NULL, NULL);
1387 TRACE("DC_ORIENTATION: %d\n", landscape);
1389 hr = create_Feature(root, L"psk:PageOrientation", &feature);
1390 if (hr != S_OK) goto fail;
1392 fail:
1393 if (feature) IXMLDOMElement_Release(feature);
1394 return hr;
1397 static HRESULT write_DocumentCollate_caps(const WCHAR *device, IXMLDOMElement *root)
1399 HRESULT hr = S_OK;
1400 int collate;
1401 IXMLDOMElement *feature = NULL;
1403 FIXME("stub\n");
1405 collate = DeviceCapabilitiesW(device, NULL, DC_COLLATE, NULL, NULL);
1406 TRACE("DC_COLLATE: %d\n", collate);
1408 hr = create_Feature(root, L"psk:DocumentCollate", &feature);
1409 if (hr != S_OK) goto fail;
1411 fail:
1412 if (feature) IXMLDOMElement_Release(feature);
1413 return hr;
1416 static HRESULT write_JobInputBin_caps(const WCHAR *device, IXMLDOMElement *root)
1418 HRESULT hr = S_OK;
1419 int count, i;
1420 WORD *bin;
1421 IXMLDOMElement *feature = NULL;
1423 FIXME("stub\n");
1425 count = DeviceCapabilitiesW(device, NULL, DC_BINS, NULL, NULL);
1426 if (count <= 0)
1427 return HRESULT_FROM_WIN32(GetLastError());
1429 bin = calloc(count, sizeof(*bin));
1430 if (!bin) return E_OUTOFMEMORY;
1432 count = DeviceCapabilitiesW(device, NULL, DC_BINS, (LPWSTR)bin, NULL);
1433 if (count <= 0)
1435 hr = HRESULT_FROM_WIN32(GetLastError());
1436 goto fail;
1439 hr = create_Feature(root, L"psk:JobInputBin", &feature);
1440 if (hr != S_OK) goto fail;
1442 for (i = 0; i < count; i++)
1446 fail:
1447 if (feature) IXMLDOMElement_Release(feature);
1448 free(bin);
1449 return hr;
1452 static HRESULT write_JobCopies_caps(const WCHAR *device, IXMLDOMElement *root)
1454 HRESULT hr = S_OK;
1455 int copies;
1456 IXMLDOMElement *feature = NULL;
1458 FIXME("stub\n");
1460 copies = DeviceCapabilitiesW(device, NULL, DC_COPIES, NULL, NULL);
1461 TRACE("DC_COPIES: %d\n", copies);
1463 hr = create_ParameterDef(root, L"psk:JobCopiesAllDocuments", &feature);
1464 if (hr != S_OK) goto fail;
1466 fail:
1467 if (feature) IXMLDOMElement_Release(feature);
1468 return hr;
1471 static HRESULT write_print_capabilities(const WCHAR *device, IStream *stream)
1473 static const char xmldecl[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1474 HRESULT hr;
1475 IXMLDOMDocument *doc;
1476 IXMLDOMElement *root = NULL;
1477 VARIANT var;
1479 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
1480 &IID_IXMLDOMDocument, (void **)&doc);
1481 if (hr != S_OK) return hr;
1483 hr = IXMLDOMDocument_createElement(doc, (BSTR)L"psf:PrintCapabilities", &root);
1484 if (hr != S_OK) goto fail;
1486 hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)root, NULL);
1487 if (hr != S_OK) goto fail;
1489 hr = write_attributes(root);
1490 if (hr != S_OK) goto fail;
1492 hr = write_PageMediaSize_caps(device, root);
1493 if (hr != S_OK) goto fail;
1494 hr = write_PageOutputColor_caps(device, root);
1495 if (hr != S_OK) goto fail;
1496 hr = write_PageScaling_caps(device, root);
1497 if (hr != S_OK) goto fail;
1498 hr = write_PageResolution_caps(device, root);
1499 if (hr != S_OK) goto fail;
1500 hr = write_PageOrientation_caps(device, root);
1501 if (hr != S_OK) goto fail;
1502 hr = write_DocumentCollate_caps(device, root);
1503 if (hr != S_OK) goto fail;
1504 hr = write_JobInputBin_caps(device, root);
1505 if (hr != S_OK) goto fail;
1506 hr = write_JobCopies_caps(device, root);
1507 if (hr != S_OK) goto fail;
1509 hr = IStream_Write(stream, xmldecl, strlen(xmldecl), NULL);
1510 if (hr != S_OK) goto fail;
1512 V_VT(&var) = VT_UNKNOWN;
1513 V_UNKNOWN(&var) = (IUnknown *)stream;
1514 hr = IXMLDOMDocument_save(doc, var);
1516 fail:
1517 if (root) IXMLDOMElement_Release(root);
1518 IXMLDOMDocument_Release(doc);
1519 return hr;
1522 HRESULT WINAPI PTGetPrintCapabilities(HPTPROVIDER provider, IStream *stream, IStream *caps, BSTR *error)
1524 struct prn_provider *prov = (struct prn_provider *)provider;
1525 struct ticket ticket;
1526 HRESULT hr;
1528 TRACE("%p,%p,%p,%p\n", provider, stream, caps, error);
1530 if (!is_valid_provider(provider) || !stream || !caps)
1531 return E_INVALIDARG;
1533 hr = parse_ticket(stream, kPTJobScope, &ticket);
1534 if (hr != S_OK) return hr;
1536 return write_print_capabilities(prov->name, caps);