[WIN32SS][FONT] Fix font metrics (#713)
[reactos.git] / win32ss / gdi / eng / mapping.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Functions for mapping files and sections
5 * FILE: win32ss/gdi/eng/mapping.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 HANDLE ghSystem32Directory;
15 HANDLE ghRootDirectory;
16
17 PVOID
18 NTAPI
19 EngMapSectionView(
20 _In_ HANDLE hSection,
21 _In_ SIZE_T cjSize,
22 _In_ ULONG cjOffset,
23 _Out_ PHANDLE phSecure)
24 {
25 LARGE_INTEGER liSectionOffset;
26 PVOID pvBaseAddress;
27 NTSTATUS Status;
28
29 /* Check if the size is ok (for 64 bit) */
30 if (cjSize > ULONG_MAX)
31 {
32 DPRINT1("chSize out of range: 0x%Id\n", cjSize);
33 return NULL;
34 }
35
36 /* Align the offset at allocation granularity and compensate for the size */
37 liSectionOffset.QuadPart = cjOffset & ~(MM_ALLOCATION_GRANULARITY - 1);
38 cjSize += cjOffset & (MM_ALLOCATION_GRANULARITY - 1);
39
40 /* Map the section */
41 Status = ZwMapViewOfSection(hSection,
42 NtCurrentProcess(),
43 &pvBaseAddress,
44 0,
45 cjSize,
46 &liSectionOffset,
47 &cjSize,
48 ViewShare,
49 0,
50 PAGE_READWRITE);
51 if (!NT_SUCCESS(Status))
52 {
53 DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status);
54 return NULL;
55 }
56
57 /* Secure the section memory */
58 *phSecure = EngSecureMem(pvBaseAddress, (ULONG)cjSize);
59 if (!*phSecure)
60 {
61 ZwUnmapViewOfSection(NtCurrentProcess(), pvBaseAddress);
62 return NULL;
63 }
64
65 /* Return the address where the requested data starts */
66 return (PUCHAR)pvBaseAddress + (cjOffset & (MM_ALLOCATION_GRANULARITY - 1));
67 }
68
69 VOID
70 NTAPI
71 EngUnmapSectionView(
72 _In_ PVOID pvBits,
73 _In_ ULONG cjOffset,
74 _In_ HANDLE hSecure)
75 {
76 NTSTATUS Status;
77
78 /* Unsecure the memory */
79 EngUnsecureMem(hSecure);
80
81 /* Calculate the real start of the section view */
82 pvBits = (PUCHAR)pvBits - (cjOffset & (MM_ALLOCATION_GRANULARITY - 1));
83
84 /* Unmap the section view */
85 Status = MmUnmapViewOfSection(PsGetCurrentProcess(), pvBits);
86 ASSERT(NT_SUCCESS(Status));
87 }
88
89 PVOID
90 NTAPI
91 EngCreateSection(
92 _In_ ULONG fl,
93 _In_ SIZE_T cjSize,
94 _In_ ULONG ulTag)
95 {
96 NTSTATUS Status;
97 PENGSECTION pSection;
98 PVOID pvSectionObject;
99 LARGE_INTEGER liSize;
100
101 /* Allocate a section object */
102 pSection = EngAllocMem(0, sizeof(ENGSECTION), 'stsU');
103 if (!pSection) return NULL;
104
105 liSize.QuadPart = cjSize;
106 Status = MmCreateSection(&pvSectionObject,
107 SECTION_ALL_ACCESS,
108 NULL,
109 &liSize,
110 PAGE_READWRITE,
111 SEC_COMMIT,
112 NULL,
113 NULL);
114 if (!NT_SUCCESS(Status))
115 {
116 DPRINT1("Failed to create a section Status=0x%x\n", Status);
117 EngFreeMem(pSection);
118 return NULL;
119 }
120
121 /* Set the fields of the section */
122 pSection->ulTag = ulTag;
123 pSection->pvSectionObject = pvSectionObject;
124 pSection->pvMappedBase = NULL;
125 pSection->cjViewSize = cjSize;
126
127 return pSection;
128 }
129
130 PVOID
131 NTAPI
132 EngCreateSectionHack(
133 _In_ ULONG fl,
134 _In_ SIZE_T cjSize,
135 _In_ ULONG ulTag)
136 {
137 NTSTATUS Status;
138 PENGSECTION pSection;
139 PVOID pvSectionObject;
140 LARGE_INTEGER liSize;
141
142 /* Allocate a section object */
143 pSection = EngAllocMem(0, sizeof(ENGSECTION), 'stsU');
144 if (!pSection) return NULL;
145
146 liSize.QuadPart = cjSize;
147 Status = MmCreateSection(&pvSectionObject,
148 SECTION_ALL_ACCESS,
149 NULL,
150 &liSize,
151 PAGE_READWRITE,
152 SEC_COMMIT | 1,
153 NULL,
154 NULL);
155 if (!NT_SUCCESS(Status))
156 {
157 DPRINT1("Failed to create a section Status=0x%x\n", Status);
158 EngFreeMem(pSection);
159 return NULL;
160 }
161
162 /* Set the fields of the section */
163 pSection->ulTag = ulTag;
164 pSection->pvSectionObject = pvSectionObject;
165 pSection->pvMappedBase = NULL;
166 pSection->cjViewSize = cjSize;
167
168 return pSection;
169 }
170
171 _Success_(return!=FALSE)
172 BOOL
173 APIENTRY
174 EngMapSection(
175 _In_ PVOID pvSection,
176 _In_ BOOL bMap,
177 _In_ HANDLE hProcess,
178 _When_(bMap, _Outptr_) PVOID* pvBaseAddress)
179 {
180 NTSTATUS Status;
181 PENGSECTION pSection = pvSection;
182 PEPROCESS pepProcess;
183
184 /* Get a pointer to the process */
185 Status = ObReferenceObjectByHandle(hProcess,
186 PROCESS_VM_OPERATION,
187 NULL,
188 KernelMode,
189 (PVOID*)&pepProcess,
190 NULL);
191 if (!NT_SUCCESS(Status))
192 {
193 DPRINT1("Could not access process %p, Status=0x%lx\n", hProcess, Status);
194 return FALSE;
195 }
196
197 if (bMap)
198 {
199 /* Make sure the section isn't already mapped */
200 ASSERT(pSection->pvMappedBase == NULL);
201
202 /* Map the section into the process address space */
203 Status = MmMapViewOfSection(pSection->pvSectionObject,
204 pepProcess,
205 &pSection->pvMappedBase,
206 0,
207 pSection->cjViewSize,
208 NULL,
209 &pSection->cjViewSize,
210 0,
211 0,
212 PAGE_READWRITE);
213 if (!NT_SUCCESS(Status))
214 {
215 DPRINT1("Failed to map a section Status=0x%x\n", Status);
216 }
217 }
218 else
219 {
220 /* Make sure the section is mapped */
221 ASSERT(pSection->pvMappedBase);
222
223 /* Unmap the section from the process address space */
224 Status = MmUnmapViewOfSection(pepProcess, pSection->pvMappedBase);
225 if (NT_SUCCESS(Status))
226 {
227 pSection->pvMappedBase = NULL;
228 }
229 else
230 {
231 DPRINT1("Failed to unmap a section @ %p Status=0x%x\n",
232 pSection->pvMappedBase, Status);
233 }
234 }
235
236 /* Dereference the process */
237 ObDereferenceObject(pepProcess);
238
239 /* Set the new mapping base and return bool status */
240 *pvBaseAddress = pSection->pvMappedBase;
241 return NT_SUCCESS(Status);
242 }
243
244 BOOL
245 APIENTRY
246 EngFreeSectionMem(
247 _In_opt_ PVOID pvSection,
248 _In_opt_ PVOID pvMappedBase)
249 {
250 NTSTATUS Status;
251 PENGSECTION pSection = pvSection;
252 BOOL bResult = TRUE;
253
254 /* Did the caller give us a mapping base? */
255 if (pvMappedBase)
256 {
257 Status = MmUnmapViewInSessionSpace(pvMappedBase);
258 if (!NT_SUCCESS(Status))
259 {
260 DPRINT1("MmUnmapViewInSessionSpace failed: 0x%lx\n", Status);
261 bResult = FALSE;
262 }
263 }
264
265 /* Check if we should free the section as well */
266 if (pSection)
267 {
268 /* Dereference the kernel section */
269 ObDereferenceObject(pSection->pvSectionObject);
270
271 /* Finally free the section memory itself */
272 EngFreeMem(pSection);
273 }
274
275 return bResult;
276 }
277
278 _Check_return_
279 _Success_(return!=NULL)
280 __drv_allocatesMem(Mem)
281 _Post_writable_byte_size_(cjSize)
282 PVOID
283 APIENTRY
284 EngAllocSectionMem(
285 _Outptr_ PVOID *ppvSection,
286 _In_ ULONG fl,
287 _In_ SIZE_T cjSize,
288 _In_ ULONG ulTag)
289 {
290 NTSTATUS Status;
291 PENGSECTION pSection;
292
293 /* Check parameter */
294 if (cjSize == 0) return NULL;
295
296 /* Allocate a section object */
297 pSection = EngCreateSectionHack(fl, cjSize, ulTag);
298 if (!pSection)
299 {
300 *ppvSection = NULL;
301 return NULL;
302 }
303
304 /* Map the section in session space */
305 Status = MmMapViewInSessionSpace(pSection->pvSectionObject,
306 &pSection->pvMappedBase,
307 &pSection->cjViewSize);
308 if (!NT_SUCCESS(Status))
309 {
310 DPRINT1("Failed to map a section Status=0x%x\n", Status);
311 *ppvSection = NULL;
312 EngFreeSectionMem(pSection, NULL);
313 return NULL;
314 }
315
316 if (fl & FL_ZERO_MEMORY)
317 {
318 RtlZeroMemory(pSection->pvMappedBase, cjSize);
319 }
320
321 /* Set section pointer and return base address */
322 *ppvSection = pSection;
323 return pSection->pvMappedBase;
324 }
325
326 _Check_return_
327 PFILEVIEW
328 NTAPI
329 EngLoadModuleEx(
330 _In_z_ LPWSTR pwsz,
331 _In_ ULONG cjSizeOfModule,
332 _In_ FLONG fl)
333 {
334 PFILEVIEW pFileView = NULL;
335 OBJECT_ATTRIBUTES ObjectAttributes;
336 HANDLE hRootDir;
337 UNICODE_STRING ustrFileName;
338 IO_STATUS_BLOCK IoStatusBlock;
339 FILE_BASIC_INFORMATION FileInformation;
340 HANDLE hFile;
341 NTSTATUS Status;
342 LARGE_INTEGER liSize;
343
344 if (fl & FVF_FONTFILE)
345 {
346 pFileView = EngAllocMem(0, sizeof(FONTFILEVIEW), 'vffG');
347 }
348 else
349 {
350 pFileView = EngAllocMem(0, sizeof(FILEVIEW), 'liFg');
351 }
352
353 /* Check for success */
354 if (!pFileView) return NULL;
355
356 /* Check if the file is relative to system32 */
357 if (fl & FVF_SYSTEMROOT)
358 {
359 hRootDir = ghSystem32Directory;
360 }
361 else
362 {
363 hRootDir = ghRootDirectory;
364 }
365
366 /* Initialize unicode string and object attributes */
367 RtlInitUnicodeString(&ustrFileName, pwsz);
368 InitializeObjectAttributes(&ObjectAttributes,
369 &ustrFileName,
370 OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
371 hRootDir,
372 NULL);
373
374 /* Now open the file */
375 Status = ZwCreateFile(&hFile,
376 FILE_READ_DATA,
377 &ObjectAttributes,
378 &IoStatusBlock,
379 NULL,
380 FILE_ATTRIBUTE_NORMAL,
381 0,
382 FILE_OPEN,
383 FILE_NON_DIRECTORY_FILE,
384 NULL,
385 0);
386 if (!NT_SUCCESS(Status))
387 {
388 DPRINT1("Failed to open file, hFile=%p, Status=0x%x\n", hFile, Status);
389 EngFreeMem(pFileView);
390 return NULL;
391 }
392
393 Status = ZwQueryInformationFile(hFile,
394 &IoStatusBlock,
395 &FileInformation,
396 sizeof(FILE_BASIC_INFORMATION),
397 FileBasicInformation);
398 if (NT_SUCCESS(Status))
399 {
400 pFileView->LastWriteTime = FileInformation.LastWriteTime;
401 }
402
403 /* Create a section from the file */
404 liSize.QuadPart = cjSizeOfModule;
405 Status = MmCreateSection(&pFileView->pSection,
406 SECTION_ALL_ACCESS,
407 NULL,
408 &liSize,
409 fl & FVF_READONLY ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE,
410 SEC_COMMIT,
411 hFile,
412 NULL);
413
414 /* Close the file handle */
415 ZwClose(hFile);
416
417 if (!NT_SUCCESS(Status))
418 {
419 DPRINT1("Failed to create a section Status=0x%x\n", Status);
420 EngFreeMem(pFileView);
421 return NULL;
422 }
423
424
425 pFileView->pvKView = NULL;
426 pFileView->pvViewFD = NULL;
427 pFileView->cjView = 0;
428
429 return pFileView;
430 }
431
432 HANDLE
433 APIENTRY
434 EngLoadModule(
435 _In_ LPWSTR pwsz)
436 {
437 /* Forward to EngLoadModuleEx */
438 return (HANDLE)EngLoadModuleEx(pwsz, 0, FVF_READONLY | FVF_SYSTEMROOT);
439 }
440
441 HANDLE
442 APIENTRY
443 EngLoadModuleForWrite(
444 _In_ LPWSTR pwsz,
445 _In_ ULONG cjSizeOfModule)
446 {
447 /* Forward to EngLoadModuleEx */
448 return (HANDLE)EngLoadModuleEx(pwsz, cjSizeOfModule, FVF_SYSTEMROOT);
449 }
450
451 _Check_return_
452 _Success_(return!=NULL)
453 _Post_writable_byte_size_(*pulSize)
454 PVOID
455 APIENTRY
456 EngMapModule(
457 _In_ HANDLE h,
458 _Out_ PULONG pulSize)
459 {
460 PFILEVIEW pFileView = (PFILEVIEW)h;
461 NTSTATUS Status;
462
463 pFileView->cjView = 0;
464
465 /* FIXME: Use system space because ARM3 doesn't support executable sections yet */
466 Status = MmMapViewInSystemSpace(pFileView->pSection,
467 &pFileView->pvKView,
468 &pFileView->cjView);
469 if (!NT_SUCCESS(Status))
470 {
471 DPRINT1("Failed to map a section Status=0x%x\n", Status);
472 *pulSize = 0;
473 return NULL;
474 }
475
476 *pulSize = (ULONG)pFileView->cjView;
477 return pFileView->pvKView;
478 }
479
480 VOID
481 APIENTRY
482 EngFreeModule(
483 _In_ _Post_invalid_ HANDLE h)
484 {
485 PFILEVIEW pFileView = (PFILEVIEW)h;
486 NTSTATUS Status;
487
488 /* FIXME: Use system space because ARM3 doesn't support executable sections yet */
489 Status = MmUnmapViewInSystemSpace(pFileView->pvKView);
490 if (!NT_SUCCESS(Status))
491 {
492 DPRINT1("MmUnmapViewInSessionSpace failed: 0x%lx\n", Status);
493 ASSERT(FALSE);
494 }
495
496 /* Dereference the section */
497 ObDereferenceObject(pFileView->pSection);
498
499 /* Free the file view memory */
500 EngFreeMem(pFileView);
501 }
502
503 _Success_(return != 0)
504 _When_(cjSize != 0, _At_(return, _Out_writes_bytes_(cjSize)))
505 PVOID
506 APIENTRY
507 EngMapFile(
508 _In_ LPWSTR pwsz,
509 _In_ ULONG cjSize,
510 _Out_ ULONG_PTR *piFile)
511 {
512 HANDLE hModule;
513 PVOID pvBase;
514
515 /* Load the file */
516 hModule = EngLoadModuleEx(pwsz, 0, 0);
517 if (!hModule)
518 {
519 *piFile = 0;
520 return NULL;
521 }
522
523 /* Map the file */
524 pvBase = EngMapModule(hModule, &cjSize);
525 if (!pvBase)
526 {
527 EngFreeModule(hModule);
528 hModule = NULL;
529 }
530
531 /* Set iFile and return mapped base */
532 *piFile = (ULONG_PTR)hModule;
533 return pvBase;
534 }
535
536 BOOL
537 APIENTRY
538 EngUnmapFile(
539 _In_ ULONG_PTR iFile)
540 {
541 HANDLE hModule = (HANDLE)iFile;
542
543 EngFreeModule(hModule);
544
545 return TRUE;
546 }
547
548 _Check_return_
549 _Success_(return!=FALSE)
550 BOOL
551 APIENTRY
552 EngMapFontFileFD(
553 _In_ ULONG_PTR iFile,
554 _Outptr_result_bytebuffer_(*pcjBuf) PULONG *ppjBuf,
555 _Out_ ULONG *pcjBuf)
556 {
557 // www.osr.com/ddk/graphics/gdifncs_0co7.htm
558 UNIMPLEMENTED;
559 return FALSE;
560 }
561
562 VOID
563 APIENTRY
564 EngUnmapFontFileFD(
565 _In_ ULONG_PTR iFile)
566 {
567 // http://www.osr.com/ddk/graphics/gdifncs_6wbr.htm
568 UNIMPLEMENTED;
569 }
570
571 __drv_preferredFunction("EngMapFontFileFD", "Obsolete")
572 _Check_return_
573 _Success_(return!=FALSE)
574 BOOL
575 APIENTRY
576 EngMapFontFile(
577 _In_ ULONG_PTR iFile,
578 _Outptr_result_bytebuffer_(*pcjBuf) PULONG *ppjBuf,
579 _Out_ ULONG *pcjBuf)
580 {
581 // www.osr.com/ddk/graphics/gdifncs_3up3.htm
582 return EngMapFontFileFD(iFile, ppjBuf, pcjBuf);
583 }
584
585 VOID
586 APIENTRY
587 EngUnmapFontFile(
588 _In_ ULONG_PTR iFile)
589 {
590 // www.osr.com/ddk/graphics/gdifncs_09wn.htm
591 EngUnmapFontFileFD(iFile);
592 }