reactos/subsystems/win32/win32k/misc/file.c
Jérôme Gardou 88c9e7c6e8 Sync with trunk (r47116), hopefully without breaking anything.
svn path=/branches/reactos-yarotows/; revision=47117
2010-05-07 07:41:13 +00:00

373 lines
10 KiB
C

/*
* COPYRIGHT: GPL, see COPYING in the top level directory
* PROJECT: ReactOS win32 kernel mode subsystem server
* PURPOSE: File access support routines
* FILE: subsystem/win32/win32k/misc/registry.c
* PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
#include <win32k.h>
#define NDEBUG
#include <debug.h>
BOOL
NTAPI
W32kDosPathNameToNtPathName(
IN PCWSTR pwszDosPathName,
OUT PUNICODE_STRING pustrNtPathName)
{
NTSTATUS Status;
/* Prepend "\??\" */
pustrNtPathName->Length = 0;
Status = RtlAppendUnicodeToString(pustrNtPathName, L"\\??\\");
if (!NT_SUCCESS(Status))
{
return FALSE;
}
/* Append the dos name */
Status = RtlAppendUnicodeToString(pustrNtPathName, pwszDosPathName);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
return TRUE;
}
HANDLE
NTAPI
W32kOpenFile(PCWSTR pwszFileName, DWORD dwDesiredAccess)
{
UNICODE_STRING ustrFile;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE hFile = INVALID_HANDLE_VALUE;
NTSTATUS Status;
DPRINT("W32kOpenFile(%S)\n", pwszFileName);
RtlInitUnicodeString(&ustrFile, pwszFileName);
InitializeObjectAttributes(&ObjectAttributes, &ustrFile, 0, NULL, NULL);
Status = ZwCreateFile(&hFile,
dwDesiredAccess,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
hFile = NULL;
}
DPRINT("Leaving W32kOpenFile, Status=0x%x, hFile=0x%x\n", Status, hFile);
return hFile;
}
HANDLE
NTAPI
W32kCreateFileSection(HANDLE hFile,
ULONG flAllocation,
DWORD flPageProtection,
ULONGLONG ullMaxSize)
{
NTSTATUS Status;
HANDLE hSection = NULL;
ACCESS_MASK amDesiredAccess;
/* Set access mask */
amDesiredAccess = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
/* Check if write access is requested */
if (flPageProtection == PAGE_READWRITE)
{
/* Add it to access mask */
amDesiredAccess |= SECTION_MAP_WRITE;
}
/* Now create the actual section */
Status = ZwCreateSection(&hSection,
amDesiredAccess,
NULL,
NULL,
flPageProtection,
flAllocation,
hFile);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
}
DPRINT("Leaving W32kCreateFileSection, Status=0x%x, hSection=0x%x\n", Status, hSection);
/* Return section handle */
return hSection;
}
PVOID
NTAPI
W32kMapViewOfSection(
HANDLE hSection,
DWORD dwPageProtect,
ULONG_PTR ulSectionOffset)
{
NTSTATUS Status;
LARGE_INTEGER liSectionOffset;
ULONG_PTR ulViewSize;
PVOID pvBase = 0;
ulViewSize =
liSectionOffset.QuadPart = ulSectionOffset;
Status = ZwMapViewOfSection(hSection,
NtCurrentProcess(),
&pvBase,
0,
0,
&liSectionOffset,
&ulViewSize,
ViewShare,
0,
dwPageProtect);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
}
DPRINT("Leaving W32kMapViewOfSection, Status=0x%x, pvBase=0x%x\n", Status, pvBase);
return pvBase;
}
typedef struct tagBITMAPV5INFO
{
BITMAPV5HEADER bmiHeader;
RGBQUAD bmiColors[256];
} BITMAPV5INFO, *PBITMAPV5INFO;
// FIXME: this should go to dibobj.c
NTSTATUS
ProbeAndConvertBitmapInfo(
OUT BITMAPV5HEADER *pbmhDst,
OUT RGBQUAD *pbmiColorsDst,
ULONG cColors,
IN PBITMAPINFO pbmiUnsafe)
{
DWORD dwSize;
RGBQUAD *pbmiColors;
ULONG ulWidthBytes;
/* Get the size and probe */
ProbeForRead(&pbmiUnsafe->bmiHeader.biSize, sizeof(DWORD), 1);
dwSize = pbmiUnsafe->bmiHeader.biSize;
ProbeForRead(pbmiUnsafe, dwSize, 1);
/* Check the size */
// FIXME: are intermediate sizes allowed? As what are they interpreted?
// make sure we don't use a too big dwSize later
if (dwSize != sizeof(BITMAPCOREHEADER) &&
dwSize != sizeof(BITMAPINFOHEADER) &&
dwSize != sizeof(BITMAPV4HEADER) &&
dwSize != sizeof(BITMAPV5HEADER))
{
return STATUS_INVALID_PARAMETER;
}
pbmiColors = (RGBQUAD*)((PCHAR)pbmiUnsafe + dwSize);
pbmhDst->bV5Size = sizeof(BITMAPV5HEADER);
if (dwSize == sizeof(BITMAPCOREHEADER))
{
PBITMAPCOREHEADER pbch = (PBITMAPCOREHEADER)pbmiUnsafe;
/* Manually copy the fields that are present */
pbmhDst->bV5Width = pbch->bcWidth;
pbmhDst->bV5Height = pbch->bcHeight;
pbmhDst->bV5Planes = pbch->bcPlanes;
pbmhDst->bV5BitCount = pbch->bcBitCount;
/* Set some default values */
pbmhDst->bV5Compression = BI_RGB;
pbmhDst->bV5SizeImage = 0;
pbmhDst->bV5XPelsPerMeter = 72;
pbmhDst->bV5YPelsPerMeter = 72;
pbmhDst->bV5ClrUsed = 0;
pbmhDst->bV5ClrImportant = 0;
}
else
{
/* Copy valid fields */
memcpy(pbmhDst, pbmiUnsafe, dwSize);
/* Zero out the rest of the V5 header */
memset((char*)pbmhDst + dwSize, 0, sizeof(BITMAPV5HEADER) - dwSize);
}
if (dwSize < sizeof(BITMAPV4HEADER))
{
if (pbmhDst->bV5Compression == BI_BITFIELDS)
{
DWORD *pMasks = (DWORD*)pbmiColors;
pbmhDst->bV5RedMask = pMasks[0];
pbmhDst->bV5GreenMask = pMasks[1];
pbmhDst->bV5BlueMask = pMasks[2];
pbmhDst->bV5AlphaMask = 0;
pbmhDst->bV5ClrUsed = 0;
}
// pbmhDst->bV5CSType;
// pbmhDst->bV5Endpoints;
// pbmhDst->bV5GammaRed;
// pbmhDst->bV5GammaGreen;
// pbmhDst->bV5GammaBlue;
}
if (dwSize < sizeof(BITMAPV5HEADER))
{
// pbmhDst->bV5Intent;
// pbmhDst->bV5ProfileData;
// pbmhDst->bV5ProfileSize;
// pbmhDst->bV5Reserved;
}
ulWidthBytes = ((pbmhDst->bV5Width * pbmhDst->bV5Planes *
pbmhDst->bV5BitCount + 31) & ~31) / 8;
if (pbmhDst->bV5SizeImage == 0)
pbmhDst->bV5SizeImage = abs(ulWidthBytes * pbmhDst->bV5Height);
if (pbmhDst->bV5ClrUsed == 0)
pbmhDst->bV5ClrUsed = pbmhDst->bV5BitCount == 1 ? 2 :
(pbmhDst->bV5BitCount == 4 ? 16 :
(pbmhDst->bV5BitCount == 8 ? 256 : 0));
if (pbmhDst->bV5Planes != 1)
{
return STATUS_INVALID_PARAMETER;
}
if (pbmhDst->bV5BitCount != 0 && pbmhDst->bV5BitCount != 1 &&
pbmhDst->bV5BitCount != 4 && pbmhDst->bV5BitCount != 8 &&
pbmhDst->bV5BitCount != 16 && pbmhDst->bV5BitCount != 24 &&
pbmhDst->bV5BitCount != 32)
{
DPRINT("Invalid bit count: %d\n", pbmhDst->bV5BitCount);
return STATUS_INVALID_PARAMETER;
}
if ((pbmhDst->bV5BitCount == 0 &&
pbmhDst->bV5Compression != BI_JPEG && pbmhDst->bV5Compression != BI_PNG))
{
DPRINT("Bit count 0 is invalid for compression %d.\n", pbmhDst->bV5Compression);
return STATUS_INVALID_PARAMETER;
}
if (pbmhDst->bV5Compression == BI_BITFIELDS &&
pbmhDst->bV5BitCount != 16 && pbmhDst->bV5BitCount != 32)
{
DPRINT("Bit count %d is invalid for compression BI_BITFIELDS.\n", pbmhDst->bV5BitCount);
return STATUS_INVALID_PARAMETER;
}
/* Copy Colors */
cColors = min(cColors, pbmhDst->bV5ClrUsed);
memcpy(pbmiColorsDst, pbmiColors, cColors * sizeof(RGBQUAD));
return STATUS_SUCCESS;
}
HBITMAP
NTAPI
UserLoadImage(PCWSTR pwszName)
{
NTSTATUS Status;
HANDLE hFile, hSection;
BITMAPFILEHEADER *pbmfh;
LPBITMAPINFO pbmi;
ULONG cjInfoSize;
PVOID pvBits;
HBITMAP hbmp = 0;
BITMAPV5INFO bmiLocal;
DPRINT("Enter UserLoadImage(%ls)\n", pwszName);
/* Open the file */
hFile = W32kOpenFile(pwszName, FILE_READ_DATA);
if (!hFile)
{
return NULL;
}
/* Create a section */
hSection = W32kCreateFileSection(hFile, SEC_COMMIT, PAGE_READONLY, 0);
ZwClose(hFile);
if (!hSection)
{
return NULL;
}
/* Map the section */
pbmfh = W32kMapViewOfSection(hSection, PAGE_READONLY, 0);
ZwClose(hSection);
if (!pbmfh)
{
return NULL;
}
/* Get a pointer to the BITMAPINFO */
pbmi = (LPBITMAPINFO)(pbmfh + 1);
/* Create a normalized local BITMAPINFO */
_SEH2_TRY
{
Status = ProbeAndConvertBitmapInfo(&bmiLocal.bmiHeader,
bmiLocal.bmiColors,
256,
pbmi);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if (NT_SUCCESS(Status))
{
cjInfoSize = bmiLocal.bmiHeader.bV5Size +
bmiLocal.bmiHeader.bV5ClrUsed * sizeof(RGBQUAD);
pvBits = (PVOID)((PCHAR)pbmi + cjInfoSize);
// FIXME: use Gre... so that the BITMAPINFO doesn't get probed
hbmp = NtGdiCreateDIBitmapInternal(NULL,
bmiLocal.bmiHeader.bV5Width,
bmiLocal.bmiHeader.bV5Height,
CBM_INIT,
pvBits,
pbmi,
DIB_RGB_COLORS,
bmiLocal.bmiHeader.bV5Size,
bmiLocal.bmiHeader.bV5SizeImage,
0,
0);
}
/* Unmap our section, we don't need it anymore */
ZwUnmapViewOfSection(NtCurrentProcess(), pbmfh);
DPRINT("Leaving UserLoadImage, hbmp = %p\n", hbmp);
return hbmp;
}