[PRINTING]
[reactos.git] / reactos / win32ss / printing / base / winspool / devmode.c
1 /*
2 * PROJECT: ReactOS Spooler API
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
4 * PURPOSE: Functions giving information about DEVMODE structures
5 * COPYRIGHT: Copyright 2016 Colin Finck <colin@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 typedef struct _MINIMUM_SIZE_TABLE
11 {
12 DWORD dwField;
13 WORD wSize;
14 }
15 MINIMUM_SIZE_TABLE, *PMINIMUM_SIZE_TABLE;
16
17 /**
18 * Minimum required DEVMODEA structure size based on the used fields. Must be in descending order!
19 */
20 static MINIMUM_SIZE_TABLE MinimumSizeA[] = {
21 { DM_PANNINGHEIGHT, FIELD_OFFSET(DEVMODEA, dmPanningHeight) + RTL_FIELD_SIZE(DEVMODEA, dmPanningHeight) },
22 { DM_PANNINGWIDTH, FIELD_OFFSET(DEVMODEA, dmPanningWidth) + RTL_FIELD_SIZE(DEVMODEA, dmPanningWidth) },
23 { DM_DITHERTYPE, FIELD_OFFSET(DEVMODEA, dmDitherType) + RTL_FIELD_SIZE(DEVMODEA, dmDitherType) },
24 { DM_MEDIATYPE, FIELD_OFFSET(DEVMODEA, dmMediaType) + RTL_FIELD_SIZE(DEVMODEA, dmMediaType) },
25 { DM_ICMINTENT, FIELD_OFFSET(DEVMODEA, dmICMIntent) + RTL_FIELD_SIZE(DEVMODEA, dmICMIntent) },
26 { DM_ICMMETHOD, FIELD_OFFSET(DEVMODEA, dmICMMethod) + RTL_FIELD_SIZE(DEVMODEA, dmICMMethod) },
27 { DM_DISPLAYFREQUENCY, FIELD_OFFSET(DEVMODEA, dmDisplayFrequency) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayFrequency) },
28 { DM_NUP, FIELD_OFFSET(DEVMODEA, dmNup) + RTL_FIELD_SIZE(DEVMODEA, dmNup) },
29 { DM_DISPLAYFLAGS, FIELD_OFFSET(DEVMODEA, dmDisplayFlags) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayFlags) },
30 { DM_PELSHEIGHT, FIELD_OFFSET(DEVMODEA, dmPelsHeight) + RTL_FIELD_SIZE(DEVMODEA, dmPelsHeight) },
31 { DM_PELSWIDTH, FIELD_OFFSET(DEVMODEA, dmPelsWidth) + RTL_FIELD_SIZE(DEVMODEA, dmPelsWidth) },
32 { DM_BITSPERPEL, FIELD_OFFSET(DEVMODEA, dmBitsPerPel) + RTL_FIELD_SIZE(DEVMODEA, dmBitsPerPel) },
33 { DM_LOGPIXELS, FIELD_OFFSET(DEVMODEA, dmLogPixels) + RTL_FIELD_SIZE(DEVMODEA, dmLogPixels) },
34 { DM_FORMNAME, FIELD_OFFSET(DEVMODEA, dmFormName) + RTL_FIELD_SIZE(DEVMODEA, dmFormName) },
35 { DM_COLLATE, FIELD_OFFSET(DEVMODEA, dmCollate) + RTL_FIELD_SIZE(DEVMODEA, dmCollate) },
36 { DM_TTOPTION, FIELD_OFFSET(DEVMODEA, dmTTOption) + RTL_FIELD_SIZE(DEVMODEA, dmTTOption) },
37 { DM_YRESOLUTION, FIELD_OFFSET(DEVMODEA, dmYResolution) + RTL_FIELD_SIZE(DEVMODEA, dmYResolution) },
38 { DM_DUPLEX, FIELD_OFFSET(DEVMODEA, dmDuplex) + RTL_FIELD_SIZE(DEVMODEA, dmDuplex) },
39 { DM_COLOR, FIELD_OFFSET(DEVMODEA, dmColor) + RTL_FIELD_SIZE(DEVMODEA, dmColor) },
40 { DM_DISPLAYFIXEDOUTPUT, FIELD_OFFSET(DEVMODEA, dmDisplayFixedOutput) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayFixedOutput) },
41 { DM_DISPLAYORIENTATION, FIELD_OFFSET(DEVMODEA, dmDisplayOrientation) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayOrientation) },
42 { DM_POSITION, FIELD_OFFSET(DEVMODEA, dmPosition) + RTL_FIELD_SIZE(DEVMODEA, dmPosition) },
43 { DM_PRINTQUALITY, FIELD_OFFSET(DEVMODEA, dmPrintQuality) + RTL_FIELD_SIZE(DEVMODEA, dmPrintQuality) },
44 { DM_DEFAULTSOURCE, FIELD_OFFSET(DEVMODEA, dmDefaultSource) + RTL_FIELD_SIZE(DEVMODEA, dmDefaultSource) },
45 { DM_COPIES, FIELD_OFFSET(DEVMODEA, dmCopies) + RTL_FIELD_SIZE(DEVMODEA, dmCopies) },
46 { DM_SCALE, FIELD_OFFSET(DEVMODEA, dmScale) + RTL_FIELD_SIZE(DEVMODEA, dmScale) },
47 { DM_PAPERWIDTH, FIELD_OFFSET(DEVMODEA, dmPaperWidth) + RTL_FIELD_SIZE(DEVMODEA, dmPaperWidth) },
48 { DM_PAPERLENGTH, FIELD_OFFSET(DEVMODEA, dmPaperLength) + RTL_FIELD_SIZE(DEVMODEA, dmPaperLength) },
49 { DM_PAPERSIZE, FIELD_OFFSET(DEVMODEA, dmPaperSize) + RTL_FIELD_SIZE(DEVMODEA, dmPaperSize) },
50 { DM_ORIENTATION, FIELD_OFFSET(DEVMODEA, dmOrientation) + RTL_FIELD_SIZE(DEVMODEA, dmOrientation) },
51 { 0, 0 }
52 };
53
54 /**
55 * Minimum required DEVMODEW structure size based on the used fields. Must be in descending order!
56 */
57 static MINIMUM_SIZE_TABLE MinimumSizeW[] = {
58 { DM_PANNINGHEIGHT, FIELD_OFFSET(DEVMODEW, dmPanningHeight) + RTL_FIELD_SIZE(DEVMODEW, dmPanningHeight) },
59 { DM_PANNINGWIDTH, FIELD_OFFSET(DEVMODEW, dmPanningWidth) + RTL_FIELD_SIZE(DEVMODEW, dmPanningWidth) },
60 { DM_DITHERTYPE, FIELD_OFFSET(DEVMODEW, dmDitherType) + RTL_FIELD_SIZE(DEVMODEW, dmDitherType) },
61 { DM_MEDIATYPE, FIELD_OFFSET(DEVMODEW, dmMediaType) + RTL_FIELD_SIZE(DEVMODEW, dmMediaType) },
62 { DM_ICMINTENT, FIELD_OFFSET(DEVMODEW, dmICMIntent) + RTL_FIELD_SIZE(DEVMODEW, dmICMIntent) },
63 { DM_ICMMETHOD, FIELD_OFFSET(DEVMODEW, dmICMMethod) + RTL_FIELD_SIZE(DEVMODEW, dmICMMethod) },
64 { DM_DISPLAYFREQUENCY, FIELD_OFFSET(DEVMODEW, dmDisplayFrequency) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayFrequency) },
65 { DM_NUP, FIELD_OFFSET(DEVMODEW, dmNup) + RTL_FIELD_SIZE(DEVMODEW, dmNup) },
66 { DM_DISPLAYFLAGS, FIELD_OFFSET(DEVMODEW, dmDisplayFlags) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayFlags) },
67 { DM_PELSHEIGHT, FIELD_OFFSET(DEVMODEW, dmPelsHeight) + RTL_FIELD_SIZE(DEVMODEW, dmPelsHeight) },
68 { DM_PELSWIDTH, FIELD_OFFSET(DEVMODEW, dmPelsWidth) + RTL_FIELD_SIZE(DEVMODEW, dmPelsWidth) },
69 { DM_BITSPERPEL, FIELD_OFFSET(DEVMODEW, dmBitsPerPel) + RTL_FIELD_SIZE(DEVMODEW, dmBitsPerPel) },
70 { DM_LOGPIXELS, FIELD_OFFSET(DEVMODEW, dmLogPixels) + RTL_FIELD_SIZE(DEVMODEW, dmLogPixels) },
71 { DM_FORMNAME, FIELD_OFFSET(DEVMODEW, dmFormName) + RTL_FIELD_SIZE(DEVMODEW, dmFormName) },
72 { DM_COLLATE, FIELD_OFFSET(DEVMODEW, dmCollate) + RTL_FIELD_SIZE(DEVMODEW, dmCollate) },
73 { DM_TTOPTION, FIELD_OFFSET(DEVMODEW, dmTTOption) + RTL_FIELD_SIZE(DEVMODEW, dmTTOption) },
74 { DM_YRESOLUTION, FIELD_OFFSET(DEVMODEW, dmYResolution) + RTL_FIELD_SIZE(DEVMODEW, dmYResolution) },
75 { DM_DUPLEX, FIELD_OFFSET(DEVMODEW, dmDuplex) + RTL_FIELD_SIZE(DEVMODEW, dmDuplex) },
76 { DM_COLOR, FIELD_OFFSET(DEVMODEW, dmColor) + RTL_FIELD_SIZE(DEVMODEW, dmColor) },
77 { DM_DISPLAYFIXEDOUTPUT, FIELD_OFFSET(DEVMODEW, dmDisplayFixedOutput) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayFixedOutput) },
78 { DM_DISPLAYORIENTATION, FIELD_OFFSET(DEVMODEW, dmDisplayOrientation) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayOrientation) },
79 { DM_POSITION, FIELD_OFFSET(DEVMODEW, dmPosition) + RTL_FIELD_SIZE(DEVMODEW, dmPosition) },
80 { DM_PRINTQUALITY, FIELD_OFFSET(DEVMODEW, dmPrintQuality) + RTL_FIELD_SIZE(DEVMODEW, dmPrintQuality) },
81 { DM_DEFAULTSOURCE, FIELD_OFFSET(DEVMODEW, dmDefaultSource) + RTL_FIELD_SIZE(DEVMODEW, dmDefaultSource) },
82 { DM_COPIES, FIELD_OFFSET(DEVMODEW, dmCopies) + RTL_FIELD_SIZE(DEVMODEW, dmCopies) },
83 { DM_SCALE, FIELD_OFFSET(DEVMODEW, dmScale) + RTL_FIELD_SIZE(DEVMODEW, dmScale) },
84 { DM_PAPERWIDTH, FIELD_OFFSET(DEVMODEW, dmPaperWidth) + RTL_FIELD_SIZE(DEVMODEW, dmPaperWidth) },
85 { DM_PAPERLENGTH, FIELD_OFFSET(DEVMODEW, dmPaperLength) + RTL_FIELD_SIZE(DEVMODEW, dmPaperLength) },
86 { DM_PAPERSIZE, FIELD_OFFSET(DEVMODEW, dmPaperSize) + RTL_FIELD_SIZE(DEVMODEW, dmPaperSize) },
87 { DM_ORIENTATION, FIELD_OFFSET(DEVMODEW, dmOrientation) + RTL_FIELD_SIZE(DEVMODEW, dmOrientation) },
88 { 0, 0 }
89 };
90
91 /**
92 * Replace the last character by a null terminator if the given ANSI string is not null-terminated.
93 */
94 static __inline void
95 _FixStringA(PBYTE String, DWORD cbString)
96 {
97 const PBYTE pLastCharacter = &String[cbString / sizeof(BYTE) - 1];
98 PBYTE p = String;
99
100 while (*p)
101 {
102 if (p == pLastCharacter)
103 {
104 *p = 0;
105 break;
106 }
107
108 p++;
109 }
110 }
111
112 /**
113 * Replace the last character by a null terminator if the given Unicode string is not null-terminated.
114 */
115 static __inline void
116 _FixStringW(PWSTR String, DWORD cbString)
117 {
118 const PWSTR pLastCharacter = &String[cbString / sizeof(WCHAR) - 1];
119 PWSTR p = String;
120
121 while (*p)
122 {
123 if (p == pLastCharacter)
124 {
125 *p = 0;
126 break;
127 }
128
129 p++;
130 }
131 }
132
133 BOOL WINAPI
134 IsValidDevmodeA(PDEVMODEA pDevmode, size_t DevmodeSize)
135 {
136 PMINIMUM_SIZE_TABLE pTable = MinimumSizeA;
137 WORD wRequiredSize;
138
139 // Check if a Devmode was given at all.
140 if (!pDevmode)
141 goto Failure;
142
143 // Verify that DevmodeSize is large enough to hold the public and private members of the structure.
144 if (DevmodeSize < pDevmode->dmSize + pDevmode->dmDriverExtra)
145 goto Failure;
146
147 // If the structure has private members, the public structure must be 32-bit packed.
148 if (pDevmode->dmDriverExtra && pDevmode->dmSize % 4)
149 goto Failure;
150
151 // Now determine the minimum possible dmSize based on the given fields in dmFields.
152 wRequiredSize = FIELD_OFFSET(DEVMODEA, dmFields) + RTL_FIELD_SIZE(DEVMODEA, dmFields);
153
154 while (pTable->dwField)
155 {
156 if (pDevmode->dmFields & pTable->dwField)
157 {
158 wRequiredSize = pTable->wSize;
159 break;
160 }
161
162 pTable++;
163 }
164
165 // Verify that the value in dmSize is big enough for the used fields.
166 if (pDevmode->dmSize < wRequiredSize)
167 goto Failure;
168
169 // Check if dmDeviceName and (if used) dmFormName are null-terminated.
170 // Fix this if they aren't.
171 _FixStringA(pDevmode->dmDeviceName, sizeof(pDevmode->dmDeviceName));
172 if (pDevmode->dmFields & DM_FORMNAME)
173 _FixStringA(pDevmode->dmFormName, sizeof(pDevmode->dmFormName));
174
175 // Return success without setting the error code.
176 return TRUE;
177
178 Failure:
179 SetLastError(ERROR_INVALID_DATA);
180 return FALSE;
181 }
182
183 BOOL WINAPI
184 IsValidDevmodeW(PDEVMODEW pDevmode, size_t DevmodeSize)
185 {
186 PMINIMUM_SIZE_TABLE pTable = MinimumSizeW;
187 WORD wRequiredSize;
188
189 // Check if a Devmode was given at all.
190 if (!pDevmode)
191 goto Failure;
192
193 // Verify that DevmodeSize is large enough to hold the public and private members of the structure.
194 if (DevmodeSize < pDevmode->dmSize + pDevmode->dmDriverExtra)
195 goto Failure;
196
197 // If the structure has private members, the public structure must be 32-bit packed.
198 if (pDevmode->dmDriverExtra && pDevmode->dmSize % 4)
199 goto Failure;
200
201 // Now determine the minimum possible dmSize based on the given fields in dmFields.
202 wRequiredSize = FIELD_OFFSET(DEVMODEW, dmFields) + RTL_FIELD_SIZE(DEVMODEW, dmFields);
203
204 while (pTable->dwField)
205 {
206 if (pDevmode->dmFields & pTable->dwField)
207 {
208 wRequiredSize = pTable->wSize;
209 break;
210 }
211
212 pTable++;
213 }
214
215 // Verify that the value in dmSize is big enough for the used fields.
216 if (pDevmode->dmSize < wRequiredSize)
217 goto Failure;
218
219 // Check if dmDeviceName and (if used) dmFormName are null-terminated.
220 // Fix this if they aren't.
221 _FixStringW(pDevmode->dmDeviceName, sizeof(pDevmode->dmDeviceName));
222 if (pDevmode->dmFields & DM_FORMNAME)
223 _FixStringW(pDevmode->dmFormName, sizeof(pDevmode->dmFormName));
224
225 // Return success without setting the error code.
226 return TRUE;
227
228 Failure:
229 SetLastError(ERROR_INVALID_DATA);
230 return FALSE;
231 }