Sync to trunk (r46918)
[reactos.git] / subsystems / win32 / win32k / misc / file.c
1 /*
2 * COPYRIGHT: GPL, see COPYING in the top level directory
3 * PROJECT: ReactOS win32 kernel mode subsystem server
4 * PURPOSE: File access support routines
5 * FILE: subsystem/win32/win32k/misc/registry.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7 */
8
9 #include <w32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 BOOL
15 NTAPI
16 W32kDosPathNameToNtPathName(
17 IN PCWSTR pwszDosPathName,
18 OUT PUNICODE_STRING pustrNtPathName)
19 {
20 NTSTATUS Status;
21
22 /* Prepend "\??\" */
23 pustrNtPathName->Length = 0;
24 Status = RtlAppendUnicodeToString(pustrNtPathName, L"\\??\\");
25 if (!NT_SUCCESS(Status))
26 {
27 return FALSE;
28 }
29
30 /* Append the dos name */
31 Status = RtlAppendUnicodeToString(pustrNtPathName, pwszDosPathName);
32 if (!NT_SUCCESS(Status))
33 {
34 return FALSE;
35 }
36
37 return TRUE;
38 }
39
40
41 HANDLE
42 NTAPI
43 W32kOpenFile(PCWSTR pwszFileName, DWORD dwDesiredAccess)
44 {
45 UNICODE_STRING ustrFile;
46 OBJECT_ATTRIBUTES ObjectAttributes;
47 IO_STATUS_BLOCK IoStatusBlock;
48 HANDLE hFile = INVALID_HANDLE_VALUE;
49 NTSTATUS Status;
50
51 DPRINT("W32kOpenFile(%S)\n", pwszFileName);
52
53 RtlInitUnicodeString(&ustrFile, pwszFileName);
54
55 InitializeObjectAttributes(&ObjectAttributes, &ustrFile, 0, NULL, NULL);
56
57 Status = ZwCreateFile(&hFile,
58 dwDesiredAccess,
59 &ObjectAttributes,
60 &IoStatusBlock,
61 NULL,
62 FILE_ATTRIBUTE_NORMAL,
63 0,
64 FILE_OPEN,
65 FILE_NON_DIRECTORY_FILE,
66 NULL,
67 0);
68 if (!NT_SUCCESS(Status))
69 {
70 SetLastNtError(Status);
71 hFile = NULL;
72 }
73
74 DPRINT("Leaving W32kOpenFile, Status=0x%x, hFile=0x%x\n", Status, hFile);
75 return hFile;
76 }
77
78 HANDLE
79 NTAPI
80 W32kCreateFileSection(HANDLE hFile,
81 ULONG flAllocation,
82 DWORD flPageProtection,
83 ULONGLONG ullMaxSize)
84 {
85 NTSTATUS Status;
86 HANDLE hSection = NULL;
87 ACCESS_MASK amDesiredAccess;
88
89 /* Set access mask */
90 amDesiredAccess = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
91
92 /* Check if write access is requested */
93 if (flPageProtection == PAGE_READWRITE)
94 {
95 /* Add it to access mask */
96 amDesiredAccess |= SECTION_MAP_WRITE;
97 }
98
99 /* Now create the actual section */
100 Status = ZwCreateSection(&hSection,
101 amDesiredAccess,
102 NULL,
103 NULL,
104 flPageProtection,
105 flAllocation,
106 hFile);
107 if (!NT_SUCCESS(Status))
108 {
109 SetLastNtError(Status);
110 }
111
112 DPRINT("Leaving W32kCreateFileSection, Status=0x%x, hSection=0x%x\n", Status, hSection);
113
114 /* Return section handle */
115 return hSection;
116 }
117
118 PVOID
119 NTAPI
120 W32kMapViewOfSection(
121 HANDLE hSection,
122 DWORD dwPageProtect,
123 ULONG_PTR ulSectionOffset)
124 {
125 NTSTATUS Status;
126 LARGE_INTEGER liSectionOffset;
127 ULONG_PTR ulViewSize;
128 PVOID pvBase = 0;
129
130 ulViewSize =
131 liSectionOffset.QuadPart = ulSectionOffset;
132 Status = ZwMapViewOfSection(hSection,
133 NtCurrentProcess(),
134 &pvBase,
135 0,
136 0,
137 &liSectionOffset,
138 &ulViewSize,
139 ViewShare,
140 0,
141 dwPageProtect);
142 if (!NT_SUCCESS(Status))
143 {
144 SetLastNtError(Status);
145 }
146
147 DPRINT("Leaving W32kMapViewOfSection, Status=0x%x, pvBase=0x%x\n", Status, pvBase);
148
149 return pvBase;
150 }
151
152 typedef struct tagBITMAPV5INFO
153 {
154 BITMAPV5HEADER bmiHeader;
155 RGBQUAD bmiColors[256];
156 } BITMAPV5INFO, *PBITMAPV5INFO;
157
158 // FIXME: this should go to dibobj.c
159 NTSTATUS
160 ProbeAndConvertBitmapInfo(
161 OUT BITMAPV5HEADER *pbmhDst,
162 OUT RGBQUAD *pbmiColorsDst,
163 ULONG cColors,
164 IN PBITMAPINFO pbmiUnsafe)
165 {
166 DWORD dwSize;
167 RGBQUAD *pbmiColors;
168 ULONG ulWidthBytes;
169
170 /* Get the size and probe */
171 ProbeForRead(&pbmiUnsafe->bmiHeader.biSize, sizeof(DWORD), 1);
172 dwSize = pbmiUnsafe->bmiHeader.biSize;
173 ProbeForRead(pbmiUnsafe, dwSize, 1);
174
175 /* Check the size */
176 // FIXME: are intermediate sizes allowed? As what are they interpreted?
177 // make sure we don't use a too big dwSize later
178 if (dwSize != sizeof(BITMAPCOREHEADER) &&
179 dwSize != sizeof(BITMAPINFOHEADER) &&
180 dwSize != sizeof(BITMAPV4HEADER) &&
181 dwSize != sizeof(BITMAPV5HEADER))
182 {
183 return STATUS_INVALID_PARAMETER;
184 }
185
186 pbmiColors = (RGBQUAD*)((PCHAR)pbmiUnsafe + dwSize);
187
188 pbmhDst->bV5Size = sizeof(BITMAPV5HEADER);
189
190 if (dwSize == sizeof(BITMAPCOREHEADER))
191 {
192 PBITMAPCOREHEADER pbch = (PBITMAPCOREHEADER)pbmiUnsafe;
193
194 /* Manually copy the fields that are present */
195 pbmhDst->bV5Width = pbch->bcWidth;
196 pbmhDst->bV5Height = pbch->bcHeight;
197 pbmhDst->bV5Planes = pbch->bcPlanes;
198 pbmhDst->bV5BitCount = pbch->bcBitCount;
199
200 /* Set some default values */
201 pbmhDst->bV5Compression = BI_RGB;
202 pbmhDst->bV5SizeImage = 0;
203 pbmhDst->bV5XPelsPerMeter = 72;
204 pbmhDst->bV5YPelsPerMeter = 72;
205 pbmhDst->bV5ClrUsed = 0;
206 pbmhDst->bV5ClrImportant = 0;
207 }
208 else
209 {
210 /* Copy valid fields */
211 memcpy(pbmhDst, pbmiUnsafe, dwSize);
212
213 /* Zero out the rest of the V5 header */
214 memset((char*)pbmhDst + dwSize, 0, sizeof(BITMAPV5HEADER) - dwSize);
215 }
216
217
218 if (dwSize < sizeof(BITMAPV4HEADER))
219 {
220 if (pbmhDst->bV5Compression == BI_BITFIELDS)
221 {
222 DWORD *pMasks = (DWORD*)pbmiColors;
223 pbmhDst->bV5RedMask = pMasks[0];
224 pbmhDst->bV5GreenMask = pMasks[1];
225 pbmhDst->bV5BlueMask = pMasks[2];
226 pbmhDst->bV5AlphaMask = 0;
227 pbmhDst->bV5ClrUsed = 0;
228 }
229
230 // pbmhDst->bV5CSType;
231 // pbmhDst->bV5Endpoints;
232 // pbmhDst->bV5GammaRed;
233 // pbmhDst->bV5GammaGreen;
234 // pbmhDst->bV5GammaBlue;
235 }
236
237 if (dwSize < sizeof(BITMAPV5HEADER))
238 {
239 // pbmhDst->bV5Intent;
240 // pbmhDst->bV5ProfileData;
241 // pbmhDst->bV5ProfileSize;
242 // pbmhDst->bV5Reserved;
243 }
244
245 ulWidthBytes = ((pbmhDst->bV5Width * pbmhDst->bV5Planes *
246 pbmhDst->bV5BitCount + 31) & ~31) / 8;
247
248 if (pbmhDst->bV5SizeImage == 0)
249 pbmhDst->bV5SizeImage = abs(ulWidthBytes * pbmhDst->bV5Height);
250
251 if (pbmhDst->bV5ClrUsed == 0)
252 pbmhDst->bV5ClrUsed = pbmhDst->bV5BitCount == 1 ? 2 :
253 (pbmhDst->bV5BitCount == 4 ? 16 :
254 (pbmhDst->bV5BitCount == 8 ? 256 : 0));
255
256 if (pbmhDst->bV5Planes != 1)
257 {
258 return STATUS_INVALID_PARAMETER;
259 }
260
261 if (pbmhDst->bV5BitCount != 0 && pbmhDst->bV5BitCount != 1 &&
262 pbmhDst->bV5BitCount != 4 && pbmhDst->bV5BitCount != 8 &&
263 pbmhDst->bV5BitCount != 16 && pbmhDst->bV5BitCount != 24 &&
264 pbmhDst->bV5BitCount != 32)
265 {
266 DPRINT("Invalid bit count: %d\n", pbmhDst->bV5BitCount);
267 return STATUS_INVALID_PARAMETER;
268 }
269
270 if ((pbmhDst->bV5BitCount == 0 &&
271 pbmhDst->bV5Compression != BI_JPEG && pbmhDst->bV5Compression != BI_PNG))
272 {
273 DPRINT("Bit count 0 is invalid for compression %d.\n", pbmhDst->bV5Compression);
274 return STATUS_INVALID_PARAMETER;
275 }
276
277 if (pbmhDst->bV5Compression == BI_BITFIELDS &&
278 pbmhDst->bV5BitCount != 16 && pbmhDst->bV5BitCount != 32)
279 {
280 DPRINT("Bit count %d is invalid for compression BI_BITFIELDS.\n", pbmhDst->bV5BitCount);
281 return STATUS_INVALID_PARAMETER;
282 }
283
284 /* Copy Colors */
285 cColors = min(cColors, pbmhDst->bV5ClrUsed);
286 memcpy(pbmiColorsDst, pbmiColors, cColors * sizeof(RGBQUAD));
287
288 return STATUS_SUCCESS;
289 }
290
291
292 HBITMAP
293 NTAPI
294 UserLoadImage(PCWSTR pwszName)
295 {
296 NTSTATUS Status;
297 HANDLE hFile, hSection;
298 BITMAPFILEHEADER *pbmfh;
299 LPBITMAPINFO pbmi;
300 ULONG cjInfoSize;
301 PVOID pvBits;
302 HBITMAP hbmp = 0;
303 BITMAPV5INFO bmiLocal;
304
305 DPRINT("Enter UserLoadImage(%ls)\n", pwszName);
306
307 /* Open the file */
308 hFile = W32kOpenFile(pwszName, FILE_READ_DATA);
309 if (!hFile)
310 {
311 return NULL;
312 }
313
314 /* Create a section */
315 hSection = W32kCreateFileSection(hFile, SEC_COMMIT, PAGE_READONLY, 0);
316 ZwClose(hFile);
317 if (!hSection)
318 {
319 return NULL;
320 }
321
322 /* Map the section */
323 pbmfh = W32kMapViewOfSection(hSection, PAGE_READONLY, 0);
324 ZwClose(hSection);
325 if (!pbmfh)
326 {
327 return NULL;
328 }
329
330 /* Get a pointer to the BITMAPINFO */
331 pbmi = (LPBITMAPINFO)(pbmfh + 1);
332
333 /* Create a normalized local BITMAPINFO */
334 _SEH2_TRY
335 {
336 Status = ProbeAndConvertBitmapInfo(&bmiLocal.bmiHeader,
337 bmiLocal.bmiColors,
338 256,
339 pbmi);
340 }
341 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
342 {
343 Status = _SEH2_GetExceptionCode();
344 }
345 _SEH2_END
346
347 if (NT_SUCCESS(Status))
348 {
349 cjInfoSize = bmiLocal.bmiHeader.bV5Size +
350 bmiLocal.bmiHeader.bV5ClrUsed * sizeof(RGBQUAD);
351 pvBits = (PVOID)((PCHAR)pbmi + cjInfoSize);
352
353 // FIXME: use Gre... so that the BITMAPINFO doesn't get probed
354 hbmp = NtGdiCreateDIBitmapInternal(NULL,
355 bmiLocal.bmiHeader.bV5Width,
356 bmiLocal.bmiHeader.bV5Height,
357 CBM_INIT,
358 pvBits,
359 pbmi,
360 DIB_RGB_COLORS,
361 bmiLocal.bmiHeader.bV5Size,
362 bmiLocal.bmiHeader.bV5SizeImage,
363 0,
364 0);
365 }
366
367 /* Unmap our section, we don't need it anymore */
368 ZwUnmapViewOfSection(NtCurrentProcess(), pbmfh);
369
370 DPRINT("Leaving UserLoadImage, hbmp = %p\n", hbmp);
371 return hbmp;
372 }