1 /*
2  * PROJECT:     ReactOS Local Spooler
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Functions for printer driver information
5  * COPYRIGHT:   Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 
11 // Local Constants
12 static DWORD dwDriverInfo1Offsets[] = {
13     FIELD_OFFSET(DRIVER_INFO_1W, pName),
14     MAXDWORD
15 };
16 
17 static DWORD dwDriverInfo2Offsets[] = {
18     FIELD_OFFSET(DRIVER_INFO_2W, pName),
19     FIELD_OFFSET(DRIVER_INFO_2W, pEnvironment),
20     FIELD_OFFSET(DRIVER_INFO_2W, pDriverPath),
21     FIELD_OFFSET(DRIVER_INFO_2W, pDataFile),
22     FIELD_OFFSET(DRIVER_INFO_2W, pConfigFile),
23     MAXDWORD
24 };
25 
26 static DWORD dwDriverInfo3Offsets[] = {
27     FIELD_OFFSET(DRIVER_INFO_3W, pName),
28     FIELD_OFFSET(DRIVER_INFO_3W, pEnvironment),
29     FIELD_OFFSET(DRIVER_INFO_3W, pDriverPath),
30     FIELD_OFFSET(DRIVER_INFO_3W, pDataFile),
31     FIELD_OFFSET(DRIVER_INFO_3W, pConfigFile),
32     FIELD_OFFSET(DRIVER_INFO_3W, pHelpFile),
33     FIELD_OFFSET(DRIVER_INFO_3W, pDependentFiles),
34     FIELD_OFFSET(DRIVER_INFO_3W, pMonitorName),
35     FIELD_OFFSET(DRIVER_INFO_3W, pDefaultDataType),
36     MAXDWORD
37 };
38 
39 static void
40 ToMultiSz(LPWSTR pString)
41 {
42     while (*pString)
43     {
44         if (*pString == '|')
45             *pString = '\0';
46         pString++;
47     }
48 }
49 
50 
51 static void
52 _LocalGetPrinterDriverLevel1(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_1W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
53 {
54     DWORD n;
55     PCWSTR pwszStrings[1];
56 
57     /* This value is only here to send something, I have not verified if it is actually correct */
58     pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver;
59 
60     // Calculate the string lengths.
61     if (!ppDriverInfo)
62     {
63         for (n = 0; n < _countof(pwszStrings); ++n)
64         {
65             *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
66         }
67 
68         *pcbNeeded += sizeof(DRIVER_INFO_1W);
69         return;
70     }
71 
72 
73     // Finally copy the structure and advance to the next one in the output buffer.
74     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo1Offsets, *ppDriverInfoEnd);
75     (*ppDriverInfo)++;
76 }
77 
78 static void
79 _LocalGetPrinterDriverLevel2(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_2W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
80 {
81     DWORD n;
82     PCWSTR pwszStrings[5];
83 
84     /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
85     pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver;  // pName
86     pwszStrings[1] = wszCurrentEnvironment;  // pEnvironment
87     pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll";  // pDriverPath
88     pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll";  // pDataFile
89     pwszStrings[4] = L"c:\\reactos\\system32\\localspl.dll";  // pConfigFile
90 
91     // Calculate the string lengths.
92     if (!ppDriverInfo)
93     {
94         for (n = 0; n < _countof(pwszStrings); ++n)
95         {
96             *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
97         }
98 
99         *pcbNeeded += sizeof(DRIVER_INFO_2W);
100         return;
101     }
102 
103     (*ppDriverInfo)->cVersion = 3;
104 
105     // Finally copy the structure and advance to the next one in the output buffer.
106     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo2Offsets, *ppDriverInfoEnd);
107     (*ppDriverInfo)++;
108 }
109 
110 static void
111 _LocalGetPrinterDriverLevel3(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_3W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
112 {
113     DWORD n;
114     PCWSTR pwszStrings[9];
115 
116     /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
117     pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver;  // pName
118     pwszStrings[1] = wszCurrentEnvironment;  // pEnvironment
119     pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll";  // pDriverPath
120     pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll";  // pDataFile
121     pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll";  // pConfigFile
122     pwszStrings[5] = L"";  // pHelpFile
123     pwszStrings[6] = L"localspl.dll|printui.dll|";  // pDependentFiles, | is separator and terminator!
124     pwszStrings[7] = NULL;  // pMonitorName
125     pwszStrings[8] = NULL;  // pDefaultDataType
126 
127 
128     // Calculate the string lengths.
129     if (!ppDriverInfo)
130     {
131         for (n = 0; n < _countof(pwszStrings); ++n)
132         {
133             if (pwszStrings[n])
134             {
135                 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
136             }
137         }
138 
139         *pcbNeeded += sizeof(DRIVER_INFO_3W);
140         return;
141     }
142 
143     (*ppDriverInfo)->cVersion = 3;
144 
145     // Finally copy the structure and advance to the next one in the output buffer.
146     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo3Offsets, *ppDriverInfoEnd);
147     ToMultiSz((*ppDriverInfo)->pDependentFiles);
148     (*ppDriverInfo)++;
149 }
150 
151 
152 BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
153 {
154     DWORD dwErrorCode;
155     PBYTE pEnd = &pDriverInfo[cbBuf];
156     PLOCAL_HANDLE pHandle;
157     PLOCAL_PRINTER_HANDLE pPrinterHandle;
158 
159     TRACE("LocalGetPrinterDriver(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
160 
161     // Check if this is a printer handle.
162     pHandle = (PLOCAL_HANDLE)hPrinter;
163     if (pHandle->HandleType != HandleType_Printer)
164     {
165         dwErrorCode = ERROR_INVALID_HANDLE;
166         goto Cleanup;
167     }
168 
169     pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
170 
171     // Only support 3 levels for now
172     if (Level > 3)
173     {
174         // The caller supplied an invalid level.
175         dwErrorCode = ERROR_INVALID_LEVEL;
176         goto Cleanup;
177     }
178 
179     // Count the required buffer size.
180     *pcbNeeded = 0;
181 
182     if (Level == 1)
183         _LocalGetPrinterDriverLevel1(pPrinterHandle, NULL, NULL, pcbNeeded);
184     else if (Level == 2)
185         _LocalGetPrinterDriverLevel2(pPrinterHandle, NULL, NULL, pcbNeeded);
186     else if (Level == 3)
187         _LocalGetPrinterDriverLevel3(pPrinterHandle, NULL, NULL, pcbNeeded);
188 
189     // Check if the supplied buffer is large enough.
190     if (cbBuf < *pcbNeeded)
191     {
192         dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
193         goto Cleanup;
194     }
195 
196     // Copy over the information.
197     pEnd = &pDriverInfo[*pcbNeeded];
198 
199     if (Level == 1)
200         _LocalGetPrinterDriverLevel1(pPrinterHandle, (PDRIVER_INFO_1W*)&pDriverInfo, &pEnd, NULL);
201     else if (Level == 2)
202         _LocalGetPrinterDriverLevel2(pPrinterHandle, (PDRIVER_INFO_2W*)&pDriverInfo, &pEnd, NULL);
203     else if (Level == 3)
204         _LocalGetPrinterDriverLevel3(pPrinterHandle, (PDRIVER_INFO_3W*)&pDriverInfo, &pEnd, NULL);
205 
206     dwErrorCode = ERROR_SUCCESS;
207 
208 Cleanup:
209     SetLastError(dwErrorCode);
210     return (dwErrorCode == ERROR_SUCCESS);
211 }
212